Files
Wu Clan 5e438c685d Refactor the backend architecture (#299)
* define the basic architecture

* Update script and deployment file locations

* Update the route registration

* Fix CI download dependencies

* Updated ruff to 0.3.3

* Update app subdirectory naming

* Update the model import

* fix pre-commit pdm lock

* Update the service directory naming

* Add CRUD method documents

* Fix the issue of circular import

* Update the README document

* Update the SQL statement for create tables

* Update docker scripts and documentation

* Fix docker scripts

* Update the backend README.md

* Add the security folder and move the redis client

* Update the configuration item

* Fix environment configuration reads

* Update the default configuration

* Updated README description

* Updated the user registration API

* Fix test cases

* Update the celery configuration

* Update and fix celery configuration

* Updated the celery structure

* Update celery tasks and api

* Add celery flower

* Update the import style

* Update contributors
2024-03-22 18:16:15 +08:00

86 lines
2.6 KiB
Python

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
from __future__ import annotations
import math
from typing import TYPE_CHECKING, Dict, 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
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):
page: int = Query(1, ge=1, description='Page number')
size: int = Query(20, gt=0, le=100, description='Page size') # 默认 20 条记录
def to_raw_params(self) -> RawParams:
return RawParams(
limit=self.size,
offset=self.size * (self.page - 1),
)
class _Page(AbstractPage[T], Generic[T]):
items: Sequence[T] # 数据
total: int # 总数据数
page: int # 第n页
size: int # 每页数量
total_pages: int # 总页数
links: Dict[str, str | None] # 跳转链接
__params_type__ = _Params # 使用自定义的Params
@classmethod
def create(
cls,
items: Sequence[T],
total: int,
params: _Params,
) -> _Page[T]:
page = params.page
size = params.size
total_pages = math.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,
'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)
class _PageData(BaseModel, Generic[DataT]):
page_data: DataT | None = None
async def paging_data(db: AsyncSession, select: Select, page_data_schema: SchemaT) -> 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']
return page_data
# 分页依赖注入
DependsPagination = Depends(pagination_ctx(_Page))