fastapi-pagination高级用法

祥开龙角应三农,小队旌旗猎猎风。

models.py

class Group(Model):
    id = IntField(pk=True)
    name = CharField(max_length=10)

class User(Model):
    id = IntField(pk=True)
    group = ForeignKeyField('models.Group')
    name = CharField(max_length=10)

utils.py

async def get_user_data(group_id: int, user_data: list[dict]) -> list[dict]:
    return [dict(i, group=group_id) for i in user_data]

views.py

@router.get('')
async def user_pages(params: Params = Depends(), group_id: str = None):
    user_data = await User.all().prefetch_related('group')
    user_list = await get_user_data(group_id=group_id, user_data=user_data)
    data = paginate(user_list, params=params)
    return Response(status=0, data=data)

修改后的views.py

  • 示例1
from fastapi_pagination.ext.tortoise import paginate

@router.get('')
async def user_pages(params: Params = Depends(), group_id: str = None):
    queryset = User.all().prefetch_related('group') # 这里去掉await
    async def transformer(items):
        return await get_user_data(group_id=group_id, user_data=items)
    data = await paginate(
        queryset, params=params, transformer=transformer
    )
    return MyResponse(status=0, data=data)
  • 示例2:(能修改get_user_data方法的情况)
import functools

# 把user_data放在第一个位置参数
async def get_user_data(user_data: list[dict], group_id, **kw) -> list[dict]:
    return [dict(i, group_id=group_id) for i in user_data]

@router.get('')
async def user_pages(params: Params = Depends(), group_id: str = None):
    queryset = User.all().prefetch_related('group')
    transformer = functools.partial(get_user_data, group_id=group_id)
    data = await paginate(
        queryset, params=params, transformer=transformer
    )
    return MyResponse(status=0, data=data)

一个完整的示例:

#!/usr/bin/env python
from contextlib import asynccontextmanager
from functools import partial
from pathlib import Path
from typing import (
    TYPE_CHECKING,
    Annotated,
    Any,
    AsyncGenerator,
    Optional,
)

import fastapi_cdn_host
import uvicorn
from faker import Faker
from fastapi import Depends, FastAPI
from fastapi_pagination import LimitOffsetPage, Page, Params, add_pagination
from fastapi_pagination.ext.tortoise import paginate
from pydantic import BaseModel, Field
from tortoise import fields, models
from tortoise.contrib.fastapi import RegisterTortoise
from tortoise.contrib.pydantic import PydanticModel, pydantic_model_creator
from tortoise.exceptions import DoesNotExist

faker = Faker()


class Group(models.Model):
    id = fields.IntField(pk=True)
    name = fields.TextField()
    users: fields.ReverseRelation["User"]


class User(models.Model):
    id = fields.IntField(pk=True)
    name = fields.TextField(null=False)
    email = fields.TextField(null=False)
    group: fields.ForeignKeyRelation[Group] = fields.ForeignKeyField(
        "models.Group", related_name="users"
    )


if TYPE_CHECKING:  # pragma: nocoverage

    class UserIn(User, PydanticModel):  # type:ignore[misc]
        pass

    class UserOut(User, PydanticModel):  # type:ignore[misc]
        pass
else:
    UserOut = pydantic_model_creator(User, name="User")

    class UserIn(pydantic_model_creator(User, name="UserIn", exclude_readonly=True)):
        group_id: int = Field(gt=0)


async def _initial_users() -> None:
    await Group.bulk_create([Group(name=faker.name()) for _ in range(10)])
    gs = await Group.all()
    for i in range(100):
        await User.create(
            name=faker.name(),
            email=faker.email(),
            group=gs[i % len(gs)],
        )


class UserInfoSchema(BaseModel):
    user_id: int
    info: Annotated[str, "<name email>"]
    group: str


async def build_user_info(items: list[UserOut], group_name="") -> list[UserInfoSchema]:
    return [
        UserInfoSchema(
            user_id=i.id, info=f"<{i.name} {i.email}>", group=group_name or i.group.name
        )
        for i in items
    ]


async def get_user_data(group_id, items) -> list[UserInfoSchema]:
    try:
        g = await Group.get(id=group_id)
        group_name = g.name
    except (DoesNotExist, TypeError, ValueError):
        group_name = ""
    return await build_user_info(items, group_name)


@asynccontextmanager
async def lifespan(app: FastAPI) -> AsyncGenerator[None, None]:
    async with RegisterTortoise(
        app,
        db_url="sqlite://:memory:",
        modules={"models": [__name__]},
        generate_schemas=True,
    ):
        await _initial_users()
        add_pagination(app)
        yield


app = FastAPI(title="Tortoise ORM Pagination example", lifespan=lifespan)
fastapi_cdn_host.patch_docs(app)


@app.post("/users", response_model=UserOut)
async def create_user(user_in: UserIn) -> Any:
    return await User.create(**user_in.dict())


@app.get("/users/default", response_model=Page[UserInfoSchema])
@app.get("/users/limit-offset", response_model=LimitOffsetPage[UserInfoSchema])
async def get_users() -> Any:
    data = await paginate(
        User.all().prefetch_related("group"),
        transformer=partial(build_user_info, group_name=""),
    )
    # print(type(data.items))
    # print(type(data.items[0]))
    return data


class ResponseModel(BaseModel):
    status: int
    data: Page[UserInfoSchema]
    msg: Optional[str] = ""


async def build_user_data(
    user_data: list[UserOut], group_id: Optional[str] = None
) -> list[UserInfoSchema]:
    return await get_user_data(group_id=group_id, items=user_data)


@app.get("/users/info", response_model=ResponseModel, summary="分页用户列表")
async def get_user_infos(
    params: Params = Depends(), group_id: Optional[str] = None
) -> Any:
    queryset = User.all().prefetch_related("group")
    if group_id:
        queryset = queryset.filter(group_id=group_id)
    transformer = partial(build_user_data, group_id=group_id)
    data = await paginate(queryset, params=params, transformer=transformer)
    return ResponseModel(status=0, data=data)


class MyResponse:
    def __init__(self, data: Any, status: int, msg="") -> None:
        self.data = data
        self.status = status
        if msg:
            self.msg = msg

    def __str__(self):
        return {"data": self.data, "status": self.status}


@app.get("/users/info2")
async def get_user_infos2(params: Params = Depends(), group_id: str = None):
    queryset = User.all().prefetch_related("group")

    async def transformer(user_data):
        return await get_user_data(group_id=group_id, items=user_data)

    data = await paginate(queryset, params=params, transformer=transformer)
    return MyResponse(status=0, data=data, msg="bibi")


if __name__ == "__main__":
    uvicorn.run(f"{Path(__file__).stem}:app")
posted @ 2024-06-13 15:53  waketzheng  阅读(179)  评论(0编辑  收藏  举报