Reputation: 319
How to use the object id and get the corresponding page number where that object belongs on all pages of the pagination in django-rest-framework
.
What I'm trying to do here is sort of reverse pagination with django-rest-framework
.
Is there any way to calculate the page number where a particular object belongs from all pages of the pagination and display it with the object(like in the serializer) ?
Any answer would be great! Thank you!
Upvotes: 1
Views: 754
Reputation: 319
I wanted drf
pagination to give me the entire page where a particular object belongs to (with other fellow objects as well). So I overrode the paginate_queryset
method in rest-framewok
pagination.PageNumberPagination
to achieve what I want and that worked. So I though to post it here as well.
In my case I have posts and answers followed by those posts. What I needed was to have a query parameter for answer id in the url which gives the entire page where that particular answer and other answers exist. Basically this is like reverse pagination.
So if I enter the following url, I'll get the result as it appears in the image.
URL: http://localhost:8000/answer_api/?postBelong=1&answer=164
So we don't need to enter the page number in the url. Only the answer id is enough and it gives entire page.
This is the code that I overrode.
def paginate_queryset(self, queryset, request, view=None):
"""
Overriding the method to get an entire page which a particular answer is belonged,
as asked by the user in the query parameter 'answer'
"""
answer_id = request.query_params.get('answer', None)
post_belong = request.query_params.get('postBelong', None)
'''here it calculates the corresponding page number where does the answer_id belong'''
page_num = 1
try:
answers = queryset.filter(postBelong=post_belong)
for index, answer in enumerate(answers):
if str(answer.id) == str(answer_id):
page_num = index // ANSWERS_PER_PAGE + 1
except Exception as exp:
msg = str(exp)
raise NotFound(msg)
page_size = self.get_page_size(request)
if not page_size:
return None
paginator = self.django_paginator_class(queryset, page_size)
page_number = request.query_params.get(self.page_query_param, page_num) # changed here as the page_num
if page_number in self.last_page_strings:
page_number = paginator.num_pages
try:
self.page = paginator.page(page_number)
except InvalidPage as exc:
msg = self.invalid_page_message.format(
page_number=page_number, message=str(exc)
)
raise NotFound(msg)
if paginator.num_pages > 1 and self.template is not None:
# The browsable API should display pagination controls.
self.display_page_controls = True
self.request = request
return list(self.page)
If there is any other way to do this, please comment below because I'm also still learning these things.
Thank you!
Upvotes: 0
Reputation: 32244
You can perform a count of all results that would appear before the object and then divide that number by the page size to get the page that the object would appear on
obj = Model.objects.get(attr=value)
queryset = Model.objects.order_by('pk')
num_preceeding_results = Model.objects.filter(pk__lt=obj.pk).count()
page = num_preceeding_results // page_size + 1
Upvotes: 2