Django Rest Framework Pagination Settings - Conten

2019-04-13 02:42发布

问题:

6.30.15 - HOW CAN I MAKE THIS QUESTION BETTER AND MORE HELPFUL TO OTHERS? FEEDBACK WOULD BE HELPFUL. THANKS!

I am using DRF as server side to a Dojo/Dgrid web application. Dojo needs a content-range or range response from the server. Currently it doesn't send any and so the pagination for dgrid.grid isn't working properly.

In the DRF documentation it states" Pagination links that are included in response headers, such as Content-Range or Link." But doesn't give a clear process on HOW to set the DRF API to do this. I am still relatively new to web app development. Any help would be appreciated!

回答1:

1. Including Link Header in response:

To include a Link header in your response, you need to create a custom pagination serializer class, This should subclass pagination.BasePagination and override the get_paginated_response(self, data) method.

Example (taken from docs):

Suppose we want to replace the default pagination output style with a modified format that includes the next and previous links in a Link header, we override the get_paginated_response() .

class LinkHeaderPagination(pagination.PageNumberPagination):

    def get_paginated_response(self, data):
        next_url = self.get_next_link()
        previous_url = self.get_previous_link()

        if next_url is not None and previous_url is not None:
            link = '<{next_url}; rel="next">, <{previous_url}; rel="prev">'
        elif next_url is not None:
            link = '<{next_url}; rel="next">'
        elif previous_url is not None:
            link = '<{previous_url}; rel="prev">'
        else:
            link = ''

        link = link.format(next_url=next_url, previous_url=previous_url)
        headers = {'Link': link} if link else {}

        return Response(data, headers=headers)

After this, we need to include this pagination class in our settings so that it is used by DRF instead of the default pagination classes.

REST_FRAMEWORK = {
    'DEFAULT_PAGINATION_CLASS': 'my_project.apps.core.pagination.LinkHeaderPagination',
    'PAGE_SIZE': 100
}

API responses for list endpoints will now include a Link header.

2. Including Content-Range Header in response:

You can also send Content-Range header instead of Link. Just create a headers dictionary with Content-Range as the key and value as how many items are being returned and how many total items exist.

For example:

class ContentRangeHeaderPagination(pagination.PageNumberPagination):

    def get_paginated_response(self, data):
        total_items = self.page.paginator.count
        item_starting_index = self.page.start_index() - 1 # In a page, indexing starts from 1
        item_ending_index = self.page.end_index() - 1

        content_range = 'items {0}-{1}/{2}'.format(item_starting_index, item_ending_index, total_items)      

        headers = {'Content-Range': content_range} 

        return Response(data, headers=headers)

Suppose this is the header received:

Content-Range: items 0-9/50 

This tells us that the response has a Content-Range header with value as items 0-9/50. This indicates that first 10 items are returned out of total 50.

You can also use * instead of total no. of items if calculating total is expensive.

Content-Range: items 0-9/* # Use this if total is expensive to calculate


回答2:

DRF recommends a thirdparty package in its documentation: django-rest-framework-link-header-pagination

It is supposed to follow the same path as the Github API, which is basically the proper way of doing what the other answer suggest.

Here is a sample Link header taken from Github's API guide:

Link: <https://api.github.com/search/code?q=addClass+user%3Amozilla&page=15>; rel="next",
  <https://api.github.com/search/code?q=addClass+user%3Amozilla&page=34>; rel="last",
  <https://api.github.com/search/code?q=addClass+user%3Amozilla&page=1>; rel="first",
  <https://api.github.com/search/code?q=addClass+user%3Amozilla&page=13>; rel="prev"

I haven't tried the package yet but I'll report back once done.