mirror of
https://github.com/encode/django-rest-framework.git
synced 2025-02-02 20:54:42 +03:00
Polishing to page size query parameters & more docs
This commit is contained in:
parent
9973cf329a
commit
31f01bd631
|
@ -123,18 +123,36 @@ Each of the generic views provided is built by combining one of the base views b
|
|||
|
||||
Extends REST framework's `APIView` class, adding support for serialization of model instances and model querysets.
|
||||
|
||||
**Attributes**:
|
||||
|
||||
* `model` - The model that should be used for this view. Used as a fallback for determining the serializer if `serializer_class` is not set, and as a fallback for determining the queryset if `queryset` is not set. Otherwise not required.
|
||||
* `serializer_class` - The serializer class that should be used for validating and deserializing input, and for serializing output. If unset, this defaults to creating a serializer class using `self.model`, with the `DEFAULT_MODEL_SERIALIZER_CLASS` setting as the base serializer class.
|
||||
|
||||
## MultipleObjectAPIView
|
||||
|
||||
Provides a base view for acting on a single object, by combining REST framework's `APIView`, and Django's [MultipleObjectMixin].
|
||||
|
||||
**See also:** ccbv.co.uk documentation for [MultipleObjectMixin][multiple-object-mixin-classy].
|
||||
|
||||
**Attributes**:
|
||||
|
||||
* `queryset` - The queryset that should be used for returning objects from this view. If unset, defaults to the default queryset manager for `self.model`.
|
||||
* `paginate_by` - The size of pages to use with paginated data. If set to `None` then pagination is turned off. If unset this uses the same value as the `PAGINATE_BY` setting, which defaults to `None`.
|
||||
* `paginate_by_param` - The name of a query parameter, which can be used by the client to overide the default page size to use for pagination. If unset this uses the same value as the `PAGINATE_BY_PARAM` setting, which defaults to `None`.
|
||||
|
||||
## SingleObjectAPIView
|
||||
|
||||
Provides a base view for acting on a single object, by combining REST framework's `APIView`, and Django's [SingleObjectMixin].
|
||||
|
||||
**See also:** ccbv.co.uk documentation for [SingleObjectMixin][single-object-mixin-classy].
|
||||
|
||||
**Attributes**:
|
||||
|
||||
* `queryset` - The queryset that should be used when retrieving an object from this view. If unset, defaults to the default queryset manager for `self.model`.
|
||||
* `pk_kwarg` - The URL kwarg that should be used to look up objects by primary key. Defaults to `'pk'`. [Can only be set to non-default on Django 1.4+]
|
||||
* `slug_kwarg` - The URL kwarg that should be used to look up objects by a slug. Defaults to `'slug'`. [Can only be set to non-default on Django 1.4+]
|
||||
* `slug_field` - The field on the model that should be used to look up objects by a slug. If used, this should typically be set to a field with `unique=True`. Defaults to `'slug'`.
|
||||
|
||||
---
|
||||
|
||||
# Mixins
|
||||
|
@ -147,10 +165,6 @@ Provides a `.list(request, *args, **kwargs)` method, that implements listing a q
|
|||
|
||||
Should be mixed in with [MultipleObjectAPIView].
|
||||
|
||||
**Arguments**:
|
||||
|
||||
* `page_size_kwarg` - Allows you to overwrite the global settings `PAGE_SIZE_KWARG` for a specific view. You can also turn it off for a specific view by setting it to `None`. Default is `page_size`.
|
||||
|
||||
## CreateModelMixin
|
||||
|
||||
Provides a `.create(request, *args, **kwargs)` method, that implements creating and saving a new model instance.
|
||||
|
|
|
@ -96,11 +96,21 @@ Default: `rest_framework.serializers.ModelSerializer`
|
|||
|
||||
Default: `rest_framework.pagination.PaginationSerializer`
|
||||
|
||||
## FORMAT_SUFFIX_KWARG
|
||||
## FILTER_BACKEND
|
||||
|
||||
**TODO**
|
||||
The filter backend class that should be used for generic filtering. If set to `None` then generic filtering is disabled.
|
||||
|
||||
Default: `'format'`
|
||||
## PAGINATE_BY
|
||||
|
||||
The default page size to use for pagination. If set to `None`, pagination is disabled by default.
|
||||
|
||||
Default: `None`
|
||||
|
||||
## PAGINATE_BY_KWARG
|
||||
|
||||
The name of a query parameter, which can be used by the client to overide the default page size to use for pagination. If set to `None`, clients may not override the default page size.
|
||||
|
||||
Default: `None`
|
||||
|
||||
## UNAUTHENTICATED_USER
|
||||
|
||||
|
@ -150,14 +160,10 @@ Default: `'accept'`
|
|||
|
||||
Default: `'format'`
|
||||
|
||||
## PAGE_SIZE_KWARG
|
||||
## FORMAT_SUFFIX_KWARG
|
||||
|
||||
Allows you to globally pass a page size parameter for an individual request.
|
||||
**TODO**
|
||||
|
||||
The name of the GET parameter of views which inherit ListModelMixin for requesting data with an individual page size.
|
||||
|
||||
If the value if this setting is `None` the passing a page size is turned off by default.
|
||||
|
||||
Default: `'page_size'`
|
||||
Default: `'format'`
|
||||
|
||||
[cite]: http://www.python.org/dev/peps/pep-0020/
|
||||
|
|
|
@ -7,7 +7,8 @@
|
|||
## Master
|
||||
|
||||
* Support for `read_only_fields` on `ModelSerializer` classes.
|
||||
* Support for individual page sizes per request via `page_size` GET parameter in views which inherit ListModelMixin.
|
||||
* Support for clients overriding the pagination page sizes. Use the `PAGINATE_BY_PARAM` setting or set the `paginate_by_param` attribute on a generic view.
|
||||
* 201 Responses now return a 'Location' header.
|
||||
|
||||
## 2.1.2
|
||||
|
||||
|
|
|
@ -14,6 +14,7 @@ class GenericAPIView(views.APIView):
|
|||
"""
|
||||
Base class for all other generic views.
|
||||
"""
|
||||
model = None
|
||||
serializer_class = None
|
||||
model_serializer_class = api_settings.DEFAULT_MODEL_SERIALIZER_CLASS
|
||||
|
||||
|
@ -30,8 +31,10 @@ class GenericAPIView(views.APIView):
|
|||
def get_serializer_class(self):
|
||||
"""
|
||||
Return the class to use for the serializer.
|
||||
Use `self.serializer_class`, falling back to constructing a
|
||||
model serializer class from `self.model_serializer_class`
|
||||
|
||||
Defaults to using `self.serializer_class`, falls back to constructing a
|
||||
model serializer class using `self.model_serializer_class`, with
|
||||
`self.model` as the model.
|
||||
"""
|
||||
serializer_class = self.serializer_class
|
||||
|
||||
|
@ -58,29 +61,42 @@ class MultipleObjectAPIView(MultipleObjectMixin, GenericAPIView):
|
|||
|
||||
pagination_serializer_class = api_settings.DEFAULT_PAGINATION_SERIALIZER_CLASS
|
||||
paginate_by = api_settings.PAGINATE_BY
|
||||
paginate_by_param = api_settings.PAGINATE_BY_PARAM
|
||||
filter_backend = api_settings.FILTER_BACKEND
|
||||
|
||||
def filter_queryset(self, queryset):
|
||||
"""
|
||||
Given a queryset, filter it with whichever filter backend is in use.
|
||||
"""
|
||||
if not self.filter_backend:
|
||||
return queryset
|
||||
backend = self.filter_backend()
|
||||
return backend.filter_queryset(self.request, queryset, self)
|
||||
|
||||
def get_pagination_serializer_class(self):
|
||||
def get_pagination_serializer(self, page=None):
|
||||
"""
|
||||
Return the class to use for the pagination serializer.
|
||||
Return a serializer instance to use with paginated data.
|
||||
"""
|
||||
class SerializerClass(self.pagination_serializer_class):
|
||||
class Meta:
|
||||
object_serializer_class = self.get_serializer_class()
|
||||
|
||||
return SerializerClass
|
||||
|
||||
def get_pagination_serializer(self, page=None):
|
||||
pagination_serializer_class = self.get_pagination_serializer_class()
|
||||
pagination_serializer_class = SerializerClass
|
||||
context = self.get_serializer_context()
|
||||
return pagination_serializer_class(instance=page, context=context)
|
||||
|
||||
def get_paginate_by(self, queryset):
|
||||
"""
|
||||
Return the size of pages to use with pagination.
|
||||
"""
|
||||
if self.paginate_by_param:
|
||||
params = self.request.QUERY_PARAMS
|
||||
try:
|
||||
return int(params[self.paginate_by_param])
|
||||
except (KeyError, ValueError):
|
||||
pass
|
||||
return self.paginate_by
|
||||
|
||||
|
||||
class SingleObjectAPIView(SingleObjectMixin, GenericAPIView):
|
||||
"""
|
||||
|
|
|
@ -7,7 +7,6 @@ which allows mixin classes to be composed in interesting ways.
|
|||
from django.http import Http404
|
||||
from rest_framework import status
|
||||
from rest_framework.response import Response
|
||||
from rest_framework.settings import api_settings
|
||||
|
||||
|
||||
class CreateModelMixin(object):
|
||||
|
@ -40,7 +39,6 @@ class ListModelMixin(object):
|
|||
Should be mixed in with `MultipleObjectAPIView`.
|
||||
"""
|
||||
empty_error = u"Empty list and '%(class_name)s.allow_empty' is False."
|
||||
page_size_kwarg = api_settings.PAGE_SIZE_KWARG
|
||||
|
||||
def list(self, request, *args, **kwargs):
|
||||
queryset = self.get_queryset()
|
||||
|
@ -66,17 +64,6 @@ class ListModelMixin(object):
|
|||
|
||||
return Response(serializer.data)
|
||||
|
||||
def get_paginate_by(self, queryset):
|
||||
if self.page_size_kwarg is not None:
|
||||
page_size_kwarg = self.request.QUERY_PARAMS.get(self.page_size_kwarg)
|
||||
if page_size_kwarg:
|
||||
try:
|
||||
page_size = int(page_size_kwarg)
|
||||
return page_size
|
||||
except ValueError:
|
||||
pass
|
||||
return super(ListModelMixin, self).get_paginate_by(queryset)
|
||||
|
||||
|
||||
class RetrieveModelMixin(object):
|
||||
"""
|
||||
|
|
|
@ -54,12 +54,19 @@ DEFAULTS = {
|
|||
'user': None,
|
||||
'anon': None,
|
||||
},
|
||||
|
||||
# Pagination
|
||||
'PAGINATE_BY': None,
|
||||
'PAGINATE_BY_PARAM': None,
|
||||
|
||||
# Filtering
|
||||
'FILTER_BACKEND': None,
|
||||
|
||||
# Authentication
|
||||
'UNAUTHENTICATED_USER': 'django.contrib.auth.models.AnonymousUser',
|
||||
'UNAUTHENTICATED_TOKEN': None,
|
||||
|
||||
# Browser enhancements
|
||||
'FORM_METHOD_OVERRIDE': '_method',
|
||||
'FORM_CONTENT_OVERRIDE': '_content',
|
||||
'FORM_CONTENTTYPE_OVERRIDE': '_content_type',
|
||||
|
@ -67,8 +74,6 @@ DEFAULTS = {
|
|||
'URL_FORMAT_OVERRIDE': 'format',
|
||||
|
||||
'FORMAT_SUFFIX_KWARG': 'format',
|
||||
|
||||
'PAGE_SIZE_KWARG': 'page_size'
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -36,25 +36,17 @@ if django_filters:
|
|||
|
||||
class DefaultPageSizeKwargView(generics.ListAPIView):
|
||||
"""
|
||||
View for testing default page_size usage
|
||||
View for testing default paginate_by_param usage
|
||||
"""
|
||||
model = BasicModel
|
||||
|
||||
|
||||
class CustomPageSizeKwargView(generics.ListAPIView):
|
||||
class PaginateByParamView(generics.ListAPIView):
|
||||
"""
|
||||
View for testing custom page_size usage
|
||||
View for testing custom paginate_by_param usage
|
||||
"""
|
||||
model = BasicModel
|
||||
page_size_kwarg = 'ps'
|
||||
|
||||
|
||||
class NonePageSizeKwargView(generics.ListAPIView):
|
||||
"""
|
||||
View for testing None page_size usage
|
||||
"""
|
||||
model = BasicModel
|
||||
page_size_kwarg = None
|
||||
paginate_by_param = 'page_size'
|
||||
|
||||
|
||||
class IntegrationTestPagination(TestCase):
|
||||
|
@ -181,9 +173,9 @@ class UnitTestPagination(TestCase):
|
|||
self.assertEquals(serializer.data['results'], self.objects[20:])
|
||||
|
||||
|
||||
class TestDefaultPageSizeKwarg(TestCase):
|
||||
class TestUnpaginated(TestCase):
|
||||
"""
|
||||
Tests for list views with default page size kwarg
|
||||
Tests for list views without pagination.
|
||||
"""
|
||||
|
||||
def setUp(self):
|
||||
|
@ -199,26 +191,17 @@ class TestDefaultPageSizeKwarg(TestCase):
|
|||
]
|
||||
self.view = DefaultPageSizeKwargView.as_view()
|
||||
|
||||
def test_default_page_size(self):
|
||||
def test_unpaginated(self):
|
||||
"""
|
||||
Tests the default page size for this view.
|
||||
no page size --> no limit --> no meta data
|
||||
"""
|
||||
request = factory.get('/')
|
||||
response = self.view(request).render()
|
||||
response = self.view(request)
|
||||
self.assertEquals(response.data, self.data)
|
||||
|
||||
def test_default_page_size_kwarg(self):
|
||||
"""
|
||||
If page_size_kwarg is set not set, the default page_size kwarg should limit per view requests.
|
||||
"""
|
||||
request = factory.get('/?page_size=5')
|
||||
response = self.view(request).render()
|
||||
self.assertEquals(response.data['count'], 13)
|
||||
self.assertEquals(response.data['results'], self.data[:5])
|
||||
|
||||
|
||||
class TestCustomPageSizeKwarg(TestCase):
|
||||
class TestCustomPaginateByParam(TestCase):
|
||||
"""
|
||||
Tests for list views with default page size kwarg
|
||||
"""
|
||||
|
@ -234,7 +217,7 @@ class TestCustomPageSizeKwarg(TestCase):
|
|||
{'id': obj.id, 'text': obj.text}
|
||||
for obj in self.objects.all()
|
||||
]
|
||||
self.view = CustomPageSizeKwargView.as_view()
|
||||
self.view = PaginateByParamView.as_view()
|
||||
|
||||
def test_default_page_size(self):
|
||||
"""
|
||||
|
@ -245,55 +228,11 @@ class TestCustomPageSizeKwarg(TestCase):
|
|||
response = self.view(request).render()
|
||||
self.assertEquals(response.data, self.data)
|
||||
|
||||
def test_disabled_default_page_size_kwarg(self):
|
||||
def test_paginate_by_param(self):
|
||||
"""
|
||||
If page_size_kwarg is set set, the default page_size kwarg should not work.
|
||||
If paginate_by_param is set, the new kwarg should limit per view requests.
|
||||
"""
|
||||
request = factory.get('/?page_size=5')
|
||||
response = self.view(request).render()
|
||||
self.assertEquals(response.data, self.data)
|
||||
|
||||
def test_custom_page_size_kwarg(self):
|
||||
"""
|
||||
If page_size_kwarg is set set, the new kwarg should limit per view requests.
|
||||
"""
|
||||
request = factory.get('/?ps=5')
|
||||
response = self.view(request).render()
|
||||
self.assertEquals(response.data['count'], 13)
|
||||
self.assertEquals(response.data['results'], self.data[:5])
|
||||
|
||||
|
||||
class TestNonePageSizeKwarg(TestCase):
|
||||
"""
|
||||
Tests for list views with default page size kwarg
|
||||
"""
|
||||
|
||||
def setUp(self):
|
||||
"""
|
||||
Create 13 BasicModel instances.
|
||||
"""
|
||||
for i in range(13):
|
||||
BasicModel(text=i).save()
|
||||
self.objects = BasicModel.objects
|
||||
self.data = [
|
||||
{'id': obj.id, 'text': obj.text}
|
||||
for obj in self.objects.all()
|
||||
]
|
||||
self.view = NonePageSizeKwargView.as_view()
|
||||
|
||||
def test_default_page_size(self):
|
||||
"""
|
||||
Tests the default page size for this view.
|
||||
no page size --> no limit --> no meta data
|
||||
"""
|
||||
request = factory.get('/')
|
||||
response = self.view(request).render()
|
||||
self.assertEquals(response.data, self.data)
|
||||
|
||||
def test_none_page_size_kwarg(self):
|
||||
"""
|
||||
If page_size_kwarg is set to None, custom page_size per request should be disabled.
|
||||
"""
|
||||
request = factory.get('/?page_size=5')
|
||||
response = self.view(request).render()
|
||||
self.assertEquals(response.data, self.data)
|
||||
|
|
Loading…
Reference in New Issue
Block a user