跳转至

分页

Django Ninja 带有分页支持。这允许你将大型结果集拆分为单独的页面。

要将分页应用于一个函数 - 只需应用 paginate 装饰器:

from ninja.pagination import paginate

@api.get('/users', response=List[UserSchema])
@paginate
def list_users(request):
    return User.objects.all()

就是这样!

现在你可以使用 limitoffset GET 参数查询用户

/api/users?limit=10&offset=0

默认情况下,限制设置为 100 (你可以在你的 settings.py 中使用 NINJA_PAGINATION_PER_PAGE 来更改它)

内置分页类

LimitOffsetPagination 限制偏移分页 (默认)

这是默认的分页类 (你可以在你的 settings.py 中使用 NINJA_PAGINATION_CLASS 指向一个类的路径来更改它)

from ninja.pagination import paginate, LimitOffsetPagination

@api.get('/users', response=List[UserSchema])
@paginate(LimitOffsetPagination)
def list_users(request):
    return User.objects.all()

示例查询:

/api/users?limit=10&offset=0

这个类有两个输入参数:

  • limit - 定义页面上的查询集数量 (default = 100, 可以在 NINJA_PAGINATION_PER_PAGE 中修改)
  • offset - 设置页面窗口偏移量 (default: 0, 索引从 0 开始)

PageNumberPagination 页码分页

from ninja.pagination import paginate, PageNumberPagination

@api.get('/users', response=List[UserSchema])
@paginate(PageNumberPagination)
def list_users(request):
    return User.objects.all()

示例查询:

/api/users?page=2

这个类有一个参数 page 并且默认每页输出 100 个查询集 (可以通过 settings.py 更改)

页面编号从 1 开始。

你也可以为每个视图单独设置自定义的页面大小值:

@api.get("/users")
@paginate(PageNumberPagination, page_size=50)
def list_users(...

在视图函数中访问分页参数

如果你需要在你的视图函数中访问用于分页的 Input 参数 - use pass_parameter 参数

在那种情况下,输入数据将在 **kwargs 中可用:

@api.get("/someview")
@paginate(pass_parameter="pagination_info")
def someview(request, **kwargs):
    page = kwargs["pagination_info"].page
    return ...

创建自定义分页类

要创建自定义分页类,你应该继承 ninja.pagination.PaginationBase 并覆盖 InputOutput 模式类以及 paginate_queryset(self, queryset, request, **params) 方法:

  • Input 模式是一个描述应传递给分页器的参数(例如页码或 limit/offset值 )的模式类。
  • Output 模式描述页面输出的模式(例如计数/下一页/项目等)。
  • paginate_queryset 方法接收初始的查询集,并且应该返回一个仅包含所请求页面中数据的可迭代对象。该方法接受以下参数:
    • queryset: 由 API 函数返回的查询集(或可迭代对象)。
    • pagination - paginator.Input 参数 (已解析和验证)
    • **params: 关键字参数,将包含装饰函数接收的所有参数。

示例:

from ninja.pagination import paginate, PaginationBase
from ninja import Schema


class CustomPagination(PaginationBase):
    # only `skip` param, defaults to 5 per page
    class Input(Schema):
        skip: int


    class Output(Schema):
        items: List[Any] # `items` is a default attribute
        total: int
        per_page: int

    def paginate_queryset(self, queryset, pagination: Input, **params):
        skip = pagination.skip
        return {
            'items': queryset[skip : skip + 5],
            'total': queryset.count(),
            'per_page': 5,
        }


@api.get('/users', response=List[UserSchema])
@paginate(CustomPagination)
def list_users(request):
    return User.objects.all()

提示:你可以从参数中获取请求对象:

def paginate_queryset(self, queryset, pagination: Input, **params):
    request = params["request"]

异步分页

标准的 Django Ninja 分页类支持异步。 如果你想用自定义分页类处理异步请求,你应该继承 ninja.pagination.AsyncPaginationBase 并覆盖 apaginate_queryset(self, queryset, request, **params) 方法。

输出属性

默认情况下页面项被放置在 'items' 属性中。 要覆盖此行为,可以使用 items_attribute:

class CustomPagination(PaginationBase):
    ...
    class Output(Schema):
        results: List[Any]
        total: int
        per_page: int

    items_attribute: str = "results"

一次对多个操作应用分页

经常会有这样的情况,你需要对所有返回查询集或列表的视图添加分页

你可以使用内置的路由类 (RouterPaginated) 它会自动将分页注入到所有定义为 response=List[SomeSchema] 的操作中:

from ninja.pagination import RouterPaginated

router = RouterPaginated()


@router.get("/items", response=List[MySchema])
def items(request):
    return MyModel.objects.all()

@router.get("/other-items", response=List[OtherSchema])
def ohter_items(request):
    return OtherModel.objects.all()

在这个例子中,这两个操作都将启用分页。

要将分页应用于主 api 实例,可以使用 default_router 参数:

api = NinjaAPI(default_router=RouterPaginated())

@api.get(...

大功告成

继续下一章节! 响应渲染

评论


本文总阅读量