Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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.

like image 364
LondonAppDev Avatar asked Nov 12 '13 11:11

LondonAppDev


2 Answers

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.

like image 117
John Moutafis Avatar answered Oct 26 '22 05:10

John Moutafis


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

like image 20
bahoo Avatar answered Oct 26 '22 06:10

bahoo