From b4d23a6106c3e7f1b343094921b0ade2f203fb53 Mon Sep 17 00:00:00 2001 From: Wu Clan Date: Fri, 17 Jan 2025 00:16:50 +0800 Subject: [PATCH 1/3] Add response model include data schema --- backend/common/pagination.py | 91 +++++++++++++++------- backend/common/response/response_schema.py | 43 +++++++--- backend/pyproject.toml | 2 +- backend/requirements.txt | 2 +- backend/uv.lock | 9 +-- 5 files changed, 104 insertions(+), 43 deletions(-) diff --git a/backend/common/pagination.py b/backend/common/pagination.py index 6e7f0a74..9a0b2685 100644 --- a/backend/common/pagination.py +++ b/backend/common/pagination.py @@ -2,27 +2,25 @@ # -*- coding: utf-8 -*- from __future__ import annotations -import math - -from typing import TYPE_CHECKING, Dict, Generic, Sequence, TypeVar +from math import ceil +from typing import TYPE_CHECKING, Generic, Sequence, TypeVar from fastapi import Depends, Query from fastapi_pagination import pagination_ctx from fastapi_pagination.bases import AbstractPage, AbstractParams, RawParams from fastapi_pagination.ext.sqlalchemy import paginate from fastapi_pagination.links.bases import create_links -from pydantic import BaseModel +from pydantic import BaseModel, Field if TYPE_CHECKING: from sqlalchemy import Select from sqlalchemy.ext.asyncio import AsyncSession T = TypeVar('T') -DataT = TypeVar('DataT') SchemaT = TypeVar('SchemaT') -class _Params(BaseModel, AbstractParams): +class _CustomPageParams(BaseModel, AbstractParams): page: int = Query(1, ge=1, description='Page number') size: int = Query(20, gt=0, le=100, description='Page size') # 默认 20 条记录 @@ -33,53 +31,92 @@ def to_raw_params(self) -> RawParams: ) -class _Page(AbstractPage[T], Generic[T]): - items: Sequence[T] # 数据 - total: int # 总数据数 - page: int # 第n页 - size: int # 每页数量 - total_pages: int # 总页数 - links: Dict[str, str | None] # 跳转链接 +class _Links(BaseModel): + first: str = Field(..., description='首页链接') + last: str = Field(..., description='尾页链接') + self: str = Field(..., description='当前页链接') + next: str | None = Field(None, description='下一页链接') + prev: str | None = Field(None, description='上一页链接') + + +class _PageDetails(BaseModel): + items: Sequence[SchemaT] = Field(description='当前页数据') + total: int = Field(..., description='总条数') + page: int = Field(..., description='当前页') + size: int = Field(..., description='每页数量') + total_pages: int = Field(..., description='总页数') + links: _Links + - __params_type__ = _Params # 使用自定义的Params +class _CustomPage(_PageDetails, AbstractPage[T], Generic[T]): + __params_type__ = _CustomPageParams @classmethod def create( cls, - items: Sequence[T], + items: Sequence[SchemaT], total: int, - params: _Params, - ) -> _Page[T]: + params: _CustomPageParams, + ) -> _CustomPage[T]: page = params.page size = params.size - total_pages = math.ceil(total / params.size) + total_pages = ceil(total / params.size) links = create_links(**{ 'first': {'page': 1, 'size': f'{size}'}, - 'last': {'page': f'{math.ceil(total / params.size)}', 'size': f'{size}'} if total > 0 else None, + 'last': {'page': f'{ceil(total / params.size)}', 'size': f'{size}'} if total > 0 else 1, 'next': {'page': f'{page + 1}', 'size': f'{size}'} if (page + 1) <= total_pages else None, 'prev': {'page': f'{page - 1}', 'size': f'{size}'} if (page - 1) >= 1 else None, }).model_dump() - return cls(items=items, total=total, page=params.page, size=params.size, total_pages=total_pages, links=links) + return cls( + items=items, + total=total, + page=params.page, + size=params.size, + total_pages=total_pages, + links=links, + ) + + +class PageData(_PageDetails, Generic[SchemaT]): + """ + 包含 data schema 的统一返回模型,适用于分页接口 + + E.g. :: + + @router.get('/test', response_model=ResponseSchemaModel[PageData[GetApiListDetails]]) + def test(): + return ResponseSchemaModel[PageData[GetApiListDetails]](data=GetApiListDetails(...)) + + @router.get('/test') + def test() -> ResponseSchemaModel[PageData[GetApiListDetails]]: + return ResponseSchemaModel[PageData[GetApiListDetails]](data=GetApiListDetails(...)) + + + @router.get('/test') + def test() -> ResponseSchemaModel[PageData[GetApiListDetails]]: + res = CustomResponseCode.HTTP_200 + return ResponseSchemaModel[PageData[GetApiListDetails]]( + code=res.code, msg=res.msg, data=GetApiListDetails(...) + ) + """ -class _PageData(BaseModel, Generic[DataT]): - page_data: DataT | None = None + ... -async def paging_data(db: AsyncSession, select: Select, page_data_schema: SchemaT) -> dict: +async def paging_data(db: AsyncSession, select: Select) -> dict: """ 基于 SQLAlchemy 创建分页数据 :param db: :param select: - :param page_data_schema: :return: """ - _paginate = await paginate(db, select) - page_data = _PageData[_Page[page_data_schema]](page_data=_paginate).model_dump()['page_data'] + paginated_data: _CustomPage = await paginate(db, select) + page_data = paginated_data.model_dump() return page_data # 分页依赖注入 -DependsPagination = Depends(pagination_ctx(_Page)) +DependsPagination = Depends(pagination_ctx(_CustomPage)) diff --git a/backend/common/response/response_schema.py b/backend/common/response/response_schema.py index 068483c1..fefa1fc0 100644 --- a/backend/common/response/response_schema.py +++ b/backend/common/response/response_schema.py @@ -1,7 +1,7 @@ #!/usr/bin/env python3 # -*- coding: utf-8 -*- from datetime import datetime -from typing import Any +from typing import Any, Generic, TypeVar from fastapi import Response from pydantic import BaseModel, ConfigDict @@ -10,14 +10,12 @@ from backend.core.conf import settings from backend.utils.serializers import MsgSpecJSONResponse -_ExcludeData = set[int | str] | dict[int | str, Any] - -__all__ = ['ResponseModel', 'response_base'] +SchemaT = TypeVar('SchemaT') class ResponseModel(BaseModel): """ - 统一返回模型 + 通用型统一返回模型,不包含 data 数据结构 E.g. :: @@ -45,6 +43,31 @@ def test() -> ResponseModel: data: Any | None = None +class ResponseSchemaModel(ResponseModel, Generic[SchemaT]): + """ + 包含 data schema 的统一返回模型,适用于非分页接口 + + E.g. :: + + @router.get('/test', response_model=ResponseSchemaModel[GetApiListDetails]) + def test(): + return ResponseSchemaModel[GetApiListDetails](data=GetApiListDetails(...)) + + + @router.get('/test') + def test() -> ResponseSchemaModel[GetApiListDetails]: + return ResponseSchemaModel[GetApiListDetails](data=GetApiListDetails(...)) + + + @router.get('/test') + def test() -> ResponseSchemaModel[GetApiListDetails]: + res = CustomResponseCode.HTTP_200 + return ResponseSchemaModel[GetApiListDetails](code=res.code, msg=res.msg, data=GetApiListDetails(...)) + """ + + data: SchemaT + + class ResponseBase: """ 统一返回方法 @@ -61,7 +84,9 @@ def test() -> ResponseModel: """ @staticmethod - def __response(*, res: CustomResponseCode | CustomResponse = None, data: Any | None = None) -> ResponseModel: + def __response( + *, res: CustomResponseCode | CustomResponse = None, data: Any | None = None + ) -> ResponseModel | ResponseSchemaModel: """ 请求成功返回通用方法 @@ -76,7 +101,7 @@ def success( *, res: CustomResponseCode | CustomResponse = CustomResponseCode.HTTP_200, data: Any | None = None, - ) -> ResponseModel: + ) -> ResponseModel | ResponseSchemaModel: return self.__response(res=res, data=data) def fail( @@ -84,7 +109,7 @@ def fail( *, res: CustomResponseCode | CustomResponse = CustomResponseCode.HTTP_400, data: Any = None, - ) -> ResponseModel: + ) -> ResponseModel | ResponseSchemaModel: return self.__response(res=res, data=data) @staticmethod @@ -92,7 +117,7 @@ def fast_success( *, res: CustomResponseCode | CustomResponse = CustomResponseCode.HTTP_200, data: Any | None = None, - ) -> Response: + ) -> Response | ResponseSchemaModel: """ 此方法是为了提高接口响应速度而创建的,如果返回数据无需进行 pydantic 解析和验证,则推荐使用,相反,请不要使用! diff --git a/backend/pyproject.toml b/backend/pyproject.toml index 301e902f..1acd5ef7 100644 --- a/backend/pyproject.toml +++ b/backend/pyproject.toml @@ -24,7 +24,7 @@ dependencies = [ "fast-captcha>=0.3.2", "fastapi[all]==0.111.0", "fastapi-limiter>=0.1.6", - "fastapi-pagination==0.12.13", + "fastapi-pagination>=0.12.34", "itsdangerous>=2.2.0", "loguru>=0.7.2", "msgspec>=0.19.0", diff --git a/backend/requirements.txt b/backend/requirements.txt index 8dc8ebf8..e0c924ab 100644 --- a/backend/requirements.txt +++ b/backend/requirements.txt @@ -36,7 +36,7 @@ fastapi==0.111.0 fastapi-cli==0.0.5 fastapi-limiter==0.1.6 fastapi-oauth20==0.0.1a2 -fastapi-pagination==0.12.13 +fastapi-pagination==0.12.34 filelock==3.16.1 flower==2.0.1 greenlet==3.1.1 diff --git a/backend/uv.lock b/backend/uv.lock index 61f5535e..0759ca74 100644 --- a/backend/uv.lock +++ b/backend/uv.lock @@ -617,7 +617,7 @@ requires-dist = [ { name = "fastapi", extras = ["all"], specifier = "==0.111.0" }, { name = "fastapi-limiter", specifier = ">=0.1.6" }, { name = "fastapi-oauth20", specifier = ">=0.0.1a2" }, - { name = "fastapi-pagination", specifier = "==0.12.13" }, + { name = "fastapi-pagination", specifier = ">=0.12.34" }, { name = "flower", specifier = ">=2.0.0" }, { name = "itsdangerous", specifier = ">=2.2.0" }, { name = "jinja2", specifier = ">=3.1.4" }, @@ -693,16 +693,15 @@ wheels = [ [[package]] name = "fastapi-pagination" -version = "0.12.13" +version = "0.12.34" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "fastapi" }, { name = "pydantic" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/af/b4/fe7b2ba2eed6787e4a4f8caa5c10fee1ea2a9c2e55c61c5b795bf6591bbb/fastapi_pagination-0.12.13.tar.gz", hash = "sha256:29b09902e6a946957bbb7d78dac14505b23686236312ebae17be9748d143de3e", size = 21680 } +sdist = { url = "https://files.pythonhosted.org/packages/83/4d/6e695098ce33b3394cf26b335ca4ec6407f9421cfdf9ad6a38775580db21/fastapi_pagination-0.12.34.tar.gz", hash = "sha256:05ee8c0bc572072160f7f30900bfd87869e1880c87bc5797922fec2e49e65f11", size = 26901 } wheels = [ - { url = "https://files.pythonhosted.org/packages/fd/6e/9e30c1cbf1c4ea1888a22a9cd988e9d897706d367351533e752a1312fd3d/fastapi_pagination-0.12.13-py3-none-any.whl", hash = "sha256:c8f94327c9d705f89b236c18b72548c6cb5ac9ba559d7b325f479e1c8ccb0c0d", size = 36016 }, + { url = "https://files.pythonhosted.org/packages/72/f3/a0a1e7efd88dba07743665d1f6f88008c9a1e174458581ecaa53b8699a7c/fastapi_pagination-0.12.34-py3-none-any.whl", hash = "sha256:089d1078aae1784395b4dbd923d0c8246641ddcc291c5ec6d92a30edb92ecbdd", size = 43308 }, ] [[package]] From 07b37010b7ad6f9763e5e5d853e97a2868a2d105 Mon Sep 17 00:00:00 2001 From: Wu Clan Date: Fri, 17 Jan 2025 00:40:50 +0800 Subject: [PATCH 2/3] Fix paging data usage --- backend/app/admin/api/v1/log/login_log.py | 3 +-- backend/app/admin/api/v1/log/opera_log.py | 3 +-- backend/app/admin/api/v1/sys/api.py | 4 ++-- backend/app/admin/api/v1/sys/casbin.py | 3 +-- backend/app/admin/api/v1/sys/config.py | 3 +-- backend/app/admin/api/v1/sys/data_rule.py | 2 +- backend/app/admin/api/v1/sys/dict_data.py | 2 +- backend/app/admin/api/v1/sys/dict_type.py | 4 ++-- backend/app/admin/api/v1/sys/notice.py | 4 ++-- backend/app/admin/api/v1/sys/role.py | 2 +- backend/app/admin/api/v1/sys/user.py | 2 +- backend/templates/py/api.jinja | 4 ++-- 12 files changed, 16 insertions(+), 20 deletions(-) diff --git a/backend/app/admin/api/v1/log/login_log.py b/backend/app/admin/api/v1/log/login_log.py index e99fe9fb..7a7e865a 100644 --- a/backend/app/admin/api/v1/log/login_log.py +++ b/backend/app/admin/api/v1/log/login_log.py @@ -4,7 +4,6 @@ from fastapi import APIRouter, Depends, Query -from backend.app.admin.schema.login_log import GetLoginLogListDetails from backend.app.admin.service.login_log_service import login_log_service from backend.common.pagination import DependsPagination, paging_data from backend.common.response.response_schema import ResponseModel, response_base @@ -31,7 +30,7 @@ async def get_pagination_login_logs( ip: Annotated[str | None, Query()] = None, ) -> ResponseModel: log_select = await login_log_service.get_select(username=username, status=status, ip=ip) - page_data = await paging_data(db, log_select, GetLoginLogListDetails) + page_data = await paging_data(db, log_select) return response_base.success(data=page_data) diff --git a/backend/app/admin/api/v1/log/opera_log.py b/backend/app/admin/api/v1/log/opera_log.py index d6387366..c90a12de 100644 --- a/backend/app/admin/api/v1/log/opera_log.py +++ b/backend/app/admin/api/v1/log/opera_log.py @@ -4,7 +4,6 @@ from fastapi import APIRouter, Depends, Query -from backend.app.admin.schema.opera_log import GetOperaLogListDetails from backend.app.admin.service.opera_log_service import opera_log_service from backend.common.pagination import DependsPagination, paging_data from backend.common.response.response_schema import ResponseModel, response_base @@ -31,7 +30,7 @@ async def get_pagination_opera_logs( ip: Annotated[str | None, Query()] = None, ) -> ResponseModel: log_select = await opera_log_service.get_select(username=username, status=status, ip=ip) - page_data = await paging_data(db, log_select, GetOperaLogListDetails) + page_data = await paging_data(db, log_select) return response_base.success(data=page_data) diff --git a/backend/app/admin/api/v1/sys/api.py b/backend/app/admin/api/v1/sys/api.py index 7e225ddc..999694b0 100644 --- a/backend/app/admin/api/v1/sys/api.py +++ b/backend/app/admin/api/v1/sys/api.py @@ -4,7 +4,7 @@ from fastapi import APIRouter, Depends, Path, Query, Request -from backend.app.admin.schema.api import CreateApiParam, GetApiListDetails, UpdateApiParam +from backend.app.admin.schema.api import CreateApiParam, UpdateApiParam from backend.app.admin.service.api_service import api_service from backend.common.pagination import DependsPagination, paging_data from backend.common.response.response_schema import ResponseModel, response_base @@ -44,7 +44,7 @@ async def get_pagination_apis( path: Annotated[str | None, Query()] = None, ) -> ResponseModel: api_select = await api_service.get_select(request=request, name=name, method=method, path=path) - page_data = await paging_data(db, api_select, GetApiListDetails) + page_data = await paging_data(db, api_select) return response_base.success(data=page_data) diff --git a/backend/app/admin/api/v1/sys/casbin.py b/backend/app/admin/api/v1/sys/casbin.py index 58943d80..7d4eb0d0 100644 --- a/backend/app/admin/api/v1/sys/casbin.py +++ b/backend/app/admin/api/v1/sys/casbin.py @@ -11,7 +11,6 @@ DeleteAllPoliciesParam, DeletePolicyParam, DeleteUserRoleParam, - GetPolicyListDetails, UpdatePoliciesParam, UpdatePolicyParam, ) @@ -40,7 +39,7 @@ async def get_pagination_casbin( sub: Annotated[str | None, Query(description='用户 uuid / 角色')] = None, ) -> ResponseModel: casbin_select = await casbin_service.get_casbin_list(ptype=ptype, sub=sub) - page_data = await paging_data(db, casbin_select, GetPolicyListDetails) + page_data = await paging_data(db, casbin_select) return response_base.success(data=page_data) diff --git a/backend/app/admin/api/v1/sys/config.py b/backend/app/admin/api/v1/sys/config.py index 7a9e6625..6f51885a 100644 --- a/backend/app/admin/api/v1/sys/config.py +++ b/backend/app/admin/api/v1/sys/config.py @@ -6,7 +6,6 @@ from backend.app.admin.schema.config import ( CreateAnyConfigParam, - GetAnyConfigListDetails, SaveConfigParam, UpdateAnyConfigParam, ) @@ -98,7 +97,7 @@ async def get_pagination_config( type: Annotated[str | None, Query()] = None, ) -> ResponseModel: config_select = await config_service.get_select(name=name, type=type) - page_data = await paging_data(db, config_select, GetAnyConfigListDetails) + page_data = await paging_data(db, config_select) return response_base.success(data=page_data) diff --git a/backend/app/admin/api/v1/sys/data_rule.py b/backend/app/admin/api/v1/sys/data_rule.py index 10f17976..7901f5fa 100644 --- a/backend/app/admin/api/v1/sys/data_rule.py +++ b/backend/app/admin/api/v1/sys/data_rule.py @@ -53,7 +53,7 @@ async def get_data_rule(pk: Annotated[int, Path(...)]) -> ResponseModel: ) async def get_pagination_data_rule(db: CurrentSession, name: Annotated[str | None, Query()] = None) -> ResponseModel: data_rule_select = await data_rule_service.get_select(name=name) - page_data = await paging_data(db, data_rule_select, GetDataRuleListDetails) + page_data = await paging_data(db, data_rule_select) return response_base.success(data=page_data) diff --git a/backend/app/admin/api/v1/sys/dict_data.py b/backend/app/admin/api/v1/sys/dict_data.py index 8ae5ff10..979d7fb5 100644 --- a/backend/app/admin/api/v1/sys/dict_data.py +++ b/backend/app/admin/api/v1/sys/dict_data.py @@ -39,7 +39,7 @@ async def get_pagination_dict_datas( status: Annotated[int | None, Query()] = None, ) -> ResponseModel: dict_data_select = await dict_data_service.get_select(label=label, value=value, status=status) - page_data = await paging_data(db, dict_data_select, GetDictDataListDetails) + page_data = await paging_data(db, dict_data_select) return response_base.success(data=page_data) diff --git a/backend/app/admin/api/v1/sys/dict_type.py b/backend/app/admin/api/v1/sys/dict_type.py index 00da6b1e..d2914d02 100644 --- a/backend/app/admin/api/v1/sys/dict_type.py +++ b/backend/app/admin/api/v1/sys/dict_type.py @@ -4,7 +4,7 @@ from fastapi import APIRouter, Depends, Path, Query -from backend.app.admin.schema.dict_type import CreateDictTypeParam, GetDictTypeListDetails, UpdateDictTypeParam +from backend.app.admin.schema.dict_type import CreateDictTypeParam, UpdateDictTypeParam from backend.app.admin.service.dict_type_service import dict_type_service from backend.common.pagination import DependsPagination, paging_data from backend.common.response.response_schema import ResponseModel, response_base @@ -31,7 +31,7 @@ async def get_pagination_dict_types( status: Annotated[int | None, Query()] = None, ) -> ResponseModel: dict_type_select = await dict_type_service.get_select(name=name, code=code, status=status) - page_data = await paging_data(db, dict_type_select, GetDictTypeListDetails) + page_data = await paging_data(db, dict_type_select) return response_base.success(data=page_data) diff --git a/backend/app/admin/api/v1/sys/notice.py b/backend/app/admin/api/v1/sys/notice.py index dc785998..95e6e4dc 100644 --- a/backend/app/admin/api/v1/sys/notice.py +++ b/backend/app/admin/api/v1/sys/notice.py @@ -4,7 +4,7 @@ from fastapi import APIRouter, Depends, Path, Query -from backend.app.admin.schema.notice import CreateNoticeParam, GetNoticeListDetails, UpdateNoticeParam +from backend.app.admin.schema.notice import CreateNoticeParam, UpdateNoticeParam from backend.app.admin.service.notice_service import notice_service from backend.common.pagination import DependsPagination, paging_data from backend.common.response.response_schema import ResponseModel, response_base @@ -32,7 +32,7 @@ async def get_notice(pk: Annotated[int, Path(...)]) -> ResponseModel: ) async def get_pagination_notice(db: CurrentSession) -> ResponseModel: notice_select = await notice_service.get_select() - page_data = await paging_data(db, notice_select, GetNoticeListDetails) + page_data = await paging_data(db, notice_select) return response_base.success(data=page_data) diff --git a/backend/app/admin/api/v1/sys/role.py b/backend/app/admin/api/v1/sys/role.py index 74e3f8a6..cdb356f9 100644 --- a/backend/app/admin/api/v1/sys/role.py +++ b/backend/app/admin/api/v1/sys/role.py @@ -72,7 +72,7 @@ async def get_pagination_roles( status: Annotated[int | None, Query()] = None, ) -> ResponseModel: role_select = await role_service.get_select(name=name, status=status) - page_data = await paging_data(db, role_select, GetRoleListDetails) + page_data = await paging_data(db, role_select) return response_base.success(data=page_data) diff --git a/backend/app/admin/api/v1/sys/user.py b/backend/app/admin/api/v1/sys/user.py index d67c9baa..961821ca 100644 --- a/backend/app/admin/api/v1/sys/user.py +++ b/backend/app/admin/api/v1/sys/user.py @@ -108,7 +108,7 @@ async def get_pagination_users( status: Annotated[int | None, Query()] = None, ): user_select = await user_service.get_select(dept=dept, username=username, phone=phone, status=status) - page_data = await paging_data(db, user_select, GetUserInfoListDetails) + page_data = await paging_data(db, user_select) return response_base.success(data=page_data) diff --git a/backend/templates/py/api.jinja b/backend/templates/py/api.jinja index 275c5b6b..24f3ed3d 100644 --- a/backend/templates/py/api.jinja +++ b/backend/templates/py/api.jinja @@ -2,7 +2,7 @@ # -*- coding: utf-8 -*- from typing import Annotated -from backend.app.{{ app_name }}.schema.{{ table_name_en }} import Create{{ schema_name }}Param, Get{{ schema_name }}ListDetails, Update{{ schema_name }}Param +from backend.app.{{ app_name }}.schema.{{ table_name_en }} import Create{{ schema_name }}Param, Update{{ schema_name }}Param from backend.app.{{ app_name }}.service.{{ table_name_en }}_service import {{ table_name_en }}_service from backend.common.pagination import DependsPagination, paging_data from backend.common.response.response_schema import ResponseModel, response_base @@ -31,7 +31,7 @@ async def get_{{ table_name_en }}(pk: Annotated[int, Path(...)]) -> ResponseMode ) async def get_pagination_{{ table_name_en }}(db: CurrentSession) -> ResponseModel: {{ table_name_en }}_select = await {{ table_name_en }}_service.get_select() - page_data = await paging_data(db, {{ table_name_en }}_select, Get{{ schema_name }}ListDetails) + page_data = await paging_data(db, {{ table_name_en }}_select) return response_base.success(data=page_data) From 05ebad1e0a0ad5911efaa1ef5cf682386cd5f82a Mon Sep 17 00:00:00 2001 From: Wu Clan Date: Fri, 17 Jan 2025 10:10:13 +0800 Subject: [PATCH 3/3] optimize annotations --- backend/common/pagination.py | 4 ++-- backend/common/response/response_schema.py | 24 ++++++---------------- 2 files changed, 8 insertions(+), 20 deletions(-) diff --git a/backend/common/pagination.py b/backend/common/pagination.py index 9a0b2685..e356c050 100644 --- a/backend/common/pagination.py +++ b/backend/common/pagination.py @@ -40,7 +40,7 @@ class _Links(BaseModel): class _PageDetails(BaseModel): - items: Sequence[SchemaT] = Field(description='当前页数据') + items: list = Field([], description='当前页数据') total: int = Field(..., description='总条数') page: int = Field(..., description='当前页') size: int = Field(..., description='每页数量') @@ -102,7 +102,7 @@ def test() -> ResponseSchemaModel[PageData[GetApiListDetails]]: ) """ - ... + items: Sequence[SchemaT] async def paging_data(db: AsyncSession, select: Select) -> dict: diff --git a/backend/common/response/response_schema.py b/backend/common/response/response_schema.py index fefa1fc0..9f3193c6 100644 --- a/backend/common/response/response_schema.py +++ b/backend/common/response/response_schema.py @@ -15,7 +15,7 @@ class ResponseModel(BaseModel): """ - 通用型统一返回模型,不包含 data 数据结构 + 通用型统一返回模型,不包含 data schema E.g. :: @@ -69,26 +69,14 @@ def test() -> ResponseSchemaModel[GetApiListDetails]: class ResponseBase: - """ - 统一返回方法 - - .. tip:: - - 此类中的方法将返回 ResponseModel 模型,作为一种编码风格而存在; - - E.g. :: - - @router.get('/test') - def test() -> ResponseModel: - return response_base.success(data={'test': 'test'}) - """ + """统一返回方法""" @staticmethod def __response( *, res: CustomResponseCode | CustomResponse = None, data: Any | None = None ) -> ResponseModel | ResponseSchemaModel: """ - 请求成功返回通用方法 + 请求返回通用方法 :param res: 返回信息 :param data: 返回数据 @@ -117,13 +105,13 @@ def fast_success( *, res: CustomResponseCode | CustomResponse = CustomResponseCode.HTTP_200, data: Any | None = None, - ) -> Response | ResponseSchemaModel: + ) -> Response: """ - 此方法是为了提高接口响应速度而创建的,如果返回数据无需进行 pydantic 解析和验证,则推荐使用,相反,请不要使用! + 此方法是为了提高接口响应速度而创建的,在解析较大 json 时有显著性能提升,但将丢失 pydantic 解析和验证 .. warning:: - 使用此返回方法时,不要指定接口参数 response_model,也不要在接口函数后添加箭头返回类型 + 使用此返回方法时,不能指定接口参数 response_model 和箭头返回类型 :param res: :param data: