Django-Rest-Framework: Paginate Nested Object

I have two models:

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") 

And the corresponding serializers:

 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') 

Now I want to paginate the wordinbook_set pages. Outside of the serializer, this is easy:

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

But that leaves me with two separate serialized objects.

Question: how can I split wordinbook_set inside serializer?
The json result should look like this:

 {id: '...', title: '...', author: '...', wordinbook_set: [ 10 WordInBook objects here ]} 
+5
source share
2 answers

Since the PaginationSerializer was removed in DRF 3.1, you must implement your own logic, for more information, refer to: fooobar.com/questions/735249 / ...

So, you need to modify your BookSerializer to enable pagination behavior as follows:

Bookseerializer

 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 

First, you need to use the Paginator found in django.core.paginator to break down the iterative object:

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

Then get the landing page from the paginated data:

 words_in_book = paginator.page(page) 

Serialize pagination with set = True:

 serializer = WordInBookSerializer(words_in_book, many=True) 

To make a dynamic page size, you can use query_params to get the desired page size, for example, you can choose a page size of 10 in the request and be 100 in another request to get the page size:

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

Finally, to allow the user to request a specific page, use query_params again to retrieve it:

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

Hmm, believe that you need to work a little with him.

First - define @detail_route in the BooksViewSet - say, word-in-book:

 @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) 

This way you get an extra endpoint:

/books/1/word-in-book/ , which will return you paginated words in book models.

Hope this helps.

I believe that pagination is not possible in your case - you can just transform the code a bit to return: let's say: 10 first objects.

0
source

Source: https://habr.com/ru/post/1260357/


All Articles