使用 ModelViewSet 的 django-filter 和 django 自定义分页

django-filter and django custom pagination with ModelViewSet

我实现了一个结合了 django-filter 和 django 默认分页的模型视图集。当我使用 django-filter 或 django 分页时,它工作正常。但是当它们同时使用时,我会得到重复的响应结果。

那么在带有 CBV 的 django-filter 中使用分页的正确方法是什么?

class TableMetaView(ModelViewSet):
    """
    This will be used to create new tables.
    You require to add the table fields in json request and also the job request associated with that
    table.
    If you want to create new table then pass CREATE NEW TABLE
    In response you will get the table list along with the job request for each tables
    """

    serializer_class = TableMetaSerializer
    queryset = TableMeta.objects.all()
    renderer_classes = [JSONRenderer]
    filterset_fields = [
        "schema_name",
        "type",
        "status",
        "grouping__name",
        "dataset__name",
    ]
    ordering_fields = ["created_on", "modified_on"]
    ordering = ["-modified_on"]
    pagination_class = StandardResultsSetPagination

    permission_classes = [
        UserHasDatasetChangeAccess & IsTableEditable,
    ]

    def get_queryset(self):
        if getattr(self, "swagger_fake_view", False):
            # queryset just for schema generation metadata
            return TableMeta.objects.none()
        return TableMeta.objects.filter(
            dataset=get_object_or_404(DataSet, id=self.request.META.get(DATASET_ID, ""))
        )

经过大量搜索后,我设法做了一些更改,现在代码 运行 可以正常使用 django-filters 和分页。

custom_pagination.py

from collections import OrderedDict

from constance import config
from rest_framework.pagination import (  # noqa
    CursorPagination,
    LimitOffsetPagination,
    PageNumberPagination,
)
from rest_framework.response import Response


class MyPagination(PageNumberPagination):
    page_size = 5
    page_size_query_param = "page_size"
    max_page_size = 50

    def get_paginated_response(self, data):
        return Response(
            OrderedDict(
                {
                    "next": self.get_next_link(),
                    "previous": self.get_previous_link(),
                    "results": data,
                }
            )
        )

views.py

class TableMetaView(ModelViewSet):
    """
    This will be used to create new tables.
    You require to add the table fields in json request and also the job request associated with that
    table.
    If you want to create new table then pass CREATE NEW TABLE
    In response you will get the table list along with the job request for each tables
    """

    serializer_class = TableMetaSerializer
    queryset = TableMeta.objects.all()
    renderer_classes = [JSONRenderer]
    filterset_class = TableFilter
    ordering_fields = ["created_on", "modified_on"]
    ordering = ["-modified_on"]
    pagination_class = MyPagination

    permission_classes = [
        UserHasDatasetChangeAccess & IsTableEditable,
    ]

    def get_queryset(self):
        if getattr(self, "swagger_fake_view", False):
            # queryset just for schema generation metadata
            return TableMeta.objects.none()
        return TableMeta.objects.filter(
            dataset=get_object_or_404(DataSet, id=self.request.META.get(DATASET_ID, ""))
        )

    def list(self, request: Request, *args: Any, **kwargs: Any) -> Response:
        filtered_qs = self.filterset_class(request.GET, queryset=self.get_queryset()).qs
        page = self.paginate_queryset(queryset=filtered_qs)
        serializer = self.serializer_class(page, many=True)
        return self.get_paginated_response(serializer.data)

custom_filter.py

class TableFilter(django_filters.FilterSet):
    class Meta:
        model = TableMeta
        fields = {
            "name": ["exact", "icontains"],
            "schema_name": ["exact"],
            "type": ["exact"],
            "status": ["exact"],
            "grouping__name": ["exact"],
            "dataset__name": ["exact"],
        }

还需要设置默认顺序

models.py

class TableMeta(models.Model):
  class Meta:
    ordering = ['-modified_on'] # list of fields here

此后 django-filters 和分页在 ModelViewSet 中工作正常。