mirror of
				https://github.com/encode/django-rest-framework.git
				synced 2025-11-04 09:57:55 +03:00 
			
		
		
		
	Added pagination mixin. Need to write tests
This commit is contained in:
		
							parent
							
								
									a53101bea9
								
							
						
					
					
						commit
						1eb2dfcc3a
					
				| 
						 | 
					@ -4,6 +4,7 @@ classes that can be added to a `View`.
 | 
				
			||||||
"""
 | 
					"""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from django.contrib.auth.models import AnonymousUser
 | 
					from django.contrib.auth.models import AnonymousUser
 | 
				
			||||||
 | 
					from django.core.paginator import Paginator
 | 
				
			||||||
from django.db.models.query import QuerySet
 | 
					from django.db.models.query import QuerySet
 | 
				
			||||||
from django.db.models.fields.related import ForeignKey
 | 
					from django.db.models.fields.related import ForeignKey
 | 
				
			||||||
from django.http import HttpResponse
 | 
					from django.http import HttpResponse
 | 
				
			||||||
| 
						 | 
					@ -637,4 +638,92 @@ class ListModelMixin(object):
 | 
				
			||||||
            queryset = queryset.order_by(*args)
 | 
					            queryset = queryset.order_by(*args)
 | 
				
			||||||
        return queryset.filter(**kwargs)
 | 
					        return queryset.filter(**kwargs)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					########## Pagination Mixins ##########
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class PaginatorMixin(object):
 | 
				
			||||||
 | 
					    """
 | 
				
			||||||
 | 
					    Adds pagination support to GET requests
 | 
				
			||||||
 | 
					    Obviously should only be used on lists :)
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    A default limit can be set by setting `limit` on the object. This will also
 | 
				
			||||||
 | 
					    be used as the maximum if the client sets the `limit` GET param
 | 
				
			||||||
 | 
					    """
 | 
				
			||||||
 | 
					    limit = 20
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def get_limit(self):
 | 
				
			||||||
 | 
					        """ Helper method to determine what the `limit` should be """
 | 
				
			||||||
 | 
					        try:
 | 
				
			||||||
 | 
					            limit = int(self.request.GET.get('limit', self.limit))
 | 
				
			||||||
 | 
					            return min(limit, self.limit)
 | 
				
			||||||
 | 
					        except ValueError:
 | 
				
			||||||
 | 
					            return self.limit
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def url_with_page_number(self, page_number):
 | 
				
			||||||
 | 
					        """ Constructs a url used for getting the next/previous urls """
 | 
				
			||||||
 | 
					        url = "%s?page=%d" % (self.request.path, page_number)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        limit = self.get_limit()
 | 
				
			||||||
 | 
					        if limit != self.limit:
 | 
				
			||||||
 | 
					            url = "%s&limit=%d" % (url, limit)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return url
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def next(self, page):
 | 
				
			||||||
 | 
					        """ Returns a url to the next page of results (if any) """
 | 
				
			||||||
 | 
					        if not page.has_next():
 | 
				
			||||||
 | 
					            return None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return self.url_with_page_number(page.next_page_number())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def previous(self, page):
 | 
				
			||||||
 | 
					        """ Returns a url to the previous page of results (if any) """
 | 
				
			||||||
 | 
					        if not page.has_previous():
 | 
				
			||||||
 | 
					            return None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return self.url_with_page_number(page.previous_page_number())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def serialize_page_info(self, page):
 | 
				
			||||||
 | 
					        """ This is some useful information that is added to the response """
 | 
				
			||||||
 | 
					        return {
 | 
				
			||||||
 | 
					            'next': self.next(page),
 | 
				
			||||||
 | 
					            'page': page.number,
 | 
				
			||||||
 | 
					            'pages': page.paginator.num_pages,
 | 
				
			||||||
 | 
					            'per_page': self.get_limit(),
 | 
				
			||||||
 | 
					            'previous': self.previous(page),
 | 
				
			||||||
 | 
					            'total': page.paginator.count,
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def filter_response(self, obj):
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        Given the response content, paginate and then serialize.
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        The response is modified to include to useful data relating to the number
 | 
				
			||||||
 | 
					        of objects, number of pages, next/previous urls etc. etc.
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        The serialised objects are put into `results` on this new, modified
 | 
				
			||||||
 | 
					        response
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        # We don't want to paginate responses for anything other than GET requests
 | 
				
			||||||
 | 
					        if self.method.upper() != 'GET':
 | 
				
			||||||
 | 
					            return self._resource.filter_response(obj)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        paginator = Paginator(obj, self.get_limit())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        try:
 | 
				
			||||||
 | 
					            page_num = int(self.request.GET.get('page', '1'))
 | 
				
			||||||
 | 
					        except ValueError:
 | 
				
			||||||
 | 
					            page_num = 1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if page_num not in paginator.page_range:
 | 
				
			||||||
 | 
					            raise ErrorResponse(status.HTTP_404_NOT_FOUND, {'detail': 'That page contains no results'})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        page = paginator.page(page_num)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        serialized_object_list = self._resource.filter_response(page.object_list)
 | 
				
			||||||
 | 
					        serialized_page_info = self.serialize_page_info(page)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        serialized_page_info['results'] = serialized_object_list
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return serialized_page_info
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue
	
	Block a user