diff options
Diffstat (limited to 'docs/api-guide')
| -rwxr-xr-x | docs/api-guide/authentication.md | 54 | ||||
| -rw-r--r-- | docs/api-guide/exceptions.md | 12 | ||||
| -rw-r--r-- | docs/api-guide/fields.md | 33 | ||||
| -rw-r--r-- | docs/api-guide/filtering.md | 11 | ||||
| -rw-r--r-- | docs/api-guide/format-suffixes.md | 12 | ||||
| -rwxr-xr-x | docs/api-guide/generic-views.md | 12 | ||||
| -rw-r--r-- | docs/api-guide/pagination.md | 169 | ||||
| -rw-r--r-- | docs/api-guide/parsers.md | 53 | ||||
| -rw-r--r-- | docs/api-guide/relations.md | 1 | ||||
| -rw-r--r-- | docs/api-guide/renderers.md | 80 | ||||
| -rw-r--r-- | docs/api-guide/routers.md | 52 | ||||
| -rw-r--r-- | docs/api-guide/serializers.md | 65 | ||||
| -rw-r--r-- | docs/api-guide/versioning.md | 3 | ||||
| -rw-r--r-- | docs/api-guide/viewsets.md | 2 | 
14 files changed, 420 insertions, 139 deletions
| diff --git a/docs/api-guide/authentication.md b/docs/api-guide/authentication.md index 2074f1bf..4b8110bd 100755 --- a/docs/api-guide/authentication.md +++ b/docs/api-guide/authentication.md @@ -34,7 +34,7 @@ The value of `request.user` and `request.auth` for unauthenticated requests can  ## Setting the authentication scheme -The default authentication schemes may be set globally, using the `DEFAULT_AUTHENTICATION` setting.  For example. +The default authentication schemes may be set globally, using the `DEFAULT_AUTHENTICATION_CLASSES` setting.  For example.      REST_FRAMEWORK = {          'DEFAULT_AUTHENTICATION_CLASSES': ( @@ -126,7 +126,6 @@ To use the `TokenAuthentication` scheme you'll need to [configure the authentica          'rest_framework.authtoken'      ) -  ---  **Note:** Make sure to run `manage.py syncdb` after changing your settings. The `rest_framework.authtoken` app provides both Django (from v1.7) and South database migrations. See [Schema migrations](#schema-migrations) below. @@ -249,8 +248,6 @@ Unauthenticated responses that are denied permission will result in an `HTTP 403  If you're using an AJAX style API with SessionAuthentication, you'll need to make sure you include a valid CSRF token for any "unsafe" HTTP method calls, such as `PUT`, `PATCH`, `POST` or `DELETE` requests.  See the [Django CSRF documentation][csrf-ajax] for more details. ---- -  # Custom authentication  To implement a custom authentication scheme, subclass `BaseAuthentication` and override the `.authenticate(self, request)` method.  The method should return a two-tuple of `(user, auth)` if authentication succeeds, or `None` otherwise. @@ -293,13 +290,48 @@ The following example will authenticate any incoming request as the user given b  The following third party packages are also available. -## Digest Authentication +## Django OAuth Toolkit -HTTP digest authentication is a widely implemented scheme that was intended to replace HTTP basic authentication, and which provides a simple encrypted authentication mechanism. [Juan Riaza][juanriaza] maintains the [djangorestframework-digestauth][djangorestframework-digestauth] package which provides HTTP digest authentication support for REST framework. +The [Django OAuth Toolkit][django-oauth-toolkit] package provides OAuth 2.0 support, and works with Python 2.7 and Python 3.3+. The package is maintained by [Evonove][evonove] and uses the excellent [OAuthLib][oauthlib].  The package is well documented, and well supported and is currently our **recommended package for OAuth 2.0 support**. -## Django OAuth Toolkit +#### Installation & configuration + +Install using `pip`. + +    pip install django-oauth-toolkit + +Add the package to your `INSTALLED_APPS` and modify your REST framework settings. + +    INSTALLED_APPS = ( +        ... +        'oauth2_provider', +    ) + +    REST_FRAMEWORK = { +        'DEFAULT_AUTHENTICATION_CLASSES': ( +            'oauth2_provider.ext.rest_framework.OAuth2Authentication', +        ) +    } + +For more details see the [Django REST framework - Getting started][django-oauth-toolkit-getting-started] documentation. + +## Django REST framework OAuth + +The [Django REST framework OAuth][django-rest-framework-oauth] package provides both OAuth1 and OAuth2 support for REST framework. + +This package was previously included directly in REST framework but is now supported and maintained as a third party package. -The [Django OAuth Toolkit][django-oauth-toolkit] package provides OAuth 2.0 support, and works with Python 2.7 and Python 3.3+.  The package is maintained by [Evonove][evonove] and uses the excellent [OAuthLib][oauthlib].  The package is well documented, and comes as a recommended alternative for OAuth 2.0 support. +#### Installation & configuration + +Install the package using `pip`. + +    pip install djangorestframework-oauth + +For details on configuration and usage see the Django REST framework OAuth documentation for [authentication][django-rest-framework-oauth-authentication] and [permissions][django-rest-framework-oauth-permissions]. + +## Digest Authentication + +HTTP digest authentication is a widely implemented scheme that was intended to replace HTTP basic authentication, and which provides a simple encrypted authentication mechanism. [Juan Riaza][juanriaza] maintains the [djangorestframework-digestauth][djangorestframework-digestauth] package which provides HTTP digest authentication support for REST framework.  ## Django OAuth2 Consumer @@ -328,10 +360,14 @@ HTTP Signature (currently a [IETF draft][http-signature-ietf-draft]) provides a  [oauth]: http://oauth.net/2/  [permission]: permissions.md  [throttling]: throttling.md -[csrf-ajax]: https://docs.djangoproject.com/en/dev/ref/contrib/csrf/#ajax +[csrf-ajax]: https://docs.djangoproject.com/en/dev/ref/csrf/#ajax  [mod_wsgi_official]: http://code.google.com/p/modwsgi/wiki/ConfigurationDirectives#WSGIPassAuthorization  [custom-user-model]: https://docs.djangoproject.com/en/dev/topics/auth/customizing/#specifying-a-custom-user-model  [south-dependencies]: http://south.readthedocs.org/en/latest/dependencies.html +[django-oauth-toolkit-getting-started]: https://django-oauth-toolkit.readthedocs.org/en/latest/rest-framework/getting_started.html +[django-rest-framework-oauth]: http://jpadilla.github.io/django-rest-framework-oauth/ +[django-rest-framework-oauth-authentication]: http://jpadilla.github.io/django-rest-framework-oauth/authentication/ +[django-rest-framework-oauth-permissions]: http://jpadilla.github.io/django-rest-framework-oauth/permissions/  [juanriaza]: https://github.com/juanriaza  [djangorestframework-digestauth]: https://github.com/juanriaza/django-rest-framework-digestauth  [oauth-1.0a]: http://oauth.net/core/1.0a diff --git a/docs/api-guide/exceptions.md b/docs/api-guide/exceptions.md index 50bd14dd..56811ec3 100644 --- a/docs/api-guide/exceptions.md +++ b/docs/api-guide/exceptions.md @@ -18,7 +18,7 @@ The handled exceptions are:  In each case, REST framework will return a response with an appropriate status code and content-type.  The body of the response will include any additional details regarding the nature of the error. -By default all error responses will include a key `detail` in the body of the response, but other keys may also be included. +Most error responses will include a key `detail` in the body of the response.  For example, the following request: @@ -33,6 +33,16 @@ Might receive an error response indicating that the `DELETE` method is not allow      {"detail": "Method 'DELETE' not allowed."} +Validation errors are handled slightly differently, and will include the field names as the keys in the response. If the validation error was not specific to a particular field then it will use the "non_field_errors" key, or whatever string value has been set for the `NON_FIELD_ERRORS_KEY` setting. + +Any example validation error might look like this: + +    HTTP/1.1 400 Bad Request +    Content-Type: application/json +    Content-Length: 94 + +    {"amount": ["A valid integer is required."], "description": ["This field may not be blank."]} +  ## Custom exception handling  You can implement custom exception handling by creating a handler function that converts exceptions raised in your API views into response objects.  This allows you to control the style of error responses used by your API. diff --git a/docs/api-guide/fields.md b/docs/api-guide/fields.md index f06db56c..10291c12 100644 --- a/docs/api-guide/fields.md +++ b/docs/api-guide/fields.md @@ -41,6 +41,8 @@ Defaults to `False`  Normally an error will be raised if a field is not supplied during deserialization.  Set to false if this field is not required to be present during deserialization. +Setting this to `False` also allows the object attribute or dictionary key to be omitted from output when serializing the instance. If the key is not present it will simply not be included in the output representation. +  Defaults to `True`.  ### `allow_null` @@ -180,6 +182,12 @@ Corresponds to `django.db.models.fields.URLField`.  Uses Django's `django.core.v  **Signature:** `URLField(max_length=200, min_length=None, allow_blank=False)` +## UUIDField + +A field that ensures the input is a valid UUID string. The `to_internal_value` method will return a `uuid.UUID` instance. On output the field will return a string in the canonical hyphenated format, for example: + +    "de305d54-75b4-431b-adb2-eb6b9e546013" +  ---  # Numeric fields @@ -318,7 +326,7 @@ Both the `allow_blank` and `allow_null` are valid options on `ChoiceField`, alth  ## MultipleChoiceField -A field that can accept a set of zero, one or many values, chosen from a limited set of choices. Takes a single mandatory argument. `to_internal_representation` returns a `set` containing the selected values. +A field that can accept a set of zero, one or many values, chosen from a limited set of choices. Takes a single mandatory argument. `to_internal_value` returns a `set` containing the selected values.  **Signature:** `MultipleChoiceField(choices)` @@ -372,7 +380,7 @@ A field class that validates a list of objects.  **Signature**: `ListField(child)` -- `child` - A field instance that should be used for validating the objects in the list. +- `child` - A field instance that should be used for validating the objects in the list. If this argument is not provided then objects in the list will not be validated.  For example, to validate a list of integers you might use something like the following: @@ -387,6 +395,23 @@ The `ListField` class also supports a declarative style that allows you to write  We can now reuse our custom `StringListField` class throughout our application, without having to provide a `child` argument to it. +## DictField + +A field class that validates a dictionary of objects. The keys in `DictField` are always assumed to be string values. + +**Signature**: `DictField(child)` + +- `child` - A field instance that should be used for validating the values in the dictionary. If this argument is not provided then values in the mapping will not be validated. + +For example, to create a field that validates a mapping of strings to strings, you would write something like this: + +    document = DictField(child=CharField()) + +You can also use the declarative style, as with `ListField`. For example: + +    class DocumentField(DictField): +        child = CharField() +  ---  # Miscellaneous fields @@ -436,7 +461,7 @@ This is a read-only field. It gets its value by calling a method on the serializ  **Signature**: `SerializerMethodField(method_name=None)` -- `method-name` - The name of the method on the serializer to be called. If not included this defaults to `get_<field_name>`. +- `method_name` - The name of the method on the serializer to be called. If not included this defaults to `get_<field_name>`.  The serializer method referred to by the `method_name` argument should accept a single argument (in addition to `self`), which is the object being serialized. It should return whatever you want to be included in the serialized representation of the object. For example: @@ -480,7 +505,7 @@ Let's look at an example of serializing a class that represents an RGB color val      class ColorField(serializers.Field):          """ -        Color objects are serialized into "rgb(#, #, #)" notation. +        Color objects are serialized into 'rgb(#, #, #)' notation.          """          def to_representation(self, obj):              return "rgb(%d, %d, %d)" % (obj.red, obj.green, obj.blue) diff --git a/docs/api-guide/filtering.md b/docs/api-guide/filtering.md index 83977048..b16b6be5 100644 --- a/docs/api-guide/filtering.md +++ b/docs/api-guide/filtering.md @@ -316,6 +316,7 @@ Typically you'd instead control this by setting `order_by` on the initial querys          queryset = User.objects.all()          serializer_class = UserSerializer          filter_backends = (filters.OrderingFilter,) +        ordering_fields = ('username', 'email')          ordering = ('username',)  The `ordering` attribute may be either a string or a list/tuple of strings. @@ -390,16 +391,16 @@ We could achieve the same behavior by overriding `get_queryset()` on the views,  The following third party packages provide additional filter implementations. -## Django REST framework chain +## Django REST framework filters package -The [django-rest-framework-chain package][django-rest-framework-chain] works together with the `DjangoFilterBackend` class, and allows you to easily create filters across relationships, or create multiple filter lookup types for a given field. +The [django-rest-framework-filters package][django-rest-framework-filters] works together with the `DjangoFilterBackend` class, and allows you to easily create filters across relationships, or create multiple filter lookup types for a given field.  [cite]: https://docs.djangoproject.com/en/dev/topics/db/queries/#retrieving-specific-objects-with-filters  [django-filter]: https://github.com/alex/django-filter  [django-filter-docs]: https://django-filter.readthedocs.org/en/latest/index.html -[guardian]: http://pythonhosted.org/django-guardian/ -[view-permissions]: http://pythonhosted.org/django-guardian/userguide/assign.html +[guardian]: https://django-guardian.readthedocs.org/ +[view-permissions]: https://django-guardian.readthedocs.org/en/latest/userguide/assign.html  [view-permissions-blogpost]: http://blog.nyaruka.com/adding-a-view-permission-to-django-models  [nullbooleanselect]: https://github.com/django/django/blob/master/django/forms/widgets.py  [search-django-admin]: https://docs.djangoproject.com/en/dev/ref/contrib/admin/#django.contrib.admin.ModelAdmin.search_fields -[django-rest-framework-chain]: https://github.com/philipn/django-rest-framework-chain +[django-rest-framework-filters]: https://github.com/philipn/django-rest-framework-filters diff --git a/docs/api-guide/format-suffixes.md b/docs/api-guide/format-suffixes.md index 20c1e995..35dbcd39 100644 --- a/docs/api-guide/format-suffixes.md +++ b/docs/api-guide/format-suffixes.md @@ -55,6 +55,18 @@ The name of the kwarg used may be modified by using the `FORMAT_SUFFIX_KWARG` se  Also note that `format_suffix_patterns` does not support descending into `include` URL patterns. +### Using with `i18n_patterns` + +If using the `i18n_patterns` function provided by Django, as well as `format_suffix_patterns` you should make sure that the `i18n_patterns` function is applied as the final, or outermost function. For example: + +    url patterns = [ +        … +    ] + +    urlpatterns = i18n_patterns( +        format_suffix_patterns(urlpatterns, allowed=['json', 'html']) +    ) +  ---  ## Accept headers vs. format suffixes diff --git a/docs/api-guide/generic-views.md b/docs/api-guide/generic-views.md index f5bbdfdd..61c8e8d8 100755 --- a/docs/api-guide/generic-views.md +++ b/docs/api-guide/generic-views.md @@ -93,17 +93,13 @@ The following attributes are used to control pagination when used with list view  * `filter_backends` - A list of filter backend classes that should be used for filtering the queryset.  Defaults to the same value as the `DEFAULT_FILTER_BACKENDS` setting. -**Deprecated attributes**: - -* `model` - This shortcut may be used instead of setting either (or both) of the `queryset`/`serializer_class` attributes. The explicit style is preferred over the `.model` shortcut, and usage of this attribute is now deprecated. -  ### Methods  **Base methods**:  #### `get_queryset(self)` -Returns the queryset that should be used for list views, and that should be used as the base for lookups in detail views.  Defaults to returning the queryset specified by the `queryset` attribute, or the default queryset for the model if the `model` shortcut is being used. +Returns the queryset that should be used for list views, and that should be used as the base for lookups in detail views.  Defaults to returning the queryset specified by the `queryset` attribute.  This method should always be used rather than accessing `self.queryset` directly, as `self.queryset` gets evaluated only once, and those results are cached for all subsequent requests. @@ -153,7 +149,7 @@ For example:  #### `get_serializer_class(self)` -Returns the class that should be used for the serializer.  Defaults to returning the `serializer_class` attribute, or dynamically generating a serializer class if the `model` shortcut is being used. +Returns the class that should be used for the serializer.  Defaults to returning the `serializer_class` attribute.  May be overridden to provide dynamic behavior, such as using different serializers for read and write operations, or providing different serializers to different types of users. @@ -214,6 +210,8 @@ You won't typically need to override the following methods, although you might n  The mixin classes provide the actions that are used to provide the basic view behavior.  Note that the mixin classes provide action methods rather than defining the handler methods, such as `.get()` and `.post()`, directly.  This allows for more flexible composition of behavior. +The mixin classes can be imported from `rest_framework.mixins`. +  ## ListModelMixin  Provides a `.list(request, *args, **kwargs)` method, that implements listing a queryset. @@ -258,6 +256,8 @@ If an object is deleted this returns a `204 No Content` response, otherwise it w  The following classes are the concrete generic views.  If you're using generic views this is normally the level you'll be working at unless you need heavily customized behavior. +The view classes can be imported from `rest_framework.generics`. +  ## CreateAPIView  Used for **create-only** endpoints. diff --git a/docs/api-guide/pagination.md b/docs/api-guide/pagination.md index 83429292..8ab2edd5 100644 --- a/docs/api-guide/pagination.md +++ b/docs/api-guide/pagination.md @@ -6,147 +6,110 @@ source: pagination.py  >  > — [Django documentation][cite] -REST framework includes a `PaginationSerializer` class that makes it easy to return paginated data in a way that can then be rendered to arbitrary media types. +REST framework includes support for customizable pagination styles. This allows you to modify how large result sets are split into individual pages of data. -## Paginating basic data +The pagination API can support either: -Let's start by taking a look at an example from the Django documentation. +* Pagination links that are provided as part of the content of the response. +* Pagination links that are included in response headers, such as `Content-Range` or `Link`. -    from django.core.paginator import Paginator +The built-in styles currently all use links included as part of the content of the response. This style is more accessible when using the browsable API. -    objects = ['john', 'paul', 'george', 'ringo'] -    paginator = Paginator(objects, 2) -    page = paginator.page(1) -    page.object_list -    # ['john', 'paul'] +Pagination is only performed automatically if you're using the generic views or viewsets. If you're using a regular `APIView`, you'll need to call into the pagination API yourself to ensure you return a paginated response. See the source code for the `mixins.ListMixin` and `generics.GenericAPIView` classes for an example. -At this point we've got a page object.  If we wanted to return this page object as a JSON response, we'd need to provide the client with context such as next and previous links, so that it would be able to page through the remaining results. +## Setting the pagination style -    from rest_framework.pagination import PaginationSerializer +The default pagination style may be set globally, using the `DEFAULT_PAGINATION_CLASS` settings key. For example, to use the built-in limit/offset pagination, you would do: -    serializer = PaginationSerializer(instance=page) -    serializer.data -    # {'count': 4, 'next': '?page=2', 'previous': None, 'results': [u'john', u'paul']} - -The `context` argument of the `PaginationSerializer` class may optionally include the request.  If the request is included in the context then the next and previous links returned by the serializer will use absolute URLs instead of relative URLs. - -    request = RequestFactory().get('/foobar') -    serializer = PaginationSerializer(instance=page, context={'request': request}) -    serializer.data -    # {'count': 4, 'next': 'http://testserver/foobar?page=2', 'previous': None, 'results': [u'john', u'paul']} - -We could now return that data in a `Response` object, and it would be rendered into the correct media type. - -## Paginating QuerySets - -Our first example worked because we were using primitive objects.  If we wanted to paginate a queryset or other complex data, we'd need to specify a serializer to use to serialize the result set itself. - -We can do this using the `object_serializer_class` attribute on the inner `Meta` class of the pagination serializer.  For example. - -    class UserSerializer(serializers.ModelSerializer): -        """ -        Serializes user querysets. -        """ -        class Meta: -            model = User -            fields = ('username', 'email') +    REST_FRAMEWORK = { +        'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.LimitOffsetPagination' +    } -    class PaginatedUserSerializer(pagination.PaginationSerializer): -        """ -        Serializes page objects of user querysets. -        """ -        class Meta: -            object_serializer_class = UserSerializer +You can also set the pagination class on an individual view by using the `pagination_class` attribute. Typically you'll want to use the same pagination style throughout your API, although you might want to vary individual aspects of the pagination, such as default or maximum page size, on a per-view basis. -We could now use our pagination serializer in a view like this. +## Modifying the pagination style -    @api_view('GET') -    def user_list(request): -        queryset = User.objects.all() -        paginator = Paginator(queryset, 20) +If you want to modify particular aspects of the pagination style, you'll want to override one of the pagination classes, and set the attributes that you want to change. -        page = request.QUERY_PARAMS.get('page') -        try: -            users = paginator.page(page) -        except PageNotAnInteger: -            # If page is not an integer, deliver first page. -            users = paginator.page(1) -        except EmptyPage: -            # If page is out of range (e.g. 9999), -            # deliver last page of results. -            users = paginator.page(paginator.num_pages) +    class LargeResultsSetPagination(PageNumberPagination): +        paginate_by = 1000 +        paginate_by_param = 'page_size' +        max_paginate_by = 10000 -        serializer_context = {'request': request} -        serializer = PaginatedUserSerializer(users, -                                             context=serializer_context) -        return Response(serializer.data) +    class StandardResultsSetPagination(PageNumberPagination): +        paginate_by = 100 +        paginate_by_param = 'page_size' +        max_paginate_by = 1000 -## Pagination in the generic views +You can then apply your new style to a view using the `.pagination_class` attribute: -The generic class based views `ListAPIView` and `ListCreateAPIView` provide pagination of the returned querysets by default.  You can customise this behaviour by altering the pagination style, by modifying the default number of results, by allowing clients to override the page size using a query parameter, or by turning pagination off completely. +    class BillingRecordsView(generics.ListAPIView): +        queryset = Billing.objects.all() +        serializer = BillingRecordsSerializer +        pagination_class = LargeResultsSetPagination -The default pagination style may be set globally, using the `DEFAULT_PAGINATION_SERIALIZER_CLASS`, `PAGINATE_BY`, `PAGINATE_BY_PARAM`, and `MAX_PAGINATE_BY` settings.  For example. +Or apply the style globally, using the `DEFAULT_PAGINATION_CLASS` settings key. For example:      REST_FRAMEWORK = { -        'PAGINATE_BY': 10,                 # Default to 10 -        'PAGINATE_BY_PARAM': 'page_size',  # Allow client to override, using `?page_size=xxx`. -        'MAX_PAGINATE_BY': 100             # Maximum limit allowed when using `?page_size=xxx`. -    } +        'DEFAULT_PAGINATION_CLASS': 'apps.core.pagination.StandardResultsSetPagination'
    } -You can also set the pagination style on a per-view basis, using the `ListAPIView` generic class-based view. +# API Reference -    class PaginatedListView(ListAPIView): -        queryset = ExampleModel.objects.all() -        serializer_class = ExampleModelSerializer -        paginate_by = 10 -        paginate_by_param = 'page_size' -        max_paginate_by = 100 +## PageNumberPagination -Note that using a `paginate_by` value of `None` will turn off pagination for the view. -Note if you use the `PAGINATE_BY_PARAM` settings, you also have to set the `paginate_by_param` attribute in your view to `None` in order to turn off pagination for those requests that contain the `paginate_by_param` parameter. - -For more complex requirements such as serialization that differs depending on the requested media type you can override the `.get_paginate_by()` and `.get_pagination_serializer_class()` methods. +## LimitOffsetPagination  --- -# Custom pagination serializers +# Custom pagination styles + +To create a custom pagination serializer class you should subclass `pagination.BasePagination` and override the `paginate_queryset(self, queryset, request, view=None)` and `get_paginated_response(self, data)` methods: -To create a custom pagination serializer class you should override `pagination.BasePaginationSerializer` and set the fields that you want the serializer to return. +* The `paginate_queryset` method is passed the initial queryset and should return an iterable object that contains only the data in the requested page. +* The `get_paginated_response` method is passed the serialized page data and should return a `Response` instance. -You can also override the name used for the object list field, by setting the `results_field` attribute, which defaults to `'results'`. +Note that the `paginate_queryset` method may set state on the pagination instance, that may later be used by the `get_paginated_response` method.  ## Example -For example, to nest a pair of links labelled 'prev' and 'next', and set the name for the results field to 'objects', you might use something like this. +Let's modify the built-in `PageNumberPagination` style, so that instead of include the pagination links in the body of the response, we'll instead include a `Link` header, in a [similar style to the GitHub API][github-link-pagination]. -    from rest_framework import pagination -    from rest_framework import serializers +    class LinkHeaderPagination(pagination.PageNumberPagination): +        def get_paginated_response(self, data): +            next_url = self.get_next_link()
            previous_url = self.get_previous_link() -    class LinksSerializer(serializers.Serializer): -        next = pagination.NextPageField(source='*') -        prev = pagination.PreviousPageField(source='*') +            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 = '' -    class CustomPaginationSerializer(pagination.BasePaginationSerializer): -        links = LinksSerializer(source='*')  # Takes the page object as the source -        total_results = serializers.ReadOnlyField(source='paginator.count') +            link = link.format(next_url=next_url, previous_url=previous_url) +            headers = {'Link': link} if link else {} -        results_field = 'objects' +            return Response(data, headers=headers) -## Using your custom pagination serializer +## Using your custom pagination class -To have your custom pagination serializer be used by default, use the `DEFAULT_PAGINATION_SERIALIZER_CLASS` setting: +To have your custom pagination class be used by default, use the `DEFAULT_PAGINATION_CLASS` setting:      REST_FRAMEWORK = { -        'DEFAULT_PAGINATION_SERIALIZER_CLASS': -            'example_app.pagination.CustomPaginationSerializer', +        'DEFAULT_PAGINATION_CLASS': 'my_project.apps.core.pagination.LinkHeaderPagination', +        'PAGINATE_BY': 10      } -Alternatively, to set your custom pagination serializer on a per-view basis, use the `pagination_serializer_class` attribute on a generic class based view: +API responses for list endpoints will now include a `Link` header, instead of including the pagination links as part of the body of the response, for example: -    class PaginatedListView(generics.ListAPIView): -        model = ExampleModel -        pagination_serializer_class = CustomPaginationSerializer -        paginate_by = 10 +--- + +![Link Header][link-header] + +*A custom pagination style, using the 'Link' header'* + +---  # Third party packages @@ -157,5 +120,7 @@ The following third party packages are also available.  The [`DRF-extensions` package][drf-extensions] includes a [`PaginateByMaxMixin` mixin class][paginate-by-max-mixin] that allows your API clients to specify `?page_size=max` to obtain the maximum allowed page size.  [cite]: https://docs.djangoproject.com/en/dev/topics/pagination/ +[github-link-pagination]: https://developer.github.com/guides/traversing-with-pagination/ +[link-header]: ../img/link-header-pagination.png  [drf-extensions]: http://chibisov.github.io/drf-extensions/docs/  [paginate-by-max-mixin]: http://chibisov.github.io/drf-extensions/docs/#paginatebymaxmixin diff --git a/docs/api-guide/parsers.md b/docs/api-guide/parsers.md index 9323d382..c242f878 100644 --- a/docs/api-guide/parsers.md +++ b/docs/api-guide/parsers.md @@ -26,7 +26,7 @@ As an example, if you are sending `json` encoded data using jQuery with the [.aj  ## Setting the parsers -The default set of parsers may be set globally, using the `DEFAULT_PARSER_CLASSES` setting.  For example, the following settings would allow requests with `JSON` content. +The default set of parsers may be set globally, using the `DEFAULT_PARSER_CLASSES` setting. For example, the following settings would allow only requests with `JSON` content, instead of the default of JSON or form data.      REST_FRAMEWORK = {          'DEFAULT_PARSER_CLASSES': ( @@ -37,8 +37,8 @@ The default set of parsers may be set globally, using the `DEFAULT_PARSER_CLASSE  You can also set the parsers used for an individual view, or viewset,  using the `APIView` class based views. -	from rest_framework.parsers import JSONParser -	from rest_framework.response import Response +    from rest_framework.parsers import JSONParser +    from rest_framework.response import Response      from rest_framework.views import APIView      class ExampleView(APIView): @@ -108,7 +108,7 @@ If the view used with `FileUploadParser` is called with a `filename` URL keyword          def put(self, request, filename, format=None):              file_obj = request.data['file']              # ... -            # do some staff with uploaded file +            # do some stuff with uploaded file              # ...              return Response(status=204) @@ -162,6 +162,48 @@ The following is an example plaintext parser that will populate the `request.dat  The following third party packages are also available. +## YAML + +[REST framework YAML][rest-framework-yaml] provides [YAML][yaml] parsing and rendering support. It was previously included directly in the REST framework package, and is now instead supported as a third-party package. + +#### Installation & configuration + +Install using pip. + +    $ pip install djangorestframework-yaml + +Modify your REST framework settings. + +    REST_FRAMEWORK = { +        'DEFAULT_PARSER_CLASSES': ( +            'rest_framework_yaml.parsers.YAMLParser', +        ), +        'DEFAULT_RENDERER_CLASSES': ( +            'rest_framework_yaml.renderers.YAMLRenderer', +        ), +    } + +## XML + +[REST Framework XML][rest-framework-xml] provides a simple informal XML format. It was previously included directly in the REST framework package, and is now instead supported as a third-party package. + +#### Installation & configuration + +Install using pip. + +    $ pip install djangorestframework-xml + +Modify your REST framework settings. + +    REST_FRAMEWORK = { +        'DEFAULT_PARSER_CLASSES': ( +            'rest_framework_xml.parsers.XMLParser', +        ), +        'DEFAULT_RENDERER_CLASSES': ( +            'rest_framework_xml.renderers.XMLRenderer', +        ), +    } +  ## MessagePack  [MessagePack][messagepack] is a fast, efficient binary serialization format.  [Juan Riaza][juanriaza] maintains the [djangorestframework-msgpack][djangorestframework-msgpack] package which provides MessagePack renderer and parser support for REST framework. @@ -173,6 +215,9 @@ The following third party packages are also available.  [jquery-ajax]: http://api.jquery.com/jQuery.ajax/  [cite]: https://groups.google.com/d/topic/django-developers/dxI4qVzrBY4/discussion  [upload-handlers]: https://docs.djangoproject.com/en/dev/topics/http/file-uploads/#upload-handlers +[rest-framework-yaml]: http://jpadilla.github.io/django-rest-framework-yaml/ +[rest-framework-xml]: http://jpadilla.github.io/django-rest-framework-xml/ +[yaml]: http://www.yaml.org/  [messagepack]: https://github.com/juanriaza/django-rest-framework-msgpack  [juanriaza]: https://github.com/juanriaza  [vbabiy]: https://github.com/vbabiy diff --git a/docs/api-guide/relations.md b/docs/api-guide/relations.md index e56db229..50e3b7b5 100644 --- a/docs/api-guide/relations.md +++ b/docs/api-guide/relations.md @@ -231,6 +231,7 @@ This field is always read-only.  * `view_name` - The view name that should be used as the target of the relationship.  If you're using [the standard router classes][routers] this will be a string with the format `<model_name>-detail`.  **required**.  * `lookup_field` - The field on the target that should be used for the lookup.  Should correspond to a URL keyword argument on the referenced view.  Default is `'pk'`. +* `lookup_url_kwarg` - The name of the keyword argument defined in the URL conf that corresponds to the lookup field. Defaults to using the same value as `lookup_field`.  * `format` - If using format suffixes, hyperlinked fields will use the same format suffix for the target unless overridden by using the `format` argument.  --- diff --git a/docs/api-guide/renderers.md b/docs/api-guide/renderers.md index 69460dbc..83ded849 100644 --- a/docs/api-guide/renderers.md +++ b/docs/api-guide/renderers.md @@ -342,13 +342,81 @@ Templates will render with a `RequestContext` which includes the `status_code` a  The following third party packages are also available. +## YAML + +[REST framework YAML][rest-framework-yaml] provides [YAML][yaml] parsing and rendering support. It was previously included directly in the REST framework package, and is now instead supported as a third-party package. + +#### Installation & configuration + +Install using pip. + +    $ pip install djangorestframework-yaml + +Modify your REST framework settings. + +    REST_FRAMEWORK = { +        'DEFAULT_PARSER_CLASSES': ( +            'rest_framework_yaml.parsers.YAMLParser', +        ), +        'DEFAULT_RENDERER_CLASSES': ( +            'rest_framework_yaml.renderers.YAMLRenderer', +        ), +    } + +## XML + +[REST Framework XML][rest-framework-xml] provides a simple informal XML format. It was previously included directly in the REST framework package, and is now instead supported as a third-party package. + +#### Installation & configuration + +Install using pip. + +    $ pip install djangorestframework-xml + +Modify your REST framework settings. + +    REST_FRAMEWORK = { +        'DEFAULT_PARSER_CLASSES': ( +            'rest_framework_xml.parsers.XMLParser', +        ), +        'DEFAULT_RENDERER_CLASSES': ( +            'rest_framework_xml.renderers.XMLRenderer', +        ), +    } + +## JSONP + +[REST framework JSONP][rest-framework-jsonp] provides JSONP rendering support. It was previously included directly in the REST framework package, and is now instead supported as a third-party package. + +--- + +**Warning**: If you require cross-domain AJAX requests, you should generally be using the more modern approach of [CORS][cors] as an alternative to `JSONP`. See the [CORS documentation][cors-docs] for more details. + +The `jsonp` approach is essentially a browser hack, and is [only appropriate for globally readable API endpoints][jsonp-security], where `GET` requests are unauthenticated and do not require any user permissions. + +--- + +#### Installation & configuration + +Install using pip. + +    $ pip install djangorestframework-jsonp + +Modify your REST framework settings. + +    REST_FRAMEWORK = { +        'DEFAULT_RENDERER_CLASSES': ( +            'rest_framework_yaml.renderers.JSONPRenderer', +        ), +    } +  ## MessagePack  [MessagePack][messagepack] is a fast, efficient binary serialization format.  [Juan Riaza][juanriaza] maintains the [djangorestframework-msgpack][djangorestframework-msgpack] package which provides MessagePack renderer and parser support for REST framework.  ## CSV -Comma-separated values are a plain-text tabular data format, that can be easily imported into spreadsheet applications.  [Mjumbe Poe][mjumbewu] maintains the [djangorestframework-csv][djangorestframework-csv] package which provides CSV renderer support for REST framework. +Comma-separated values are a plain-text tabular data format, that can be easily imported into spreadsheet applications. [Mjumbe Poe][mjumbewu] maintains the [djangorestframework-csv][djangorestframework-csv] package which provides CSV renderer support for REST framework.  ## UltraJSON @@ -358,7 +426,6 @@ Comma-separated values are a plain-text tabular data format, that can be easily  [djangorestframework-camel-case] provides camel case JSON renderers and parsers for REST framework.  This allows serializers to use Python-style underscored field names, but be exposed in the API as Javascript-style camel case field names.  It is maintained by [Vitaly Babiy][vbabiy]. -  ## Pandas (CSV, Excel, PNG)  [Django REST Pandas] provides a serializer and renderers that support additional data processing and output via the [Pandas] DataFrame API.  Django REST Pandas includes renderers for Pandas-style CSV files, Excel workbooks (both `.xls` and `.xlsx`), and a number of [other formats]. It is maintained by [S. Andrew Sheppard][sheppard] as part of the [wq Project][wq]. @@ -373,10 +440,19 @@ Comma-separated values are a plain-text tabular data format, that can be easily  [application/vnd.github+json]: http://developer.github.com/v3/media/  [application/vnd.collection+json]: http://www.amundsen.com/media-types/collection/  [django-error-views]: https://docs.djangoproject.com/en/dev/topics/http/views/#customizing-error-views +[rest-framework-jsonp]: http://jpadilla.github.io/django-rest-framework-jsonp/ +[cors]: http://www.w3.org/TR/cors/ +[cors-docs]: http://www.django-rest-framework.org/topics/ajax-csrf-cors/ +[jsonp-security]: http://stackoverflow.com/questions/613962/is-jsonp-safe-to-use +[rest-framework-yaml]: http://jpadilla.github.io/django-rest-framework-yaml/ +[rest-framework-xml]: http://jpadilla.github.io/django-rest-framework-xml/  [messagepack]: http://msgpack.org/  [juanriaza]: https://github.com/juanriaza  [mjumbewu]: https://github.com/mjumbewu  [vbabiy]: https://github.com/vbabiy +[rest-framework-yaml]: http://jpadilla.github.io/django-rest-framework-yaml/ +[rest-framework-xml]: http://jpadilla.github.io/django-rest-framework-xml/ +[yaml]: http://www.yaml.org/  [djangorestframework-msgpack]: https://github.com/juanriaza/django-rest-framework-msgpack  [djangorestframework-csv]: https://github.com/mjumbewu/django-rest-framework-csv  [ultrajson]: https://github.com/esnme/ultrajson diff --git a/docs/api-guide/routers.md b/docs/api-guide/routers.md index 929a1710..592f7d66 100644 --- a/docs/api-guide/routers.md +++ b/docs/api-guide/routers.md @@ -28,7 +28,7 @@ There are two mandatory arguments to the `register()` method:  Optionally, you may also specify an additional argument: -* `base_name` - The base to use for the URL names that are created.  If unset the basename will be automatically generated based on the `model` or `queryset` attribute on the viewset, if it has one.  Note that if the viewset does not include a `model` or `queryset` attribute then you must set `base_name` when registering the viewset. +* `base_name` - The base to use for the URL names that are created.  If unset the basename will be automatically generated based on the `queryset` attribute of the viewset, if it has one.  Note that if the viewset does not include a `queryset` attribute then you must set `base_name` when registering the viewset.  The example above would generate the following URL patterns: @@ -49,6 +49,38 @@ This means you'll need to explicitly set the `base_name` argument when registeri  --- +### Using `include` with routers + +The `.urls` attribute on a router instance is simply a standard list of URL patterns. There are a number of different styles for how you can include these URLs. + +For example, you can append `router.urls` to a list of existing views… + +    router = routers.SimpleRouter() +    router.register(r'users', UserViewSet) +    router.register(r'accounts', AccountViewSet) +     +    urlpatterns = [ +        url(r'^forgot-password/$', ForgotPasswordFormView.as_view()), +    ] +     +    urlpatterns += router.urls + +Alternatively you can use Django's `include` function, like so… + +    urlpatterns = [ +        url(r'^forgot-password/$', ForgotPasswordFormView.as_view()), +        url(r'^', include(router.urls)), +    ] + +Router URL patterns can also be namespaces. + +    urlpatterns = [ +        url(r'^forgot-password/$', ForgotPasswordFormView.as_view()), +        url(r'^api/', include(router.urls, namespace='api')), +    ] + +If using namespacing with hyperlinked serializers you'll also need to ensure that any `view_name` parameters on the serializers correctly reflect the namespace. In the example above you'd need to include a parameter such as `view_name='api:user-detail'` for serializer fields hyperlinked to the user detail view. +  ### Extra link and actions  Any methods on the viewset decorated with `@detail_route` or `@list_route` will also be routed. @@ -68,6 +100,24 @@ The following URL pattern would additionally be generated:  * URL pattern: `^users/{pk}/set_password/$`  Name: `'user-set-password'` +If you do not want to use the default URL generated for your custom action, you can instead use the url_path parameter to customize it. + +For example, if you want to change the URL for our custom action to `^users/{pk}/change-password/$`, you could write: + +    from myapp.permissions import IsAdminOrIsSelf +    from rest_framework.decorators import detail_route +     +    class UserViewSet(ModelViewSet): +        ... +         +        @detail_route(methods=['post'], permission_classes=[IsAdminOrIsSelf], url_path='change-password') +        def set_password(self, request, pk=None): +            ... + +The above example would now generate the following URL pattern: + +* URL pattern: `^users/{pk}/change-password/$`  Name: `'user-change-password'` +  For more information see the viewset documentation on [marking extra actions for routing][route-decorators].  # API Guide diff --git a/docs/api-guide/serializers.md b/docs/api-guide/serializers.md index b9f0e7bc..9a9d5032 100644 --- a/docs/api-guide/serializers.md +++ b/docs/api-guide/serializers.md @@ -384,7 +384,7 @@ This manager class now more nicely encapsulates that user instances and profile              has_support_contract=validated_data['profile']['has_support_contract']          ) -For more details on this approach see the Django documentation on [model managers](model-managers), and [this blogpost on using model and manger classes](encapsulation-blogpost). +For more details on this approach see the Django documentation on [model managers](model-managers), and [this blogpost on using model and manager classes](encapsulation-blogpost).  ## Dealing with multiple objects @@ -457,7 +457,7 @@ To do so, open the Django shell, using `python manage.py shell`, then import the          name = CharField(allow_blank=True, max_length=100, required=False)          owner = PrimaryKeyRelatedField(queryset=User.objects.all()) -## Specifying which fields should be included +## Specifying which fields to include  If you only want a subset of the default fields to be used in a model serializer, you can do so using `fields` or `exclude` options, just as you would with a `ModelForm`. @@ -499,7 +499,7 @@ You can add extra fields to a `ModelSerializer` or override the default fields b  Extra fields can correspond to any property or callable on the model. -## Specifying which fields should be read-only +## Specifying read only fields  You may wish to specify multiple fields as read-only. Instead of adding each field explicitly with the `read_only=True` attribute, you may use the shortcut Meta option, `read_only_fields`. @@ -528,7 +528,7 @@ Please review the [Validators Documentation](/api-guide/validators/) for details  --- -## Specifying additional keyword arguments for fields. +## Additional keyword arguments  There is also a shortcut allowing you to specify arbitrary additional keyword arguments on fields, using the `extra_kwargs` option. Similarly to `read_only_fields` this means you do not need to explicitly declare the field on the serializer. @@ -567,6 +567,63 @@ The inner `Meta` class on serializers is not inherited from parent classes by de  Typically we would recommend *not* using inheritance on inner Meta classes, but instead declaring all options explicitly. +## Customizing field mappings + +The ModelSerializer class also exposes an API that you can override in order to alter how serializer fields are automatically determined when instantiating the serializer. + +Normally if a `ModelSerializer` does not generate the fields you need by default the you should either add them to the class explicitly, or simply use a regular `Serializer` class instead. However in some cases you may want to create a new base class that defines how the serializer fields are created for any given model. + +### `.serializer_field_mapping` + +A mapping of Django model classes to REST framework serializer classes. You can override this mapping to alter the default serializer classes that should be used for each model class. + +### `.serializer_relational_field` + +This property should be the serializer field class, that is used for relational fields by default. For `ModelSerializer` this defaults to `PrimaryKeyRelatedField`. For `HyperlinkedModelSerializer` this defaults to `HyperlinkedRelatedField`. + +### The field_class and field_kwargs API + +The following methods are called to determine the class and keyword arguments for each field that should be automatically included on the serializer. Each of these methods should return a two tuple of `(field_class, field_kwargs)`. + +### `.build_standard_field(self, field_name, model_field)` + +Called to generate a serializer field that maps to a standard model field. + +The default implementation returns a serializer class based on the `serializer_field_mapping` attribute. + +### `.build_relational_field(self, field_name, relation_info)` + +Called to generate a serializer field that maps to a relational model field. + +The default implementation returns a serializer class based on the `serializer_relational_field` attribute. + +The `relation_info` argument is a named tuple, that contains `model_field`, `related_model`, `to_many` and `has_through_model` properties. + +### `.build_nested_field(self, field_name, relation_info, nested_depth)` + +Called to generate a serializer field that maps to a relational model field, when the `depth` option has been set. + +The default implementation dynamically creates a nested serializer class based on either `ModelSerializer` or `HyperlinkedModelSerializer`. + +The `nested_depth` will be the value of the `depth` option, minus one. + +The `relation_info` argument is a named tuple, that contains `model_field`, `related_model`, `to_many` and `has_through_model` properties. + +### `.build_property_field(self, field_name, model_class)` + +Called to generate a serializer field that maps to a property or zero-argument method on the model class. + +The default implementation returns a `ReadOnlyField` class. + +### `.build_url_field(self, field_name, model_class)` + +Called to generate a serializer field for the serializer's own `url` field. The default implementation returns a `HyperlinkedIdentityField` class. + +### `.build_unknown_field(self, field_name, model_class)` + +Called when the field name did not map to any model field or model property. +The default implementation raises an error, although subclasses may customize this behavior. +  ---  # HyperlinkedModelSerializer diff --git a/docs/api-guide/versioning.md b/docs/api-guide/versioning.md index 92380cc0..7463f190 100644 --- a/docs/api-guide/versioning.md +++ b/docs/api-guide/versioning.md @@ -10,6 +10,8 @@ API versioning allows you to alter behavior between different clients. REST fram  Versioning is determined by the incoming client request, and may either be based on the request URL, or based on the request headers. +There are a number of valid approaches to approaching versioning. [Non-versioned systems can also be appropriate][roy-fielding-on-versioning], particularly if you're engineering for very long-term systems with multiple clients outside of your control. +  ## Versioning with REST framework  When API versioning is enabled, the `request.version` attribute will contain a string that corresponds to the version requested in the incoming client request. @@ -195,6 +197,7 @@ The following example uses a custom `X-API-Version` header to determine the requ  If your versioning scheme is based on the request URL, you will also want to alter how versioned URLs are determined. In order to do so you should override the `.reverse()` method on the class. See the source code for examples.  [cite]: http://www.slideshare.net/evolve_conference/201308-fielding-evolve/31 +[roy-fielding-on-versioning]: http://www.infoq.com/articles/roy-fielding-on-versioning  [klabnik-guidelines]: http://blog.steveklabnik.com/posts/2011-07-03-nobody-understands-rest-or-http#i_want_my_api_to_be_versioned  [heroku-guidelines]: https://github.com/interagent/http-api-design#version-with-accepts-header  [json-parameters]: http://tools.ietf.org/html/rfc4627#section-6 diff --git a/docs/api-guide/viewsets.md b/docs/api-guide/viewsets.md index 3e37cef8..b09dfc9e 100644 --- a/docs/api-guide/viewsets.md +++ b/docs/api-guide/viewsets.md @@ -146,7 +146,7 @@ The decorators can additionally take extra arguments that will be set for the ro          def set_password(self, request, pk=None):             ... -Theses decorators will route `GET` requests by default, but may also accept other HTTP methods, by using the `methods` argument.  For example: +These decorators will route `GET` requests by default, but may also accept other HTTP methods, by using the `methods` argument.  For example:          @detail_route(methods=['post', 'delete'])          def unset_password(self, request, pk=None): | 
