【问题标题】:Django-Rest-Framework: Paginate nested objectDjango-Rest-Framework:分页嵌套对象
【发布时间】:2017-04-09 23:11:31
【问题描述】:

我有两个模型:

class Book(models.Model):
    title = models.CharField(max_length=250)
    author = models.CharField(max_length=250)
class WordInBook(models.Model):
    book = models.ForeignKey("Book")
    word = models.ForeignKey("Word")

以及对应的序列化器:

class BookSerializer(ModelSerializer):
    wordinbook_set = WordInBookSerializer(many=True)

    class Meta:
        model = Book
        fields = ('id', 'title', 'author', 'wordinbook_set')

class WordInBookSerializer(ModelSerializer):
    class Meta:
        model = WordInBook
        fields = ('word')

现在我想对 wordinbook_set 进行分页。在序列化器之外很容易:

book = Book.objects.get(pk=book_id)
paginator = Paginator(book.wordinbook_set.all(), 10)
words = paginator.page(page).object_list

但这给我留下了两个单独的序列化对象。

问题:如何在序列化程序中对 wordinbook_set 进行分页?
生成的 json 应该如下所示:

{id: '...', title: '...', author: '...', wordinbook_set: [ 10 WordInBook objects here ]}

【问题讨论】:

    标签: django serialization pagination django-rest-framework


    【解决方案1】:

    嗯,相信你应该以不同的方式处理它。

    首先 - 在 BooksViewSet 上定义 @detail_route - 让我们说书中的文字:

    @detail_route(method=['GET'], url_path='word-in-book')
    def word_in_book(self, request, *args, **kwargs):
        object = self.get_object()
        queryset = object.wordinbook_set.all()
    
        page = self.paginate_queryset(queryset)
        if page is not None:
            serializer = WordInBookSerializer(page, many=True)
            return self.get_paginated_response(serializer.data)
    
        serializer = self.get_serializer(queryset, many=True)
        return Response(serializer.data)
    

    这样你会得到额外的端点:

    /books/1/word-in-book/ 将返回书​​籍模型中单词的分页结果。

    希望这会有所帮助。

    我相信在您的情况下分页是不可能的 - 您可以稍微转换代码以返回让我们说:10 个第一个对象。

    【讨论】:

      【解决方案2】:

      由于在 DRF 3.1 中删除了 PaginationSerializer,您必须实现自己的逻辑,更多详细信息请参阅: https://stackoverflow.com/a/31500287/7469841

      因此,您必须更改 BookSerializer 以包含分页行为,如下所示:

      图书序列化器

      class BookSerializer(ModelSerializer):
              wordinbook_set = serializers.SerializerMethodField('paginated_wordinbook')
      
              class Meta:
                  model = Book
                  fields = ('id', 'title', 'author', 'wordinbook_set')
      
              def paginated_wordinbook(self, obj):
                  page_size = self.context['request'].query_params.get('size') or 10
                  paginator = Paginator(obj.wordinbook_set.all(), page_size)
                  page = self.context['request'].query_params.get('page') or 1
      
                  words_in_book = paginator.page(page)
                  serializer = WordInBookSerializer(words_in_book, many=True)
      
                  return serializer.data
      

      首先,您必须使用 django.core.paginator 中的 Paginator 对可迭代对象进行分页:

      paginator = Paginator(obj.wordinbook_set.all(), page_size)
      

      然后从分页数据中获取目标页面:

      words_in_book = paginator.page(page)
      

      使用 many=True 序列化分页集:

      serializer = WordInBookSerializer(words_in_book, many=True)
      

      还可以使页面大小动态化,您可以使用 query_params 来接收所需的页面大小,例如,您可以在请求中选择页面大小为 10,在不同请求中选择为 100,检索页面大小:

      page_size = self.context['request'].query_params.get('size') or 10
      

      最后为了允许用户请求某个页面,再次使用 query_params 来接收它:

      page = self.context['request'].query_params.get('page') or 1
      

      【讨论】:

      • Wii 从 paginated_wordinbook 返回的数据包含下一页的链接,就像 ListAPIView 中的传统 Pagination 类一样
      猜你喜欢
      • 1970-01-01
      • 2016-01-22
      • 1970-01-01
      • 2017-12-29
      • 1970-01-01
      • 1970-01-01
      • 2021-11-30
      • 2014-07-07
      • 2020-07-11
      相关资源
      最近更新 更多