Janitha Nawarathna
Janitha Nawarathna

Reputation: 319

How to send the object is and get the corresponding page number where that item exists in Django Rest Framework pagination?

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

Answers (2)

Janitha Nawarathna
Janitha Nawarathna

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

enter image description here

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

Iain Shelvington
Iain Shelvington

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

Related Questions