将ListModelMixin与APIView结合使用以显示分页 [英] Combine ListModelMixin with APIView to show pagination

查看:386
本文介绍了将ListModelMixin与APIView结合使用以显示分页的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想在我的API中显示分页功能,并且我将APIView与多个序列化程序一起使用.
我知道用ListView显示分页非常容易.
我在某处看到可以组合使用ListModelMixinAPIView的方法,但是如果我的代码如下:

I want to show the pagination feature in my API and I am using APIView with multiple serializers.
I know it is very easy to show pagination with ListView.
I have seen somewhere that combining ListModelMixin and APIView works but if my code is as follows:

class ListModelMixin(object):
    def list(self, request, *args, **kwargs):
        queryset = self.filter_queryset(self.get_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(serilaizer.data)

class ItemsAPIView(APIView):
    permission_classes = (permissions.IsAuthenticated,)
    pagination_class = api_settings.DEFAULT_PAGINATION_CLASS

    def get(self, request, format=None):
        """
        Return a list of all devices of this user.
        """
        reply = {}
        try:
            products = BaseItem.objects.owned_items().filter(owner=request.user)
            reply['data'] = OwnedItemSerializer(products, many=True).data

            items = BaseItem.objects.dev_items().filter(owner=request.user)
            reply['data'].extend(ItemSerializer(items, many=True).data)

        except:
            reply['data'] = []
        return Response(reply, status.HTTP_200_OK)

如何合并它们以便获得分页结果?
预先感谢!

How can I combine them so I can get paginated results?
Thanks in advance!

推荐答案

首先,您当前正在做的事情过于复杂,没有理由.

First things first, what you are currently doing is too complex without reason.

为了实现可分页"查询集,最好使用简单的过滤器组合而不是模型方法来更改owned_items()dev_items().通过示例进行澄清:

In order to achieve a "paginatable" queryset, it is preferred to change your owned_items() and dev_items() in simple filter combinations, rather than model methods. To clarify by example:

products = BaseItem.objects.filter(owner=request.user, owned=True)

代替

products = BaseItem.objects.owned_items().filter(owner=request.user)

这样,您可以生成一个更易于分页的单个查询集:

That way, you can produce a single queryset which will be easier to paginate:

user_items = BaseItem.objects.filter(
                 Q(owner=request.user, owned=True) |
                 Q(owner=request.user, dev=True)
             )

注释1:如果愿意,您可以进一步简化事情,但这超出了您的问题范围.值得深思,请查看以下内容:

Note 1: You can simplify things further if you like, but that gets out of scope of your question. As food for thought, check this out:

user_items =  BaseItem.objects.filter(owner=request.user).distinct()

注2::您应该对单个模型使用单个序列化程序,因为您所做的事情会增加复杂性而无益(高风险,低回报的情况)

Note 2: You should use a single serializer for a single model because what you are doing adds complexity without benefit (high risk-low reward situation)

具有以上提到并假定的条件:

With the above mentioned and assumed:

有一些方法可以在这里实现您想要的:

There are some ways to achieve what you want here:

  1. 通过使用 GeneriAPIView ListModelMixin ,您可以在一种具有自动分页的.list()方法的方法:

  1. By utilizing GeneriAPIView and ListModelMixin you can refactor your class in such a way to have a .list() method with auto-pagination:

from rest_framework import mixins, generics

class ItemsAPIView(mixins.ListModelMixin, generics.GenericAPIView,):
    permission_classes = (permissions.IsAuthenticated,)
    pagination_class = api_settings.DEFAULT_PAGINATION_CLASS
    serializer_class = OwnedItemSerializer

    # You can define .get in here if you really need it.
    # You can also override .list to add specific functionality

  • 如果您不想使用以上内容,并且希望保留您的APIView,则可以保留get方法并为其提供分页,如本

  • If you don't want to use the above, and you want to keep your APIView, then you can keep your get method and provide pagination for it as mentioned in this Q&A example:

    class ItemsAPIView(APIView):
        permission_classes = (permissions.IsAuthenticated,)
        pagination_class = api_settings.DEFAULT_PAGINATION_CLASS
        serializer_class = MyNewUnifiedSerializerClass
    
        def get(self, request):
            user_items =  BaseItem.objects.filter(
                              owner=request.user
                          ).distinct()
            page = self.paginate_queryset(user_items)
    
            if page is not None:
                serializer = self.serializer_class(page, many=True)
                return self.get_paginated_response(serializer.data)
    
            serializer = self.get_serializer(user_items, many=True)
            return Response(serializer.data)
    
        # Now add the pagination handlers taken from 
        #  django-rest-framework/rest_framework/generics.py
    
        @property
        def paginator(self):
            """
            The paginator instance associated with the view, or `None`.
            """
            if not hasattr(self, '_paginator'):
                if self.pagination_class is None:
                    self._paginator = None
                else:
                    self._paginator = self.pagination_class()
                return self._paginator
    
         def paginate_queryset(self, queryset):
             """
             Return a single page of results, 
             or `None` if pagination is disabled.
             """
             if self.paginator is None:
                 return None
             return self.paginator.paginate_queryset(
                        queryset, 
                        self.request, 
                        view=self
                    )
    
         def get_paginated_response(self, data):
             """
             Return a paginated style `Response` object 
             for the given output data.
             """
             assert self.paginator is not None
             return self.paginator.get_paginated_response(data)
    

  • 这篇关于将ListModelMixin与APIView结合使用以显示分页的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

    查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆