Django-Rest-Framework:Paginate嵌套对象

Ale*_*der 6 django serialization pagination django-rest-framework

我有两个型号:

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")
Run Code Online (Sandbox Code Playgroud)

和相应的序列化器:

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')
Run Code Online (Sandbox Code Playgroud)

现在我想分页wordinbook_set.在序列化器之外很容易:

book = Book.objects.get(pk=book_id)
paginator = Paginator(book.wordinbook_set.all(), 10)
words = paginator.page(page).object_list
Run Code Online (Sandbox Code Playgroud)

但这留下了两个独立的序列化对象.

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

{id: '...', title: '...', author: '...', wordinbook_set: [ 10 WordInBook objects here ]}
Run Code Online (Sandbox Code Playgroud)

小智 5

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

因此,您必须更改BookSerializer,以包括以下分页行为:

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
Run Code Online (Sandbox Code Playgroud)

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

paginator = Paginator(obj.wordinbook_set.all(), page_size)
Run Code Online (Sandbox Code Playgroud)

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

words_in_book = paginator.page(page)
Run Code Online (Sandbox Code Playgroud)

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

serializer = WordInBookSerializer(words_in_book, many=True)
Run Code Online (Sandbox Code Playgroud)

同样,为了使页面大小动态化,您可以使用query_params来接收所需的页面大小,例如,您可以将页面大小选择为请求中的10和其他请求中的100,以检索页面大小:

page_size = self.context['request'].query_params.get('size') or 10
Run Code Online (Sandbox Code Playgroud)

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

page = self.context['request'].query_params.get('page') or 1
Run Code Online (Sandbox Code Playgroud)

  • Wii 从 pagination_wordinbook 返回的数据包含下一页的链接,就像 ListAPIView 中的传统 Pagination 类一样 (2认同)

opa*_*ski 2

嗯,相信你应该用不同的方式来解决这个问题。

首先 - 定义@detail_route-BooksViewSet让我们说一下书中的单词:

@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)
Run Code Online (Sandbox Code Playgroud)

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

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

希望这可以帮助。

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