LondonAppDev
LondonAppDev

Reputation: 9633

Django Rest Framework Paginate By Specified GET Parameter

I am using the Django REST Framework and I need to paginate a list based on a GET parameter provided with the request.

I know that I can set 'PAGINATE_BY': 10 in the settings, however I want to allow the caller to specify the number they want to paginate by when making the request.

I currently have the following serializer:

from api.models import Countries
from rest_framework import serializers

class CountrySerializer(serializers.Serializer):
    country_geoname_id = serializers.CharField(required=True)
    country_code = serializers.CharField(source="iso", max_length=2L, required=True)
    country_name = serializers.CharField(max_length=64L, required=True)

    def transform_iso(self, obj, value):
        return "country_code"

And I have tried the following view:

@api_view(['GET'])
def country_list(request):
    """
    List all countries
    """
    if request.method == 'GET':
        queryset = Countries.objects.all()
        serializer = CountrySerializer(queryset, many=True, data=request.DATA)
        paginate_by = request.GET.get('limit', 10)
        return Response(serializer.data)

However I feel I am missing something, and I have been unable to figure it out from the documentation.

Should I be doing the pagination in the serializer or in the view?

Thanks in advance.

Upvotes: 7

Views: 8549

Answers (2)

John Moutafis
John Moutafis

Reputation: 23134

Let's break the problem down:

  1. You need to create a pagination method that allows the user to define the page size:

    As stated in the PageNumberPagination in the DRF documentation, you can define a parameter name by overriding the page_size_query_param:

    If set, this is a string value indicating the name of a query parameter that allows the client to set the page size on a per-request basis. Defaults to None, indicating that the client may not control the requested page size.

    You can achieve that by one of the following ways:

    • In settings.py add the following:

      REST_FRAMEWORK = {
          'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination',
          'PAGE_SIZE': 10,
          'PAGINATE_BY_PARAM': 'page_size'
      }
      
    • Or you can create a custom pagination class and override your settings there:

      from rest_framework.pagination import PageNumberPagination
      
      class MyPagination(PageNumberPagination):
          page_size = 10
          page_size_query_param = 'page_size'
      
  2. Finally you need to define which pagination class you will use in your view function.

    The following example will work for either of the aforementioned cases by just changing the value of the paginator variable to PageNumberPaginator or MyPaginator:

    from rest_framework.pagination import PageNumberPagination
    
    @api_view(['GET'])
    def country_list(request):
    """
    List all countries
    """
    if request.method == 'GET':
        paginator = PageNumberPagination()
        queryset = Countries.objects.all()
        context = paginator.paginate_queryset(queryset, request)
        serializer = CountrySerializer(context, many=True)
        return paginator.get_paginated_response(serializer.data)
    

Now you have function based view with pagination and a query parameter to change the page size.

Upvotes: 9

bahoo
bahoo

Reputation: 402

Try the PAGINATE_BY_PARAM setting. This snippet should get you pretty close:

class CountryListView(ListAPIView):
    model = Countries
    serializer_class = CountrySerializer
    paginate_by_param = 'limit'

See http://www.django-rest-framework.org/api-guide/pagination#pagination-in-the-generic-views

My snippet uses generic views to take a lot of the repetition out, I recommend giving those a look, too. http://www.django-rest-framework.org/api-guide/generic-views

Upvotes: 2

Related Questions