Django Rest Framework:用于自定义操作的DRYer分页

时间:2019-06-15 09:33:19

标签: django django-rest-framework

假设我需要设置几个objects/pastobjects/future形式的GET端点。示例:

@action(detail=False, methods=["GET"], name="Past Objects")
def past(self, request, *args, **kwargs):
    startdate = datetime.datetime.now()
    some_user = UserProfile.objects.get(user__username="someuser")

    queryset = self.queryset.filter(
        other__attribute__profile=some_user,
        creation_date__lte=startdate
        ).order_by("-creation_date")

    page = self.paginate_queryset(queryset)

    if page is not None:
        serializer = self.get_serializer(page, many=True)
        return self.get_paginated_response(serializer.data)

    serializer = self.get_serializer(queryset, many=True)
    return Response(serializer.data)

以上工作正常。但是是否有避免使用page = ... -> serializer= ...部分的地方?

我已经在我的ModelViewSet中指定了它:

pagination_class = CustomObjectPagination

但是分页似乎仅自动应用于默认方法,例如 get_queryset ,而不是自定义操作。每次指定诸如past之类的自定义操作时,我都必须编写此样板吗?

page = self.paginate_queryset(queryset)

if page is not None:
    serializer = self.get_serializer(page, many=True)
    return self.get_paginated_response(serializer.data)

serializer = self.get_serializer(queryset, many=True)
return Response(serializer.data)

编辑:应该更清楚地说明我是否在专门询问是否有内置方法来完成上述操作。

2 个答案:

答案 0 :(得分:1)

我认为我们没有内置的功能可将分页应用于动作。但是,我们可以有一个简单的装饰器来执行此操作。使用此装饰器时,请确保您的操作返回一个列表或QuerySet。

from functools import wraps
from django.db.models import QuerySet

def paginate(func):

    @wraps(func)
    def inner(self, *args, **kwargs):
        queryset = func(self, *args, **kwargs)
        assert isinstance(queryset, (list, QuerySet)), "apply_pagination expects a List or a QuerySet"

        page = self.paginate_queryset(queryset)
        if page is not None:
            serializer = self.get_serializer(page, many=True)
            return self.get_paginated_response(serializer.data)

        serializer = self.get_serializer(queryset, many=True)
        return Response(serializer.data)
    return inner

@paginate
@action(detail=False, methods=["GET"], name="Past Objects")
def past(self, request, *args, **kwargs):
    startdate = datetime.datetime.now()
    some_user = UserProfile.objects.get(user__username="someuser")

    queryset = self.queryset.filter(
        other__attribute__profile=some_user,
        creation_date__lte=startdate
        ).order_by("-creation_date")

    return queryset

答案 1 :(得分:0)

我为此编写了一个简单的函数:

def response_with_paginator(viewset, queryset):
    page = viewset.paginate_queryset(queryset)
    if page is not None:
        serializer = viewset.get_serializer(page, many=True)
        return viewset.get_paginated_response(serializer.data)

    return Response(viewset.get_serializer(queryset, many=True).data)

用法如下:

@action(...)
def comments(self, ...):
    queryset = Comment.objects.filter(...)
    return response_with_paginator(self, queryset)