From 6fdeed2e2c2f385e99a5fb42f169526a229bfa4b Mon Sep 17 00:00:00 2001 From: Carlton Gibson Date: Tue, 3 Apr 2018 14:37:24 +0100 Subject: [PATCH] Deployed fc588f53 with MkDocs version: 0.16.3 --- api-guide/authentication/index.html | 27 ++- api-guide/exceptions/index.html | 30 ++++ api-guide/fields/index.html | 23 ++- api-guide/metadata/index.html | 2 +- api-guide/permissions/index.html | 6 + api-guide/routers/index.html | 97 +++++----- api-guide/schemas/index.html | 3 +- api-guide/serializers/index.html | 10 +- api-guide/settings/index.html | 2 +- api-guide/throttling/index.html | 2 +- api-guide/validators/index.html | 3 +- api-guide/versioning/index.html | 2 +- api-guide/viewsets/index.html | 46 +++-- css/default.css | 16 +- mkdocs/search_index.json | 167 +++++++++++------- sitemap.xml | 122 ++++++------- topics/api-clients/index.html | 2 +- topics/contributing/index.html | 8 +- topics/documenting-your-api/index.html | 24 ++- topics/funding/index.html | 2 +- topics/jobs/index.html | 1 + topics/release-notes/index.html | 116 +++++++++++- topics/tutorials-and-resources/index.html | 3 + .../index.html | 4 +- tutorial/6-viewsets-and-routers/index.html | 10 +- .../7-schemas-and-client-libraries/index.html | 2 +- 26 files changed, 504 insertions(+), 226 deletions(-) diff --git a/api-guide/authentication/index.html b/api-guide/authentication/index.html index 5bac589d1..f289afca8 100644 --- a/api-guide/authentication/index.html +++ b/api-guide/authentication/index.html @@ -660,9 +660,34 @@ urlpatterns += [

The obtain_auth_token view will return a JSON response when valid username and password fields are POSTed to the view using form data or JSON:

{ 'token' : '9944b09199c62bcf9418ad846dd0e4bbdfc6ee4b' }
 
-

Note that the default obtain_auth_token view explicitly uses JSON requests and responses, rather than using default renderer and parser classes in your settings. If you need a customized version of the obtain_auth_token view, you can do so by overriding the ObtainAuthToken view class, and using that in your url conf instead.

+

Note that the default obtain_auth_token view explicitly uses JSON requests and responses, rather than using default renderer and parser classes in your settings.

By default there are no permissions or throttling applied to the obtain_auth_token view. If you do wish to apply throttling you'll need to override the view class, and include them using the throttle_classes attribute.

+

If you need a customized version of the obtain_auth_token view, you can do so by subclassing the ObtainAuthToken view class, and using that in your url conf instead.

+

For example, you may return additional user information beyond the token value:

+
from rest_framework.authtoken.views import ObtainAuthToken
+from rest_framework.authtoken.models import Token
+from rest_framework.response import Response
+
+class CustomAuthToken(ObtainAuthToken):
+
+    def post(self, request, *args, **kwargs):
+        serializer = self.serializer_class(data=request.data,
+                                           context={'request': request})
+        serializer.is_valid(raise_exception=True)
+        user = serializer.validated_data['user']
+        token, created = Token.objects.get_or_create(user=user)
+        return Response({
+            'token': token.key,
+            'user_id': user.pk,
+            'email': user.email
+        })
+
+

And in your urls.py:

+
urlpatterns += [
+    url(r'^api-token-auth/', CustomAuthToken.as_view())
+]
+
With Django admin

It is also possible to create Tokens manually through admin interface. In case you are using a large user base, we recommend that you monkey patch the TokenAdmin class to customize it to your needs, more specifically by declaring the user field as raw_field.

your_app/admin.py:

diff --git a/api-guide/exceptions/index.html b/api-guide/exceptions/index.html index 453c7a3b6..5a21b4fc8 100644 --- a/api-guide/exceptions/index.html +++ b/api-guide/exceptions/index.html @@ -445,6 +445,20 @@ +
  • + Generic Error Views +
  • + + +
  • + rest_framework.exceptions.server_error +
  • + +
  • + rest_framework.exceptions.server_error +
  • + +

    @@ -625,6 +639,22 @@ dictionary of items:

    The generic views use the raise_exception=True flag, which means that you can override the style of validation error responses globally in your API. To do so, use a custom exception handler, as described above.

    By default this exception results in a response with the HTTP status code "400 Bad Request".

    +
    +

    Generic Error Views

    +

    Django REST Framework provides two error views suitable for providing generic JSON 500 Server Error and +400 Bad Request responses. (Django's default error views provide HTML responses, which may not be appropriate for an +API-only application.)

    +

    Use these as per Django's Customizing error views documentation.

    +

    rest_framework.exceptions.server_error

    +

    Returns a response with status code 500 and application/json content type.

    +

    Set as handler500:

    +
    handler500 = 'rest_framework.exceptions.server_error'
    +
    +

    rest_framework.exceptions.server_error

    +

    Returns a response with status code 400 and application/json content type.

    +

    Set as handler400:

    +
    handler400 = 'rest_framework.exceptions.bad_request'
    +
    diff --git a/api-guide/fields/index.html b/api-guide/fields/index.html index 0168af95b..6f151278e 100644 --- a/api-guide/fields/index.html +++ b/api-guide/fields/index.html @@ -528,6 +528,10 @@ DictField +
  • + HStoreField +
  • +
  • JSONField
  • @@ -579,7 +583,7 @@
  • - djangrestframework-recursive + djangorestframework-recursive
  • @@ -634,16 +638,16 @@ 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

    -

    Normally an error will be raised if None is passed to a serializer field. Set this keyword argument to True if None should be considered a valid value.

    -

    Note that setting this argument to True will imply a default value of null for serialization output, but does not imply a default for input deserialization.

    -

    Defaults to False

    default

    If set, this gives the default value that will be used for the field if no input value is supplied. If not set the default behaviour is to not populate the attribute at all.

    The default is not applied during partial update operations. In the partial update case only fields that are provided in the incoming data will have a validated value returned.

    May be set to a function or other callable, in which case the value will be evaluated each time it is used. When called, it will receive no arguments. If the callable has a set_context method, that will be called each time before getting the value with the field instance as only argument. This works the same way as for validators.

    When serializing the instance, default will be used if the the object attribute or dictionary key is not present in the instance.

    Note that setting a default value implies that the field is not required. Including both the default and required keyword arguments is invalid and will raise an error.

    +

    allow_null

    +

    Normally an error will be raised if None is passed to a serializer field. Set this keyword argument to True if None should be considered a valid value.

    +

    Note that, without an explicit default, setting this argument to True will imply a default value of null for serialization output, but does not imply a default for input deserialization.

    +

    Defaults to False

    source

    The name of the attribute that will be used to populate the field. May be a method that only takes a self argument, such as URLField(source='get_absolute_url'), or may use dotted notation to traverse attributes, such as EmailField(source='user.email'). When serializing fields with dotted notation, it may be necessary to provide a default value if any object is not present or is empty during attribute traversal.

    The value source='*' has a special meaning, and is used to indicate that the entire object should be passed through to the field. This can be useful for creating nested representations, or for fields which require access to the complete object in order to determine the output representation.

    @@ -924,6 +928,13 @@ Django's regular HStoreField +

    A preconfigured DictField that is compatible with Django's postgres HStoreField.

    +

    Signature: HStoreField(child=<A_FIELD_INSTANCE>)

    + +

    Note that the child field must be an instance of CharField, as the hstore extension stores values as strings.

    JSONField

    A field class that validates that the incoming data structure consists of valid JSON primitives. In its alternate binary mode, it will represent and validate JSON-encoded binary strings.

    Signature: JSONField(binary)

    @@ -1189,7 +1200,7 @@ or overly complex.

    The drf-compound-fields package provides "compound" serializer fields, such as lists of simple values, which can be described by other fields rather than serializers with the many=True option. Also provided are fields for typed dictionaries and values that can be either a specific type or a list of items of that type.

    DRF Extra Fields

    The drf-extra-fields package provides extra serializer fields for REST framework, including Base64ImageField and PointField classes.

    -

    djangrestframework-recursive

    +

    djangorestframework-recursive

    the djangorestframework-recursive package provides a RecursiveField for serializing and deserializing recursive structures

    django-rest-framework-gis

    The django-rest-framework-gis package provides geographic addons for django rest framework like a GeometryField field and a GeoJSON serializer.

    diff --git a/api-guide/metadata/index.html b/api-guide/metadata/index.html index 0eee4b40b..22ea4ef94 100644 --- a/api-guide/metadata/index.html +++ b/api-guide/metadata/index.html @@ -491,7 +491,7 @@ Content-Type: application/json

    Creating schema endpoints

    If you have specific requirements for creating schema endpoints that are accessed with regular GET requests, you might consider re-using the metadata API for doing so.

    For example, the following additional route could be used on a viewset to provide a linkable schema endpoint.

    -
    @list_route(methods=['GET'])
    +
    @action(methods=['GET'], detail=False)
     def schema(self, request):
         meta = self.metadata_class()
         data = meta.determine_metadata(request, self)
    diff --git a/api-guide/permissions/index.html b/api-guide/permissions/index.html
    index 7da8265bc..f39e4d421 100644
    --- a/api-guide/permissions/index.html
    +++ b/api-guide/permissions/index.html
    @@ -468,6 +468,10 @@
                           Django Rest Framework API Key
                         
  • +
  • + Django Rest Framework Role Filters +
  • +
    @@ -680,6 +684,8 @@ class BlacklistPermission(permissions.BasePermission):

    The Django Rest Framework Roles package makes it easier to parameterize your API over multiple types of users.

    Django Rest Framework API Key

    The Django Rest Framework API Key package allows you to ensure that every request made to the server requires an API key header. You can generate one from the django admin interface.

    +

    Django Rest Framework Role Filters

    +

    The Django Rest Framework Role Filters package provides simple filtering over multiple types of roles.

    diff --git a/api-guide/routers/index.html b/api-guide/routers/index.html index 0a6ec01bf..88b0300aa 100644 --- a/api-guide/routers/index.html +++ b/api-guide/routers/index.html @@ -519,77 +519,75 @@ urlpatterns += router.urls url(r'^', include(router.urls)), ]
    -

    Router URL patterns can also be namespaces.

    +

    You may use include with an application namespace:

    urlpatterns = [
         url(r'^forgot-password/$', ForgotPasswordFormView.as_view()),
    -    url(r'^api/', include(router.urls, namespace='api')),
    +    url(r'^api/', include((router.urls, 'app_name'))),
     ]
     
    -

    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.

    - -

    Any methods on the viewset decorated with @detail_route or @list_route will also be routed. -For example, given a method like this on the UserViewSet class:

    +

    Or both an application and instance namespace:

    +
    urlpatterns = [
    +    url(r'^forgot-password/$', ForgotPasswordFormView.as_view()),
    +    url(r'^api/', include((router.urls, 'app_name'), namespace='instance_name')),
    +]
    +
    +

    See Django's URL namespaces docs and the include API reference for more details.

    +
    +

    Note: 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 examples above you'd need to include a parameter such as +view_name='app_name:user-detail' for serializer fields hyperlinked to the user detail view.

    +

    The automatic view_name generation uses a pattern like %(model_name)-detail. Unless your models names actually clash +you may be better off not namespacing your Django REST Framework views when using hyperlinked serializers.

    +
    +

    Routing for extra actions

    +

    A viewset may mark extra actions for routing by decorating a method with the @action decorator. These extra actions will be included in the generated routes. For example, given the set_password method on the UserViewSet class:

    from myapp.permissions import IsAdminOrIsSelf
    -from rest_framework.decorators import detail_route
    +from rest_framework.decorators import action
     
     class UserViewSet(ModelViewSet):
         ...
     
    -    @detail_route(methods=['post'], permission_classes=[IsAdminOrIsSelf])
    +    @action(methods=['post'], detail=True, permission_classes=[IsAdminOrIsSelf])
         def set_password(self, request, pk=None):
             ...
     
    -

    The following URL pattern would additionally be generated:

    +

    The following route would be generated:

    -

    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.

    +

    By default, the URL pattern is based on the method name, and the URL name is the combination of the ViewSet.basename and the hyphenated method name. +If you don't want to use the defaults for either of these values, you can instead provide the url_path and url_name arguments to the @action decorator.

    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
    +from rest_framework.decorators import action
     
     class UserViewSet(ModelViewSet):
         ...
     
    -    @detail_route(methods=['post'], permission_classes=[IsAdminOrIsSelf], url_path='change-password')
    +    @action(methods=['post'], detail=True, permission_classes=[IsAdminOrIsSelf],
    +            url_path='change-password', url_name='change_password')
         def set_password(self, request, pk=None):
             ...
     

    The above example would now generate the following URL pattern:

    -

    In the case you do not want to use the default name generated for your custom action, you can use the url_name parameter to customize it.

    -

    For example, if you want to change the name of our custom action to 'user-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_name='change-password')
    -    def set_password(self, request, pk=None):
    -        ...
    -
    -

    The above example would now generate the following URL pattern:

    - -

    You can also use url_path and url_name parameters together to obtain extra control on URL generation for custom views.

    -

    For more information see the viewset documentation on marking extra actions for routing.

    API Guide

    SimpleRouter

    -

    This router includes routes for the standard set of list, create, retrieve, update, partial_update and destroy actions. The viewset can also mark additional methods to be routed, using the @detail_route or @list_route decorators.

    +

    This router includes routes for the standard set of list, create, retrieve, update, partial_update and destroy actions. The viewset can also mark additional methods to be routed, using the @action decorator.

    - + - +
    URL StyleHTTP MethodActionURL Name
    {prefix}/GETlist{basename}-list
    POSTcreate
    {prefix}/{methodname}/GET, or as specified by `methods` argument`@list_route` decorated method{basename}-{methodname}
    {prefix}/{url_path}/GET, or as specified by `methods` argument`@action(detail=False)` decorated method{basename}-{url_name}
    {prefix}/{lookup}/GETretrieve{basename}-detail
    PUTupdate
    PATCHpartial_update
    DELETEdestroy
    {prefix}/{lookup}/{methodname}/GET, or as specified by `methods` argument`@detail_route` decorated method{basename}-{methodname}
    {prefix}/{lookup}/{url_path}/GET, or as specified by `methods` argument`@action(detail=True)` decorated method{basename}-{url_name}

    By default the URLs created by SimpleRouter are appended with a trailing slash. @@ -609,12 +607,12 @@ This behavior can be modified by setting the trailing_slash argumen [.format]GETautomatically generated root viewapi-root {prefix}/[.format]GETlist{basename}-list POSTcreate - {prefix}/{methodname}/[.format]GET, or as specified by `methods` argument`@list_route` decorated method{basename}-{methodname} + {prefix}/{url_path}/[.format]GET, or as specified by `methods` argument`@action(detail=False)` decorated method{basename}-{url_name} {prefix}/{lookup}/[.format]GETretrieve{basename}-detail PUTupdate PATCHpartial_update DELETEdestroy - {prefix}/{lookup}/{methodname}/[.format]GET, or as specified by `methods` argument`@detail_route` decorated method{basename}-{methodname} + {prefix}/{lookup}/{url_path}/[.format]GET, or as specified by `methods` argument`@action(detail=True)` decorated method{basename}-{url_name}

    As with SimpleRouter the trailing slashes on the URL routes can be removed by setting the trailing_slash argument to False when instantiating the router.

    @@ -635,17 +633,19 @@ This behavior can be modified by setting the trailing_slash argumen -

    initkwargs: A dictionary of any additional arguments that should be passed when instantiating the view. Note that the suffix argument is reserved for identifying the viewset type, used when generating the view name and breadcrumb links.

    +

    initkwargs: A dictionary of any additional arguments that should be passed when instantiating the view. Note that the detail, basename, and suffix arguments are reserved for viewset introspection and are also used by the browsable API to generate the view name and breadcrumb links.

    Customizing dynamic routes

    -

    You can also customize how the @list_route and @detail_route decorators are routed. -To route either or both of these decorators, include a DynamicListRoute and/or DynamicDetailRoute named tuple in the .routes list.

    -

    The arguments to DynamicListRoute and DynamicDetailRoute are:

    -

    url: A string representing the URL to be routed. May include the same format strings as Route, and additionally accepts the {methodname} and {methodnamehyphen} format strings.

    -

    name: The name of the URL as used in reverse calls. May include the following format strings: {basename}, {methodname} and {methodnamehyphen}.

    +

    You can also customize how the @action decorator is routed. Include the DynamicRoute named tuple in the .routes list, setting the detail argument as appropriate for the list-based and detail-based routes. In addition to detail, the arguments to DynamicRoute are:

    +

    url: A string representing the URL to be routed. May include the same format strings as Route, and additionally accepts the {url_path} format string.

    +

    name: The name of the URL as used in reverse calls. May include the following format strings:

    +

    initkwargs: A dictionary of any additional arguments that should be passed when instantiating the view.

    Example

    The following example will only route to the list and retrieve actions, and does not use the trailing slash convention.

    -
    from rest_framework.routers import Route, DynamicDetailRoute, SimpleRouter
    +
    from rest_framework.routers import Route, DynamicRoute, SimpleRouter
     
     class CustomReadOnlyRouter(SimpleRouter):
         """
    @@ -664,9 +664,10 @@ class CustomReadOnlyRouter(SimpleRouter):
                 name='{basename}-detail',
                 initkwargs={'suffix': 'Detail'}
             ),
    -        DynamicDetailRoute(
    -            url=r'^{prefix}/{lookup}/{methodnamehyphen}$',
    -            name='{basename}-{methodnamehyphen}',
    +        DynamicRoute(
    +            url=r'^{prefix}/{lookup}/{url_path}$',
    +            name='{basename}-{url_name}',
    +            detail=True,
                 initkwargs={}
             )
         ]
    @@ -681,7 +682,7 @@ class CustomReadOnlyRouter(SimpleRouter):
         serializer_class = UserSerializer
         lookup_field = 'username'
     
    -    @detail_route()
    +    @action(detail=True)
         def group_names(self, request, pk=None):
             """
             Returns a list of all the group names that the given
    diff --git a/api-guide/schemas/index.html b/api-guide/schemas/index.html
    index c509ac03a..4997d3b88 100644
    --- a/api-guide/schemas/index.html
    +++ b/api-guide/schemas/index.html
    @@ -1014,7 +1014,7 @@ that do not expect a request body.

    if method=='POST': extra_fields = # ... list of extra fields for POST ... - manual_fields = super().get_manual_fields() + manual_fields = super().get_manual_fields(path, method) return manual_fields + extra_fields
    @@ -1044,6 +1044,7 @@ plus an optional description.

    The ManualSchema constructor takes two arguments:

    fields: A list of coreapi.Field instances. Required.

    description: A string description. Optional.

    +

    encoding: Default None. A string encoding, e.g application/json. Optional.


    Core API

    This documentation gives a brief overview of the components within the coreapi diff --git a/api-guide/serializers/index.html b/api-guide/serializers/index.html index b9bf128bf..d99891477 100644 --- a/api-guide/serializers/index.html +++ b/api-guide/serializers/index.html @@ -773,7 +773,7 @@ class BlogPostSerializer(serializers.Serializer):

    Note: If your <field_name> is declared on your serializer with the parameter required=False then this validation step will not take place if the field is not included.


    Object-level validation

    -

    To do any other validation that requires access to multiple fields, add a method called .validate() to your Serializer subclass. This method takes a single argument, which is a dictionary of field values. It should raise a ValidationError if necessary, or just return the validated values. For example:

    +

    To do any other validation that requires access to multiple fields, add a method called .validate() to your Serializer subclass. This method takes a single argument, which is a dictionary of field values. It should raise a serializers.ValidationError if necessary, or just return the validated values. For example:

    from rest_framework import serializers
     
     class EventSerializer(serializers.Serializer):
    @@ -1306,7 +1306,7 @@ def all_high_scores(request):
         return Response(serializer.data)
     
    Read-write BaseSerializer classes
    -

    To create a read-write serializer we first need to implement a .to_internal_value() method. This method returns the validated values that will be used to construct the object instance, and may raise a ValidationError if the supplied data is in an incorrect format.

    +

    To create a read-write serializer we first need to implement a .to_internal_value() method. This method returns the validated values that will be used to construct the object instance, and may raise a serializers.ValidationError if the supplied data is in an incorrect format.

    Once you've implemented .to_internal_value(), the basic validation API will be available on the serializer, and you will be able to use .is_valid(), .validated_data and .errors.

    If you want to also support .save() you'll need to also implement either or both of the .create() and .update() methods.

    Here's a complete example of our previous HighScoreSerializer, that's been updated to support both read and write operations.

    @@ -1317,15 +1317,15 @@ def all_high_scores(request): # Perform the data validation. if not score: - raise ValidationError({ + raise serializers.ValidationError({ 'score': 'This field is required.' }) if not player_name: - raise ValidationError({ + raise serializers.ValidationError({ 'player_name': 'This field is required.' }) if len(player_name) > 10: - raise ValidationError({ + raise serializers.ValidationError({ 'player_name': 'May not be more than 10 characters.' }) diff --git a/api-guide/settings/index.html b/api-guide/settings/index.html index 6285af41b..d31189224 100644 --- a/api-guide/settings/index.html +++ b/api-guide/settings/index.html @@ -562,7 +562,7 @@ If set to None then generic filtering is disabled.


    MAX_PAGINATE_BY


    -

    This setting is pending deprecation.

    +

    This setting has been removed.

    See the pagination documentation for further guidance on setting the pagination style.


    SEARCH_PARAM

    diff --git a/api-guide/throttling/index.html b/api-guide/throttling/index.html index 8266609af..049b05cea 100644 --- a/api-guide/throttling/index.html +++ b/api-guide/throttling/index.html @@ -454,7 +454,7 @@

    Throttling

    HTTP/1.1 420 Enhance Your Calm

    -

    Twitter API rate limiting response

    +

    Twitter API rate limiting response

    Throttling is similar to permissions, in that it determines if a request should be authorized. Throttles indicate a temporary state, and are used to control the rate of requests that clients can make to an API.

    As with permissions, multiple throttles may be used. Your API might have a restrictive throttle for unauthenticated requests, and a less restrictive throttle for authenticated requests.

    diff --git a/api-guide/validators/index.html b/api-guide/validators/index.html index 439863609..ef18e4be6 100644 --- a/api-guide/validators/index.html +++ b/api-guide/validators/index.html @@ -622,7 +622,6 @@ class ExampleSerializer(serializers.Serializer):

    A default class that can be used to only set a default argument during create operations. During updates the field is omitted.

    It takes a single argument, which is the default value or callable that should be used during create operations.

    created_at = serializers.DateTimeField(
    -    read_only=True,
         default=serializers.CreateOnlyDefault(timezone.now)
     )
     
    @@ -648,7 +647,7 @@ in the .validate() method, or else in the view.

    class Meta: fields = ('client', 'date', 'amount') - extra_kwargs = {'client': {'required': 'False'}} + extra_kwargs = {'client': {'required': False}} validators = [] # Remove a default "unique together" constraint.

    Updating nested serializers

    diff --git a/api-guide/versioning/index.html b/api-guide/versioning/index.html index d3dcef7a4..4f5cfa9fe 100644 --- a/api-guide/versioning/index.html +++ b/api-guide/versioning/index.html @@ -477,7 +477,7 @@ reverse('bookings-list', request=request)

    The above function will apply any URL transformations appropriate to the request version. For example:

    Versioned APIs and hyperlinked serializers

    diff --git a/api-guide/viewsets/index.html b/api-guide/viewsets/index.html index 2c6ea3cc8..bafa99835 100644 --- a/api-guide/viewsets/index.html +++ b/api-guide/viewsets/index.html @@ -394,6 +394,10 @@ ViewSet actions +
  • + Introspecting ViewSet actions +
  • +
  • Marking extra actions for routing
  • @@ -542,9 +546,15 @@ urlpatterns = router.urls def destroy(self, request, pk=None): pass -

    During dispatch the name of the current action is available via the .action attribute. -You may inspect .action to adjust behaviour based on the current action.

    -

    For example, you could restrict permissions to everything except the list action similar to this:

    +

    Introspecting ViewSet actions

    +

    During dispatch, the following attributes are available on the ViewSet.

    + +

    You may inspect these attributes to adjust behaviour based on the current action. For example, you could restrict permissions to everything except the list action similar to this:

    def get_permissions(self):
         """
         Instantiates and returns the list of permissions that this view requires.
    @@ -556,13 +566,11 @@ You may inspect .action to adjust behaviour based on the current ac
         return [permission() for permission in permission_classes]
     

    Marking extra actions for routing

    -

    If you have ad-hoc methods that you need to be routed to, you can mark them as requiring routing using the @detail_route or @list_route decorators.

    -

    The @detail_route decorator contains pk in its URL pattern and is intended for methods which require a single instance. The @list_route decorator is intended for methods which operate on a list of objects.

    -

    For example:

    +

    If you have ad-hoc methods that should be routable, you can mark them as such with the @action decorator. Like regular actions, extra actions may be intended for either a list of objects, or a single instance. To indicate this, set the detail argument to True or False. The router will configure its URL patterns accordingly. e.g., the DefaultRouter will configure detail actions to contain pk in their URL patterns.

    +

    A more complete example of extra actions:

    from django.contrib.auth.models import User
    -from rest_framework import status
    -from rest_framework import viewsets
    -from rest_framework.decorators import detail_route, list_route
    +from rest_framework import status, viewsets
    +from rest_framework.decorators import action
     from rest_framework.response import Response
     from myapp.serializers import UserSerializer, PasswordSerializer
     
    @@ -573,7 +581,7 @@ class UserViewSet(viewsets.ModelViewSet):
         queryset = User.objects.all()
         serializer_class = UserSerializer
     
    -    @detail_route(methods=['post'])
    +    @action(methods=['post'], detail=True)
         def set_password(self, request, pk=None):
             user = self.get_object()
             serializer = PasswordSerializer(data=request.data)
    @@ -585,7 +593,7 @@ class UserViewSet(viewsets.ModelViewSet):
                 return Response(serializer.errors,
                                 status=status.HTTP_400_BAD_REQUEST)
     
    -    @list_route()
    +    @action(detail=False)
         def recent_users(self, request):
             recent_users = User.objects.all().order('-last_login')
     
    @@ -597,17 +605,18 @@ class UserViewSet(viewsets.ModelViewSet):
             serializer = self.get_serializer(recent_users, many=True)
             return Response(serializer.data)
     
    -

    The decorators can additionally take extra arguments that will be set for the routed view only. For example...

    -
        @detail_route(methods=['post'], permission_classes=[IsAdminOrIsSelf])
    +

    The decorator can additionally take extra arguments that will be set for the routed view only. For example:

    +
        @action(methods=['post'], detail=True, permission_classes=[IsAdminOrIsSelf])
         def set_password(self, request, pk=None):
            ...
     
    -

    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'])
    +

    These decorator will route GET requests by default, but may also accept other HTTP methods by setting the methods argument. For example:

    +
        @action(methods=['post', 'delete'], detail=True)
         def unset_password(self, request, pk=None):
            ...
     

    The two new actions will then be available at the urls ^users/{pk}/set_password/$ and ^users/{pk}/unset_password/$

    +

    To view all extra actions, call the .get_extra_actions() method.

    Reversing action URLs

    If you need to get the URL of an action, use the .reverse_action() method. This is a convenience wrapper for reverse(), automatically passing the view's request object and prepending the url_name with the .basename attribute.

    Note that the basename is provided by the router during ViewSet registration. If you are not using a router, then you must provide the basename argument to the .as_view() method.

    @@ -616,7 +625,12 @@ class UserViewSet(viewsets.ModelViewSet): 'http://localhost:8000/api/users/1/set_password'
    -

    The url_name argument should match the same argument to the @list_route and @detail_route decorators. Additionally, this can be used to reverse the default list and detail routes.

    +

    Alternatively, you can use the url_name attribute set by the @action decorator.

    +
    >>> view.reverse_action(view.set_password.url_name, args=['1'])
    +'http://localhost:8000/api/users/1/set_password'
    +
    + +

    The url_name argument for .reverse_action() should match the same argument to the @action decorator. Additionally, this method can be used to reverse the default actions, such as list and create.


    API Reference

    ViewSet

    diff --git a/css/default.css b/css/default.css index a0a286b22..bb17a3a11 100644 --- a/css/default.css +++ b/css/default.css @@ -160,9 +160,19 @@ body, .navbar .navbar-inner .container-fluid{ margin: 0 auto; } -body{ - background: url("../img/grid.png") repeat-x; - background-attachment: fixed; +/* Replacement for `body { background-attachment: fixed; }`, which + has performance issues when scrolling on large displays. */ +body::before { + content: ' '; + position: fixed; + width: 100%; + height: 100%; + top: 0; + left: 0; + background-color: #f8f8f8; + background: url(../img/grid.png) repeat-x; + will-change: transform; + z-index: -1; } diff --git a/mkdocs/search_index.json b/mkdocs/search_index.json index fbe4210fd..b6345f1b6 100644 --- a/mkdocs/search_index.json +++ b/mkdocs/search_index.json @@ -247,7 +247,7 @@ }, { "location": "/tutorial/4-authentication-and-permissions/", - "text": "Tutorial 4: Authentication & Permissions\n\n\nCurrently our API doesn't have any restrictions on who can edit or delete code snippets. We'd like to have some more advanced behavior in order to make sure that:\n\n\n\n\nCode snippets are always associated with a creator.\n\n\nOnly authenticated users may create snippets.\n\n\nOnly the creator of a snippet may update or delete it.\n\n\nUnauthenticated requests should have full read-only access.\n\n\n\n\nAdding information to our model\n\n\nWe're going to make a couple of changes to our \nSnippet\n model class.\nFirst, let's add a couple of fields. One of those fields will be used to represent the user who created the code snippet. The other field will be used to store the highlighted HTML representation of the code.\n\n\nAdd the following two fields to the \nSnippet\n model in \nmodels.py\n.\n\n\nowner = models.ForeignKey('auth.User', related_name='snippets', on_delete=models.CASCADE)\nhighlighted = models.TextField()\n\n\n\nWe'd also need to make sure that when the model is saved, that we populate the highlighted field, using the \npygments\n code highlighting library.\n\n\nWe'll need some extra imports:\n\n\nfrom pygments.lexers import get_lexer_by_name\nfrom pygments.formatters.html import HtmlFormatter\nfrom pygments import highlight\n\n\n\nAnd now we can add a \n.save()\n method to our model class:\n\n\ndef save(self, *args, **kwargs):\n \"\"\"\n Use the `pygments` library to create a highlighted HTML\n representation of the code snippet.\n \"\"\"\n lexer = get_lexer_by_name(self.language)\n linenos = self.linenos and 'table' or False\n options = self.title and {'title': self.title} or {}\n formatter = HtmlFormatter(style=self.style, linenos=linenos,\n full=True, **options)\n self.highlighted = highlight(self.code, lexer, formatter)\n super(Snippet, self).save(*args, **kwargs)\n\n\n\nWhen that's all done we'll need to update our database tables.\nNormally we'd create a database migration in order to do that, but for the purposes of this tutorial, let's just delete the database and start again.\n\n\nrm -f db.sqlite3\nrm -r snippets/migrations\npython manage.py makemigrations snippets\npython manage.py migrate\n\n\n\nYou might also want to create a few different users, to use for testing the API. The quickest way to do this will be with the \ncreatesuperuser\n command.\n\n\npython manage.py createsuperuser\n\n\n\nAdding endpoints for our User models\n\n\nNow that we've got some users to work with, we'd better add representations of those users to our API. Creating a new serializer is easy. In \nserializers.py\n add:\n\n\nfrom django.contrib.auth.models import User\n\nclass UserSerializer(serializers.ModelSerializer):\n snippets = serializers.PrimaryKeyRelatedField(many=True, queryset=Snippet.objects.all())\n\n class Meta:\n model = User\n fields = ('id', 'username', 'snippets')\n\n\n\nBecause \n'snippets'\n is a \nreverse\n relationship on the User model, it will not be included by default when using the \nModelSerializer\n class, so we needed to add an explicit field for it.\n\n\nWe'll also add a couple of views to \nviews.py\n. We'd like to just use read-only views for the user representations, so we'll use the \nListAPIView\n and \nRetrieveAPIView\n generic class-based views.\n\n\nfrom django.contrib.auth.models import User\n\n\nclass UserList(generics.ListAPIView):\n queryset = User.objects.all()\n serializer_class = UserSerializer\n\n\nclass UserDetail(generics.RetrieveAPIView):\n queryset = User.objects.all()\n serializer_class = UserSerializer\n\n\n\nMake sure to also import the \nUserSerializer\n class\n\n\nfrom snippets.serializers import UserSerializer\n\n\n\nFinally we need to add those views into the API, by referencing them from the URL conf. Add the following to the patterns in \nurls.py\n.\n\n\nurl(r'^users/$', views.UserList.as_view()),\nurl(r'^users/(?P[0-9]+)/$', views.UserDetail.as_view()),\n\n\n\nAssociating Snippets with Users\n\n\nRight now, if we created a code snippet, there'd be no way of associating the user that created the snippet, with the snippet instance. The user isn't sent as part of the serialized representation, but is instead a property of the incoming request.\n\n\nThe way we deal with that is by overriding a \n.perform_create()\n method on our snippet views, that allows us to modify how the instance save is managed, and handle any information that is implicit in the incoming request or requested URL.\n\n\nOn the \nSnippetList\n view class, add the following method:\n\n\ndef perform_create(self, serializer):\n serializer.save(owner=self.request.user)\n\n\n\nThe \ncreate()\n method of our serializer will now be passed an additional \n'owner'\n field, along with the validated data from the request.\n\n\nUpdating our serializer\n\n\nNow that snippets are associated with the user that created them, let's update our \nSnippetSerializer\n to reflect that. Add the following field to the serializer definition in \nserializers.py\n:\n\n\nowner = serializers.ReadOnlyField(source='owner.username')\n\n\n\nNote\n: Make sure you also add \n'owner',\n to the list of fields in the inner \nMeta\n class.\n\n\nThis field is doing something quite interesting. The \nsource\n argument controls which attribute is used to populate a field, and can point at any attribute on the serialized instance. It can also take the dotted notation shown above, in which case it will traverse the given attributes, in a similar way as it is used with Django's template language.\n\n\nThe field we've added is the untyped \nReadOnlyField\n class, in contrast to the other typed fields, such as \nCharField\n, \nBooleanField\n etc... The untyped \nReadOnlyField\n is always read-only, and will be used for serialized representations, but will not be used for updating model instances when they are deserialized. We could have also used \nCharField(read_only=True)\n here.\n\n\nAdding required permissions to views\n\n\nNow that code snippets are associated with users, we want to make sure that only authenticated users are able to create, update and delete code snippets.\n\n\nREST framework includes a number of permission classes that we can use to restrict who can access a given view. In this case the one we're looking for is \nIsAuthenticatedOrReadOnly\n, which will ensure that authenticated requests get read-write access, and unauthenticated requests get read-only access.\n\n\nFirst add the following import in the views module\n\n\nfrom rest_framework import permissions\n\n\n\nThen, add the following property to \nboth\n the \nSnippetList\n and \nSnippetDetail\n view classes.\n\n\npermission_classes = (permissions.IsAuthenticatedOrReadOnly,)\n\n\n\nAdding login to the Browsable API\n\n\nIf you open a browser and navigate to the browsable API at the moment, you'll find that you're no longer able to create new code snippets. In order to do so we'd need to be able to login as a user.\n\n\nWe can add a login view for use with the browsable API, by editing the URLconf in our project-level \nurls.py\n file.\n\n\nAdd the following import at the top of the file:\n\n\nfrom django.conf.urls import include\n\n\n\nAnd, at the end of the file, add a pattern to include the login and logout views for the browsable API.\n\n\nurlpatterns += [\n url(r'^api-auth/', include('rest_framework.urls')),\n]\n\n\n\nThe \nr'^api-auth/'\n part of pattern can actually be whatever URL you want to use.\n\n\nNow if you open up the browser again and refresh the page you'll see a 'Login' link in the top right of the page. If you log in as one of the users you created earlier, you'll be able to create code snippets again.\n\n\nOnce you've created a few code snippets, navigate to the '/users/' endpoint, and notice that the representation includes a list of the snippet ids that are associated with each user, in each user's 'snippets' field.\n\n\nObject level permissions\n\n\nReally we'd like all code snippets to be visible to anyone, but also make sure that only the user that created a code snippet is able to update or delete it.\n\n\nTo do that we're going to need to create a custom permission.\n\n\nIn the snippets app, create a new file, \npermissions.py\n\n\nfrom rest_framework import permissions\n\n\nclass IsOwnerOrReadOnly(permissions.BasePermission):\n \"\"\"\n Custom permission to only allow owners of an object to edit it.\n \"\"\"\n\n def has_object_permission(self, request, view, obj):\n # Read permissions are allowed to any request,\n # so we'll always allow GET, HEAD or OPTIONS requests.\n if request.method in permissions.SAFE_METHODS:\n return True\n\n # Write permissions are only allowed to the owner of the snippet.\n return obj.owner == request.user\n\n\n\nNow we can add that custom permission to our snippet instance endpoint, by editing the \npermission_classes\n property on the \nSnippetDetail\n view class:\n\n\npermission_classes = (permissions.IsAuthenticatedOrReadOnly,\n IsOwnerOrReadOnly,)\n\n\n\nMake sure to also import the \nIsOwnerOrReadOnly\n class.\n\n\nfrom snippets.permissions import IsOwnerOrReadOnly\n\n\n\nNow, if you open a browser again, you find that the 'DELETE' and 'PUT' actions only appear on a snippet instance endpoint if you're logged in as the same user that created the code snippet.\n\n\nAuthenticating with the API\n\n\nBecause we now have a set of permissions on the API, we need to authenticate our requests to it if we want to edit any snippets. We haven't set up any \nauthentication classes\n, so the defaults are currently applied, which are \nSessionAuthentication\n and \nBasicAuthentication\n.\n\n\nWhen we interact with the API through the web browser, we can login, and the browser session will then provide the required authentication for the requests.\n\n\nIf we're interacting with the API programmatically we need to explicitly provide the authentication credentials on each request.\n\n\nIf we try to create a snippet without authenticating, we'll get an error:\n\n\nhttp POST http://127.0.0.1:8000/snippets/ code=\"print 123\"\n\n{\n \"detail\": \"Authentication credentials were not provided.\"\n}\n\n\n\nWe can make a successful request by including the username and password of one of the users we created earlier.\n\n\nhttp -a admin:password123 POST http://127.0.0.1:8000/snippets/ code=\"print 789\"\n\n{\n \"id\": 1,\n \"owner\": \"admin\",\n \"title\": \"foo\",\n \"code\": \"print 789\",\n \"linenos\": false,\n \"language\": \"python\",\n \"style\": \"friendly\"\n}\n\n\n\nSummary\n\n\nWe've now got a fairly fine-grained set of permissions on our Web API, and end points for users of the system and for the code snippets that they have created.\n\n\nIn \npart 5\n of the tutorial we'll look at how we can tie everything together by creating an HTML endpoint for our highlighted snippets, and improve the cohesion of our API by using hyperlinking for the relationships within the system.", + "text": "Tutorial 4: Authentication & Permissions\n\n\nCurrently our API doesn't have any restrictions on who can edit or delete code snippets. We'd like to have some more advanced behavior in order to make sure that:\n\n\n\n\nCode snippets are always associated with a creator.\n\n\nOnly authenticated users may create snippets.\n\n\nOnly the creator of a snippet may update or delete it.\n\n\nUnauthenticated requests should have full read-only access.\n\n\n\n\nAdding information to our model\n\n\nWe're going to make a couple of changes to our \nSnippet\n model class.\nFirst, let's add a couple of fields. One of those fields will be used to represent the user who created the code snippet. The other field will be used to store the highlighted HTML representation of the code.\n\n\nAdd the following two fields to the \nSnippet\n model in \nmodels.py\n.\n\n\nowner = models.ForeignKey('auth.User', related_name='snippets', on_delete=models.CASCADE)\nhighlighted = models.TextField()\n\n\n\nWe'd also need to make sure that when the model is saved, that we populate the highlighted field, using the \npygments\n code highlighting library.\n\n\nWe'll need some extra imports:\n\n\nfrom pygments.lexers import get_lexer_by_name\nfrom pygments.formatters.html import HtmlFormatter\nfrom pygments import highlight\n\n\n\nAnd now we can add a \n.save()\n method to our model class:\n\n\ndef save(self, *args, **kwargs):\n \"\"\"\n Use the `pygments` library to create a highlighted HTML\n representation of the code snippet.\n \"\"\"\n lexer = get_lexer_by_name(self.language)\n linenos = 'table' if self.linenos else False\n options = {'title': self.title} if self.title else {}\n formatter = HtmlFormatter(style=self.style, linenos=linenos,\n full=True, **options)\n self.highlighted = highlight(self.code, lexer, formatter)\n super(Snippet, self).save(*args, **kwargs)\n\n\n\nWhen that's all done we'll need to update our database tables.\nNormally we'd create a database migration in order to do that, but for the purposes of this tutorial, let's just delete the database and start again.\n\n\nrm -f db.sqlite3\nrm -r snippets/migrations\npython manage.py makemigrations snippets\npython manage.py migrate\n\n\n\nYou might also want to create a few different users, to use for testing the API. The quickest way to do this will be with the \ncreatesuperuser\n command.\n\n\npython manage.py createsuperuser\n\n\n\nAdding endpoints for our User models\n\n\nNow that we've got some users to work with, we'd better add representations of those users to our API. Creating a new serializer is easy. In \nserializers.py\n add:\n\n\nfrom django.contrib.auth.models import User\n\nclass UserSerializer(serializers.ModelSerializer):\n snippets = serializers.PrimaryKeyRelatedField(many=True, queryset=Snippet.objects.all())\n\n class Meta:\n model = User\n fields = ('id', 'username', 'snippets')\n\n\n\nBecause \n'snippets'\n is a \nreverse\n relationship on the User model, it will not be included by default when using the \nModelSerializer\n class, so we needed to add an explicit field for it.\n\n\nWe'll also add a couple of views to \nviews.py\n. We'd like to just use read-only views for the user representations, so we'll use the \nListAPIView\n and \nRetrieveAPIView\n generic class-based views.\n\n\nfrom django.contrib.auth.models import User\n\n\nclass UserList(generics.ListAPIView):\n queryset = User.objects.all()\n serializer_class = UserSerializer\n\n\nclass UserDetail(generics.RetrieveAPIView):\n queryset = User.objects.all()\n serializer_class = UserSerializer\n\n\n\nMake sure to also import the \nUserSerializer\n class\n\n\nfrom snippets.serializers import UserSerializer\n\n\n\nFinally we need to add those views into the API, by referencing them from the URL conf. Add the following to the patterns in \nurls.py\n.\n\n\nurl(r'^users/$', views.UserList.as_view()),\nurl(r'^users/(?P[0-9]+)/$', views.UserDetail.as_view()),\n\n\n\nAssociating Snippets with Users\n\n\nRight now, if we created a code snippet, there'd be no way of associating the user that created the snippet, with the snippet instance. The user isn't sent as part of the serialized representation, but is instead a property of the incoming request.\n\n\nThe way we deal with that is by overriding a \n.perform_create()\n method on our snippet views, that allows us to modify how the instance save is managed, and handle any information that is implicit in the incoming request or requested URL.\n\n\nOn the \nSnippetList\n view class, add the following method:\n\n\ndef perform_create(self, serializer):\n serializer.save(owner=self.request.user)\n\n\n\nThe \ncreate()\n method of our serializer will now be passed an additional \n'owner'\n field, along with the validated data from the request.\n\n\nUpdating our serializer\n\n\nNow that snippets are associated with the user that created them, let's update our \nSnippetSerializer\n to reflect that. Add the following field to the serializer definition in \nserializers.py\n:\n\n\nowner = serializers.ReadOnlyField(source='owner.username')\n\n\n\nNote\n: Make sure you also add \n'owner',\n to the list of fields in the inner \nMeta\n class.\n\n\nThis field is doing something quite interesting. The \nsource\n argument controls which attribute is used to populate a field, and can point at any attribute on the serialized instance. It can also take the dotted notation shown above, in which case it will traverse the given attributes, in a similar way as it is used with Django's template language.\n\n\nThe field we've added is the untyped \nReadOnlyField\n class, in contrast to the other typed fields, such as \nCharField\n, \nBooleanField\n etc... The untyped \nReadOnlyField\n is always read-only, and will be used for serialized representations, but will not be used for updating model instances when they are deserialized. We could have also used \nCharField(read_only=True)\n here.\n\n\nAdding required permissions to views\n\n\nNow that code snippets are associated with users, we want to make sure that only authenticated users are able to create, update and delete code snippets.\n\n\nREST framework includes a number of permission classes that we can use to restrict who can access a given view. In this case the one we're looking for is \nIsAuthenticatedOrReadOnly\n, which will ensure that authenticated requests get read-write access, and unauthenticated requests get read-only access.\n\n\nFirst add the following import in the views module\n\n\nfrom rest_framework import permissions\n\n\n\nThen, add the following property to \nboth\n the \nSnippetList\n and \nSnippetDetail\n view classes.\n\n\npermission_classes = (permissions.IsAuthenticatedOrReadOnly,)\n\n\n\nAdding login to the Browsable API\n\n\nIf you open a browser and navigate to the browsable API at the moment, you'll find that you're no longer able to create new code snippets. In order to do so we'd need to be able to login as a user.\n\n\nWe can add a login view for use with the browsable API, by editing the URLconf in our project-level \nurls.py\n file.\n\n\nAdd the following import at the top of the file:\n\n\nfrom django.conf.urls import include\n\n\n\nAnd, at the end of the file, add a pattern to include the login and logout views for the browsable API.\n\n\nurlpatterns += [\n url(r'^api-auth/', include('rest_framework.urls')),\n]\n\n\n\nThe \nr'^api-auth/'\n part of pattern can actually be whatever URL you want to use.\n\n\nNow if you open up the browser again and refresh the page you'll see a 'Login' link in the top right of the page. If you log in as one of the users you created earlier, you'll be able to create code snippets again.\n\n\nOnce you've created a few code snippets, navigate to the '/users/' endpoint, and notice that the representation includes a list of the snippet ids that are associated with each user, in each user's 'snippets' field.\n\n\nObject level permissions\n\n\nReally we'd like all code snippets to be visible to anyone, but also make sure that only the user that created a code snippet is able to update or delete it.\n\n\nTo do that we're going to need to create a custom permission.\n\n\nIn the snippets app, create a new file, \npermissions.py\n\n\nfrom rest_framework import permissions\n\n\nclass IsOwnerOrReadOnly(permissions.BasePermission):\n \"\"\"\n Custom permission to only allow owners of an object to edit it.\n \"\"\"\n\n def has_object_permission(self, request, view, obj):\n # Read permissions are allowed to any request,\n # so we'll always allow GET, HEAD or OPTIONS requests.\n if request.method in permissions.SAFE_METHODS:\n return True\n\n # Write permissions are only allowed to the owner of the snippet.\n return obj.owner == request.user\n\n\n\nNow we can add that custom permission to our snippet instance endpoint, by editing the \npermission_classes\n property on the \nSnippetDetail\n view class:\n\n\npermission_classes = (permissions.IsAuthenticatedOrReadOnly,\n IsOwnerOrReadOnly,)\n\n\n\nMake sure to also import the \nIsOwnerOrReadOnly\n class.\n\n\nfrom snippets.permissions import IsOwnerOrReadOnly\n\n\n\nNow, if you open a browser again, you find that the 'DELETE' and 'PUT' actions only appear on a snippet instance endpoint if you're logged in as the same user that created the code snippet.\n\n\nAuthenticating with the API\n\n\nBecause we now have a set of permissions on the API, we need to authenticate our requests to it if we want to edit any snippets. We haven't set up any \nauthentication classes\n, so the defaults are currently applied, which are \nSessionAuthentication\n and \nBasicAuthentication\n.\n\n\nWhen we interact with the API through the web browser, we can login, and the browser session will then provide the required authentication for the requests.\n\n\nIf we're interacting with the API programmatically we need to explicitly provide the authentication credentials on each request.\n\n\nIf we try to create a snippet without authenticating, we'll get an error:\n\n\nhttp POST http://127.0.0.1:8000/snippets/ code=\"print 123\"\n\n{\n \"detail\": \"Authentication credentials were not provided.\"\n}\n\n\n\nWe can make a successful request by including the username and password of one of the users we created earlier.\n\n\nhttp -a admin:password123 POST http://127.0.0.1:8000/snippets/ code=\"print 789\"\n\n{\n \"id\": 1,\n \"owner\": \"admin\",\n \"title\": \"foo\",\n \"code\": \"print 789\",\n \"linenos\": false,\n \"language\": \"python\",\n \"style\": \"friendly\"\n}\n\n\n\nSummary\n\n\nWe've now got a fairly fine-grained set of permissions on our Web API, and end points for users of the system and for the code snippets that they have created.\n\n\nIn \npart 5\n of the tutorial we'll look at how we can tie everything together by creating an HTML endpoint for our highlighted snippets, and improve the cohesion of our API by using hyperlinking for the relationships within the system.", "title": "4 - Authentication and permissions" }, { @@ -257,7 +257,7 @@ }, { "location": "/tutorial/4-authentication-and-permissions/#adding-information-to-our-model", - "text": "We're going to make a couple of changes to our Snippet model class.\nFirst, let's add a couple of fields. One of those fields will be used to represent the user who created the code snippet. The other field will be used to store the highlighted HTML representation of the code. Add the following two fields to the Snippet model in models.py . owner = models.ForeignKey('auth.User', related_name='snippets', on_delete=models.CASCADE)\nhighlighted = models.TextField() We'd also need to make sure that when the model is saved, that we populate the highlighted field, using the pygments code highlighting library. We'll need some extra imports: from pygments.lexers import get_lexer_by_name\nfrom pygments.formatters.html import HtmlFormatter\nfrom pygments import highlight And now we can add a .save() method to our model class: def save(self, *args, **kwargs):\n \"\"\"\n Use the `pygments` library to create a highlighted HTML\n representation of the code snippet.\n \"\"\"\n lexer = get_lexer_by_name(self.language)\n linenos = self.linenos and 'table' or False\n options = self.title and {'title': self.title} or {}\n formatter = HtmlFormatter(style=self.style, linenos=linenos,\n full=True, **options)\n self.highlighted = highlight(self.code, lexer, formatter)\n super(Snippet, self).save(*args, **kwargs) When that's all done we'll need to update our database tables.\nNormally we'd create a database migration in order to do that, but for the purposes of this tutorial, let's just delete the database and start again. rm -f db.sqlite3\nrm -r snippets/migrations\npython manage.py makemigrations snippets\npython manage.py migrate You might also want to create a few different users, to use for testing the API. The quickest way to do this will be with the createsuperuser command. python manage.py createsuperuser", + "text": "We're going to make a couple of changes to our Snippet model class.\nFirst, let's add a couple of fields. One of those fields will be used to represent the user who created the code snippet. The other field will be used to store the highlighted HTML representation of the code. Add the following two fields to the Snippet model in models.py . owner = models.ForeignKey('auth.User', related_name='snippets', on_delete=models.CASCADE)\nhighlighted = models.TextField() We'd also need to make sure that when the model is saved, that we populate the highlighted field, using the pygments code highlighting library. We'll need some extra imports: from pygments.lexers import get_lexer_by_name\nfrom pygments.formatters.html import HtmlFormatter\nfrom pygments import highlight And now we can add a .save() method to our model class: def save(self, *args, **kwargs):\n \"\"\"\n Use the `pygments` library to create a highlighted HTML\n representation of the code snippet.\n \"\"\"\n lexer = get_lexer_by_name(self.language)\n linenos = 'table' if self.linenos else False\n options = {'title': self.title} if self.title else {}\n formatter = HtmlFormatter(style=self.style, linenos=linenos,\n full=True, **options)\n self.highlighted = highlight(self.code, lexer, formatter)\n super(Snippet, self).save(*args, **kwargs) When that's all done we'll need to update our database tables.\nNormally we'd create a database migration in order to do that, but for the purposes of this tutorial, let's just delete the database and start again. rm -f db.sqlite3\nrm -r snippets/migrations\npython manage.py makemigrations snippets\npython manage.py migrate You might also want to create a few different users, to use for testing the API. The quickest way to do this will be with the createsuperuser command. python manage.py createsuperuser", "title": "Adding information to our model" }, { @@ -342,7 +342,7 @@ }, { "location": "/tutorial/6-viewsets-and-routers/", - "text": "Tutorial 6: ViewSets & Routers\n\n\nREST framework includes an abstraction for dealing with \nViewSets\n, that allows the developer to concentrate on modeling the state and interactions of the API, and leave the URL construction to be handled automatically, based on common conventions.\n\n\nViewSet\n classes are almost the same thing as \nView\n classes, except that they provide operations such as \nread\n, or \nupdate\n, and not method handlers such as \nget\n or \nput\n.\n\n\nA \nViewSet\n class is only bound to a set of method handlers at the last moment, when it is instantiated into a set of views, typically by using a \nRouter\n class which handles the complexities of defining the URL conf for you.\n\n\nRefactoring to use ViewSets\n\n\nLet's take our current set of views, and refactor them into view sets.\n\n\nFirst of all let's refactor our \nUserList\n and \nUserDetail\n views into a single \nUserViewSet\n. We can remove the two views, and replace them with a single class:\n\n\nfrom rest_framework import viewsets\n\nclass UserViewSet(viewsets.ReadOnlyModelViewSet):\n \"\"\"\n This viewset automatically provides `list` and `detail` actions.\n \"\"\"\n queryset = User.objects.all()\n serializer_class = UserSerializer\n\n\n\nHere we've used the \nReadOnlyModelViewSet\n class to automatically provide the default 'read-only' operations. We're still setting the \nqueryset\n and \nserializer_class\n attributes exactly as we did when we were using regular views, but we no longer need to provide the same information to two separate classes.\n\n\nNext we're going to replace the \nSnippetList\n, \nSnippetDetail\n and \nSnippetHighlight\n view classes. We can remove the three views, and again replace them with a single class.\n\n\nfrom rest_framework.decorators import detail_route\nfrom rest_framework.response import Response\n\nclass SnippetViewSet(viewsets.ModelViewSet):\n \"\"\"\n This viewset automatically provides `list`, `create`, `retrieve`,\n `update` and `destroy` actions.\n\n Additionally we also provide an extra `highlight` action.\n \"\"\"\n queryset = Snippet.objects.all()\n serializer_class = SnippetSerializer\n permission_classes = (permissions.IsAuthenticatedOrReadOnly,\n IsOwnerOrReadOnly,)\n\n @detail_route(renderer_classes=[renderers.StaticHTMLRenderer])\n def highlight(self, request, *args, **kwargs):\n snippet = self.get_object()\n return Response(snippet.highlighted)\n\n def perform_create(self, serializer):\n serializer.save(owner=self.request.user)\n\n\n\nThis time we've used the \nModelViewSet\n class in order to get the complete set of default read and write operations.\n\n\nNotice that we've also used the \n@detail_route\n decorator to create a custom action, named \nhighlight\n. This decorator can be used to add any custom endpoints that don't fit into the standard \ncreate\n/\nupdate\n/\ndelete\n style.\n\n\nCustom actions which use the \n@detail_route\n decorator will respond to \nGET\n requests by default. We can use the \nmethods\n argument if we wanted an action that responded to \nPOST\n requests.\n\n\nThe URLs for custom actions by default depend on the method name itself. If you want to change the way url should be constructed, you can include url_path as a decorator keyword argument.\n\n\nBinding ViewSets to URLs explicitly\n\n\nThe handler methods only get bound to the actions when we define the URLConf.\nTo see what's going on under the hood let's first explicitly create a set of views from our ViewSets.\n\n\nIn the \nsnippets/urls.py\n file we bind our \nViewSet\n classes into a set of concrete views.\n\n\nfrom snippets.views import SnippetViewSet, UserViewSet, api_root\nfrom rest_framework import renderers\n\nsnippet_list = SnippetViewSet.as_view({\n 'get': 'list',\n 'post': 'create'\n})\nsnippet_detail = SnippetViewSet.as_view({\n 'get': 'retrieve',\n 'put': 'update',\n 'patch': 'partial_update',\n 'delete': 'destroy'\n})\nsnippet_highlight = SnippetViewSet.as_view({\n 'get': 'highlight'\n}, renderer_classes=[renderers.StaticHTMLRenderer])\nuser_list = UserViewSet.as_view({\n 'get': 'list'\n})\nuser_detail = UserViewSet.as_view({\n 'get': 'retrieve'\n})\n\n\n\nNotice how we're creating multiple views from each \nViewSet\n class, by binding the http methods to the required action for each view.\n\n\nNow that we've bound our resources into concrete views, we can register the views with the URL conf as usual.\n\n\nurlpatterns = format_suffix_patterns([\n url(r'^$', api_root),\n url(r'^snippets/$', snippet_list, name='snippet-list'),\n url(r'^snippets/(?P[0-9]+)/$', snippet_detail, name='snippet-detail'),\n url(r'^snippets/(?P[0-9]+)/highlight/$', snippet_highlight, name='snippet-highlight'),\n url(r'^users/$', user_list, name='user-list'),\n url(r'^users/(?P[0-9]+)/$', user_detail, name='user-detail')\n])\n\n\n\nUsing Routers\n\n\nBecause we're using \nViewSet\n classes rather than \nView\n classes, we actually don't need to design the URL conf ourselves. The conventions for wiring up resources into views and urls can be handled automatically, using a \nRouter\n class. All we need to do is register the appropriate view sets with a router, and let it do the rest.\n\n\nHere's our re-wired \nsnippets/urls.py\n file.\n\n\nfrom django.conf.urls import url, include\nfrom rest_framework.routers import DefaultRouter\nfrom snippets import views\n\n# Create a router and register our viewsets with it.\nrouter = DefaultRouter()\nrouter.register(r'snippets', views.SnippetViewSet)\nrouter.register(r'users', views.UserViewSet)\n\n# The API URLs are now determined automatically by the router.\nurlpatterns = [\n url(r'^', include(router.urls))\n]\n\n\n\nRegistering the viewsets with the router is similar to providing a urlpattern. We include two arguments - the URL prefix for the views, and the viewset itself.\n\n\nThe \nDefaultRouter\n class we're using also automatically creates the API root view for us, so we can now delete the \napi_root\n method from our \nviews\n module.\n\n\nTrade-offs between views vs viewsets\n\n\nUsing viewsets can be a really useful abstraction. It helps ensure that URL conventions will be consistent across your API, minimizes the amount of code you need to write, and allows you to concentrate on the interactions and representations your API provides rather than the specifics of the URL conf.\n\n\nThat doesn't mean it's always the right approach to take. There's a similar set of trade-offs to consider as when using class-based views instead of function based views. Using viewsets is less explicit than building your views individually.\n\n\nIn \npart 7\n of the tutorial we'll look at how we can add an API schema,\nand interact with our API using a client library or command line tool.", + "text": "Tutorial 6: ViewSets & Routers\n\n\nREST framework includes an abstraction for dealing with \nViewSets\n, that allows the developer to concentrate on modeling the state and interactions of the API, and leave the URL construction to be handled automatically, based on common conventions.\n\n\nViewSet\n classes are almost the same thing as \nView\n classes, except that they provide operations such as \nread\n, or \nupdate\n, and not method handlers such as \nget\n or \nput\n.\n\n\nA \nViewSet\n class is only bound to a set of method handlers at the last moment, when it is instantiated into a set of views, typically by using a \nRouter\n class which handles the complexities of defining the URL conf for you.\n\n\nRefactoring to use ViewSets\n\n\nLet's take our current set of views, and refactor them into view sets.\n\n\nFirst of all let's refactor our \nUserList\n and \nUserDetail\n views into a single \nUserViewSet\n. We can remove the two views, and replace them with a single class:\n\n\nfrom rest_framework import viewsets\n\nclass UserViewSet(viewsets.ReadOnlyModelViewSet):\n \"\"\"\n This viewset automatically provides `list` and `detail` actions.\n \"\"\"\n queryset = User.objects.all()\n serializer_class = UserSerializer\n\n\n\nHere we've used the \nReadOnlyModelViewSet\n class to automatically provide the default 'read-only' operations. We're still setting the \nqueryset\n and \nserializer_class\n attributes exactly as we did when we were using regular views, but we no longer need to provide the same information to two separate classes.\n\n\nNext we're going to replace the \nSnippetList\n, \nSnippetDetail\n and \nSnippetHighlight\n view classes. We can remove the three views, and again replace them with a single class.\n\n\nfrom rest_framework.decorators import action\nfrom rest_framework.response import Response\n\nclass SnippetViewSet(viewsets.ModelViewSet):\n \"\"\"\n This viewset automatically provides `list`, `create`, `retrieve`,\n `update` and `destroy` actions.\n\n Additionally we also provide an extra `highlight` action.\n \"\"\"\n queryset = Snippet.objects.all()\n serializer_class = SnippetSerializer\n permission_classes = (permissions.IsAuthenticatedOrReadOnly,\n IsOwnerOrReadOnly,)\n\n @action(detail=True, renderer_classes=[renderers.StaticHTMLRenderer])\n def highlight(self, request, *args, **kwargs):\n snippet = self.get_object()\n return Response(snippet.highlighted)\n\n def perform_create(self, serializer):\n serializer.save(owner=self.request.user)\n\n\n\nThis time we've used the \nModelViewSet\n class in order to get the complete set of default read and write operations.\n\n\nNotice that we've also used the \n@action\n decorator to create a custom action, named \nhighlight\n. This decorator can be used to add any custom endpoints that don't fit into the standard \ncreate\n/\nupdate\n/\ndelete\n style.\n\n\nCustom actions which use the \n@action\n decorator will respond to \nGET\n requests by default. We can use the \nmethods\n argument if we wanted an action that responded to \nPOST\n requests.\n\n\nThe URLs for custom actions by default depend on the method name itself. If you want to change the way url should be constructed, you can include \nurl_path\n as a decorator keyword argument.\n\n\nBinding ViewSets to URLs explicitly\n\n\nThe handler methods only get bound to the actions when we define the URLConf.\nTo see what's going on under the hood let's first explicitly create a set of views from our ViewSets.\n\n\nIn the \nsnippets/urls.py\n file we bind our \nViewSet\n classes into a set of concrete views.\n\n\nfrom snippets.views import SnippetViewSet, UserViewSet, api_root\nfrom rest_framework import renderers\n\nsnippet_list = SnippetViewSet.as_view({\n 'get': 'list',\n 'post': 'create'\n})\nsnippet_detail = SnippetViewSet.as_view({\n 'get': 'retrieve',\n 'put': 'update',\n 'patch': 'partial_update',\n 'delete': 'destroy'\n})\nsnippet_highlight = SnippetViewSet.as_view({\n 'get': 'highlight'\n}, renderer_classes=[renderers.StaticHTMLRenderer])\nuser_list = UserViewSet.as_view({\n 'get': 'list'\n})\nuser_detail = UserViewSet.as_view({\n 'get': 'retrieve'\n})\n\n\n\nNotice how we're creating multiple views from each \nViewSet\n class, by binding the http methods to the required action for each view.\n\n\nNow that we've bound our resources into concrete views, we can register the views with the URL conf as usual.\n\n\nurlpatterns = format_suffix_patterns([\n url(r'^$', api_root),\n url(r'^snippets/$', snippet_list, name='snippet-list'),\n url(r'^snippets/(?P[0-9]+)/$', snippet_detail, name='snippet-detail'),\n url(r'^snippets/(?P[0-9]+)/highlight/$', snippet_highlight, name='snippet-highlight'),\n url(r'^users/$', user_list, name='user-list'),\n url(r'^users/(?P[0-9]+)/$', user_detail, name='user-detail')\n])\n\n\n\nUsing Routers\n\n\nBecause we're using \nViewSet\n classes rather than \nView\n classes, we actually don't need to design the URL conf ourselves. The conventions for wiring up resources into views and urls can be handled automatically, using a \nRouter\n class. All we need to do is register the appropriate view sets with a router, and let it do the rest.\n\n\nHere's our re-wired \nsnippets/urls.py\n file.\n\n\nfrom django.conf.urls import url, include\nfrom rest_framework.routers import DefaultRouter\nfrom snippets import views\n\n# Create a router and register our viewsets with it.\nrouter = DefaultRouter()\nrouter.register(r'snippets', views.SnippetViewSet)\nrouter.register(r'users', views.UserViewSet)\n\n# The API URLs are now determined automatically by the router.\nurlpatterns = [\n url(r'^', include(router.urls))\n]\n\n\n\nRegistering the viewsets with the router is similar to providing a urlpattern. We include two arguments - the URL prefix for the views, and the viewset itself.\n\n\nThe \nDefaultRouter\n class we're using also automatically creates the API root view for us, so we can now delete the \napi_root\n method from our \nviews\n module.\n\n\nTrade-offs between views vs viewsets\n\n\nUsing viewsets can be a really useful abstraction. It helps ensure that URL conventions will be consistent across your API, minimizes the amount of code you need to write, and allows you to concentrate on the interactions and representations your API provides rather than the specifics of the URL conf.\n\n\nThat doesn't mean it's always the right approach to take. There's a similar set of trade-offs to consider as when using class-based views instead of function based views. Using viewsets is less explicit than building your views individually.\n\n\nIn \npart 7\n of the tutorial we'll look at how we can add an API schema,\nand interact with our API using a client library or command line tool.", "title": "6 - Viewsets and routers" }, { @@ -352,7 +352,7 @@ }, { "location": "/tutorial/6-viewsets-and-routers/#refactoring-to-use-viewsets", - "text": "Let's take our current set of views, and refactor them into view sets. First of all let's refactor our UserList and UserDetail views into a single UserViewSet . We can remove the two views, and replace them with a single class: from rest_framework import viewsets\n\nclass UserViewSet(viewsets.ReadOnlyModelViewSet):\n \"\"\"\n This viewset automatically provides `list` and `detail` actions.\n \"\"\"\n queryset = User.objects.all()\n serializer_class = UserSerializer Here we've used the ReadOnlyModelViewSet class to automatically provide the default 'read-only' operations. We're still setting the queryset and serializer_class attributes exactly as we did when we were using regular views, but we no longer need to provide the same information to two separate classes. Next we're going to replace the SnippetList , SnippetDetail and SnippetHighlight view classes. We can remove the three views, and again replace them with a single class. from rest_framework.decorators import detail_route\nfrom rest_framework.response import Response\n\nclass SnippetViewSet(viewsets.ModelViewSet):\n \"\"\"\n This viewset automatically provides `list`, `create`, `retrieve`,\n `update` and `destroy` actions.\n\n Additionally we also provide an extra `highlight` action.\n \"\"\"\n queryset = Snippet.objects.all()\n serializer_class = SnippetSerializer\n permission_classes = (permissions.IsAuthenticatedOrReadOnly,\n IsOwnerOrReadOnly,)\n\n @detail_route(renderer_classes=[renderers.StaticHTMLRenderer])\n def highlight(self, request, *args, **kwargs):\n snippet = self.get_object()\n return Response(snippet.highlighted)\n\n def perform_create(self, serializer):\n serializer.save(owner=self.request.user) This time we've used the ModelViewSet class in order to get the complete set of default read and write operations. Notice that we've also used the @detail_route decorator to create a custom action, named highlight . This decorator can be used to add any custom endpoints that don't fit into the standard create / update / delete style. Custom actions which use the @detail_route decorator will respond to GET requests by default. We can use the methods argument if we wanted an action that responded to POST requests. The URLs for custom actions by default depend on the method name itself. If you want to change the way url should be constructed, you can include url_path as a decorator keyword argument.", + "text": "Let's take our current set of views, and refactor them into view sets. First of all let's refactor our UserList and UserDetail views into a single UserViewSet . We can remove the two views, and replace them with a single class: from rest_framework import viewsets\n\nclass UserViewSet(viewsets.ReadOnlyModelViewSet):\n \"\"\"\n This viewset automatically provides `list` and `detail` actions.\n \"\"\"\n queryset = User.objects.all()\n serializer_class = UserSerializer Here we've used the ReadOnlyModelViewSet class to automatically provide the default 'read-only' operations. We're still setting the queryset and serializer_class attributes exactly as we did when we were using regular views, but we no longer need to provide the same information to two separate classes. Next we're going to replace the SnippetList , SnippetDetail and SnippetHighlight view classes. We can remove the three views, and again replace them with a single class. from rest_framework.decorators import action\nfrom rest_framework.response import Response\n\nclass SnippetViewSet(viewsets.ModelViewSet):\n \"\"\"\n This viewset automatically provides `list`, `create`, `retrieve`,\n `update` and `destroy` actions.\n\n Additionally we also provide an extra `highlight` action.\n \"\"\"\n queryset = Snippet.objects.all()\n serializer_class = SnippetSerializer\n permission_classes = (permissions.IsAuthenticatedOrReadOnly,\n IsOwnerOrReadOnly,)\n\n @action(detail=True, renderer_classes=[renderers.StaticHTMLRenderer])\n def highlight(self, request, *args, **kwargs):\n snippet = self.get_object()\n return Response(snippet.highlighted)\n\n def perform_create(self, serializer):\n serializer.save(owner=self.request.user) This time we've used the ModelViewSet class in order to get the complete set of default read and write operations. Notice that we've also used the @action decorator to create a custom action, named highlight . This decorator can be used to add any custom endpoints that don't fit into the standard create / update / delete style. Custom actions which use the @action decorator will respond to GET requests by default. We can use the methods argument if we wanted an action that responded to POST requests. The URLs for custom actions by default depend on the method name itself. If you want to change the way url should be constructed, you can include url_path as a decorator keyword argument.", "title": "Refactoring to use ViewSets" }, { @@ -372,7 +372,7 @@ }, { "location": "/tutorial/7-schemas-and-client-libraries/", - "text": "Tutorial 7: Schemas & client libraries\n\n\nA schema is a machine-readable document that describes the available API\nendpoints, their URLS, and what operations they support.\n\n\nSchemas can be a useful tool for auto-generated documentation, and can also\nbe used to drive dynamic client libraries that can interact with the API.\n\n\nCore API\n\n\nIn order to provide schema support REST framework uses \nCore API\n.\n\n\nCore API is a document specification for describing APIs. It is used to provide\nan internal representation format of the available endpoints and possible\ninteractions that an API exposes. It can either be used server-side, or\nclient-side.\n\n\nWhen used server-side, Core API allows an API to support rendering to a wide\nrange of schema or hypermedia formats.\n\n\nWhen used client-side, Core API allows for dynamically driven client libraries\nthat can interact with any API that exposes a supported schema or hypermedia\nformat.\n\n\nAdding a schema\n\n\nREST framework supports either explicitly defined schema views, or\nautomatically generated schemas. Since we're using viewsets and routers,\nwe can simply use the automatic schema generation.\n\n\nYou'll need to install the \ncoreapi\n python package in order to include an\nAPI schema.\n\n\n$ pip install coreapi\n\n\n\nWe can now include a schema for our API, by including an autogenerated schema\nview in our URL configuration.\n\n\nfrom rest_framework.schemas import get_schema_view\n\nschema_view = get_schema_view(title='Pastebin API')\n\nurlpatterns = [\n \u00a0 \u00a0url(r'^schema/$', schema_view),\n ...\n]\n\n\n\n\nIf you visit the API root endpoint in a browser you should now see \ncorejson\n\nrepresentation become available as an option.\n\n\n\n\nWe can also request the schema from the command line, by specifying the desired\ncontent type in the \nAccept\n header.\n\n\n$ http http://127.0.0.1:8000/schema/ Accept:application/coreapi+json\nHTTP/1.0 200 OK\nAllow: GET, HEAD, OPTIONS\nContent-Type: application/coreapi+json\n\n{\n \"_meta\": {\n \"title\": \"Pastebin API\"\n },\n \"_type\": \"document\",\n ...\n\n\n\nThe default output style is to use the \nCore JSON\n encoding.\n\n\nOther schema formats, such as \nOpen API\n (formerly Swagger) are\nalso supported.\n\n\nUsing a command line client\n\n\nNow that our API is exposing a schema endpoint, we can use a dynamic client\nlibrary to interact with the API. To demonstrate this, let's use the\nCore API command line client.\n\n\nThe command line client is available as the \ncoreapi-cli\n package:\n\n\n$ pip install coreapi-cli\n\n\n\nNow check that it is available on the command line...\n\n\n$ coreapi\nUsage: coreapi [OPTIONS] COMMAND [ARGS]...\n\n Command line client for interacting with CoreAPI services.\n\n Visit http://www.coreapi.org for more information.\n\nOptions:\n --version Display the package version number.\n --help Show this message and exit.\n\nCommands:\n...\n\n\n\nFirst we'll load the API schema using the command line client.\n\n\n$ coreapi get http://127.0.0.1:8000/schema/\n\n snippets: {\n highlight(id)\n list()\n read(id)\n }\n users: {\n list()\n read(id)\n }\n\n\n\nWe haven't authenticated yet, so right now we're only able to see the read only\nendpoints, in line with how we've set up the permissions on the API.\n\n\nLet's try listing the existing snippets, using the command line client:\n\n\n$ coreapi action snippets list\n[\n {\n \"url\": \"http://127.0.0.1:8000/snippets/1/\",\n \"id\": 1,\n \"highlight\": \"http://127.0.0.1:8000/snippets/1/highlight/\",\n \"owner\": \"lucy\",\n \"title\": \"Example\",\n \"code\": \"print('hello, world!')\",\n \"linenos\": true,\n \"language\": \"python\",\n \"style\": \"friendly\"\n },\n ...\n\n\n\nSome of the API endpoints require named parameters. For example, to get back\nthe highlight HTML for a particular snippet we need to provide an id.\n\n\n$ coreapi action snippets highlight --param id=1\n\n\n\n\n Example\n ...\n\n\n\nAuthenticating our client\n\n\nIf we want to be able to create, edit and delete snippets, we'll need to\nauthenticate as a valid user. In this case we'll just use basic auth.\n\n\nMake sure to replace the \n\n and \n\n below with your\nactual username and password.\n\n\n$ coreapi credentials add 127.0.0.1 : --auth basic\nAdded credentials\n127.0.0.1 \"Basic <...>\"\n\n\n\nNow if we fetch the schema again, we should be able to see the full\nset of available interactions.\n\n\n$ coreapi reload\nPastebin API \"http://127.0.0.1:8000/schema/\">\n snippets: {\n create(code, [title], [linenos], [language], [style])\n delete(id)\n highlight(id)\n list()\n partial_update(id, [title], [code], [linenos], [language], [style])\n read(id)\n update(id, code, [title], [linenos], [language], [style])\n }\n users: {\n list()\n read(id)\n }\n\n\n\nWe're now able to interact with these endpoints. For example, to create a new\nsnippet:\n\n\n$ coreapi action snippets create --param title=\"Example\" --param code=\"print('hello, world')\"\n{\n \"url\": \"http://127.0.0.1:8000/snippets/7/\",\n \"id\": 7,\n \"highlight\": \"http://127.0.0.1:8000/snippets/7/highlight/\",\n \"owner\": \"lucy\",\n \"title\": \"Example\",\n \"code\": \"print('hello, world')\",\n \"linenos\": false,\n \"language\": \"python\",\n \"style\": \"friendly\"\n}\n\n\n\nAnd to delete a snippet:\n\n\n$ coreapi action snippets delete --param id=7\n\n\n\nAs well as the command line client, developers can also interact with your\nAPI using client libraries. The Python client library is the first of these\nto be available, and a Javascript client library is planned to be released\nsoon.\n\n\nFor more details on customizing schema generation and using Core API\nclient libraries you'll need to refer to the full documentation.\n\n\nReviewing our work\n\n\nWith an incredibly small amount of code, we've now got a complete pastebin Web API, which is fully web browsable, includes a schema-driven client library, and comes complete with authentication, per-object permissions, and multiple renderer formats.\n\n\nWe've walked through each step of the design process, and seen how if we need to customize anything we can gradually work our way down to simply using regular Django views.\n\n\nYou can review the final \ntutorial code\n on GitHub, or try out a live example in \nthe sandbox\n.\n\n\nOnwards and upwards\n\n\nWe've reached the end of our tutorial. If you want to get more involved in the REST framework project, here are a few places you can start:\n\n\n\n\nContribute on \nGitHub\n by reviewing and submitting issues, and making pull requests.\n\n\nJoin the \nREST framework discussion group\n, and help build the community.\n\n\nFollow \nthe author\n on Twitter and say hi.\n\n\n\n\nNow go build awesome things.", + "text": "Tutorial 7: Schemas & client libraries\n\n\nA schema is a machine-readable document that describes the available API\nendpoints, their URLS, and what operations they support.\n\n\nSchemas can be a useful tool for auto-generated documentation, and can also\nbe used to drive dynamic client libraries that can interact with the API.\n\n\nCore API\n\n\nIn order to provide schema support REST framework uses \nCore API\n.\n\n\nCore API is a document specification for describing APIs. It is used to provide\nan internal representation format of the available endpoints and possible\ninteractions that an API exposes. It can either be used server-side, or\nclient-side.\n\n\nWhen used server-side, Core API allows an API to support rendering to a wide\nrange of schema or hypermedia formats.\n\n\nWhen used client-side, Core API allows for dynamically driven client libraries\nthat can interact with any API that exposes a supported schema or hypermedia\nformat.\n\n\nAdding a schema\n\n\nREST framework supports either explicitly defined schema views, or\nautomatically generated schemas. Since we're using viewsets and routers,\nwe can simply use the automatic schema generation.\n\n\nYou'll need to install the \ncoreapi\n python package in order to include an\nAPI schema.\n\n\n$ pip install coreapi\n\n\n\nWe can now include a schema for our API, by including an autogenerated schema\nview in our URL configuration.\n\n\nfrom rest_framework.schemas import get_schema_view\n\nschema_view = get_schema_view(title='Pastebin API')\n\nurlpatterns = [\n \u00a0 \u00a0url(r'^schema/$', schema_view),\n ...\n]\n\n\n\n\nIf you visit the \n/schema/\n endpoint in a browser you should now see \ncorejson\n\nrepresentation become available as an option.\n\n\n\n\nWe can also request the schema from the command line, by specifying the desired\ncontent type in the \nAccept\n header.\n\n\n$ http http://127.0.0.1:8000/schema/ Accept:application/coreapi+json\nHTTP/1.0 200 OK\nAllow: GET, HEAD, OPTIONS\nContent-Type: application/coreapi+json\n\n{\n \"_meta\": {\n \"title\": \"Pastebin API\"\n },\n \"_type\": \"document\",\n ...\n\n\n\nThe default output style is to use the \nCore JSON\n encoding.\n\n\nOther schema formats, such as \nOpen API\n (formerly Swagger) are\nalso supported.\n\n\nUsing a command line client\n\n\nNow that our API is exposing a schema endpoint, we can use a dynamic client\nlibrary to interact with the API. To demonstrate this, let's use the\nCore API command line client.\n\n\nThe command line client is available as the \ncoreapi-cli\n package:\n\n\n$ pip install coreapi-cli\n\n\n\nNow check that it is available on the command line...\n\n\n$ coreapi\nUsage: coreapi [OPTIONS] COMMAND [ARGS]...\n\n Command line client for interacting with CoreAPI services.\n\n Visit http://www.coreapi.org for more information.\n\nOptions:\n --version Display the package version number.\n --help Show this message and exit.\n\nCommands:\n...\n\n\n\nFirst we'll load the API schema using the command line client.\n\n\n$ coreapi get http://127.0.0.1:8000/schema/\n\n snippets: {\n highlight(id)\n list()\n read(id)\n }\n users: {\n list()\n read(id)\n }\n\n\n\nWe haven't authenticated yet, so right now we're only able to see the read only\nendpoints, in line with how we've set up the permissions on the API.\n\n\nLet's try listing the existing snippets, using the command line client:\n\n\n$ coreapi action snippets list\n[\n {\n \"url\": \"http://127.0.0.1:8000/snippets/1/\",\n \"id\": 1,\n \"highlight\": \"http://127.0.0.1:8000/snippets/1/highlight/\",\n \"owner\": \"lucy\",\n \"title\": \"Example\",\n \"code\": \"print('hello, world!')\",\n \"linenos\": true,\n \"language\": \"python\",\n \"style\": \"friendly\"\n },\n ...\n\n\n\nSome of the API endpoints require named parameters. For example, to get back\nthe highlight HTML for a particular snippet we need to provide an id.\n\n\n$ coreapi action snippets highlight --param id=1\n\n\n\n\n Example\n ...\n\n\n\nAuthenticating our client\n\n\nIf we want to be able to create, edit and delete snippets, we'll need to\nauthenticate as a valid user. In this case we'll just use basic auth.\n\n\nMake sure to replace the \n\n and \n\n below with your\nactual username and password.\n\n\n$ coreapi credentials add 127.0.0.1 : --auth basic\nAdded credentials\n127.0.0.1 \"Basic <...>\"\n\n\n\nNow if we fetch the schema again, we should be able to see the full\nset of available interactions.\n\n\n$ coreapi reload\nPastebin API \"http://127.0.0.1:8000/schema/\">\n snippets: {\n create(code, [title], [linenos], [language], [style])\n delete(id)\n highlight(id)\n list()\n partial_update(id, [title], [code], [linenos], [language], [style])\n read(id)\n update(id, code, [title], [linenos], [language], [style])\n }\n users: {\n list()\n read(id)\n }\n\n\n\nWe're now able to interact with these endpoints. For example, to create a new\nsnippet:\n\n\n$ coreapi action snippets create --param title=\"Example\" --param code=\"print('hello, world')\"\n{\n \"url\": \"http://127.0.0.1:8000/snippets/7/\",\n \"id\": 7,\n \"highlight\": \"http://127.0.0.1:8000/snippets/7/highlight/\",\n \"owner\": \"lucy\",\n \"title\": \"Example\",\n \"code\": \"print('hello, world')\",\n \"linenos\": false,\n \"language\": \"python\",\n \"style\": \"friendly\"\n}\n\n\n\nAnd to delete a snippet:\n\n\n$ coreapi action snippets delete --param id=7\n\n\n\nAs well as the command line client, developers can also interact with your\nAPI using client libraries. The Python client library is the first of these\nto be available, and a Javascript client library is planned to be released\nsoon.\n\n\nFor more details on customizing schema generation and using Core API\nclient libraries you'll need to refer to the full documentation.\n\n\nReviewing our work\n\n\nWith an incredibly small amount of code, we've now got a complete pastebin Web API, which is fully web browsable, includes a schema-driven client library, and comes complete with authentication, per-object permissions, and multiple renderer formats.\n\n\nWe've walked through each step of the design process, and seen how if we need to customize anything we can gradually work our way down to simply using regular Django views.\n\n\nYou can review the final \ntutorial code\n on GitHub, or try out a live example in \nthe sandbox\n.\n\n\nOnwards and upwards\n\n\nWe've reached the end of our tutorial. If you want to get more involved in the REST framework project, here are a few places you can start:\n\n\n\n\nContribute on \nGitHub\n by reviewing and submitting issues, and making pull requests.\n\n\nJoin the \nREST framework discussion group\n, and help build the community.\n\n\nFollow \nthe author\n on Twitter and say hi.\n\n\n\n\nNow go build awesome things.", "title": "7 - Schemas and client libraries" }, { @@ -387,7 +387,7 @@ }, { "location": "/tutorial/7-schemas-and-client-libraries/#adding-a-schema", - "text": "REST framework supports either explicitly defined schema views, or\nautomatically generated schemas. Since we're using viewsets and routers,\nwe can simply use the automatic schema generation. You'll need to install the coreapi python package in order to include an\nAPI schema. $ pip install coreapi We can now include a schema for our API, by including an autogenerated schema\nview in our URL configuration. from rest_framework.schemas import get_schema_view\n\nschema_view = get_schema_view(title='Pastebin API')\n\nurlpatterns = [\n \u00a0 \u00a0url(r'^schema/$', schema_view),\n ...\n] If you visit the API root endpoint in a browser you should now see corejson \nrepresentation become available as an option. We can also request the schema from the command line, by specifying the desired\ncontent type in the Accept header. $ http http://127.0.0.1:8000/schema/ Accept:application/coreapi+json\nHTTP/1.0 200 OK\nAllow: GET, HEAD, OPTIONS\nContent-Type: application/coreapi+json\n\n{\n \"_meta\": {\n \"title\": \"Pastebin API\"\n },\n \"_type\": \"document\",\n ... The default output style is to use the Core JSON encoding. Other schema formats, such as Open API (formerly Swagger) are\nalso supported.", + "text": "REST framework supports either explicitly defined schema views, or\nautomatically generated schemas. Since we're using viewsets and routers,\nwe can simply use the automatic schema generation. You'll need to install the coreapi python package in order to include an\nAPI schema. $ pip install coreapi We can now include a schema for our API, by including an autogenerated schema\nview in our URL configuration. from rest_framework.schemas import get_schema_view\n\nschema_view = get_schema_view(title='Pastebin API')\n\nurlpatterns = [\n \u00a0 \u00a0url(r'^schema/$', schema_view),\n ...\n] If you visit the /schema/ endpoint in a browser you should now see corejson \nrepresentation become available as an option. We can also request the schema from the command line, by specifying the desired\ncontent type in the Accept header. $ http http://127.0.0.1:8000/schema/ Accept:application/coreapi+json\nHTTP/1.0 200 OK\nAllow: GET, HEAD, OPTIONS\nContent-Type: application/coreapi+json\n\n{\n \"_meta\": {\n \"title\": \"Pastebin API\"\n },\n \"_type\": \"document\",\n ... The default output style is to use the Core JSON encoding. Other schema formats, such as Open API (formerly Swagger) are\nalso supported.", "title": "Adding a schema" }, { @@ -892,7 +892,7 @@ }, { "location": "/api-guide/viewsets/", - "text": "ViewSets\n\n\n\n\nAfter routing has determined which controller to use for a request, your controller is responsible for making sense of the request and producing the appropriate output.\n\n\n\u2014 \nRuby on Rails Documentation\n\n\n\n\nDjango REST framework allows you to combine the logic for a set of related views in a single class, called a \nViewSet\n. In other frameworks you may also find conceptually similar implementations named something like 'Resources' or 'Controllers'.\n\n\nA \nViewSet\n class is simply \na type of class-based View, that does not provide any method handlers\n such as \n.get()\n or \n.post()\n, and instead provides actions such as \n.list()\n and \n.create()\n.\n\n\nThe method handlers for a \nViewSet\n are only bound to the corresponding actions at the point of finalizing the view, using the \n.as_view()\n method.\n\n\nTypically, rather than explicitly registering the views in a viewset in the urlconf, you'll register the viewset with a router class, that automatically determines the urlconf for you.\n\n\nExample\n\n\nLet's define a simple viewset that can be used to list or retrieve all the users in the system.\n\n\nfrom django.contrib.auth.models import User\nfrom django.shortcuts import get_object_or_404\nfrom myapps.serializers import UserSerializer\nfrom rest_framework import viewsets\nfrom rest_framework.response import Response\n\nclass UserViewSet(viewsets.ViewSet):\n \"\"\"\n A simple ViewSet for listing or retrieving users.\n \"\"\"\n def list(self, request):\n queryset = User.objects.all()\n serializer = UserSerializer(queryset, many=True)\n return Response(serializer.data)\n\n def retrieve(self, request, pk=None):\n queryset = User.objects.all()\n user = get_object_or_404(queryset, pk=pk)\n serializer = UserSerializer(user)\n return Response(serializer.data)\n\n\n\nIf we need to, we can bind this viewset into two separate views, like so:\n\n\nuser_list = UserViewSet.as_view({'get': 'list'})\nuser_detail = UserViewSet.as_view({'get': 'retrieve'})\n\n\n\nTypically we wouldn't do this, but would instead register the viewset with a router, and allow the urlconf to be automatically generated.\n\n\nfrom myapp.views import UserViewSet\nfrom rest_framework.routers import DefaultRouter\n\nrouter = DefaultRouter()\nrouter.register(r'users', UserViewSet, base_name='user')\nurlpatterns = router.urls\n\n\n\nRather than writing your own viewsets, you'll often want to use the existing base classes that provide a default set of behavior. For example:\n\n\nclass UserViewSet(viewsets.ModelViewSet):\n \"\"\"\n A viewset for viewing and editing user instances.\n \"\"\"\n serializer_class = UserSerializer\n queryset = User.objects.all()\n\n\n\nThere are two main advantages of using a \nViewSet\n class over using a \nView\n class.\n\n\n\n\nRepeated logic can be combined into a single class. In the above example, we only need to specify the \nqueryset\n once, and it'll be used across multiple views.\n\n\nBy using routers, we no longer need to deal with wiring up the URL conf ourselves.\n\n\n\n\nBoth of these come with a trade-off. Using regular views and URL confs is more explicit and gives you more control. ViewSets are helpful if you want to get up and running quickly, or when you have a large API and you want to enforce a consistent URL configuration throughout.\n\n\nViewSet actions\n\n\nThe default routers included with REST framework will provide routes for a standard set of create/retrieve/update/destroy style actions, as shown below:\n\n\nclass UserViewSet(viewsets.ViewSet):\n \"\"\"\n Example empty viewset demonstrating the standard\n actions that will be handled by a router class.\n\n If you're using format suffixes, make sure to also include\n the `format=None` keyword argument for each action.\n \"\"\"\n\n def list(self, request):\n pass\n\n def create(self, request):\n pass\n\n def retrieve(self, request, pk=None):\n pass\n\n def update(self, request, pk=None):\n pass\n\n def partial_update(self, request, pk=None):\n pass\n\n def destroy(self, request, pk=None):\n pass\n\n\n\nDuring dispatch the name of the current action is available via the \n.action\n attribute.\nYou may inspect \n.action\n to adjust behaviour based on the current action.\n\n\nFor example, you could restrict permissions to everything except the \nlist\n action similar to this:\n\n\ndef get_permissions(self):\n \"\"\"\n Instantiates and returns the list of permissions that this view requires.\n \"\"\"\n if self.action == 'list':\n permission_classes = [IsAuthenticated]\n else:\n permission_classes = [IsAdmin]\n return [permission() for permission in permission_classes]\n\n\n\nMarking extra actions for routing\n\n\nIf you have ad-hoc methods that you need to be routed to, you can mark them as requiring routing using the \n@detail_route\n or \n@list_route\n decorators.\n\n\nThe \n@detail_route\n decorator contains \npk\n in its URL pattern and is intended for methods which require a single instance. The \n@list_route\n decorator is intended for methods which operate on a list of objects.\n\n\nFor example:\n\n\nfrom django.contrib.auth.models import User\nfrom rest_framework import status\nfrom rest_framework import viewsets\nfrom rest_framework.decorators import detail_route, list_route\nfrom rest_framework.response import Response\nfrom myapp.serializers import UserSerializer, PasswordSerializer\n\nclass UserViewSet(viewsets.ModelViewSet):\n \"\"\"\n A viewset that provides the standard actions\n \"\"\"\n queryset = User.objects.all()\n serializer_class = UserSerializer\n\n @detail_route(methods=['post'])\n def set_password(self, request, pk=None):\n user = self.get_object()\n serializer = PasswordSerializer(data=request.data)\n if serializer.is_valid():\n user.set_password(serializer.data['password'])\n user.save()\n return Response({'status': 'password set'})\n else:\n return Response(serializer.errors,\n status=status.HTTP_400_BAD_REQUEST)\n\n @list_route()\n def recent_users(self, request):\n recent_users = User.objects.all().order('-last_login')\n\n page = self.paginate_queryset(recent_users)\n if page is not None:\n serializer = self.get_serializer(page, many=True)\n return self.get_paginated_response(serializer.data)\n\n serializer = self.get_serializer(recent_users, many=True)\n return Response(serializer.data)\n\n\n\nThe decorators can additionally take extra arguments that will be set for the routed view only. For example...\n\n\n @detail_route(methods=['post'], permission_classes=[IsAdminOrIsSelf])\n def set_password(self, request, pk=None):\n ...\n\n\n\nThese decorators will route \nGET\n requests by default, but may also accept other HTTP methods, by using the \nmethods\n argument. For example:\n\n\n @detail_route(methods=['post', 'delete'])\n def unset_password(self, request, pk=None):\n ...\n\n\n\nThe two new actions will then be available at the urls \n^users/{pk}/set_password/$\n and \n^users/{pk}/unset_password/$\n\n\nReversing action URLs\n\n\nIf you need to get the URL of an action, use the \n.reverse_action()\n method. This is a convenience wrapper for \nreverse()\n, automatically passing the view's \nrequest\n object and prepending the \nurl_name\n with the \n.basename\n attribute.\n\n\nNote that the \nbasename\n is provided by the router during \nViewSet\n registration. If you are not using a router, then you must provide the \nbasename\n argument to the \n.as_view()\n method.\n\n\nUsing the example from the previous section:\n\n\n>>> view.reverse_action('set-password', args=['1'])\n'http://localhost:8000/api/users/1/set_password'\n\n\n\n\nThe \nurl_name\n argument should match the same argument to the \n@list_route\n and \n@detail_route\n decorators. Additionally, this can be used to reverse the default \nlist\n and \ndetail\n routes.\n\n\n\n\nAPI Reference\n\n\nViewSet\n\n\nThe \nViewSet\n class inherits from \nAPIView\n. You can use any of the standard attributes such as \npermission_classes\n, \nauthentication_classes\n in order to control the API policy on the viewset.\n\n\nThe \nViewSet\n class does not provide any implementations of actions. In order to use a \nViewSet\n class you'll override the class and define the action implementations explicitly.\n\n\nGenericViewSet\n\n\nThe \nGenericViewSet\n class inherits from \nGenericAPIView\n, and provides the default set of \nget_object\n, \nget_queryset\n methods and other generic view base behavior, but does not include any actions by default.\n\n\nIn order to use a \nGenericViewSet\n class you'll override the class and either mixin the required mixin classes, or define the action implementations explicitly.\n\n\nModelViewSet\n\n\nThe \nModelViewSet\n class inherits from \nGenericAPIView\n and includes implementations for various actions, by mixing in the behavior of the various mixin classes.\n\n\nThe actions provided by the \nModelViewSet\n class are \n.list()\n, \n.retrieve()\n, \n.create()\n, \n.update()\n, \n.partial_update()\n, and \n.destroy()\n.\n\n\nExample\n\n\nBecause \nModelViewSet\n extends \nGenericAPIView\n, you'll normally need to provide at least the \nqueryset\n and \nserializer_class\n attributes. For example:\n\n\nclass AccountViewSet(viewsets.ModelViewSet):\n \"\"\"\n A simple ViewSet for viewing and editing accounts.\n \"\"\"\n queryset = Account.objects.all()\n serializer_class = AccountSerializer\n permission_classes = [IsAccountAdminOrReadOnly]\n\n\n\nNote that you can use any of the standard attributes or method overrides provided by \nGenericAPIView\n. For example, to use a \nViewSet\n that dynamically determines the queryset it should operate on, you might do something like this:\n\n\nclass AccountViewSet(viewsets.ModelViewSet):\n \"\"\"\n A simple ViewSet for viewing and editing the accounts\n associated with the user.\n \"\"\"\n serializer_class = AccountSerializer\n permission_classes = [IsAccountAdminOrReadOnly]\n\n def get_queryset(self):\n return self.request.user.accounts.all()\n\n\n\nNote however that upon removal of the \nqueryset\n property from your \nViewSet\n, any associated \nrouter\n will be unable to derive the base_name of your Model automatically, and so you will have to specify the \nbase_name\n kwarg as part of your \nrouter registration\n.\n\n\nAlso note that although this class provides the complete set of create/list/retrieve/update/destroy actions by default, you can restrict the available operations by using the standard permission classes.\n\n\nReadOnlyModelViewSet\n\n\nThe \nReadOnlyModelViewSet\n class also inherits from \nGenericAPIView\n. As with \nModelViewSet\n it also includes implementations for various actions, but unlike \nModelViewSet\n only provides the 'read-only' actions, \n.list()\n and \n.retrieve()\n.\n\n\nExample\n\n\nAs with \nModelViewSet\n, you'll normally need to provide at least the \nqueryset\n and \nserializer_class\n attributes. For example:\n\n\nclass AccountViewSet(viewsets.ReadOnlyModelViewSet):\n \"\"\"\n A simple ViewSet for viewing accounts.\n \"\"\"\n queryset = Account.objects.all()\n serializer_class = AccountSerializer\n\n\n\nAgain, as with \nModelViewSet\n, you can use any of the standard attributes and method overrides available to \nGenericAPIView\n.\n\n\nCustom ViewSet base classes\n\n\nYou may need to provide custom \nViewSet\n classes that do not have the full set of \nModelViewSet\n actions, or that customize the behavior in some other way.\n\n\nExample\n\n\nTo create a base viewset class that provides \ncreate\n, \nlist\n and \nretrieve\n operations, inherit from \nGenericViewSet\n, and mixin the required actions:\n\n\nfrom rest_framework import mixins\n\nclass CreateListRetrieveViewSet(mixins.CreateModelMixin,\n mixins.ListModelMixin,\n mixins.RetrieveModelMixin,\n viewsets.GenericViewSet):\n \"\"\"\n A viewset that provides `retrieve`, `create`, and `list` actions.\n\n To use it, override the class and set the `.queryset` and\n `.serializer_class` attributes.\n \"\"\"\n pass\n\n\n\nBy creating your own base \nViewSet\n classes, you can provide common behavior that can be reused in multiple viewsets across your API.", + "text": "ViewSets\n\n\n\n\nAfter routing has determined which controller to use for a request, your controller is responsible for making sense of the request and producing the appropriate output.\n\n\n\u2014 \nRuby on Rails Documentation\n\n\n\n\nDjango REST framework allows you to combine the logic for a set of related views in a single class, called a \nViewSet\n. In other frameworks you may also find conceptually similar implementations named something like 'Resources' or 'Controllers'.\n\n\nA \nViewSet\n class is simply \na type of class-based View, that does not provide any method handlers\n such as \n.get()\n or \n.post()\n, and instead provides actions such as \n.list()\n and \n.create()\n.\n\n\nThe method handlers for a \nViewSet\n are only bound to the corresponding actions at the point of finalizing the view, using the \n.as_view()\n method.\n\n\nTypically, rather than explicitly registering the views in a viewset in the urlconf, you'll register the viewset with a router class, that automatically determines the urlconf for you.\n\n\nExample\n\n\nLet's define a simple viewset that can be used to list or retrieve all the users in the system.\n\n\nfrom django.contrib.auth.models import User\nfrom django.shortcuts import get_object_or_404\nfrom myapps.serializers import UserSerializer\nfrom rest_framework import viewsets\nfrom rest_framework.response import Response\n\nclass UserViewSet(viewsets.ViewSet):\n \"\"\"\n A simple ViewSet for listing or retrieving users.\n \"\"\"\n def list(self, request):\n queryset = User.objects.all()\n serializer = UserSerializer(queryset, many=True)\n return Response(serializer.data)\n\n def retrieve(self, request, pk=None):\n queryset = User.objects.all()\n user = get_object_or_404(queryset, pk=pk)\n serializer = UserSerializer(user)\n return Response(serializer.data)\n\n\n\nIf we need to, we can bind this viewset into two separate views, like so:\n\n\nuser_list = UserViewSet.as_view({'get': 'list'})\nuser_detail = UserViewSet.as_view({'get': 'retrieve'})\n\n\n\nTypically we wouldn't do this, but would instead register the viewset with a router, and allow the urlconf to be automatically generated.\n\n\nfrom myapp.views import UserViewSet\nfrom rest_framework.routers import DefaultRouter\n\nrouter = DefaultRouter()\nrouter.register(r'users', UserViewSet, base_name='user')\nurlpatterns = router.urls\n\n\n\nRather than writing your own viewsets, you'll often want to use the existing base classes that provide a default set of behavior. For example:\n\n\nclass UserViewSet(viewsets.ModelViewSet):\n \"\"\"\n A viewset for viewing and editing user instances.\n \"\"\"\n serializer_class = UserSerializer\n queryset = User.objects.all()\n\n\n\nThere are two main advantages of using a \nViewSet\n class over using a \nView\n class.\n\n\n\n\nRepeated logic can be combined into a single class. In the above example, we only need to specify the \nqueryset\n once, and it'll be used across multiple views.\n\n\nBy using routers, we no longer need to deal with wiring up the URL conf ourselves.\n\n\n\n\nBoth of these come with a trade-off. Using regular views and URL confs is more explicit and gives you more control. ViewSets are helpful if you want to get up and running quickly, or when you have a large API and you want to enforce a consistent URL configuration throughout.\n\n\nViewSet actions\n\n\nThe default routers included with REST framework will provide routes for a standard set of create/retrieve/update/destroy style actions, as shown below:\n\n\nclass UserViewSet(viewsets.ViewSet):\n \"\"\"\n Example empty viewset demonstrating the standard\n actions that will be handled by a router class.\n\n If you're using format suffixes, make sure to also include\n the `format=None` keyword argument for each action.\n \"\"\"\n\n def list(self, request):\n pass\n\n def create(self, request):\n pass\n\n def retrieve(self, request, pk=None):\n pass\n\n def update(self, request, pk=None):\n pass\n\n def partial_update(self, request, pk=None):\n pass\n\n def destroy(self, request, pk=None):\n pass\n\n\n\nIntrospecting ViewSet actions\n\n\nDuring dispatch, the following attributes are available on the \nViewSet\n.\n\n\n\n\nbasename\n - the base to use for the URL names that are created.\n\n\naction\n - the name of the current action (e.g., \nlist\n, \ncreate\n).\n\n\ndetail\n - boolean indicating if the current action is configured for a list or detail view.\n\n\nsuffix\n - the display suffix for the viewset type - mirrors the \ndetail\n attribute.\n\n\n\n\nYou may inspect these attributes to adjust behaviour based on the current action. For example, you could restrict permissions to everything except the \nlist\n action similar to this:\n\n\ndef get_permissions(self):\n \"\"\"\n Instantiates and returns the list of permissions that this view requires.\n \"\"\"\n if self.action == 'list':\n permission_classes = [IsAuthenticated]\n else:\n permission_classes = [IsAdmin]\n return [permission() for permission in permission_classes]\n\n\n\nMarking extra actions for routing\n\n\nIf you have ad-hoc methods that should be routable, you can mark them as such with the \n@action\n decorator. Like regular actions, extra actions may be intended for either a list of objects, or a single instance. To indicate this, set the \ndetail\n argument to \nTrue\n or \nFalse\n. The router will configure its URL patterns accordingly. e.g., the \nDefaultRouter\n will configure detail actions to contain \npk\n in their URL patterns.\n\n\nA more complete example of extra actions:\n\n\nfrom django.contrib.auth.models import User\nfrom rest_framework import status, viewsets\nfrom rest_framework.decorators import action\nfrom rest_framework.response import Response\nfrom myapp.serializers import UserSerializer, PasswordSerializer\n\nclass UserViewSet(viewsets.ModelViewSet):\n \"\"\"\n A viewset that provides the standard actions\n \"\"\"\n queryset = User.objects.all()\n serializer_class = UserSerializer\n\n @action(methods=['post'], detail=True)\n def set_password(self, request, pk=None):\n user = self.get_object()\n serializer = PasswordSerializer(data=request.data)\n if serializer.is_valid():\n user.set_password(serializer.data['password'])\n user.save()\n return Response({'status': 'password set'})\n else:\n return Response(serializer.errors,\n status=status.HTTP_400_BAD_REQUEST)\n\n @action(detail=False)\n def recent_users(self, request):\n recent_users = User.objects.all().order('-last_login')\n\n page = self.paginate_queryset(recent_users)\n if page is not None:\n serializer = self.get_serializer(page, many=True)\n return self.get_paginated_response(serializer.data)\n\n serializer = self.get_serializer(recent_users, many=True)\n return Response(serializer.data)\n\n\n\nThe decorator can additionally take extra arguments that will be set for the routed view only. For example:\n\n\n @action(methods=['post'], detail=True, permission_classes=[IsAdminOrIsSelf])\n def set_password(self, request, pk=None):\n ...\n\n\n\nThese decorator will route \nGET\n requests by default, but may also accept other HTTP methods by setting the \nmethods\n argument. For example:\n\n\n @action(methods=['post', 'delete'], detail=True)\n def unset_password(self, request, pk=None):\n ...\n\n\n\nThe two new actions will then be available at the urls \n^users/{pk}/set_password/$\n and \n^users/{pk}/unset_password/$\n\n\nTo view all extra actions, call the \n.get_extra_actions()\n method.\n\n\nReversing action URLs\n\n\nIf you need to get the URL of an action, use the \n.reverse_action()\n method. This is a convenience wrapper for \nreverse()\n, automatically passing the view's \nrequest\n object and prepending the \nurl_name\n with the \n.basename\n attribute.\n\n\nNote that the \nbasename\n is provided by the router during \nViewSet\n registration. If you are not using a router, then you must provide the \nbasename\n argument to the \n.as_view()\n method.\n\n\nUsing the example from the previous section:\n\n\n>>> view.reverse_action('set-password', args=['1'])\n'http://localhost:8000/api/users/1/set_password'\n\n\n\n\nAlternatively, you can use the \nurl_name\n attribute set by the \n@action\n decorator.\n\n\n>>> view.reverse_action(view.set_password.url_name, args=['1'])\n'http://localhost:8000/api/users/1/set_password'\n\n\n\n\nThe \nurl_name\n argument for \n.reverse_action()\n should match the same argument to the \n@action\n decorator. Additionally, this method can be used to reverse the default actions, such as \nlist\n and \ncreate\n.\n\n\n\n\nAPI Reference\n\n\nViewSet\n\n\nThe \nViewSet\n class inherits from \nAPIView\n. You can use any of the standard attributes such as \npermission_classes\n, \nauthentication_classes\n in order to control the API policy on the viewset.\n\n\nThe \nViewSet\n class does not provide any implementations of actions. In order to use a \nViewSet\n class you'll override the class and define the action implementations explicitly.\n\n\nGenericViewSet\n\n\nThe \nGenericViewSet\n class inherits from \nGenericAPIView\n, and provides the default set of \nget_object\n, \nget_queryset\n methods and other generic view base behavior, but does not include any actions by default.\n\n\nIn order to use a \nGenericViewSet\n class you'll override the class and either mixin the required mixin classes, or define the action implementations explicitly.\n\n\nModelViewSet\n\n\nThe \nModelViewSet\n class inherits from \nGenericAPIView\n and includes implementations for various actions, by mixing in the behavior of the various mixin classes.\n\n\nThe actions provided by the \nModelViewSet\n class are \n.list()\n, \n.retrieve()\n, \n.create()\n, \n.update()\n, \n.partial_update()\n, and \n.destroy()\n.\n\n\nExample\n\n\nBecause \nModelViewSet\n extends \nGenericAPIView\n, you'll normally need to provide at least the \nqueryset\n and \nserializer_class\n attributes. For example:\n\n\nclass AccountViewSet(viewsets.ModelViewSet):\n \"\"\"\n A simple ViewSet for viewing and editing accounts.\n \"\"\"\n queryset = Account.objects.all()\n serializer_class = AccountSerializer\n permission_classes = [IsAccountAdminOrReadOnly]\n\n\n\nNote that you can use any of the standard attributes or method overrides provided by \nGenericAPIView\n. For example, to use a \nViewSet\n that dynamically determines the queryset it should operate on, you might do something like this:\n\n\nclass AccountViewSet(viewsets.ModelViewSet):\n \"\"\"\n A simple ViewSet for viewing and editing the accounts\n associated with the user.\n \"\"\"\n serializer_class = AccountSerializer\n permission_classes = [IsAccountAdminOrReadOnly]\n\n def get_queryset(self):\n return self.request.user.accounts.all()\n\n\n\nNote however that upon removal of the \nqueryset\n property from your \nViewSet\n, any associated \nrouter\n will be unable to derive the base_name of your Model automatically, and so you will have to specify the \nbase_name\n kwarg as part of your \nrouter registration\n.\n\n\nAlso note that although this class provides the complete set of create/list/retrieve/update/destroy actions by default, you can restrict the available operations by using the standard permission classes.\n\n\nReadOnlyModelViewSet\n\n\nThe \nReadOnlyModelViewSet\n class also inherits from \nGenericAPIView\n. As with \nModelViewSet\n it also includes implementations for various actions, but unlike \nModelViewSet\n only provides the 'read-only' actions, \n.list()\n and \n.retrieve()\n.\n\n\nExample\n\n\nAs with \nModelViewSet\n, you'll normally need to provide at least the \nqueryset\n and \nserializer_class\n attributes. For example:\n\n\nclass AccountViewSet(viewsets.ReadOnlyModelViewSet):\n \"\"\"\n A simple ViewSet for viewing accounts.\n \"\"\"\n queryset = Account.objects.all()\n serializer_class = AccountSerializer\n\n\n\nAgain, as with \nModelViewSet\n, you can use any of the standard attributes and method overrides available to \nGenericAPIView\n.\n\n\nCustom ViewSet base classes\n\n\nYou may need to provide custom \nViewSet\n classes that do not have the full set of \nModelViewSet\n actions, or that customize the behavior in some other way.\n\n\nExample\n\n\nTo create a base viewset class that provides \ncreate\n, \nlist\n and \nretrieve\n operations, inherit from \nGenericViewSet\n, and mixin the required actions:\n\n\nfrom rest_framework import mixins\n\nclass CreateListRetrieveViewSet(mixins.CreateModelMixin,\n mixins.ListModelMixin,\n mixins.RetrieveModelMixin,\n viewsets.GenericViewSet):\n \"\"\"\n A viewset that provides `retrieve`, `create`, and `list` actions.\n\n To use it, override the class and set the `.queryset` and\n `.serializer_class` attributes.\n \"\"\"\n pass\n\n\n\nBy creating your own base \nViewSet\n classes, you can provide common behavior that can be reused in multiple viewsets across your API.", "title": "Viewsets" }, { @@ -907,17 +907,22 @@ }, { "location": "/api-guide/viewsets/#viewset-actions", - "text": "The default routers included with REST framework will provide routes for a standard set of create/retrieve/update/destroy style actions, as shown below: class UserViewSet(viewsets.ViewSet):\n \"\"\"\n Example empty viewset demonstrating the standard\n actions that will be handled by a router class.\n\n If you're using format suffixes, make sure to also include\n the `format=None` keyword argument for each action.\n \"\"\"\n\n def list(self, request):\n pass\n\n def create(self, request):\n pass\n\n def retrieve(self, request, pk=None):\n pass\n\n def update(self, request, pk=None):\n pass\n\n def partial_update(self, request, pk=None):\n pass\n\n def destroy(self, request, pk=None):\n pass During dispatch the name of the current action is available via the .action attribute.\nYou may inspect .action to adjust behaviour based on the current action. For example, you could restrict permissions to everything except the list action similar to this: def get_permissions(self):\n \"\"\"\n Instantiates and returns the list of permissions that this view requires.\n \"\"\"\n if self.action == 'list':\n permission_classes = [IsAuthenticated]\n else:\n permission_classes = [IsAdmin]\n return [permission() for permission in permission_classes]", + "text": "The default routers included with REST framework will provide routes for a standard set of create/retrieve/update/destroy style actions, as shown below: class UserViewSet(viewsets.ViewSet):\n \"\"\"\n Example empty viewset demonstrating the standard\n actions that will be handled by a router class.\n\n If you're using format suffixes, make sure to also include\n the `format=None` keyword argument for each action.\n \"\"\"\n\n def list(self, request):\n pass\n\n def create(self, request):\n pass\n\n def retrieve(self, request, pk=None):\n pass\n\n def update(self, request, pk=None):\n pass\n\n def partial_update(self, request, pk=None):\n pass\n\n def destroy(self, request, pk=None):\n pass", "title": "ViewSet actions" }, + { + "location": "/api-guide/viewsets/#introspecting-viewset-actions", + "text": "During dispatch, the following attributes are available on the ViewSet . basename - the base to use for the URL names that are created. action - the name of the current action (e.g., list , create ). detail - boolean indicating if the current action is configured for a list or detail view. suffix - the display suffix for the viewset type - mirrors the detail attribute. You may inspect these attributes to adjust behaviour based on the current action. For example, you could restrict permissions to everything except the list action similar to this: def get_permissions(self):\n \"\"\"\n Instantiates and returns the list of permissions that this view requires.\n \"\"\"\n if self.action == 'list':\n permission_classes = [IsAuthenticated]\n else:\n permission_classes = [IsAdmin]\n return [permission() for permission in permission_classes]", + "title": "Introspecting ViewSet actions" + }, { "location": "/api-guide/viewsets/#marking-extra-actions-for-routing", - "text": "If you have ad-hoc methods that you need to be routed to, you can mark them as requiring routing using the @detail_route or @list_route decorators. The @detail_route decorator contains pk in its URL pattern and is intended for methods which require a single instance. The @list_route decorator is intended for methods which operate on a list of objects. For example: from django.contrib.auth.models import User\nfrom rest_framework import status\nfrom rest_framework import viewsets\nfrom rest_framework.decorators import detail_route, list_route\nfrom rest_framework.response import Response\nfrom myapp.serializers import UserSerializer, PasswordSerializer\n\nclass UserViewSet(viewsets.ModelViewSet):\n \"\"\"\n A viewset that provides the standard actions\n \"\"\"\n queryset = User.objects.all()\n serializer_class = UserSerializer\n\n @detail_route(methods=['post'])\n def set_password(self, request, pk=None):\n user = self.get_object()\n serializer = PasswordSerializer(data=request.data)\n if serializer.is_valid():\n user.set_password(serializer.data['password'])\n user.save()\n return Response({'status': 'password set'})\n else:\n return Response(serializer.errors,\n status=status.HTTP_400_BAD_REQUEST)\n\n @list_route()\n def recent_users(self, request):\n recent_users = User.objects.all().order('-last_login')\n\n page = self.paginate_queryset(recent_users)\n if page is not None:\n serializer = self.get_serializer(page, many=True)\n return self.get_paginated_response(serializer.data)\n\n serializer = self.get_serializer(recent_users, many=True)\n return Response(serializer.data) The decorators can additionally take extra arguments that will be set for the routed view only. For example... @detail_route(methods=['post'], permission_classes=[IsAdminOrIsSelf])\n def set_password(self, request, pk=None):\n ... 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'])\n def unset_password(self, request, pk=None):\n ... The two new actions will then be available at the urls ^users/{pk}/set_password/$ and ^users/{pk}/unset_password/$", + "text": "If you have ad-hoc methods that should be routable, you can mark them as such with the @action decorator. Like regular actions, extra actions may be intended for either a list of objects, or a single instance. To indicate this, set the detail argument to True or False . The router will configure its URL patterns accordingly. e.g., the DefaultRouter will configure detail actions to contain pk in their URL patterns. A more complete example of extra actions: from django.contrib.auth.models import User\nfrom rest_framework import status, viewsets\nfrom rest_framework.decorators import action\nfrom rest_framework.response import Response\nfrom myapp.serializers import UserSerializer, PasswordSerializer\n\nclass UserViewSet(viewsets.ModelViewSet):\n \"\"\"\n A viewset that provides the standard actions\n \"\"\"\n queryset = User.objects.all()\n serializer_class = UserSerializer\n\n @action(methods=['post'], detail=True)\n def set_password(self, request, pk=None):\n user = self.get_object()\n serializer = PasswordSerializer(data=request.data)\n if serializer.is_valid():\n user.set_password(serializer.data['password'])\n user.save()\n return Response({'status': 'password set'})\n else:\n return Response(serializer.errors,\n status=status.HTTP_400_BAD_REQUEST)\n\n @action(detail=False)\n def recent_users(self, request):\n recent_users = User.objects.all().order('-last_login')\n\n page = self.paginate_queryset(recent_users)\n if page is not None:\n serializer = self.get_serializer(page, many=True)\n return self.get_paginated_response(serializer.data)\n\n serializer = self.get_serializer(recent_users, many=True)\n return Response(serializer.data) The decorator can additionally take extra arguments that will be set for the routed view only. For example: @action(methods=['post'], detail=True, permission_classes=[IsAdminOrIsSelf])\n def set_password(self, request, pk=None):\n ... These decorator will route GET requests by default, but may also accept other HTTP methods by setting the methods argument. For example: @action(methods=['post', 'delete'], detail=True)\n def unset_password(self, request, pk=None):\n ... The two new actions will then be available at the urls ^users/{pk}/set_password/$ and ^users/{pk}/unset_password/$ To view all extra actions, call the .get_extra_actions() method.", "title": "Marking extra actions for routing" }, { "location": "/api-guide/viewsets/#reversing-action-urls", - "text": "If you need to get the URL of an action, use the .reverse_action() method. This is a convenience wrapper for reverse() , automatically passing the view's request object and prepending the url_name with the .basename attribute. Note that the basename is provided by the router during ViewSet registration. If you are not using a router, then you must provide the basename argument to the .as_view() method. Using the example from the previous section: >>> view.reverse_action('set-password', args=['1'])\n'http://localhost:8000/api/users/1/set_password' The url_name argument should match the same argument to the @list_route and @detail_route decorators. Additionally, this can be used to reverse the default list and detail routes.", + "text": "If you need to get the URL of an action, use the .reverse_action() method. This is a convenience wrapper for reverse() , automatically passing the view's request object and prepending the url_name with the .basename attribute. Note that the basename is provided by the router during ViewSet registration. If you are not using a router, then you must provide the basename argument to the .as_view() method. Using the example from the previous section: >>> view.reverse_action('set-password', args=['1'])\n'http://localhost:8000/api/users/1/set_password' Alternatively, you can use the url_name attribute set by the @action decorator. >>> view.reverse_action(view.set_password.url_name, args=['1'])\n'http://localhost:8000/api/users/1/set_password' The url_name argument for .reverse_action() should match the same argument to the @action decorator. Additionally, this method can be used to reverse the default actions, such as list and create .", "title": "Reversing action URLs" }, { @@ -967,7 +972,7 @@ }, { "location": "/api-guide/routers/", - "text": "Routers\n\n\n\n\nResource routing allows you to quickly declare all of the common routes for a given resourceful controller. Instead of declaring separate routes for your index... a resourceful route declares them in a single line of code.\n\n\n\u2014 \nRuby on Rails Documentation\n\n\n\n\nSome Web frameworks such as Rails provide functionality for automatically determining how the URLs for an application should be mapped to the logic that deals with handling incoming requests.\n\n\nREST framework adds support for automatic URL routing to Django, and provides you with a simple, quick and consistent way of wiring your view logic to a set of URLs.\n\n\nUsage\n\n\nHere's an example of a simple URL conf, that uses \nSimpleRouter\n.\n\n\nfrom rest_framework import routers\n\nrouter = routers.SimpleRouter()\nrouter.register(r'users', UserViewSet)\nrouter.register(r'accounts', AccountViewSet)\nurlpatterns = router.urls\n\n\n\nThere are two mandatory arguments to the \nregister()\n method:\n\n\n\n\nprefix\n - The URL prefix to use for this set of routes.\n\n\nviewset\n - The viewset class.\n\n\n\n\nOptionally, you may also specify an additional argument:\n\n\n\n\nbase_name\n - The base to use for the URL names that are created. If unset the basename will be automatically generated based on the \nqueryset\n attribute of the viewset, if it has one. Note that if the viewset does not include a \nqueryset\n attribute then you must set \nbase_name\n when registering the viewset.\n\n\n\n\nThe example above would generate the following URL patterns:\n\n\n\n\nURL pattern: \n^users/$\n Name: \n'user-list'\n\n\nURL pattern: \n^users/{pk}/$\n Name: \n'user-detail'\n\n\nURL pattern: \n^accounts/$\n Name: \n'account-list'\n\n\nURL pattern: \n^accounts/{pk}/$\n Name: \n'account-detail'\n\n\n\n\n\n\nNote\n: The \nbase_name\n argument is used to specify the initial part of the view name pattern. In the example above, that's the \nuser\n or \naccount\n part.\n\n\nTypically you won't \nneed\n to specify the \nbase_name\n argument, but if you have a viewset where you've defined a custom \nget_queryset\n method, then the viewset may not have a \n.queryset\n attribute set. If you try to register that viewset you'll see an error like this:\n\n\n'base_name' argument not specified, and could not automatically determine the name from the viewset, as it does not have a '.queryset' attribute.\n\n\n\nThis means you'll need to explicitly set the \nbase_name\n argument when registering the viewset, as it could not be automatically determined from the model name.\n\n\n\n\nUsing \ninclude\n with routers\n\n\nThe \n.urls\n 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.\n\n\nFor example, you can append \nrouter.urls\n to a list of existing views\u2026\n\n\nrouter = routers.SimpleRouter()\nrouter.register(r'users', UserViewSet)\nrouter.register(r'accounts', AccountViewSet)\n\nurlpatterns = [\n url(r'^forgot-password/$', ForgotPasswordFormView.as_view()),\n]\n\nurlpatterns += router.urls\n\n\n\nAlternatively you can use Django's \ninclude\n function, like so\u2026\n\n\nurlpatterns = [\n url(r'^forgot-password/$', ForgotPasswordFormView.as_view()),\n url(r'^', include(router.urls)),\n]\n\n\n\nRouter URL patterns can also be namespaces.\n\n\nurlpatterns = [\n url(r'^forgot-password/$', ForgotPasswordFormView.as_view()),\n url(r'^api/', include(router.urls, namespace='api')),\n]\n\n\n\nIf using namespacing with hyperlinked serializers you'll also need to ensure that any \nview_name\n parameters on the serializers correctly reflect the namespace. In the example above you'd need to include a parameter such as \nview_name='api:user-detail'\n for serializer fields hyperlinked to the user detail view.\n\n\nExtra link and actions\n\n\nAny methods on the viewset decorated with \n@detail_route\n or \n@list_route\n will also be routed.\nFor example, given a method like this on the \nUserViewSet\n class:\n\n\nfrom myapp.permissions import IsAdminOrIsSelf\nfrom rest_framework.decorators import detail_route\n\nclass UserViewSet(ModelViewSet):\n ...\n\n @detail_route(methods=['post'], permission_classes=[IsAdminOrIsSelf])\n def set_password(self, request, pk=None):\n ...\n\n\n\nThe following URL pattern would additionally be generated:\n\n\n\n\nURL pattern: \n^users/{pk}/set_password/$\n Name: \n'user-set-password'\n\n\n\n\nIf 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.\n\n\nFor example, if you want to change the URL for our custom action to \n^users/{pk}/change-password/$\n, you could write:\n\n\nfrom myapp.permissions import IsAdminOrIsSelf\nfrom rest_framework.decorators import detail_route\n\nclass UserViewSet(ModelViewSet):\n ...\n\n @detail_route(methods=['post'], permission_classes=[IsAdminOrIsSelf], url_path='change-password')\n def set_password(self, request, pk=None):\n ...\n\n\n\nThe above example would now generate the following URL pattern:\n\n\n\n\nURL pattern: \n^users/{pk}/change-password/$\n Name: \n'user-change-password'\n\n\n\n\nIn the case you do not want to use the default name generated for your custom action, you can use the url_name parameter to customize it.\n\n\nFor example, if you want to change the name of our custom action to \n'user-change-password'\n, you could write:\n\n\nfrom myapp.permissions import IsAdminOrIsSelf\nfrom rest_framework.decorators import detail_route\n\nclass UserViewSet(ModelViewSet):\n ...\n\n @detail_route(methods=['post'], permission_classes=[IsAdminOrIsSelf], url_name='change-password')\n def set_password(self, request, pk=None):\n ...\n\n\n\nThe above example would now generate the following URL pattern:\n\n\n\n\nURL pattern: \n^users/{pk}/set_password/$\n Name: \n'user-change-password'\n\n\n\n\nYou can also use url_path and url_name parameters together to obtain extra control on URL generation for custom views.\n\n\nFor more information see the viewset documentation on \nmarking extra actions for routing\n.\n\n\nAPI Guide\n\n\nSimpleRouter\n\n\nThis router includes routes for the standard set of \nlist\n, \ncreate\n, \nretrieve\n, \nupdate\n, \npartial_update\n and \ndestroy\n actions. The viewset can also mark additional methods to be routed, using the \n@detail_route\n or \n@list_route\n decorators.\n\n\n\n \nURL Style\nHTTP Method\nAction\nURL Name\n\n \n{prefix}/\nGET\nlist\n{basename}-list\n\n \nPOST\ncreate\n\n \n{prefix}/{methodname}/\nGET, or as specified by `methods` argument\n`@list_route` decorated method\n{basename}-{methodname}\n\n \n{prefix}/{lookup}/\nGET\nretrieve\n{basename}-detail\n\n \nPUT\nupdate\n\n \nPATCH\npartial_update\n\n \nDELETE\ndestroy\n\n \n{prefix}/{lookup}/{methodname}/\nGET, or as specified by `methods` argument\n`@detail_route` decorated method\n{basename}-{methodname}\n\n\n\n\n\nBy default the URLs created by \nSimpleRouter\n are appended with a trailing slash.\nThis behavior can be modified by setting the \ntrailing_slash\n argument to \nFalse\n when instantiating the router. For example:\n\n\nrouter = SimpleRouter(trailing_slash=False)\n\n\n\nTrailing slashes are conventional in Django, but are not used by default in some other frameworks such as Rails. Which style you choose to use is largely a matter of preference, although some javascript frameworks may expect a particular routing style.\n\n\nThe router will match lookup values containing any characters except slashes and period characters. For a more restrictive (or lenient) lookup pattern, set the \nlookup_value_regex\n attribute on the viewset. For example, you can limit the lookup to valid UUIDs:\n\n\nclass MyModelViewSet(mixins.RetrieveModelMixin, viewsets.GenericViewSet):\n lookup_field = 'my_model_id'\n lookup_value_regex = '[0-9a-f]{32}'\n\n\n\nDefaultRouter\n\n\nThis router is similar to \nSimpleRouter\n as above, but additionally includes a default API root view, that returns a response containing hyperlinks to all the list views. It also generates routes for optional \n.json\n style format suffixes.\n\n\n\n \nURL Style\nHTTP Method\nAction\nURL Name\n\n \n[.format]\nGET\nautomatically generated root view\napi-root\n\n \n{prefix}/[.format]\nGET\nlist\n{basename}-list\n\n \nPOST\ncreate\n\n \n{prefix}/{methodname}/[.format]\nGET, or as specified by `methods` argument\n`@list_route` decorated method\n{basename}-{methodname}\n\n \n{prefix}/{lookup}/[.format]\nGET\nretrieve\n{basename}-detail\n\n \nPUT\nupdate\n\n \nPATCH\npartial_update\n\n \nDELETE\ndestroy\n\n \n{prefix}/{lookup}/{methodname}/[.format]\nGET, or as specified by `methods` argument\n`@detail_route` decorated method\n{basename}-{methodname}\n\n\n\n\n\nAs with \nSimpleRouter\n the trailing slashes on the URL routes can be removed by setting the \ntrailing_slash\n argument to \nFalse\n when instantiating the router.\n\n\nrouter = DefaultRouter(trailing_slash=False)\n\n\n\nCustom Routers\n\n\nImplementing a custom router isn't something you'd need to do very often, but it can be useful if you have specific requirements about how the URLs for your API are structured. Doing so allows you to encapsulate the URL structure in a reusable way that ensures you don't have to write your URL patterns explicitly for each new view.\n\n\nThe simplest way to implement a custom router is to subclass one of the existing router classes. The \n.routes\n attribute is used to template the URL patterns that will be mapped to each viewset. The \n.routes\n attribute is a list of \nRoute\n named tuples.\n\n\nThe arguments to the \nRoute\n named tuple are:\n\n\nurl\n: A string representing the URL to be routed. May include the following format strings:\n\n\n\n\n{prefix}\n - The URL prefix to use for this set of routes.\n\n\n{lookup}\n - The lookup field used to match against a single instance.\n\n\n{trailing_slash}\n - Either a '/' or an empty string, depending on the \ntrailing_slash\n argument.\n\n\n\n\nmapping\n: A mapping of HTTP method names to the view methods\n\n\nname\n: The name of the URL as used in \nreverse\n calls. May include the following format string:\n\n\n\n\n{basename}\n - The base to use for the URL names that are created.\n\n\n\n\ninitkwargs\n: A dictionary of any additional arguments that should be passed when instantiating the view. Note that the \nsuffix\n argument is reserved for identifying the viewset type, used when generating the view name and breadcrumb links.\n\n\nCustomizing dynamic routes\n\n\nYou can also customize how the \n@list_route\n and \n@detail_route\n decorators are routed.\nTo route either or both of these decorators, include a \nDynamicListRoute\n and/or \nDynamicDetailRoute\n named tuple in the \n.routes\n list.\n\n\nThe arguments to \nDynamicListRoute\n and \nDynamicDetailRoute\n are:\n\n\nurl\n: A string representing the URL to be routed. May include the same format strings as \nRoute\n, and additionally accepts the \n{methodname}\n and \n{methodnamehyphen}\n format strings.\n\n\nname\n: The name of the URL as used in \nreverse\n calls. May include the following format strings: \n{basename}\n, \n{methodname}\n and \n{methodnamehyphen}\n.\n\n\ninitkwargs\n: A dictionary of any additional arguments that should be passed when instantiating the view.\n\n\nExample\n\n\nThe following example will only route to the \nlist\n and \nretrieve\n actions, and does not use the trailing slash convention.\n\n\nfrom rest_framework.routers import Route, DynamicDetailRoute, SimpleRouter\n\nclass CustomReadOnlyRouter(SimpleRouter):\n \"\"\"\n A router for read-only APIs, which doesn't use trailing slashes.\n \"\"\"\n routes = [\n Route(\n url=r'^{prefix}$',\n mapping={'get': 'list'},\n name='{basename}-list',\n initkwargs={'suffix': 'List'}\n ),\n Route(\n url=r'^{prefix}/{lookup}$',\n mapping={'get': 'retrieve'},\n name='{basename}-detail',\n initkwargs={'suffix': 'Detail'}\n ),\n DynamicDetailRoute(\n url=r'^{prefix}/{lookup}/{methodnamehyphen}$',\n name='{basename}-{methodnamehyphen}',\n initkwargs={}\n )\n ]\n\n\n\nLet's take a look at the routes our \nCustomReadOnlyRouter\n would generate for a simple viewset.\n\n\nviews.py\n:\n\n\nclass UserViewSet(viewsets.ReadOnlyModelViewSet):\n \"\"\"\n A viewset that provides the standard actions\n \"\"\"\n queryset = User.objects.all()\n serializer_class = UserSerializer\n lookup_field = 'username'\n\n @detail_route()\n def group_names(self, request, pk=None):\n \"\"\"\n Returns a list of all the group names that the given\n user belongs to.\n \"\"\"\n user = self.get_object()\n groups = user.groups.all()\n return Response([group.name for group in groups])\n\n\n\nurls.py\n:\n\n\nrouter = CustomReadOnlyRouter()\nrouter.register('users', UserViewSet)\nurlpatterns = router.urls\n\n\n\nThe following mappings would be generated...\n\n\n\n \nURL\nHTTP Method\nAction\nURL Name\n\n \n/users\nGET\nlist\nuser-list\n\n \n/users/{username}\nGET\nretrieve\nuser-detail\n\n \n/users/{username}/group-names\nGET\ngroup_names\nuser-group-names\n\n\n\n\n\nFor another example of setting the \n.routes\n attribute, see the source code for the \nSimpleRouter\n class.\n\n\nAdvanced custom routers\n\n\nIf you want to provide totally custom behavior, you can override \nBaseRouter\n and override the \nget_urls(self)\n method. The method should inspect the registered viewsets and return a list of URL patterns. The registered prefix, viewset and basename tuples may be inspected by accessing the \nself.registry\n attribute.\n\n\nYou may also want to override the \nget_default_base_name(self, viewset)\n method, or else always explicitly set the \nbase_name\n argument when registering your viewsets with the router.\n\n\nThird Party Packages\n\n\nThe following third party packages are also available.\n\n\nDRF Nested Routers\n\n\nThe \ndrf-nested-routers package\n provides routers and relationship fields for working with nested resources.\n\n\nModelRouter (wq.db.rest)\n\n\nThe \nwq.db package\n provides an advanced \nModelRouter\n class (and singleton instance) that extends \nDefaultRouter\n with a \nregister_model()\n API. Much like Django's \nadmin.site.register\n, the only required argument to \nrest.router.register_model\n is a model class. Reasonable defaults for a url prefix, serializer, and viewset will be inferred from the model and global configuration.\n\n\nfrom wq.db import rest\nfrom myapp.models import MyModel\n\nrest.router.register_model(MyModel)\n\n\n\nDRF-extensions\n\n\nThe \nDRF-extensions\n package\n provides \nrouters\n for creating \nnested viewsets\n, \ncollection level controllers\n with \ncustomizable endpoint names\n.", + "text": "Routers\n\n\n\n\nResource routing allows you to quickly declare all of the common routes for a given resourceful controller. Instead of declaring separate routes for your index... a resourceful route declares them in a single line of code.\n\n\n\u2014 \nRuby on Rails Documentation\n\n\n\n\nSome Web frameworks such as Rails provide functionality for automatically determining how the URLs for an application should be mapped to the logic that deals with handling incoming requests.\n\n\nREST framework adds support for automatic URL routing to Django, and provides you with a simple, quick and consistent way of wiring your view logic to a set of URLs.\n\n\nUsage\n\n\nHere's an example of a simple URL conf, that uses \nSimpleRouter\n.\n\n\nfrom rest_framework import routers\n\nrouter = routers.SimpleRouter()\nrouter.register(r'users', UserViewSet)\nrouter.register(r'accounts', AccountViewSet)\nurlpatterns = router.urls\n\n\n\nThere are two mandatory arguments to the \nregister()\n method:\n\n\n\n\nprefix\n - The URL prefix to use for this set of routes.\n\n\nviewset\n - The viewset class.\n\n\n\n\nOptionally, you may also specify an additional argument:\n\n\n\n\nbase_name\n - The base to use for the URL names that are created. If unset the basename will be automatically generated based on the \nqueryset\n attribute of the viewset, if it has one. Note that if the viewset does not include a \nqueryset\n attribute then you must set \nbase_name\n when registering the viewset.\n\n\n\n\nThe example above would generate the following URL patterns:\n\n\n\n\nURL pattern: \n^users/$\n Name: \n'user-list'\n\n\nURL pattern: \n^users/{pk}/$\n Name: \n'user-detail'\n\n\nURL pattern: \n^accounts/$\n Name: \n'account-list'\n\n\nURL pattern: \n^accounts/{pk}/$\n Name: \n'account-detail'\n\n\n\n\n\n\nNote\n: The \nbase_name\n argument is used to specify the initial part of the view name pattern. In the example above, that's the \nuser\n or \naccount\n part.\n\n\nTypically you won't \nneed\n to specify the \nbase_name\n argument, but if you have a viewset where you've defined a custom \nget_queryset\n method, then the viewset may not have a \n.queryset\n attribute set. If you try to register that viewset you'll see an error like this:\n\n\n'base_name' argument not specified, and could not automatically determine the name from the viewset, as it does not have a '.queryset' attribute.\n\n\n\nThis means you'll need to explicitly set the \nbase_name\n argument when registering the viewset, as it could not be automatically determined from the model name.\n\n\n\n\nUsing \ninclude\n with routers\n\n\nThe \n.urls\n 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.\n\n\nFor example, you can append \nrouter.urls\n to a list of existing views\u2026\n\n\nrouter = routers.SimpleRouter()\nrouter.register(r'users', UserViewSet)\nrouter.register(r'accounts', AccountViewSet)\n\nurlpatterns = [\n url(r'^forgot-password/$', ForgotPasswordFormView.as_view()),\n]\n\nurlpatterns += router.urls\n\n\n\nAlternatively you can use Django's \ninclude\n function, like so\u2026\n\n\nurlpatterns = [\n url(r'^forgot-password/$', ForgotPasswordFormView.as_view()),\n url(r'^', include(router.urls)),\n]\n\n\n\nYou may use \ninclude\n with an application namespace:\n\n\nurlpatterns = [\n url(r'^forgot-password/$', ForgotPasswordFormView.as_view()),\n url(r'^api/', include((router.urls, 'app_name'))),\n]\n\n\n\nOr both an application and instance namespace:\n\n\nurlpatterns = [\n url(r'^forgot-password/$', ForgotPasswordFormView.as_view()),\n url(r'^api/', include((router.urls, 'app_name'), namespace='instance_name')),\n]\n\n\n\nSee Django's \nURL namespaces docs\n and the \ninclude\n API reference\n for more details.\n\n\n\n\nNote\n: If using namespacing with hyperlinked serializers you'll also need to ensure that any \nview_name\n parameters\non the serializers correctly reflect the namespace. In the examples above you'd need to include a parameter such as\n\nview_name='app_name:user-detail'\n for serializer fields hyperlinked to the user detail view.\n\n\nThe automatic \nview_name\n generation uses a pattern like \n%(model_name)-detail\n. Unless your models names actually clash\nyou may be better off \nnot\n namespacing your Django REST Framework views when using hyperlinked serializers.\n\n\n\n\nRouting for extra actions\n\n\nA viewset may \nmark extra actions for routing\n by decorating a method with the \n@action\n decorator. These extra actions will be included in the generated routes. For example, given the \nset_password\n method on the \nUserViewSet\n class:\n\n\nfrom myapp.permissions import IsAdminOrIsSelf\nfrom rest_framework.decorators import action\n\nclass UserViewSet(ModelViewSet):\n ...\n\n @action(methods=['post'], detail=True, permission_classes=[IsAdminOrIsSelf])\n def set_password(self, request, pk=None):\n ...\n\n\n\nThe following route would be generated:\n\n\n\n\nURL pattern: \n^users/{pk}/set_password/$\n\n\nURL name: \n'user-set-password'\n\n\n\n\nBy default, the URL pattern is based on the method name, and the URL name is the combination of the \nViewSet.basename\n and the hyphenated method name.\nIf you don't want to use the defaults for either of these values, you can instead provide the \nurl_path\n and \nurl_name\n arguments to the \n@action\n decorator.\n\n\nFor example, if you want to change the URL for our custom action to \n^users/{pk}/change-password/$\n, you could write:\n\n\nfrom myapp.permissions import IsAdminOrIsSelf\nfrom rest_framework.decorators import action\n\nclass UserViewSet(ModelViewSet):\n ...\n\n @action(methods=['post'], detail=True, permission_classes=[IsAdminOrIsSelf],\n url_path='change-password', url_name='change_password')\n def set_password(self, request, pk=None):\n ...\n\n\n\nThe above example would now generate the following URL pattern:\n\n\n\n\nURL path: \n^users/{pk}/change-password/$\n\n\nURL name: \n'user-change_password'\n\n\n\n\nAPI Guide\n\n\nSimpleRouter\n\n\nThis router includes routes for the standard set of \nlist\n, \ncreate\n, \nretrieve\n, \nupdate\n, \npartial_update\n and \ndestroy\n actions. The viewset can also mark additional methods to be routed, using the \n@action\n decorator.\n\n\n\n \nURL Style\nHTTP Method\nAction\nURL Name\n\n \n{prefix}/\nGET\nlist\n{basename}-list\n\n \nPOST\ncreate\n\n \n{prefix}/{url_path}/\nGET, or as specified by `methods` argument\n`@action(detail=False)` decorated method\n{basename}-{url_name}\n\n \n{prefix}/{lookup}/\nGET\nretrieve\n{basename}-detail\n\n \nPUT\nupdate\n\n \nPATCH\npartial_update\n\n \nDELETE\ndestroy\n\n \n{prefix}/{lookup}/{url_path}/\nGET, or as specified by `methods` argument\n`@action(detail=True)` decorated method\n{basename}-{url_name}\n\n\n\n\n\nBy default the URLs created by \nSimpleRouter\n are appended with a trailing slash.\nThis behavior can be modified by setting the \ntrailing_slash\n argument to \nFalse\n when instantiating the router. For example:\n\n\nrouter = SimpleRouter(trailing_slash=False)\n\n\n\nTrailing slashes are conventional in Django, but are not used by default in some other frameworks such as Rails. Which style you choose to use is largely a matter of preference, although some javascript frameworks may expect a particular routing style.\n\n\nThe router will match lookup values containing any characters except slashes and period characters. For a more restrictive (or lenient) lookup pattern, set the \nlookup_value_regex\n attribute on the viewset. For example, you can limit the lookup to valid UUIDs:\n\n\nclass MyModelViewSet(mixins.RetrieveModelMixin, viewsets.GenericViewSet):\n lookup_field = 'my_model_id'\n lookup_value_regex = '[0-9a-f]{32}'\n\n\n\nDefaultRouter\n\n\nThis router is similar to \nSimpleRouter\n as above, but additionally includes a default API root view, that returns a response containing hyperlinks to all the list views. It also generates routes for optional \n.json\n style format suffixes.\n\n\n\n \nURL Style\nHTTP Method\nAction\nURL Name\n\n \n[.format]\nGET\nautomatically generated root view\napi-root\n\n \n{prefix}/[.format]\nGET\nlist\n{basename}-list\n\n \nPOST\ncreate\n\n \n{prefix}/{url_path}/[.format]\nGET, or as specified by `methods` argument\n`@action(detail=False)` decorated method\n{basename}-{url_name}\n\n \n{prefix}/{lookup}/[.format]\nGET\nretrieve\n{basename}-detail\n\n \nPUT\nupdate\n\n \nPATCH\npartial_update\n\n \nDELETE\ndestroy\n\n \n{prefix}/{lookup}/{url_path}/[.format]\nGET, or as specified by `methods` argument\n`@action(detail=True)` decorated method\n{basename}-{url_name}\n\n\n\n\n\nAs with \nSimpleRouter\n the trailing slashes on the URL routes can be removed by setting the \ntrailing_slash\n argument to \nFalse\n when instantiating the router.\n\n\nrouter = DefaultRouter(trailing_slash=False)\n\n\n\nCustom Routers\n\n\nImplementing a custom router isn't something you'd need to do very often, but it can be useful if you have specific requirements about how the URLs for your API are structured. Doing so allows you to encapsulate the URL structure in a reusable way that ensures you don't have to write your URL patterns explicitly for each new view.\n\n\nThe simplest way to implement a custom router is to subclass one of the existing router classes. The \n.routes\n attribute is used to template the URL patterns that will be mapped to each viewset. The \n.routes\n attribute is a list of \nRoute\n named tuples.\n\n\nThe arguments to the \nRoute\n named tuple are:\n\n\nurl\n: A string representing the URL to be routed. May include the following format strings:\n\n\n\n\n{prefix}\n - The URL prefix to use for this set of routes.\n\n\n{lookup}\n - The lookup field used to match against a single instance.\n\n\n{trailing_slash}\n - Either a '/' or an empty string, depending on the \ntrailing_slash\n argument.\n\n\n\n\nmapping\n: A mapping of HTTP method names to the view methods\n\n\nname\n: The name of the URL as used in \nreverse\n calls. May include the following format string:\n\n\n\n\n{basename}\n - The base to use for the URL names that are created.\n\n\n\n\ninitkwargs\n: A dictionary of any additional arguments that should be passed when instantiating the view. Note that the \ndetail\n, \nbasename\n, and \nsuffix\n arguments are reserved for viewset introspection and are also used by the browsable API to generate the view name and breadcrumb links.\n\n\nCustomizing dynamic routes\n\n\nYou can also customize how the \n@action\n decorator is routed. Include the \nDynamicRoute\n named tuple in the \n.routes\n list, setting the \ndetail\n argument as appropriate for the list-based and detail-based routes. In addition to \ndetail\n, the arguments to \nDynamicRoute\n are:\n\n\nurl\n: A string representing the URL to be routed. May include the same format strings as \nRoute\n, and additionally accepts the \n{url_path}\n format string.\n\n\nname\n: The name of the URL as used in \nreverse\n calls. May include the following format strings:\n\n\n\n\n{basename}\n - The base to use for the URL names that are created.\n\n\n{url_name}\n - The \nurl_name\n provided to the \n@action\n.\n\n\n\n\ninitkwargs\n: A dictionary of any additional arguments that should be passed when instantiating the view.\n\n\nExample\n\n\nThe following example will only route to the \nlist\n and \nretrieve\n actions, and does not use the trailing slash convention.\n\n\nfrom rest_framework.routers import Route, DynamicRoute, SimpleRouter\n\nclass CustomReadOnlyRouter(SimpleRouter):\n \"\"\"\n A router for read-only APIs, which doesn't use trailing slashes.\n \"\"\"\n routes = [\n Route(\n url=r'^{prefix}$',\n mapping={'get': 'list'},\n name='{basename}-list',\n initkwargs={'suffix': 'List'}\n ),\n Route(\n url=r'^{prefix}/{lookup}$',\n mapping={'get': 'retrieve'},\n name='{basename}-detail',\n initkwargs={'suffix': 'Detail'}\n ),\n DynamicRoute(\n url=r'^{prefix}/{lookup}/{url_path}$',\n name='{basename}-{url_name}',\n detail=True,\n initkwargs={}\n )\n ]\n\n\n\nLet's take a look at the routes our \nCustomReadOnlyRouter\n would generate for a simple viewset.\n\n\nviews.py\n:\n\n\nclass UserViewSet(viewsets.ReadOnlyModelViewSet):\n \"\"\"\n A viewset that provides the standard actions\n \"\"\"\n queryset = User.objects.all()\n serializer_class = UserSerializer\n lookup_field = 'username'\n\n @action(detail=True)\n def group_names(self, request, pk=None):\n \"\"\"\n Returns a list of all the group names that the given\n user belongs to.\n \"\"\"\n user = self.get_object()\n groups = user.groups.all()\n return Response([group.name for group in groups])\n\n\n\nurls.py\n:\n\n\nrouter = CustomReadOnlyRouter()\nrouter.register('users', UserViewSet)\nurlpatterns = router.urls\n\n\n\nThe following mappings would be generated...\n\n\n\n \nURL\nHTTP Method\nAction\nURL Name\n\n \n/users\nGET\nlist\nuser-list\n\n \n/users/{username}\nGET\nretrieve\nuser-detail\n\n \n/users/{username}/group-names\nGET\ngroup_names\nuser-group-names\n\n\n\n\n\nFor another example of setting the \n.routes\n attribute, see the source code for the \nSimpleRouter\n class.\n\n\nAdvanced custom routers\n\n\nIf you want to provide totally custom behavior, you can override \nBaseRouter\n and override the \nget_urls(self)\n method. The method should inspect the registered viewsets and return a list of URL patterns. The registered prefix, viewset and basename tuples may be inspected by accessing the \nself.registry\n attribute.\n\n\nYou may also want to override the \nget_default_base_name(self, viewset)\n method, or else always explicitly set the \nbase_name\n argument when registering your viewsets with the router.\n\n\nThird Party Packages\n\n\nThe following third party packages are also available.\n\n\nDRF Nested Routers\n\n\nThe \ndrf-nested-routers package\n provides routers and relationship fields for working with nested resources.\n\n\nModelRouter (wq.db.rest)\n\n\nThe \nwq.db package\n provides an advanced \nModelRouter\n class (and singleton instance) that extends \nDefaultRouter\n with a \nregister_model()\n API. Much like Django's \nadmin.site.register\n, the only required argument to \nrest.router.register_model\n is a model class. Reasonable defaults for a url prefix, serializer, and viewset will be inferred from the model and global configuration.\n\n\nfrom wq.db import rest\nfrom myapp.models import MyModel\n\nrest.router.register_model(MyModel)\n\n\n\nDRF-extensions\n\n\nThe \nDRF-extensions\n package\n provides \nrouters\n for creating \nnested viewsets\n, \ncollection level controllers\n with \ncustomizable endpoint names\n.", "title": "Routers" }, { @@ -982,13 +987,13 @@ }, { "location": "/api-guide/routers/#using-include-with-routers", - "text": "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\u2026 router = routers.SimpleRouter()\nrouter.register(r'users', UserViewSet)\nrouter.register(r'accounts', AccountViewSet)\n\nurlpatterns = [\n url(r'^forgot-password/$', ForgotPasswordFormView.as_view()),\n]\n\nurlpatterns += router.urls Alternatively you can use Django's include function, like so\u2026 urlpatterns = [\n url(r'^forgot-password/$', ForgotPasswordFormView.as_view()),\n url(r'^', include(router.urls)),\n] Router URL patterns can also be namespaces. urlpatterns = [\n url(r'^forgot-password/$', ForgotPasswordFormView.as_view()),\n url(r'^api/', include(router.urls, namespace='api')),\n] 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.", + "text": "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\u2026 router = routers.SimpleRouter()\nrouter.register(r'users', UserViewSet)\nrouter.register(r'accounts', AccountViewSet)\n\nurlpatterns = [\n url(r'^forgot-password/$', ForgotPasswordFormView.as_view()),\n]\n\nurlpatterns += router.urls Alternatively you can use Django's include function, like so\u2026 urlpatterns = [\n url(r'^forgot-password/$', ForgotPasswordFormView.as_view()),\n url(r'^', include(router.urls)),\n] You may use include with an application namespace: urlpatterns = [\n url(r'^forgot-password/$', ForgotPasswordFormView.as_view()),\n url(r'^api/', include((router.urls, 'app_name'))),\n] Or both an application and instance namespace: urlpatterns = [\n url(r'^forgot-password/$', ForgotPasswordFormView.as_view()),\n url(r'^api/', include((router.urls, 'app_name'), namespace='instance_name')),\n] See Django's URL namespaces docs and the include API reference for more details. Note : If using namespacing with hyperlinked serializers you'll also need to ensure that any view_name parameters\non the serializers correctly reflect the namespace. In the examples above you'd need to include a parameter such as view_name='app_name:user-detail' for serializer fields hyperlinked to the user detail view. The automatic view_name generation uses a pattern like %(model_name)-detail . Unless your models names actually clash\nyou may be better off not namespacing your Django REST Framework views when using hyperlinked serializers.", "title": "Using include with routers" }, { - "location": "/api-guide/routers/#extra-link-and-actions", - "text": "Any methods on the viewset decorated with @detail_route or @list_route will also be routed.\nFor example, given a method like this on the UserViewSet class: from myapp.permissions import IsAdminOrIsSelf\nfrom rest_framework.decorators import detail_route\n\nclass UserViewSet(ModelViewSet):\n ...\n\n @detail_route(methods=['post'], permission_classes=[IsAdminOrIsSelf])\n def set_password(self, request, pk=None):\n ... 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\nfrom rest_framework.decorators import detail_route\n\nclass UserViewSet(ModelViewSet):\n ...\n\n @detail_route(methods=['post'], permission_classes=[IsAdminOrIsSelf], url_path='change-password')\n def set_password(self, request, pk=None):\n ... The above example would now generate the following URL pattern: URL pattern: ^users/{pk}/change-password/$ Name: 'user-change-password' In the case you do not want to use the default name generated for your custom action, you can use the url_name parameter to customize it. For example, if you want to change the name of our custom action to 'user-change-password' , you could write: from myapp.permissions import IsAdminOrIsSelf\nfrom rest_framework.decorators import detail_route\n\nclass UserViewSet(ModelViewSet):\n ...\n\n @detail_route(methods=['post'], permission_classes=[IsAdminOrIsSelf], url_name='change-password')\n def set_password(self, request, pk=None):\n ... The above example would now generate the following URL pattern: URL pattern: ^users/{pk}/set_password/$ Name: 'user-change-password' You can also use url_path and url_name parameters together to obtain extra control on URL generation for custom views. For more information see the viewset documentation on marking extra actions for routing .", - "title": "Extra link and actions" + "location": "/api-guide/routers/#routing-for-extra-actions", + "text": "A viewset may mark extra actions for routing by decorating a method with the @action decorator. These extra actions will be included in the generated routes. For example, given the set_password method on the UserViewSet class: from myapp.permissions import IsAdminOrIsSelf\nfrom rest_framework.decorators import action\n\nclass UserViewSet(ModelViewSet):\n ...\n\n @action(methods=['post'], detail=True, permission_classes=[IsAdminOrIsSelf])\n def set_password(self, request, pk=None):\n ... The following route would be generated: URL pattern: ^users/{pk}/set_password/$ URL name: 'user-set-password' By default, the URL pattern is based on the method name, and the URL name is the combination of the ViewSet.basename and the hyphenated method name.\nIf you don't want to use the defaults for either of these values, you can instead provide the url_path and url_name arguments to the @action decorator. 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\nfrom rest_framework.decorators import action\n\nclass UserViewSet(ModelViewSet):\n ...\n\n @action(methods=['post'], detail=True, permission_classes=[IsAdminOrIsSelf],\n url_path='change-password', url_name='change_password')\n def set_password(self, request, pk=None):\n ... The above example would now generate the following URL pattern: URL path: ^users/{pk}/change-password/$ URL name: 'user-change_password'", + "title": "Routing for extra actions" }, { "location": "/api-guide/routers/#api-guide", @@ -997,27 +1002,27 @@ }, { "location": "/api-guide/routers/#simplerouter", - "text": "This router includes routes for the standard set of list , create , retrieve , update , partial_update and destroy actions. The viewset can also mark additional methods to be routed, using the @detail_route or @list_route decorators. \n URL Style HTTP Method Action URL Name \n {prefix}/ GET list {basename}-list \n POST create \n {prefix}/{methodname}/ GET, or as specified by `methods` argument `@list_route` decorated method {basename}-{methodname} \n {prefix}/{lookup}/ GET retrieve {basename}-detail \n PUT update \n PATCH partial_update \n DELETE destroy \n {prefix}/{lookup}/{methodname}/ GET, or as specified by `methods` argument `@detail_route` decorated method {basename}-{methodname} By default the URLs created by SimpleRouter are appended with a trailing slash.\nThis behavior can be modified by setting the trailing_slash argument to False when instantiating the router. For example: router = SimpleRouter(trailing_slash=False) Trailing slashes are conventional in Django, but are not used by default in some other frameworks such as Rails. Which style you choose to use is largely a matter of preference, although some javascript frameworks may expect a particular routing style. The router will match lookup values containing any characters except slashes and period characters. For a more restrictive (or lenient) lookup pattern, set the lookup_value_regex attribute on the viewset. For example, you can limit the lookup to valid UUIDs: class MyModelViewSet(mixins.RetrieveModelMixin, viewsets.GenericViewSet):\n lookup_field = 'my_model_id'\n lookup_value_regex = '[0-9a-f]{32}'", + "text": "This router includes routes for the standard set of list , create , retrieve , update , partial_update and destroy actions. The viewset can also mark additional methods to be routed, using the @action decorator. \n URL Style HTTP Method Action URL Name \n {prefix}/ GET list {basename}-list \n POST create \n {prefix}/{url_path}/ GET, or as specified by `methods` argument `@action(detail=False)` decorated method {basename}-{url_name} \n {prefix}/{lookup}/ GET retrieve {basename}-detail \n PUT update \n PATCH partial_update \n DELETE destroy \n {prefix}/{lookup}/{url_path}/ GET, or as specified by `methods` argument `@action(detail=True)` decorated method {basename}-{url_name} By default the URLs created by SimpleRouter are appended with a trailing slash.\nThis behavior can be modified by setting the trailing_slash argument to False when instantiating the router. For example: router = SimpleRouter(trailing_slash=False) Trailing slashes are conventional in Django, but are not used by default in some other frameworks such as Rails. Which style you choose to use is largely a matter of preference, although some javascript frameworks may expect a particular routing style. The router will match lookup values containing any characters except slashes and period characters. For a more restrictive (or lenient) lookup pattern, set the lookup_value_regex attribute on the viewset. For example, you can limit the lookup to valid UUIDs: class MyModelViewSet(mixins.RetrieveModelMixin, viewsets.GenericViewSet):\n lookup_field = 'my_model_id'\n lookup_value_regex = '[0-9a-f]{32}'", "title": "SimpleRouter" }, { "location": "/api-guide/routers/#defaultrouter", - "text": "This router is similar to SimpleRouter as above, but additionally includes a default API root view, that returns a response containing hyperlinks to all the list views. It also generates routes for optional .json style format suffixes. \n URL Style HTTP Method Action URL Name \n [.format] GET automatically generated root view api-root \n {prefix}/[.format] GET list {basename}-list \n POST create \n {prefix}/{methodname}/[.format] GET, or as specified by `methods` argument `@list_route` decorated method {basename}-{methodname} \n {prefix}/{lookup}/[.format] GET retrieve {basename}-detail \n PUT update \n PATCH partial_update \n DELETE destroy \n {prefix}/{lookup}/{methodname}/[.format] GET, or as specified by `methods` argument `@detail_route` decorated method {basename}-{methodname} As with SimpleRouter the trailing slashes on the URL routes can be removed by setting the trailing_slash argument to False when instantiating the router. router = DefaultRouter(trailing_slash=False)", + "text": "This router is similar to SimpleRouter as above, but additionally includes a default API root view, that returns a response containing hyperlinks to all the list views. It also generates routes for optional .json style format suffixes. \n URL Style HTTP Method Action URL Name \n [.format] GET automatically generated root view api-root \n {prefix}/[.format] GET list {basename}-list \n POST create \n {prefix}/{url_path}/[.format] GET, or as specified by `methods` argument `@action(detail=False)` decorated method {basename}-{url_name} \n {prefix}/{lookup}/[.format] GET retrieve {basename}-detail \n PUT update \n PATCH partial_update \n DELETE destroy \n {prefix}/{lookup}/{url_path}/[.format] GET, or as specified by `methods` argument `@action(detail=True)` decorated method {basename}-{url_name} As with SimpleRouter the trailing slashes on the URL routes can be removed by setting the trailing_slash argument to False when instantiating the router. router = DefaultRouter(trailing_slash=False)", "title": "DefaultRouter" }, { "location": "/api-guide/routers/#custom-routers", - "text": "Implementing a custom router isn't something you'd need to do very often, but it can be useful if you have specific requirements about how the URLs for your API are structured. Doing so allows you to encapsulate the URL structure in a reusable way that ensures you don't have to write your URL patterns explicitly for each new view. The simplest way to implement a custom router is to subclass one of the existing router classes. The .routes attribute is used to template the URL patterns that will be mapped to each viewset. The .routes attribute is a list of Route named tuples. The arguments to the Route named tuple are: url : A string representing the URL to be routed. May include the following format strings: {prefix} - The URL prefix to use for this set of routes. {lookup} - The lookup field used to match against a single instance. {trailing_slash} - Either a '/' or an empty string, depending on the trailing_slash argument. mapping : A mapping of HTTP method names to the view methods name : The name of the URL as used in reverse calls. May include the following format string: {basename} - The base to use for the URL names that are created. initkwargs : A dictionary of any additional arguments that should be passed when instantiating the view. Note that the suffix argument is reserved for identifying the viewset type, used when generating the view name and breadcrumb links.", + "text": "Implementing a custom router isn't something you'd need to do very often, but it can be useful if you have specific requirements about how the URLs for your API are structured. Doing so allows you to encapsulate the URL structure in a reusable way that ensures you don't have to write your URL patterns explicitly for each new view. The simplest way to implement a custom router is to subclass one of the existing router classes. The .routes attribute is used to template the URL patterns that will be mapped to each viewset. The .routes attribute is a list of Route named tuples. The arguments to the Route named tuple are: url : A string representing the URL to be routed. May include the following format strings: {prefix} - The URL prefix to use for this set of routes. {lookup} - The lookup field used to match against a single instance. {trailing_slash} - Either a '/' or an empty string, depending on the trailing_slash argument. mapping : A mapping of HTTP method names to the view methods name : The name of the URL as used in reverse calls. May include the following format string: {basename} - The base to use for the URL names that are created. initkwargs : A dictionary of any additional arguments that should be passed when instantiating the view. Note that the detail , basename , and suffix arguments are reserved for viewset introspection and are also used by the browsable API to generate the view name and breadcrumb links.", "title": "Custom Routers" }, { "location": "/api-guide/routers/#customizing-dynamic-routes", - "text": "You can also customize how the @list_route and @detail_route decorators are routed.\nTo route either or both of these decorators, include a DynamicListRoute and/or DynamicDetailRoute named tuple in the .routes list. The arguments to DynamicListRoute and DynamicDetailRoute are: url : A string representing the URL to be routed. May include the same format strings as Route , and additionally accepts the {methodname} and {methodnamehyphen} format strings. name : The name of the URL as used in reverse calls. May include the following format strings: {basename} , {methodname} and {methodnamehyphen} . initkwargs : A dictionary of any additional arguments that should be passed when instantiating the view.", + "text": "You can also customize how the @action decorator is routed. Include the DynamicRoute named tuple in the .routes list, setting the detail argument as appropriate for the list-based and detail-based routes. In addition to detail , the arguments to DynamicRoute are: url : A string representing the URL to be routed. May include the same format strings as Route , and additionally accepts the {url_path} format string. name : The name of the URL as used in reverse calls. May include the following format strings: {basename} - The base to use for the URL names that are created. {url_name} - The url_name provided to the @action . initkwargs : A dictionary of any additional arguments that should be passed when instantiating the view.", "title": "Customizing dynamic routes" }, { "location": "/api-guide/routers/#example", - "text": "The following example will only route to the list and retrieve actions, and does not use the trailing slash convention. from rest_framework.routers import Route, DynamicDetailRoute, SimpleRouter\n\nclass CustomReadOnlyRouter(SimpleRouter):\n \"\"\"\n A router for read-only APIs, which doesn't use trailing slashes.\n \"\"\"\n routes = [\n Route(\n url=r'^{prefix}$',\n mapping={'get': 'list'},\n name='{basename}-list',\n initkwargs={'suffix': 'List'}\n ),\n Route(\n url=r'^{prefix}/{lookup}$',\n mapping={'get': 'retrieve'},\n name='{basename}-detail',\n initkwargs={'suffix': 'Detail'}\n ),\n DynamicDetailRoute(\n url=r'^{prefix}/{lookup}/{methodnamehyphen}$',\n name='{basename}-{methodnamehyphen}',\n initkwargs={}\n )\n ] Let's take a look at the routes our CustomReadOnlyRouter would generate for a simple viewset. views.py : class UserViewSet(viewsets.ReadOnlyModelViewSet):\n \"\"\"\n A viewset that provides the standard actions\n \"\"\"\n queryset = User.objects.all()\n serializer_class = UserSerializer\n lookup_field = 'username'\n\n @detail_route()\n def group_names(self, request, pk=None):\n \"\"\"\n Returns a list of all the group names that the given\n user belongs to.\n \"\"\"\n user = self.get_object()\n groups = user.groups.all()\n return Response([group.name for group in groups]) urls.py : router = CustomReadOnlyRouter()\nrouter.register('users', UserViewSet)\nurlpatterns = router.urls The following mappings would be generated... \n URL HTTP Method Action URL Name \n /users GET list user-list \n /users/{username} GET retrieve user-detail \n /users/{username}/group-names GET group_names user-group-names For another example of setting the .routes attribute, see the source code for the SimpleRouter class.", + "text": "The following example will only route to the list and retrieve actions, and does not use the trailing slash convention. from rest_framework.routers import Route, DynamicRoute, SimpleRouter\n\nclass CustomReadOnlyRouter(SimpleRouter):\n \"\"\"\n A router for read-only APIs, which doesn't use trailing slashes.\n \"\"\"\n routes = [\n Route(\n url=r'^{prefix}$',\n mapping={'get': 'list'},\n name='{basename}-list',\n initkwargs={'suffix': 'List'}\n ),\n Route(\n url=r'^{prefix}/{lookup}$',\n mapping={'get': 'retrieve'},\n name='{basename}-detail',\n initkwargs={'suffix': 'Detail'}\n ),\n DynamicRoute(\n url=r'^{prefix}/{lookup}/{url_path}$',\n name='{basename}-{url_name}',\n detail=True,\n initkwargs={}\n )\n ] Let's take a look at the routes our CustomReadOnlyRouter would generate for a simple viewset. views.py : class UserViewSet(viewsets.ReadOnlyModelViewSet):\n \"\"\"\n A viewset that provides the standard actions\n \"\"\"\n queryset = User.objects.all()\n serializer_class = UserSerializer\n lookup_field = 'username'\n\n @action(detail=True)\n def group_names(self, request, pk=None):\n \"\"\"\n Returns a list of all the group names that the given\n user belongs to.\n \"\"\"\n user = self.get_object()\n groups = user.groups.all()\n return Response([group.name for group in groups]) urls.py : router = CustomReadOnlyRouter()\nrouter.register('users', UserViewSet)\nurlpatterns = router.urls The following mappings would be generated... \n URL HTTP Method Action URL Name \n /users GET list user-list \n /users/{username} GET retrieve user-detail \n /users/{username}/group-names GET group_names user-group-names For another example of setting the .routes attribute, see the source code for the SimpleRouter class.", "title": "Example" }, { @@ -1352,7 +1357,7 @@ }, { "location": "/api-guide/serializers/", - "text": "Serializers\n\n\n\n\nExpanding the usefulness of the serializers is something that we would\nlike to address. However, it's not a trivial problem, and it\nwill take some serious design work.\n\n\n\u2014 Russell Keith-Magee, \nDjango users group\n\n\n\n\nSerializers allow complex data such as querysets and model instances to be converted to native Python datatypes that can then be easily rendered into \nJSON\n, \nXML\n or other content types. Serializers also provide deserialization, allowing parsed data to be converted back into complex types, after first validating the incoming data.\n\n\nThe serializers in REST framework work very similarly to Django's \nForm\n and \nModelForm\n classes. We provide a \nSerializer\n class which gives you a powerful, generic way to control the output of your responses, as well as a \nModelSerializer\n class which provides a useful shortcut for creating serializers that deal with model instances and querysets.\n\n\nDeclaring Serializers\n\n\nLet's start by creating a simple object we can use for example purposes:\n\n\nfrom datetime import datetime\n\nclass Comment(object):\n def __init__(self, email, content, created=None):\n self.email = email\n self.content = content\n self.created = created or datetime.now()\n\ncomment = Comment(email='leila@example.com', content='foo bar')\n\n\n\nWe'll declare a serializer that we can use to serialize and deserialize data that corresponds to \nComment\n objects.\n\n\nDeclaring a serializer looks very similar to declaring a form:\n\n\nfrom rest_framework import serializers\n\nclass CommentSerializer(serializers.Serializer):\n email = serializers.EmailField()\n content = serializers.CharField(max_length=200)\n created = serializers.DateTimeField()\n\n\n\nSerializing objects\n\n\nWe can now use \nCommentSerializer\n to serialize a comment, or list of comments. Again, using the \nSerializer\n class looks a lot like using a \nForm\n class.\n\n\nserializer = CommentSerializer(comment)\nserializer.data\n# {'email': 'leila@example.com', 'content': 'foo bar', 'created': '2016-01-27T15:17:10.375877'}\n\n\n\nAt this point we've translated the model instance into Python native datatypes. To finalise the serialization process we render the data into \njson\n.\n\n\nfrom rest_framework.renderers import JSONRenderer\n\njson = JSONRenderer().render(serializer.data)\njson\n# b'{\"email\":\"leila@example.com\",\"content\":\"foo bar\",\"created\":\"2016-01-27T15:17:10.375877\"}'\n\n\n\nDeserializing objects\n\n\nDeserialization is similar. First we parse a stream into Python native datatypes...\n\n\nfrom django.utils.six import BytesIO\nfrom rest_framework.parsers import JSONParser\n\nstream = BytesIO(json)\ndata = JSONParser().parse(stream)\n\n\n\n...then we restore those native datatypes into a dictionary of validated data.\n\n\nserializer = CommentSerializer(data=data)\nserializer.is_valid()\n# True\nserializer.validated_data\n# {'content': 'foo bar', 'email': 'leila@example.com', 'created': datetime.datetime(2012, 08, 22, 16, 20, 09, 822243)}\n\n\n\nSaving instances\n\n\nIf we want to be able to return complete object instances based on the validated data we need to implement one or both of the \n.create()\n and \n.update()\n methods. For example:\n\n\nclass CommentSerializer(serializers.Serializer):\n email = serializers.EmailField()\n content = serializers.CharField(max_length=200)\n created = serializers.DateTimeField()\n\n def create(self, validated_data):\n return Comment(**validated_data)\n\n def update(self, instance, validated_data):\n instance.email = validated_data.get('email', instance.email)\n instance.content = validated_data.get('content', instance.content)\n instance.created = validated_data.get('created', instance.created)\n return instance\n\n\n\nIf your object instances correspond to Django models you'll also want to ensure that these methods save the object to the database. For example, if \nComment\n was a Django model, the methods might look like this:\n\n\n def create(self, validated_data):\n return Comment.objects.create(**validated_data)\n\n def update(self, instance, validated_data):\n instance.email = validated_data.get('email', instance.email)\n instance.content = validated_data.get('content', instance.content)\n instance.created = validated_data.get('created', instance.created)\n instance.save()\n return instance\n\n\n\nNow when deserializing data, we can call \n.save()\n to return an object instance, based on the validated data.\n\n\ncomment = serializer.save()\n\n\n\nCalling \n.save()\n will either create a new instance, or update an existing instance, depending on if an existing instance was passed when instantiating the serializer class:\n\n\n# .save() will create a new instance.\nserializer = CommentSerializer(data=data)\n\n# .save() will update the existing `comment` instance.\nserializer = CommentSerializer(comment, data=data)\n\n\n\nBoth the \n.create()\n and \n.update()\n methods are optional. You can implement either neither, one, or both of them, depending on the use-case for your serializer class.\n\n\nPassing additional attributes to \n.save()\n\n\nSometimes you'll want your view code to be able to inject additional data at the point of saving the instance. This additional data might include information like the current user, the current time, or anything else that is not part of the request data.\n\n\nYou can do so by including additional keyword arguments when calling \n.save()\n. For example:\n\n\nserializer.save(owner=request.user)\n\n\n\nAny additional keyword arguments will be included in the \nvalidated_data\n argument when \n.create()\n or \n.update()\n are called.\n\n\nOverriding \n.save()\n directly.\n\n\nIn some cases the \n.create()\n and \n.update()\n method names may not be meaningful. For example, in a contact form we may not be creating new instances, but instead sending an email or other message.\n\n\nIn these cases you might instead choose to override \n.save()\n directly, as being more readable and meaningful.\n\n\nFor example:\n\n\nclass ContactForm(serializers.Serializer):\n email = serializers.EmailField()\n message = serializers.CharField()\n\n def save(self):\n email = self.validated_data['email']\n message = self.validated_data['message']\n send_email(from=email, message=message)\n\n\n\nNote that in the case above we're now having to access the serializer \n.validated_data\n property directly.\n\n\nValidation\n\n\nWhen deserializing data, you always need to call \nis_valid()\n before attempting to access the validated data, or save an object instance. If any validation errors occur, the \n.errors\n property will contain a dictionary representing the resulting error messages. For example:\n\n\nserializer = CommentSerializer(data={'email': 'foobar', 'content': 'baz'})\nserializer.is_valid()\n# False\nserializer.errors\n# {'email': [u'Enter a valid e-mail address.'], 'created': [u'This field is required.']}\n\n\n\nEach key in the dictionary will be the field name, and the values will be lists of strings of any error messages corresponding to that field. The \nnon_field_errors\n key may also be present, and will list any general validation errors. The name of the \nnon_field_errors\n key may be customized using the \nNON_FIELD_ERRORS_KEY\n REST framework setting.\n\n\nWhen deserializing a list of items, errors will be returned as a list of dictionaries representing each of the deserialized items.\n\n\nRaising an exception on invalid data\n\n\nThe \n.is_valid()\n method takes an optional \nraise_exception\n flag that will cause it to raise a \nserializers.ValidationError\n exception if there are validation errors.\n\n\nThese exceptions are automatically dealt with by the default exception handler that REST framework provides, and will return \nHTTP 400 Bad Request\n responses by default.\n\n\n# Return a 400 response if the data was invalid.\nserializer.is_valid(raise_exception=True)\n\n\n\nField-level validation\n\n\nYou can specify custom field-level validation by adding \n.validate_\n methods to your \nSerializer\n subclass. These are similar to the \n.clean_\n methods on Django forms.\n\n\nThese methods take a single argument, which is the field value that requires validation.\n\n\nYour \nvalidate_\n methods should return the validated value or raise a \nserializers.ValidationError\n. For example:\n\n\nfrom rest_framework import serializers\n\nclass BlogPostSerializer(serializers.Serializer):\n title = serializers.CharField(max_length=100)\n content = serializers.CharField()\n\n def validate_title(self, value):\n \"\"\"\n Check that the blog post is about Django.\n \"\"\"\n if 'django' not in value.lower():\n raise serializers.ValidationError(\"Blog post is not about Django\")\n return value\n\n\n\n\n\nNote:\n If your \n\n is declared on your serializer with the parameter \nrequired=False\n then this validation step will not take place if the field is not included.\n\n\n\n\nObject-level validation\n\n\nTo do any other validation that requires access to multiple fields, add a method called \n.validate()\n to your \nSerializer\n subclass. This method takes a single argument, which is a dictionary of field values. It should raise a \nValidationError\n if necessary, or just return the validated values. For example:\n\n\nfrom rest_framework import serializers\n\nclass EventSerializer(serializers.Serializer):\n description = serializers.CharField(max_length=100)\n start = serializers.DateTimeField()\n finish = serializers.DateTimeField()\n\n def validate(self, data):\n \"\"\"\n Check that the start is before the stop.\n \"\"\"\n if data['start'] > data['finish']:\n raise serializers.ValidationError(\"finish must occur after start\")\n return data\n\n\n\nValidators\n\n\nIndividual fields on a serializer can include validators, by declaring them on the field instance, for example:\n\n\ndef multiple_of_ten(value):\n if value % 10 != 0:\n raise serializers.ValidationError('Not a multiple of ten')\n\nclass GameRecord(serializers.Serializer):\n score = IntegerField(validators=[multiple_of_ten])\n ...\n\n\n\nSerializer classes can also include reusable validators that are applied to the complete set of field data. These validators are included by declaring them on an inner \nMeta\n class, like so:\n\n\nclass EventSerializer(serializers.Serializer):\n name = serializers.CharField()\n room_number = serializers.IntegerField(choices=[101, 102, 103, 201])\n date = serializers.DateField()\n\n class Meta:\n # Each room only has one event per day.\n validators = UniqueTogetherValidator(\n queryset=Event.objects.all(),\n fields=['room_number', 'date']\n )\n\n\n\nFor more information see the \nvalidators documentation\n.\n\n\nAccessing the initial data and instance\n\n\nWhen passing an initial object or queryset to a serializer instance, the object will be made available as \n.instance\n. If no initial object is passed then the \n.instance\n attribute will be \nNone\n.\n\n\nWhen passing data to a serializer instance, the unmodified data will be made available as \n.initial_data\n. If the data keyword argument is not passed then the \n.initial_data\n attribute will not exist.\n\n\nPartial updates\n\n\nBy default, serializers must be passed values for all required fields or they will raise validation errors. You can use the \npartial\n argument in order to allow partial updates.\n\n\n# Update `comment` with partial data\nserializer = CommentSerializer(comment, data={'content': u'foo bar'}, partial=True)\n\n\n\nDealing with nested objects\n\n\nThe previous examples are fine for dealing with objects that only have simple datatypes, but sometimes we also need to be able to represent more complex objects, where some of the attributes of an object might not be simple datatypes such as strings, dates or integers.\n\n\nThe \nSerializer\n class is itself a type of \nField\n, and can be used to represent relationships where one object type is nested inside another.\n\n\nclass UserSerializer(serializers.Serializer):\n email = serializers.EmailField()\n username = serializers.CharField(max_length=100)\n\nclass CommentSerializer(serializers.Serializer):\n user = UserSerializer()\n content = serializers.CharField(max_length=200)\n created = serializers.DateTimeField()\n\n\n\nIf a nested representation may optionally accept the \nNone\n value you should pass the \nrequired=False\n flag to the nested serializer.\n\n\nclass CommentSerializer(serializers.Serializer):\n user = UserSerializer(required=False) # May be an anonymous user.\n content = serializers.CharField(max_length=200)\n created = serializers.DateTimeField()\n\n\n\nSimilarly if a nested representation should be a list of items, you should pass the \nmany=True\n flag to the nested serialized.\n\n\nclass CommentSerializer(serializers.Serializer):\n user = UserSerializer(required=False)\n edits = EditItemSerializer(many=True) # A nested list of 'edit' items.\n content = serializers.CharField(max_length=200)\n created = serializers.DateTimeField()\n\n\n\nWritable nested representations\n\n\nWhen dealing with nested representations that support deserializing the data, any errors with nested objects will be nested under the field name of the nested object.\n\n\nserializer = CommentSerializer(data={'user': {'email': 'foobar', 'username': 'doe'}, 'content': 'baz'})\nserializer.is_valid()\n# False\nserializer.errors\n# {'user': {'email': [u'Enter a valid e-mail address.']}, 'created': [u'This field is required.']}\n\n\n\nSimilarly, the \n.validated_data\n property will include nested data structures.\n\n\nWriting \n.create()\n methods for nested representations\n\n\nIf you're supporting writable nested representations you'll need to write \n.create()\n or \n.update()\n methods that handle saving multiple objects.\n\n\nThe following example demonstrates how you might handle creating a user with a nested profile object.\n\n\nclass UserSerializer(serializers.ModelSerializer):\n profile = ProfileSerializer()\n\n class Meta:\n model = User\n fields = ('username', 'email', 'profile')\n\n def create(self, validated_data):\n profile_data = validated_data.pop('profile')\n user = User.objects.create(**validated_data)\n Profile.objects.create(user=user, **profile_data)\n return user\n\n\n\nWriting \n.update()\n methods for nested representations\n\n\nFor updates you'll want to think carefully about how to handle updates to relationships. For example if the data for the relationship is \nNone\n, or not provided, which of the following should occur?\n\n\n\n\nSet the relationship to \nNULL\n in the database.\n\n\nDelete the associated instance.\n\n\nIgnore the data and leave the instance as it is.\n\n\nRaise a validation error.\n\n\n\n\nHere's an example for an \n.update()\n method on our previous \nUserSerializer\n class.\n\n\n def update(self, instance, validated_data):\n profile_data = validated_data.pop('profile')\n # Unless the application properly enforces that this field is\n # always set, the follow could raise a `DoesNotExist`, which\n # would need to be handled.\n profile = instance.profile\n\n instance.username = validated_data.get('username', instance.username)\n instance.email = validated_data.get('email', instance.email)\n instance.save()\n\n profile.is_premium_member = profile_data.get(\n 'is_premium_member',\n profile.is_premium_member\n )\n profile.has_support_contract = profile_data.get(\n 'has_support_contract',\n profile.has_support_contract\n )\n profile.save()\n\n return instance\n\n\n\nBecause the behavior of nested creates and updates can be ambiguous, and may require complex dependencies between related models, REST framework 3 requires you to always write these methods explicitly. The default \nModelSerializer\n \n.create()\n and \n.update()\n methods do not include support for writable nested representations.\n\n\nThere are however, third-party packages available such as \nDRF Writable Nested\n that support automatic writable nested representations.\n\n\nHandling saving related instances in model manager classes\n\n\nAn alternative to saving multiple related instances in the serializer is to write custom model manager classes that handle creating the correct instances.\n\n\nFor example, suppose we wanted to ensure that \nUser\n instances and \nProfile\n instances are always created together as a pair. We might write a custom manager class that looks something like this:\n\n\nclass UserManager(models.Manager):\n ...\n\n def create(self, username, email, is_premium_member=False, has_support_contract=False):\n user = User(username=username, email=email)\n user.save()\n profile = Profile(\n user=user,\n is_premium_member=is_premium_member,\n has_support_contract=has_support_contract\n )\n profile.save()\n return user\n\n\n\nThis manager class now more nicely encapsulates that user instances and profile instances are always created at the same time. Our \n.create()\n method on the serializer class can now be re-written to use the new manager method.\n\n\ndef create(self, validated_data):\n return User.objects.create(\n username=validated_data['username'],\n email=validated_data['email']\n is_premium_member=validated_data['profile']['is_premium_member']\n has_support_contract=validated_data['profile']['has_support_contract']\n )\n\n\n\nFor more details on this approach see the Django documentation on \nmodel managers\n, and \nthis blogpost on using model and manager classes\n.\n\n\nDealing with multiple objects\n\n\nThe \nSerializer\n class can also handle serializing or deserializing lists of objects.\n\n\nSerializing multiple objects\n\n\nTo serialize a queryset or list of objects instead of a single object instance, you should pass the \nmany=True\n flag when instantiating the serializer. You can then pass a queryset or list of objects to be serialized.\n\n\nqueryset = Book.objects.all()\nserializer = BookSerializer(queryset, many=True)\nserializer.data\n# [\n# {'id': 0, 'title': 'The electric kool-aid acid test', 'author': 'Tom Wolfe'},\n# {'id': 1, 'title': 'If this is a man', 'author': 'Primo Levi'},\n# {'id': 2, 'title': 'The wind-up bird chronicle', 'author': 'Haruki Murakami'}\n# ]\n\n\n\nDeserializing multiple objects\n\n\nThe default behavior for deserializing multiple objects is to support multiple object creation, but not support multiple object updates. For more information on how to support or customize either of these cases, see the \nListSerializer\n documentation below.\n\n\nIncluding extra context\n\n\nThere are some cases where you need to provide extra context to the serializer in addition to the object being serialized. One common case is if you're using a serializer that includes hyperlinked relations, which requires the serializer to have access to the current request so that it can properly generate fully qualified URLs.\n\n\nYou can provide arbitrary additional context by passing a \ncontext\n argument when instantiating the serializer. For example:\n\n\nserializer = AccountSerializer(account, context={'request': request})\nserializer.data\n# {'id': 6, 'owner': u'denvercoder9', 'created': datetime.datetime(2013, 2, 12, 09, 44, 56, 678870), 'details': 'http://example.com/accounts/6/details'}\n\n\n\nThe context dictionary can be used within any serializer field logic, such as a custom \n.to_representation()\n method, by accessing the \nself.context\n attribute.\n\n\n\n\nModelSerializer\n\n\nOften you'll want serializer classes that map closely to Django model definitions.\n\n\nThe \nModelSerializer\n class provides a shortcut that lets you automatically create a \nSerializer\n class with fields that correspond to the Model fields.\n\n\nThe \nModelSerializer\n class is the same as a regular \nSerializer\n class, except that\n:\n\n\n\n\nIt will automatically generate a set of fields for you, based on the model.\n\n\nIt will automatically generate validators for the serializer, such as unique_together validators.\n\n\nIt includes simple default implementations of \n.create()\n and \n.update()\n.\n\n\n\n\nDeclaring a \nModelSerializer\n looks like this:\n\n\nclass AccountSerializer(serializers.ModelSerializer):\n class Meta:\n model = Account\n fields = ('id', 'account_name', 'users', 'created')\n\n\n\nBy default, all the model fields on the class will be mapped to a corresponding serializer fields.\n\n\nAny relationships such as foreign keys on the model will be mapped to \nPrimaryKeyRelatedField\n. Reverse relationships are not included by default unless explicitly included as specified in the \nserializer relations\n documentation.\n\n\nInspecting a \nModelSerializer\n\n\nSerializer classes generate helpful verbose representation strings, that allow you to fully inspect the state of their fields. This is particularly useful when working with \nModelSerializers\n where you want to determine what set of fields and validators are being automatically created for you.\n\n\nTo do so, open the Django shell, using \npython manage.py shell\n, then import the serializer class, instantiate it, and print the object representation\u2026\n\n\n>>> from myapp.serializers import AccountSerializer\n>>> serializer = AccountSerializer()\n>>> print(repr(serializer))\nAccountSerializer():\n id = IntegerField(label='ID', read_only=True)\n name = CharField(allow_blank=True, max_length=100, required=False)\n owner = PrimaryKeyRelatedField(queryset=User.objects.all())\n\n\n\nSpecifying which fields to include\n\n\nIf you only want a subset of the default fields to be used in a model serializer, you can do so using \nfields\n or \nexclude\n options, just as you would with a \nModelForm\n. It is strongly recommended that you explicitly set all fields that should be serialized using the \nfields\n attribute. This will make it less likely to result in unintentionally exposing data when your models change.\n\n\nFor example:\n\n\nclass AccountSerializer(serializers.ModelSerializer):\n class Meta:\n model = Account\n fields = ('id', 'account_name', 'users', 'created')\n\n\n\nYou can also set the \nfields\n attribute to the special value \n'__all__'\n to indicate that all fields in the model should be used.\n\n\nFor example:\n\n\nclass AccountSerializer(serializers.ModelSerializer):\n class Meta:\n model = Account\n fields = '__all__'\n\n\n\nYou can set the \nexclude\n attribute to a list of fields to be excluded from the serializer.\n\n\nFor example:\n\n\nclass AccountSerializer(serializers.ModelSerializer):\n class Meta:\n model = Account\n exclude = ('users',)\n\n\n\nIn the example above, if the \nAccount\n model had 3 fields \naccount_name\n, \nusers\n, and \ncreated\n, this will result in the fields \naccount_name\n and \ncreated\n to be serialized.\n\n\nThe names in the \nfields\n and \nexclude\n attributes will normally map to model fields on the model class.\n\n\nAlternatively names in the \nfields\n options can map to properties or methods which take no arguments that exist on the model class.\n\n\nSince version 3.3.0, it is \nmandatory\n to provide one of the attributes \nfields\n or \nexclude\n.\n\n\nSpecifying nested serialization\n\n\nThe default \nModelSerializer\n uses primary keys for relationships, but you can also easily generate nested representations using the \ndepth\n option:\n\n\nclass AccountSerializer(serializers.ModelSerializer):\n class Meta:\n model = Account\n fields = ('id', 'account_name', 'users', 'created')\n depth = 1\n\n\n\nThe \ndepth\n option should be set to an integer value that indicates the depth of relationships that should be traversed before reverting to a flat representation.\n\n\nIf you want to customize the way the serialization is done you'll need to define the field yourself.\n\n\nSpecifying fields explicitly\n\n\nYou can add extra fields to a \nModelSerializer\n or override the default fields by declaring fields on the class, just as you would for a \nSerializer\n class.\n\n\nclass AccountSerializer(serializers.ModelSerializer):\n url = serializers.CharField(source='get_absolute_url', read_only=True)\n groups = serializers.PrimaryKeyRelatedField(many=True)\n\n class Meta:\n model = Account\n\n\n\nExtra fields can correspond to any property or callable on the model.\n\n\nSpecifying read only fields\n\n\nYou may wish to specify multiple fields as read-only. Instead of adding each field explicitly with the \nread_only=True\n attribute, you may use the shortcut Meta option, \nread_only_fields\n.\n\n\nThis option should be a list or tuple of field names, and is declared as follows:\n\n\nclass AccountSerializer(serializers.ModelSerializer):\n class Meta:\n model = Account\n fields = ('id', 'account_name', 'users', 'created')\n read_only_fields = ('account_name',)\n\n\n\nModel fields which have \neditable=False\n set, and \nAutoField\n fields will be set to read-only by default, and do not need to be added to the \nread_only_fields\n option.\n\n\n\n\nNote\n: There is a special-case where a read-only field is part of a \nunique_together\n constraint at the model level. In this case the field is required by the serializer class in order to validate the constraint, but should also not be editable by the user.\n\n\nThe right way to deal with this is to specify the field explicitly on the serializer, providing both the \nread_only=True\n and \ndefault=\u2026\n keyword arguments.\n\n\nOne example of this is a read-only relation to the currently authenticated \nUser\n which is \nunique_together\n with another identifier. In this case you would declare the user field like so:\n\n\nuser = serializers.PrimaryKeyRelatedField(read_only=True, default=serializers.CurrentUserDefault())\n\n\n\nPlease review the \nValidators Documentation\n for details on the \nUniqueTogetherValidator\n and \nCurrentUserDefault\n classes.\n\n\n\n\nAdditional keyword arguments\n\n\nThere is also a shortcut allowing you to specify arbitrary additional keyword arguments on fields, using the \nextra_kwargs\n option. As in the case of \nread_only_fields\n, this means you do not need to explicitly declare the field on the serializer.\n\n\nThis option is a dictionary, mapping field names to a dictionary of keyword arguments. For example:\n\n\nclass CreateUserSerializer(serializers.ModelSerializer):\n class Meta:\n model = User\n fields = ('email', 'username', 'password')\n extra_kwargs = {'password': {'write_only': True}}\n\n def create(self, validated_data):\n user = User(\n email=validated_data['email'],\n username=validated_data['username']\n )\n user.set_password(validated_data['password'])\n user.save()\n return user\n\n\n\nRelational fields\n\n\nWhen serializing model instances, there are a number of different ways you might choose to represent relationships. The default representation for \nModelSerializer\n is to use the primary keys of the related instances.\n\n\nAlternative representations include serializing using hyperlinks, serializing complete nested representations, or serializing with a custom representation.\n\n\nFor full details see the \nserializer relations\n documentation.\n\n\nCustomizing field mappings\n\n\nThe ModelSerializer class also exposes an API that you can override in order to alter how serializer fields are automatically determined when instantiating the serializer.\n\n\nNormally if a \nModelSerializer\n does not generate the fields you need by default then you should either add them to the class explicitly, or simply use a regular \nSerializer\n 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.\n\n\n.serializer_field_mapping\n\n\nA 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.\n\n\n.serializer_related_field\n\n\nThis property should be the serializer field class, that is used for relational fields by default.\n\n\nFor \nModelSerializer\n this defaults to \nPrimaryKeyRelatedField\n.\n\n\nFor \nHyperlinkedModelSerializer\n this defaults to \nserializers.HyperlinkedRelatedField\n.\n\n\nserializer_url_field\n\n\nThe serializer field class that should be used for any \nurl\n field on the serializer.\n\n\nDefaults to \nserializers.HyperlinkedIdentityField\n\n\nserializer_choice_field\n\n\nThe serializer field class that should be used for any choice fields on the serializer.\n\n\nDefaults to \nserializers.ChoiceField\n\n\nThe field_class and field_kwargs API\n\n\nThe 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 \n(field_class, field_kwargs)\n.\n\n\n.build_standard_field(self, field_name, model_field)\n\n\nCalled to generate a serializer field that maps to a standard model field.\n\n\nThe default implementation returns a serializer class based on the \nserializer_field_mapping\n attribute.\n\n\n.build_relational_field(self, field_name, relation_info)\n\n\nCalled to generate a serializer field that maps to a relational model field.\n\n\nThe default implementation returns a serializer class based on the \nserializer_relational_field\n attribute.\n\n\nThe \nrelation_info\n argument is a named tuple, that contains \nmodel_field\n, \nrelated_model\n, \nto_many\n and \nhas_through_model\n properties.\n\n\n.build_nested_field(self, field_name, relation_info, nested_depth)\n\n\nCalled to generate a serializer field that maps to a relational model field, when the \ndepth\n option has been set.\n\n\nThe default implementation dynamically creates a nested serializer class based on either \nModelSerializer\n or \nHyperlinkedModelSerializer\n.\n\n\nThe \nnested_depth\n will be the value of the \ndepth\n option, minus one.\n\n\nThe \nrelation_info\n argument is a named tuple, that contains \nmodel_field\n, \nrelated_model\n, \nto_many\n and \nhas_through_model\n properties.\n\n\n.build_property_field(self, field_name, model_class)\n\n\nCalled to generate a serializer field that maps to a property or zero-argument method on the model class.\n\n\nThe default implementation returns a \nReadOnlyField\n class.\n\n\n.build_url_field(self, field_name, model_class)\n\n\nCalled to generate a serializer field for the serializer's own \nurl\n field. The default implementation returns a \nHyperlinkedIdentityField\n class.\n\n\n.build_unknown_field(self, field_name, model_class)\n\n\nCalled when the field name did not map to any model field or model property.\nThe default implementation raises an error, although subclasses may customize this behavior.\n\n\n\n\nHyperlinkedModelSerializer\n\n\nThe \nHyperlinkedModelSerializer\n class is similar to the \nModelSerializer\n class except that it uses hyperlinks to represent relationships, rather than primary keys.\n\n\nBy default the serializer will include a \nurl\n field instead of a primary key field.\n\n\nThe url field will be represented using a \nHyperlinkedIdentityField\n serializer field, and any relationships on the model will be represented using a \nHyperlinkedRelatedField\n serializer field.\n\n\nYou can explicitly include the primary key by adding it to the \nfields\n option, for example:\n\n\nclass AccountSerializer(serializers.HyperlinkedModelSerializer):\n class Meta:\n model = Account\n fields = ('url', 'id', 'account_name', 'users', 'created')\n\n\n\nAbsolute and relative URLs\n\n\nWhen instantiating a \nHyperlinkedModelSerializer\n you must include the current\n\nrequest\n in the serializer context, for example:\n\n\nserializer = AccountSerializer(queryset, context={'request': request})\n\n\n\nDoing so will ensure that the hyperlinks can include an appropriate hostname,\nso that the resulting representation uses fully qualified URLs, such as:\n\n\nhttp://api.example.com/accounts/1/\n\n\n\nRather than relative URLs, such as:\n\n\n/accounts/1/\n\n\n\nIf you \ndo\n want to use relative URLs, you should explicitly pass \n{'request': None}\n\nin the serializer context.\n\n\nHow hyperlinked views are determined\n\n\nThere needs to be a way of determining which views should be used for hyperlinking to model instances.\n\n\nBy default hyperlinks are expected to correspond to a view name that matches the style \n'{model_name}-detail'\n, and looks up the instance by a \npk\n keyword argument.\n\n\nYou can override a URL field view name and lookup field by using either, or both of, the \nview_name\n and \nlookup_field\n options in the \nextra_kwargs\n setting, like so:\n\n\nclass AccountSerializer(serializers.HyperlinkedModelSerializer):\n class Meta:\n model = Account\n fields = ('account_url', 'account_name', 'users', 'created')\n extra_kwargs = {\n 'url': {'view_name': 'accounts', 'lookup_field': 'account_name'},\n 'users': {'lookup_field': 'username'}\n }\n\n\n\nAlternatively you can set the fields on the serializer explicitly. For example:\n\n\nclass AccountSerializer(serializers.HyperlinkedModelSerializer):\n url = serializers.HyperlinkedIdentityField(\n view_name='accounts',\n lookup_field='slug'\n )\n users = serializers.HyperlinkedRelatedField(\n view_name='user-detail',\n lookup_field='username',\n many=True,\n read_only=True\n )\n\n class Meta:\n model = Account\n fields = ('url', 'account_name', 'users', 'created')\n\n\n\n\n\nTip\n: Properly matching together hyperlinked representations and your URL conf can sometimes be a bit fiddly. Printing the \nrepr\n of a \nHyperlinkedModelSerializer\n instance is a particularly useful way to inspect exactly which view names and lookup fields the relationships are expected to map too.\n\n\n\n\nChanging the URL field name\n\n\nThe name of the URL field defaults to 'url'. You can override this globally, by using the \nURL_FIELD_NAME\n setting.\n\n\n\n\nListSerializer\n\n\nThe \nListSerializer\n class provides the behavior for serializing and validating multiple objects at once. You won't \ntypically\n need to use \nListSerializer\n directly, but should instead simply pass \nmany=True\n when instantiating a serializer.\n\n\nWhen a serializer is instantiated and \nmany=True\n is passed, a \nListSerializer\n instance will be created. The serializer class then becomes a child of the parent \nListSerializer\n\n\nThe following argument can also be passed to a \nListSerializer\n field or a serializer that is passed \nmany=True\n:\n\n\nallow_empty\n\n\nThis is \nTrue\n by default, but can be set to \nFalse\n if you want to disallow empty lists as valid input.\n\n\nCustomizing \nListSerializer\n behavior\n\n\nThere \nare\n a few use cases when you might want to customize the \nListSerializer\n behavior. For example:\n\n\n\n\nYou want to provide particular validation of the lists, such as checking that one element does not conflict with another element in a list.\n\n\nYou want to customize the create or update behavior of multiple objects.\n\n\n\n\nFor these cases you can modify the class that is used when \nmany=True\n is passed, by using the \nlist_serializer_class\n option on the serializer \nMeta\n class.\n\n\nFor example:\n\n\nclass CustomListSerializer(serializers.ListSerializer):\n ...\n\nclass CustomSerializer(serializers.Serializer):\n ...\n class Meta:\n list_serializer_class = CustomListSerializer\n\n\n\nCustomizing multiple create\n\n\nThe default implementation for multiple object creation is to simply call \n.create()\n for each item in the list. If you want to customize this behavior, you'll need to customize the \n.create()\n method on \nListSerializer\n class that is used when \nmany=True\n is passed.\n\n\nFor example:\n\n\nclass BookListSerializer(serializers.ListSerializer):\n def create(self, validated_data):\n books = [Book(**item) for item in validated_data]\n return Book.objects.bulk_create(books)\n\nclass BookSerializer(serializers.Serializer):\n ...\n class Meta:\n list_serializer_class = BookListSerializer\n\n\n\nCustomizing multiple update\n\n\nBy default the \nListSerializer\n class does not support multiple updates. This is because the behavior that should be expected for insertions and deletions is ambiguous.\n\n\nTo support multiple updates you'll need to do so explicitly. When writing your multiple update code make sure to keep the following in mind:\n\n\n\n\nHow do you determine which instance should be updated for each item in the list of data?\n\n\nHow should insertions be handled? Are they invalid, or do they create new objects?\n\n\nHow should removals be handled? Do they imply object deletion, or removing a relationship? Should they be silently ignored, or are they invalid?\n\n\nHow should ordering be handled? Does changing the position of two items imply any state change or is it ignored?\n\n\n\n\nYou will need to add an explicit \nid\n field to the instance serializer. The default implicitly-generated \nid\n field is marked as \nread_only\n. This causes it to be removed on updates. Once you declare it explicitly, it will be available in the list serializer's \nupdate\n method.\n\n\nHere's an example of how you might choose to implement multiple updates:\n\n\nclass BookListSerializer(serializers.ListSerializer):\n def update(self, instance, validated_data):\n # Maps for id->instance and id->data item.\n book_mapping = {book.id: book for book in instance}\n data_mapping = {item['id']: item for item in validated_data}\n\n # Perform creations and updates.\n ret = []\n for book_id, data in data_mapping.items():\n book = book_mapping.get(book_id, None)\n if book is None:\n ret.append(self.child.create(data))\n else:\n ret.append(self.child.update(book, data))\n\n # Perform deletions.\n for book_id, book in book_mapping.items():\n if book_id not in data_mapping:\n book.delete()\n\n return ret\n\nclass BookSerializer(serializers.Serializer):\n # We need to identify elements in the list using their primary key,\n # so use a writable field here, rather than the default which would be read-only.\n id = serializers.IntegerField()\n ...\n\n class Meta:\n list_serializer_class = BookListSerializer\n\n\n\nIt is possible that a third party package may be included alongside the 3.1 release that provides some automatic support for multiple update operations, similar to the \nallow_add_remove\n behavior that was present in REST framework 2.\n\n\nCustomizing ListSerializer initialization\n\n\nWhen a serializer with \nmany=True\n is instantiated, we need to determine which arguments and keyword arguments should be passed to the \n.__init__()\n method for both the child \nSerializer\n class, and for the parent \nListSerializer\n class.\n\n\nThe default implementation is to pass all arguments to both classes, except for \nvalidators\n, and any custom keyword arguments, both of which are assumed to be intended for the child serializer class.\n\n\nOccasionally you might need to explicitly specify how the child and parent classes should be instantiated when \nmany=True\n is passed. You can do so by using the \nmany_init\n class method.\n\n\n @classmethod\n def many_init(cls, *args, **kwargs):\n # Instantiate the child serializer.\n kwargs['child'] = cls()\n # Instantiate the parent list serializer.\n return CustomListSerializer(*args, **kwargs)\n\n\n\n\n\nBaseSerializer\n\n\nBaseSerializer\n class that can be used to easily support alternative serialization and deserialization styles.\n\n\nThis class implements the same basic API as the \nSerializer\n class:\n\n\n\n\n.data\n - Returns the outgoing primitive representation.\n\n\n.is_valid()\n - Deserializes and validates incoming data.\n\n\n.validated_data\n - Returns the validated incoming data.\n\n\n.errors\n - Returns any errors during validation.\n\n\n.save()\n - Persists the validated data into an object instance.\n\n\n\n\nThere are four methods that can be overridden, depending on what functionality you want the serializer class to support:\n\n\n\n\n.to_representation()\n - Override this to support serialization, for read operations.\n\n\n.to_internal_value()\n - Override this to support deserialization, for write operations.\n\n\n.create()\n and \n.update()\n - Override either or both of these to support saving instances.\n\n\n\n\nBecause this class provides the same interface as the \nSerializer\n class, you can use it with the existing generic class-based views exactly as you would for a regular \nSerializer\n or \nModelSerializer\n.\n\n\nThe only difference you'll notice when doing so is the \nBaseSerializer\n classes will not generate HTML forms in the browsable API. This is because the data they return does not include all the field information that would allow each field to be rendered into a suitable HTML input.\n\n\nRead-only \nBaseSerializer\n classes\n\n\nTo implement a read-only serializer using the \nBaseSerializer\n class, we just need to override the \n.to_representation()\n method. Let's take a look at an example using a simple Django model:\n\n\nclass HighScore(models.Model):\n created = models.DateTimeField(auto_now_add=True)\n player_name = models.CharField(max_length=10)\n score = models.IntegerField()\n\n\n\nIt's simple to create a read-only serializer for converting \nHighScore\n instances into primitive data types.\n\n\nclass HighScoreSerializer(serializers.BaseSerializer):\n def to_representation(self, obj):\n return {\n 'score': obj.score,\n 'player_name': obj.player_name\n }\n\n\n\nWe can now use this class to serialize single \nHighScore\n instances:\n\n\n@api_view(['GET'])\ndef high_score(request, pk):\n instance = HighScore.objects.get(pk=pk)\n serializer = HighScoreSerializer(instance)\n return Response(serializer.data)\n\n\n\nOr use it to serialize multiple instances:\n\n\n@api_view(['GET'])\ndef all_high_scores(request):\n queryset = HighScore.objects.order_by('-score')\n serializer = HighScoreSerializer(queryset, many=True)\n return Response(serializer.data)\n\n\n\nRead-write \nBaseSerializer\n classes\n\n\nTo create a read-write serializer we first need to implement a \n.to_internal_value()\n method. This method returns the validated values that will be used to construct the object instance, and may raise a \nValidationError\n if the supplied data is in an incorrect format.\n\n\nOnce you've implemented \n.to_internal_value()\n, the basic validation API will be available on the serializer, and you will be able to use \n.is_valid()\n, \n.validated_data\n and \n.errors\n.\n\n\nIf you want to also support \n.save()\n you'll need to also implement either or both of the \n.create()\n and \n.update()\n methods.\n\n\nHere's a complete example of our previous \nHighScoreSerializer\n, that's been updated to support both read and write operations.\n\n\nclass HighScoreSerializer(serializers.BaseSerializer):\n def to_internal_value(self, data):\n score = data.get('score')\n player_name = data.get('player_name')\n\n # Perform the data validation.\n if not score:\n raise ValidationError({\n 'score': 'This field is required.'\n })\n if not player_name:\n raise ValidationError({\n 'player_name': 'This field is required.'\n })\n if len(player_name) > 10:\n raise ValidationError({\n 'player_name': 'May not be more than 10 characters.'\n })\n\n # Return the validated values. This will be available as\n # the `.validated_data` property.\n return {\n 'score': int(score),\n 'player_name': player_name\n }\n\n def to_representation(self, obj):\n return {\n 'score': obj.score,\n 'player_name': obj.player_name\n }\n\n def create(self, validated_data):\n return HighScore.objects.create(**validated_data)\n\n\n\nCreating new base classes\n\n\nThe \nBaseSerializer\n class is also useful if you want to implement new generic serializer classes for dealing with particular serialization styles, or for integrating with alternative storage backends.\n\n\nThe following class is an example of a generic serializer that can handle coercing arbitrary objects into primitive representations.\n\n\nclass ObjectSerializer(serializers.BaseSerializer):\n \"\"\"\n A read-only serializer that coerces arbitrary complex objects\n into primitive representations.\n \"\"\"\n def to_representation(self, obj):\n for attribute_name in dir(obj):\n attribute = getattr(obj, attribute_name)\n if attribute_name('_'):\n # Ignore private attributes.\n pass\n elif hasattr(attribute, '__call__'):\n # Ignore methods and other callables.\n pass\n elif isinstance(attribute, (str, int, bool, float, type(None))):\n # Primitive types can be passed through unmodified.\n output[attribute_name] = attribute\n elif isinstance(attribute, list):\n # Recursively deal with items in lists.\n output[attribute_name] = [\n self.to_representation(item) for item in attribute\n ]\n elif isinstance(attribute, dict):\n # Recursively deal with items in dictionaries.\n output[attribute_name] = {\n str(key): self.to_representation(value)\n for key, value in attribute.items()\n }\n else:\n # Force anything else to its string representation.\n output[attribute_name] = str(attribute)\n\n\n\n\n\nAdvanced serializer usage\n\n\nOverriding serialization and deserialization behavior\n\n\nIf you need to alter the serialization or deserialization behavior of a serializer class, you can do so by overriding the \n.to_representation()\n or \n.to_internal_value()\n methods.\n\n\nSome reasons this might be useful include...\n\n\n\n\nAdding new behavior for new serializer base classes.\n\n\nModifying the behavior slightly for an existing class.\n\n\nImproving serialization performance for a frequently accessed API endpoint that returns lots of data.\n\n\n\n\nThe signatures for these methods are as follows:\n\n\n.to_representation(self, obj)\n\n\nTakes the object instance that requires serialization, and should return a primitive representation. Typically this means returning a structure of built-in Python datatypes. The exact types that can be handled will depend on the render classes you have configured for your API.\n\n\nMay be overridden in order modify the representation style. For example:\n\n\ndef to_representation(self, instance):\n \"\"\"Convert `username` to lowercase.\"\"\"\n ret = super().to_representation(instance)\n ret['username'] = ret['username'].lower()\n return ret\n\n\n\n.to_internal_value(self, data)\n\n\nTakes the unvalidated incoming data as input and should return the validated data that will be made available as \nserializer.validated_data\n. The return value will also be passed to the \n.create()\n or \n.update()\n methods if \n.save()\n is called on the serializer class.\n\n\nIf any of the validation fails, then the method should raise a \nserializers.ValidationError(errors)\n. The \nerrors\n argument should be a dictionary mapping field names (or \nsettings.NON_FIELD_ERRORS_KEY\n) to a list of error messages. If you don't need to alter deserialization behavior and instead want to provide object-level validation, it's recommended that you instead override the \n.validate()\n method.\n\n\nThe \ndata\n argument passed to this method will normally be the value of \nrequest.data\n, so the datatype it provides will depend on the parser classes you have configured for your API.\n\n\nSerializer Inheritance\n\n\nSimilar to Django forms, you can extend and reuse serializers through inheritance. This allows you to declare a common set of fields or methods on a parent class that can then be used in a number of serializers. For example,\n\n\nclass MyBaseSerializer(Serializer):\n my_field = serializers.CharField()\n\n def validate_my_field(self):\n ...\n\nclass MySerializer(MyBaseSerializer):\n ...\n\n\n\nLike Django's \nModel\n and \nModelForm\n classes, the inner \nMeta\n class on serializers does not implicitly inherit from it's parents' inner \nMeta\n classes. If you want the \nMeta\n class to inherit from a parent class you must do so explicitly. For example:\n\n\nclass AccountSerializer(MyBaseSerializer):\n class Meta(MyBaseSerializer.Meta):\n model = Account\n\n\n\nTypically we would recommend \nnot\n using inheritance on inner Meta classes, but instead declaring all options explicitly.\n\n\nAdditionally, the following caveats apply to serializer inheritance:\n\n\n\n\nNormal Python name resolution rules apply. If you have multiple base classes that declare a \nMeta\n inner class, only the first one will be used. This means the child\u2019s \nMeta\n, if it exists, otherwise the \nMeta\n of the first parent, etc.\n\n\n\n\nIt\u2019s possible to declaratively remove a \nField\n inherited from a parent class by setting the name to be \nNone\n on the subclass.\n\n\nclass MyBaseSerializer(ModelSerializer):\n my_field = serializers.CharField()\n\nclass MySerializer(MyBaseSerializer):\n my_field = None\n\n\n\nHowever, you can only use this technique to opt out from a field defined declaratively by a parent class; it won\u2019t prevent the \nModelSerializer\n from generating a default field. To opt-out from default fields, see \nSpecifying which fields to include\n.\n\n\n\n\n\n\nDynamically modifying fields\n\n\nOnce a serializer has been initialized, the dictionary of fields that are set on the serializer may be accessed using the \n.fields\n attribute. Accessing and modifying this attribute allows you to dynamically modify the serializer.\n\n\nModifying the \nfields\n argument directly allows you to do interesting things such as changing the arguments on serializer fields at runtime, rather than at the point of declaring the serializer.\n\n\nExample\n\n\nFor example, if you wanted to be able to set which fields should be used by a serializer at the point of initializing it, you could create a serializer class like so:\n\n\nclass DynamicFieldsModelSerializer(serializers.ModelSerializer):\n \"\"\"\n A ModelSerializer that takes an additional `fields` argument that\n controls which fields should be displayed.\n \"\"\"\n\n def __init__(self, *args, **kwargs):\n # Don't pass the 'fields' arg up to the superclass\n fields = kwargs.pop('fields', None)\n\n # Instantiate the superclass normally\n super(DynamicFieldsModelSerializer, self).__init__(*args, **kwargs)\n\n if fields is not None:\n # Drop any fields that are not specified in the `fields` argument.\n allowed = set(fields)\n existing = set(self.fields)\n for field_name in existing - allowed:\n self.fields.pop(field_name)\n\n\n\nThis would then allow you to do the following:\n\n\n>>> class UserSerializer(DynamicFieldsModelSerializer):\n>>> class Meta:\n>>> model = User\n>>> fields = ('id', 'username', 'email')\n>>>\n>>> print UserSerializer(user)\n{'id': 2, 'username': 'jonwatts', 'email': 'jon@example.com'}\n>>>\n>>> print UserSerializer(user, fields=('id', 'email'))\n{'id': 2, 'email': 'jon@example.com'}\n\n\n\nCustomizing the default fields\n\n\nREST framework 2 provided an API to allow developers to override how a \nModelSerializer\n class would automatically generate the default set of fields.\n\n\nThis API included the \n.get_field()\n, \n.get_pk_field()\n and other methods.\n\n\nBecause the serializers have been fundamentally redesigned with 3.0 this API no longer exists. You can still modify the fields that get created but you'll need to refer to the source code, and be aware that if the changes you make are against private bits of API then they may be subject to change.\n\n\n\n\nThird party packages\n\n\nThe following third party packages are also available.\n\n\nDjango REST marshmallow\n\n\nThe \ndjango-rest-marshmallow\n package provides an alternative implementation for serializers, using the python \nmarshmallow\n library. It exposes the same API as the REST framework serializers, and can be used as a drop-in replacement in some use-cases.\n\n\nSerpy\n\n\nThe \nserpy\n package is an alternative implementation for serializers that is built for speed. \nSerpy\n serializes complex datatypes to simple native types. The native types can be easily converted to JSON or any other format needed.\n\n\nMongoengineModelSerializer\n\n\nThe \ndjango-rest-framework-mongoengine\n package provides a \nMongoEngineModelSerializer\n serializer class that supports using MongoDB as the storage layer for Django REST framework.\n\n\nGeoFeatureModelSerializer\n\n\nThe \ndjango-rest-framework-gis\n package provides a \nGeoFeatureModelSerializer\n serializer class that supports GeoJSON both for read and write operations.\n\n\nHStoreSerializer\n\n\nThe \ndjango-rest-framework-hstore\n package provides an \nHStoreSerializer\n to support \ndjango-hstore\n \nDictionaryField\n model field and its \nschema-mode\n feature.\n\n\nDynamic REST\n\n\nThe \ndynamic-rest\n package extends the ModelSerializer and ModelViewSet interfaces, adding API query parameters for filtering, sorting, and including / excluding all fields and relationships defined by your serializers.\n\n\nDynamic Fields Mixin\n\n\nThe \ndrf-dynamic-fields\n package provides a mixin to dynamically limit the fields per serializer to a subset specified by an URL parameter.\n\n\nDRF FlexFields\n\n\nThe \ndrf-flex-fields\n package extends the ModelSerializer and ModelViewSet to provide commonly used functionality for dynamically setting fields and expanding primitive fields to nested models, both from URL parameters and your serializer class definitions.\n\n\nSerializer Extensions\n\n\nThe \ndjango-rest-framework-serializer-extensions\n\npackage provides a collection of tools to DRY up your serializers, by allowing\nfields to be defined on a per-view/request basis. Fields can be whitelisted,\nblacklisted and child serializers can be optionally expanded.\n\n\nHTML JSON Forms\n\n\nThe \nhtml-json-forms\n package provides an algorithm and serializer for processing \n
    \n submissions per the (inactive) \nHTML JSON Form specification\n. The serializer facilitates processing of arbitrarily nested JSON structures within HTML. For example, \n\n will be interpreted as \n{\"items\": [{\"id\": \"5\"}]}\n.\n\n\nDRF-Base64\n\n\nDRF-Base64\n provides a set of field and model serializers that handles the upload of base64-encoded files.\n\n\nQueryFields\n\n\ndjangorestframework-queryfields\n allows API clients to specify which fields will be sent in the response via inclusion/exclusion query parameters.\n\n\nDRF Writable Nested\n\n\nThe \ndrf-writable-nested\n package provides writable nested model serializer which allows to create/update models with nested related data.", + "text": "Serializers\n\n\n\n\nExpanding the usefulness of the serializers is something that we would\nlike to address. However, it's not a trivial problem, and it\nwill take some serious design work.\n\n\n\u2014 Russell Keith-Magee, \nDjango users group\n\n\n\n\nSerializers allow complex data such as querysets and model instances to be converted to native Python datatypes that can then be easily rendered into \nJSON\n, \nXML\n or other content types. Serializers also provide deserialization, allowing parsed data to be converted back into complex types, after first validating the incoming data.\n\n\nThe serializers in REST framework work very similarly to Django's \nForm\n and \nModelForm\n classes. We provide a \nSerializer\n class which gives you a powerful, generic way to control the output of your responses, as well as a \nModelSerializer\n class which provides a useful shortcut for creating serializers that deal with model instances and querysets.\n\n\nDeclaring Serializers\n\n\nLet's start by creating a simple object we can use for example purposes:\n\n\nfrom datetime import datetime\n\nclass Comment(object):\n def __init__(self, email, content, created=None):\n self.email = email\n self.content = content\n self.created = created or datetime.now()\n\ncomment = Comment(email='leila@example.com', content='foo bar')\n\n\n\nWe'll declare a serializer that we can use to serialize and deserialize data that corresponds to \nComment\n objects.\n\n\nDeclaring a serializer looks very similar to declaring a form:\n\n\nfrom rest_framework import serializers\n\nclass CommentSerializer(serializers.Serializer):\n email = serializers.EmailField()\n content = serializers.CharField(max_length=200)\n created = serializers.DateTimeField()\n\n\n\nSerializing objects\n\n\nWe can now use \nCommentSerializer\n to serialize a comment, or list of comments. Again, using the \nSerializer\n class looks a lot like using a \nForm\n class.\n\n\nserializer = CommentSerializer(comment)\nserializer.data\n# {'email': 'leila@example.com', 'content': 'foo bar', 'created': '2016-01-27T15:17:10.375877'}\n\n\n\nAt this point we've translated the model instance into Python native datatypes. To finalise the serialization process we render the data into \njson\n.\n\n\nfrom rest_framework.renderers import JSONRenderer\n\njson = JSONRenderer().render(serializer.data)\njson\n# b'{\"email\":\"leila@example.com\",\"content\":\"foo bar\",\"created\":\"2016-01-27T15:17:10.375877\"}'\n\n\n\nDeserializing objects\n\n\nDeserialization is similar. First we parse a stream into Python native datatypes...\n\n\nfrom django.utils.six import BytesIO\nfrom rest_framework.parsers import JSONParser\n\nstream = BytesIO(json)\ndata = JSONParser().parse(stream)\n\n\n\n...then we restore those native datatypes into a dictionary of validated data.\n\n\nserializer = CommentSerializer(data=data)\nserializer.is_valid()\n# True\nserializer.validated_data\n# {'content': 'foo bar', 'email': 'leila@example.com', 'created': datetime.datetime(2012, 08, 22, 16, 20, 09, 822243)}\n\n\n\nSaving instances\n\n\nIf we want to be able to return complete object instances based on the validated data we need to implement one or both of the \n.create()\n and \n.update()\n methods. For example:\n\n\nclass CommentSerializer(serializers.Serializer):\n email = serializers.EmailField()\n content = serializers.CharField(max_length=200)\n created = serializers.DateTimeField()\n\n def create(self, validated_data):\n return Comment(**validated_data)\n\n def update(self, instance, validated_data):\n instance.email = validated_data.get('email', instance.email)\n instance.content = validated_data.get('content', instance.content)\n instance.created = validated_data.get('created', instance.created)\n return instance\n\n\n\nIf your object instances correspond to Django models you'll also want to ensure that these methods save the object to the database. For example, if \nComment\n was a Django model, the methods might look like this:\n\n\n def create(self, validated_data):\n return Comment.objects.create(**validated_data)\n\n def update(self, instance, validated_data):\n instance.email = validated_data.get('email', instance.email)\n instance.content = validated_data.get('content', instance.content)\n instance.created = validated_data.get('created', instance.created)\n instance.save()\n return instance\n\n\n\nNow when deserializing data, we can call \n.save()\n to return an object instance, based on the validated data.\n\n\ncomment = serializer.save()\n\n\n\nCalling \n.save()\n will either create a new instance, or update an existing instance, depending on if an existing instance was passed when instantiating the serializer class:\n\n\n# .save() will create a new instance.\nserializer = CommentSerializer(data=data)\n\n# .save() will update the existing `comment` instance.\nserializer = CommentSerializer(comment, data=data)\n\n\n\nBoth the \n.create()\n and \n.update()\n methods are optional. You can implement either neither, one, or both of them, depending on the use-case for your serializer class.\n\n\nPassing additional attributes to \n.save()\n\n\nSometimes you'll want your view code to be able to inject additional data at the point of saving the instance. This additional data might include information like the current user, the current time, or anything else that is not part of the request data.\n\n\nYou can do so by including additional keyword arguments when calling \n.save()\n. For example:\n\n\nserializer.save(owner=request.user)\n\n\n\nAny additional keyword arguments will be included in the \nvalidated_data\n argument when \n.create()\n or \n.update()\n are called.\n\n\nOverriding \n.save()\n directly.\n\n\nIn some cases the \n.create()\n and \n.update()\n method names may not be meaningful. For example, in a contact form we may not be creating new instances, but instead sending an email or other message.\n\n\nIn these cases you might instead choose to override \n.save()\n directly, as being more readable and meaningful.\n\n\nFor example:\n\n\nclass ContactForm(serializers.Serializer):\n email = serializers.EmailField()\n message = serializers.CharField()\n\n def save(self):\n email = self.validated_data['email']\n message = self.validated_data['message']\n send_email(from=email, message=message)\n\n\n\nNote that in the case above we're now having to access the serializer \n.validated_data\n property directly.\n\n\nValidation\n\n\nWhen deserializing data, you always need to call \nis_valid()\n before attempting to access the validated data, or save an object instance. If any validation errors occur, the \n.errors\n property will contain a dictionary representing the resulting error messages. For example:\n\n\nserializer = CommentSerializer(data={'email': 'foobar', 'content': 'baz'})\nserializer.is_valid()\n# False\nserializer.errors\n# {'email': [u'Enter a valid e-mail address.'], 'created': [u'This field is required.']}\n\n\n\nEach key in the dictionary will be the field name, and the values will be lists of strings of any error messages corresponding to that field. The \nnon_field_errors\n key may also be present, and will list any general validation errors. The name of the \nnon_field_errors\n key may be customized using the \nNON_FIELD_ERRORS_KEY\n REST framework setting.\n\n\nWhen deserializing a list of items, errors will be returned as a list of dictionaries representing each of the deserialized items.\n\n\nRaising an exception on invalid data\n\n\nThe \n.is_valid()\n method takes an optional \nraise_exception\n flag that will cause it to raise a \nserializers.ValidationError\n exception if there are validation errors.\n\n\nThese exceptions are automatically dealt with by the default exception handler that REST framework provides, and will return \nHTTP 400 Bad Request\n responses by default.\n\n\n# Return a 400 response if the data was invalid.\nserializer.is_valid(raise_exception=True)\n\n\n\nField-level validation\n\n\nYou can specify custom field-level validation by adding \n.validate_\n methods to your \nSerializer\n subclass. These are similar to the \n.clean_\n methods on Django forms.\n\n\nThese methods take a single argument, which is the field value that requires validation.\n\n\nYour \nvalidate_\n methods should return the validated value or raise a \nserializers.ValidationError\n. For example:\n\n\nfrom rest_framework import serializers\n\nclass BlogPostSerializer(serializers.Serializer):\n title = serializers.CharField(max_length=100)\n content = serializers.CharField()\n\n def validate_title(self, value):\n \"\"\"\n Check that the blog post is about Django.\n \"\"\"\n if 'django' not in value.lower():\n raise serializers.ValidationError(\"Blog post is not about Django\")\n return value\n\n\n\n\n\nNote:\n If your \n\n is declared on your serializer with the parameter \nrequired=False\n then this validation step will not take place if the field is not included.\n\n\n\n\nObject-level validation\n\n\nTo do any other validation that requires access to multiple fields, add a method called \n.validate()\n to your \nSerializer\n subclass. This method takes a single argument, which is a dictionary of field values. It should raise a \nserializers.ValidationError\n if necessary, or just return the validated values. For example:\n\n\nfrom rest_framework import serializers\n\nclass EventSerializer(serializers.Serializer):\n description = serializers.CharField(max_length=100)\n start = serializers.DateTimeField()\n finish = serializers.DateTimeField()\n\n def validate(self, data):\n \"\"\"\n Check that the start is before the stop.\n \"\"\"\n if data['start'] > data['finish']:\n raise serializers.ValidationError(\"finish must occur after start\")\n return data\n\n\n\nValidators\n\n\nIndividual fields on a serializer can include validators, by declaring them on the field instance, for example:\n\n\ndef multiple_of_ten(value):\n if value % 10 != 0:\n raise serializers.ValidationError('Not a multiple of ten')\n\nclass GameRecord(serializers.Serializer):\n score = IntegerField(validators=[multiple_of_ten])\n ...\n\n\n\nSerializer classes can also include reusable validators that are applied to the complete set of field data. These validators are included by declaring them on an inner \nMeta\n class, like so:\n\n\nclass EventSerializer(serializers.Serializer):\n name = serializers.CharField()\n room_number = serializers.IntegerField(choices=[101, 102, 103, 201])\n date = serializers.DateField()\n\n class Meta:\n # Each room only has one event per day.\n validators = UniqueTogetherValidator(\n queryset=Event.objects.all(),\n fields=['room_number', 'date']\n )\n\n\n\nFor more information see the \nvalidators documentation\n.\n\n\nAccessing the initial data and instance\n\n\nWhen passing an initial object or queryset to a serializer instance, the object will be made available as \n.instance\n. If no initial object is passed then the \n.instance\n attribute will be \nNone\n.\n\n\nWhen passing data to a serializer instance, the unmodified data will be made available as \n.initial_data\n. If the data keyword argument is not passed then the \n.initial_data\n attribute will not exist.\n\n\nPartial updates\n\n\nBy default, serializers must be passed values for all required fields or they will raise validation errors. You can use the \npartial\n argument in order to allow partial updates.\n\n\n# Update `comment` with partial data\nserializer = CommentSerializer(comment, data={'content': u'foo bar'}, partial=True)\n\n\n\nDealing with nested objects\n\n\nThe previous examples are fine for dealing with objects that only have simple datatypes, but sometimes we also need to be able to represent more complex objects, where some of the attributes of an object might not be simple datatypes such as strings, dates or integers.\n\n\nThe \nSerializer\n class is itself a type of \nField\n, and can be used to represent relationships where one object type is nested inside another.\n\n\nclass UserSerializer(serializers.Serializer):\n email = serializers.EmailField()\n username = serializers.CharField(max_length=100)\n\nclass CommentSerializer(serializers.Serializer):\n user = UserSerializer()\n content = serializers.CharField(max_length=200)\n created = serializers.DateTimeField()\n\n\n\nIf a nested representation may optionally accept the \nNone\n value you should pass the \nrequired=False\n flag to the nested serializer.\n\n\nclass CommentSerializer(serializers.Serializer):\n user = UserSerializer(required=False) # May be an anonymous user.\n content = serializers.CharField(max_length=200)\n created = serializers.DateTimeField()\n\n\n\nSimilarly if a nested representation should be a list of items, you should pass the \nmany=True\n flag to the nested serialized.\n\n\nclass CommentSerializer(serializers.Serializer):\n user = UserSerializer(required=False)\n edits = EditItemSerializer(many=True) # A nested list of 'edit' items.\n content = serializers.CharField(max_length=200)\n created = serializers.DateTimeField()\n\n\n\nWritable nested representations\n\n\nWhen dealing with nested representations that support deserializing the data, any errors with nested objects will be nested under the field name of the nested object.\n\n\nserializer = CommentSerializer(data={'user': {'email': 'foobar', 'username': 'doe'}, 'content': 'baz'})\nserializer.is_valid()\n# False\nserializer.errors\n# {'user': {'email': [u'Enter a valid e-mail address.']}, 'created': [u'This field is required.']}\n\n\n\nSimilarly, the \n.validated_data\n property will include nested data structures.\n\n\nWriting \n.create()\n methods for nested representations\n\n\nIf you're supporting writable nested representations you'll need to write \n.create()\n or \n.update()\n methods that handle saving multiple objects.\n\n\nThe following example demonstrates how you might handle creating a user with a nested profile object.\n\n\nclass UserSerializer(serializers.ModelSerializer):\n profile = ProfileSerializer()\n\n class Meta:\n model = User\n fields = ('username', 'email', 'profile')\n\n def create(self, validated_data):\n profile_data = validated_data.pop('profile')\n user = User.objects.create(**validated_data)\n Profile.objects.create(user=user, **profile_data)\n return user\n\n\n\nWriting \n.update()\n methods for nested representations\n\n\nFor updates you'll want to think carefully about how to handle updates to relationships. For example if the data for the relationship is \nNone\n, or not provided, which of the following should occur?\n\n\n\n\nSet the relationship to \nNULL\n in the database.\n\n\nDelete the associated instance.\n\n\nIgnore the data and leave the instance as it is.\n\n\nRaise a validation error.\n\n\n\n\nHere's an example for an \n.update()\n method on our previous \nUserSerializer\n class.\n\n\n def update(self, instance, validated_data):\n profile_data = validated_data.pop('profile')\n # Unless the application properly enforces that this field is\n # always set, the follow could raise a `DoesNotExist`, which\n # would need to be handled.\n profile = instance.profile\n\n instance.username = validated_data.get('username', instance.username)\n instance.email = validated_data.get('email', instance.email)\n instance.save()\n\n profile.is_premium_member = profile_data.get(\n 'is_premium_member',\n profile.is_premium_member\n )\n profile.has_support_contract = profile_data.get(\n 'has_support_contract',\n profile.has_support_contract\n )\n profile.save()\n\n return instance\n\n\n\nBecause the behavior of nested creates and updates can be ambiguous, and may require complex dependencies between related models, REST framework 3 requires you to always write these methods explicitly. The default \nModelSerializer\n \n.create()\n and \n.update()\n methods do not include support for writable nested representations.\n\n\nThere are however, third-party packages available such as \nDRF Writable Nested\n that support automatic writable nested representations.\n\n\nHandling saving related instances in model manager classes\n\n\nAn alternative to saving multiple related instances in the serializer is to write custom model manager classes that handle creating the correct instances.\n\n\nFor example, suppose we wanted to ensure that \nUser\n instances and \nProfile\n instances are always created together as a pair. We might write a custom manager class that looks something like this:\n\n\nclass UserManager(models.Manager):\n ...\n\n def create(self, username, email, is_premium_member=False, has_support_contract=False):\n user = User(username=username, email=email)\n user.save()\n profile = Profile(\n user=user,\n is_premium_member=is_premium_member,\n has_support_contract=has_support_contract\n )\n profile.save()\n return user\n\n\n\nThis manager class now more nicely encapsulates that user instances and profile instances are always created at the same time. Our \n.create()\n method on the serializer class can now be re-written to use the new manager method.\n\n\ndef create(self, validated_data):\n return User.objects.create(\n username=validated_data['username'],\n email=validated_data['email']\n is_premium_member=validated_data['profile']['is_premium_member']\n has_support_contract=validated_data['profile']['has_support_contract']\n )\n\n\n\nFor more details on this approach see the Django documentation on \nmodel managers\n, and \nthis blogpost on using model and manager classes\n.\n\n\nDealing with multiple objects\n\n\nThe \nSerializer\n class can also handle serializing or deserializing lists of objects.\n\n\nSerializing multiple objects\n\n\nTo serialize a queryset or list of objects instead of a single object instance, you should pass the \nmany=True\n flag when instantiating the serializer. You can then pass a queryset or list of objects to be serialized.\n\n\nqueryset = Book.objects.all()\nserializer = BookSerializer(queryset, many=True)\nserializer.data\n# [\n# {'id': 0, 'title': 'The electric kool-aid acid test', 'author': 'Tom Wolfe'},\n# {'id': 1, 'title': 'If this is a man', 'author': 'Primo Levi'},\n# {'id': 2, 'title': 'The wind-up bird chronicle', 'author': 'Haruki Murakami'}\n# ]\n\n\n\nDeserializing multiple objects\n\n\nThe default behavior for deserializing multiple objects is to support multiple object creation, but not support multiple object updates. For more information on how to support or customize either of these cases, see the \nListSerializer\n documentation below.\n\n\nIncluding extra context\n\n\nThere are some cases where you need to provide extra context to the serializer in addition to the object being serialized. One common case is if you're using a serializer that includes hyperlinked relations, which requires the serializer to have access to the current request so that it can properly generate fully qualified URLs.\n\n\nYou can provide arbitrary additional context by passing a \ncontext\n argument when instantiating the serializer. For example:\n\n\nserializer = AccountSerializer(account, context={'request': request})\nserializer.data\n# {'id': 6, 'owner': u'denvercoder9', 'created': datetime.datetime(2013, 2, 12, 09, 44, 56, 678870), 'details': 'http://example.com/accounts/6/details'}\n\n\n\nThe context dictionary can be used within any serializer field logic, such as a custom \n.to_representation()\n method, by accessing the \nself.context\n attribute.\n\n\n\n\nModelSerializer\n\n\nOften you'll want serializer classes that map closely to Django model definitions.\n\n\nThe \nModelSerializer\n class provides a shortcut that lets you automatically create a \nSerializer\n class with fields that correspond to the Model fields.\n\n\nThe \nModelSerializer\n class is the same as a regular \nSerializer\n class, except that\n:\n\n\n\n\nIt will automatically generate a set of fields for you, based on the model.\n\n\nIt will automatically generate validators for the serializer, such as unique_together validators.\n\n\nIt includes simple default implementations of \n.create()\n and \n.update()\n.\n\n\n\n\nDeclaring a \nModelSerializer\n looks like this:\n\n\nclass AccountSerializer(serializers.ModelSerializer):\n class Meta:\n model = Account\n fields = ('id', 'account_name', 'users', 'created')\n\n\n\nBy default, all the model fields on the class will be mapped to a corresponding serializer fields.\n\n\nAny relationships such as foreign keys on the model will be mapped to \nPrimaryKeyRelatedField\n. Reverse relationships are not included by default unless explicitly included as specified in the \nserializer relations\n documentation.\n\n\nInspecting a \nModelSerializer\n\n\nSerializer classes generate helpful verbose representation strings, that allow you to fully inspect the state of their fields. This is particularly useful when working with \nModelSerializers\n where you want to determine what set of fields and validators are being automatically created for you.\n\n\nTo do so, open the Django shell, using \npython manage.py shell\n, then import the serializer class, instantiate it, and print the object representation\u2026\n\n\n>>> from myapp.serializers import AccountSerializer\n>>> serializer = AccountSerializer()\n>>> print(repr(serializer))\nAccountSerializer():\n id = IntegerField(label='ID', read_only=True)\n name = CharField(allow_blank=True, max_length=100, required=False)\n owner = PrimaryKeyRelatedField(queryset=User.objects.all())\n\n\n\nSpecifying which fields to include\n\n\nIf you only want a subset of the default fields to be used in a model serializer, you can do so using \nfields\n or \nexclude\n options, just as you would with a \nModelForm\n. It is strongly recommended that you explicitly set all fields that should be serialized using the \nfields\n attribute. This will make it less likely to result in unintentionally exposing data when your models change.\n\n\nFor example:\n\n\nclass AccountSerializer(serializers.ModelSerializer):\n class Meta:\n model = Account\n fields = ('id', 'account_name', 'users', 'created')\n\n\n\nYou can also set the \nfields\n attribute to the special value \n'__all__'\n to indicate that all fields in the model should be used.\n\n\nFor example:\n\n\nclass AccountSerializer(serializers.ModelSerializer):\n class Meta:\n model = Account\n fields = '__all__'\n\n\n\nYou can set the \nexclude\n attribute to a list of fields to be excluded from the serializer.\n\n\nFor example:\n\n\nclass AccountSerializer(serializers.ModelSerializer):\n class Meta:\n model = Account\n exclude = ('users',)\n\n\n\nIn the example above, if the \nAccount\n model had 3 fields \naccount_name\n, \nusers\n, and \ncreated\n, this will result in the fields \naccount_name\n and \ncreated\n to be serialized.\n\n\nThe names in the \nfields\n and \nexclude\n attributes will normally map to model fields on the model class.\n\n\nAlternatively names in the \nfields\n options can map to properties or methods which take no arguments that exist on the model class.\n\n\nSince version 3.3.0, it is \nmandatory\n to provide one of the attributes \nfields\n or \nexclude\n.\n\n\nSpecifying nested serialization\n\n\nThe default \nModelSerializer\n uses primary keys for relationships, but you can also easily generate nested representations using the \ndepth\n option:\n\n\nclass AccountSerializer(serializers.ModelSerializer):\n class Meta:\n model = Account\n fields = ('id', 'account_name', 'users', 'created')\n depth = 1\n\n\n\nThe \ndepth\n option should be set to an integer value that indicates the depth of relationships that should be traversed before reverting to a flat representation.\n\n\nIf you want to customize the way the serialization is done you'll need to define the field yourself.\n\n\nSpecifying fields explicitly\n\n\nYou can add extra fields to a \nModelSerializer\n or override the default fields by declaring fields on the class, just as you would for a \nSerializer\n class.\n\n\nclass AccountSerializer(serializers.ModelSerializer):\n url = serializers.CharField(source='get_absolute_url', read_only=True)\n groups = serializers.PrimaryKeyRelatedField(many=True)\n\n class Meta:\n model = Account\n\n\n\nExtra fields can correspond to any property or callable on the model.\n\n\nSpecifying read only fields\n\n\nYou may wish to specify multiple fields as read-only. Instead of adding each field explicitly with the \nread_only=True\n attribute, you may use the shortcut Meta option, \nread_only_fields\n.\n\n\nThis option should be a list or tuple of field names, and is declared as follows:\n\n\nclass AccountSerializer(serializers.ModelSerializer):\n class Meta:\n model = Account\n fields = ('id', 'account_name', 'users', 'created')\n read_only_fields = ('account_name',)\n\n\n\nModel fields which have \neditable=False\n set, and \nAutoField\n fields will be set to read-only by default, and do not need to be added to the \nread_only_fields\n option.\n\n\n\n\nNote\n: There is a special-case where a read-only field is part of a \nunique_together\n constraint at the model level. In this case the field is required by the serializer class in order to validate the constraint, but should also not be editable by the user.\n\n\nThe right way to deal with this is to specify the field explicitly on the serializer, providing both the \nread_only=True\n and \ndefault=\u2026\n keyword arguments.\n\n\nOne example of this is a read-only relation to the currently authenticated \nUser\n which is \nunique_together\n with another identifier. In this case you would declare the user field like so:\n\n\nuser = serializers.PrimaryKeyRelatedField(read_only=True, default=serializers.CurrentUserDefault())\n\n\n\nPlease review the \nValidators Documentation\n for details on the \nUniqueTogetherValidator\n and \nCurrentUserDefault\n classes.\n\n\n\n\nAdditional keyword arguments\n\n\nThere is also a shortcut allowing you to specify arbitrary additional keyword arguments on fields, using the \nextra_kwargs\n option. As in the case of \nread_only_fields\n, this means you do not need to explicitly declare the field on the serializer.\n\n\nThis option is a dictionary, mapping field names to a dictionary of keyword arguments. For example:\n\n\nclass CreateUserSerializer(serializers.ModelSerializer):\n class Meta:\n model = User\n fields = ('email', 'username', 'password')\n extra_kwargs = {'password': {'write_only': True}}\n\n def create(self, validated_data):\n user = User(\n email=validated_data['email'],\n username=validated_data['username']\n )\n user.set_password(validated_data['password'])\n user.save()\n return user\n\n\n\nRelational fields\n\n\nWhen serializing model instances, there are a number of different ways you might choose to represent relationships. The default representation for \nModelSerializer\n is to use the primary keys of the related instances.\n\n\nAlternative representations include serializing using hyperlinks, serializing complete nested representations, or serializing with a custom representation.\n\n\nFor full details see the \nserializer relations\n documentation.\n\n\nCustomizing field mappings\n\n\nThe ModelSerializer class also exposes an API that you can override in order to alter how serializer fields are automatically determined when instantiating the serializer.\n\n\nNormally if a \nModelSerializer\n does not generate the fields you need by default then you should either add them to the class explicitly, or simply use a regular \nSerializer\n 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.\n\n\n.serializer_field_mapping\n\n\nA 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.\n\n\n.serializer_related_field\n\n\nThis property should be the serializer field class, that is used for relational fields by default.\n\n\nFor \nModelSerializer\n this defaults to \nPrimaryKeyRelatedField\n.\n\n\nFor \nHyperlinkedModelSerializer\n this defaults to \nserializers.HyperlinkedRelatedField\n.\n\n\nserializer_url_field\n\n\nThe serializer field class that should be used for any \nurl\n field on the serializer.\n\n\nDefaults to \nserializers.HyperlinkedIdentityField\n\n\nserializer_choice_field\n\n\nThe serializer field class that should be used for any choice fields on the serializer.\n\n\nDefaults to \nserializers.ChoiceField\n\n\nThe field_class and field_kwargs API\n\n\nThe 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 \n(field_class, field_kwargs)\n.\n\n\n.build_standard_field(self, field_name, model_field)\n\n\nCalled to generate a serializer field that maps to a standard model field.\n\n\nThe default implementation returns a serializer class based on the \nserializer_field_mapping\n attribute.\n\n\n.build_relational_field(self, field_name, relation_info)\n\n\nCalled to generate a serializer field that maps to a relational model field.\n\n\nThe default implementation returns a serializer class based on the \nserializer_relational_field\n attribute.\n\n\nThe \nrelation_info\n argument is a named tuple, that contains \nmodel_field\n, \nrelated_model\n, \nto_many\n and \nhas_through_model\n properties.\n\n\n.build_nested_field(self, field_name, relation_info, nested_depth)\n\n\nCalled to generate a serializer field that maps to a relational model field, when the \ndepth\n option has been set.\n\n\nThe default implementation dynamically creates a nested serializer class based on either \nModelSerializer\n or \nHyperlinkedModelSerializer\n.\n\n\nThe \nnested_depth\n will be the value of the \ndepth\n option, minus one.\n\n\nThe \nrelation_info\n argument is a named tuple, that contains \nmodel_field\n, \nrelated_model\n, \nto_many\n and \nhas_through_model\n properties.\n\n\n.build_property_field(self, field_name, model_class)\n\n\nCalled to generate a serializer field that maps to a property or zero-argument method on the model class.\n\n\nThe default implementation returns a \nReadOnlyField\n class.\n\n\n.build_url_field(self, field_name, model_class)\n\n\nCalled to generate a serializer field for the serializer's own \nurl\n field. The default implementation returns a \nHyperlinkedIdentityField\n class.\n\n\n.build_unknown_field(self, field_name, model_class)\n\n\nCalled when the field name did not map to any model field or model property.\nThe default implementation raises an error, although subclasses may customize this behavior.\n\n\n\n\nHyperlinkedModelSerializer\n\n\nThe \nHyperlinkedModelSerializer\n class is similar to the \nModelSerializer\n class except that it uses hyperlinks to represent relationships, rather than primary keys.\n\n\nBy default the serializer will include a \nurl\n field instead of a primary key field.\n\n\nThe url field will be represented using a \nHyperlinkedIdentityField\n serializer field, and any relationships on the model will be represented using a \nHyperlinkedRelatedField\n serializer field.\n\n\nYou can explicitly include the primary key by adding it to the \nfields\n option, for example:\n\n\nclass AccountSerializer(serializers.HyperlinkedModelSerializer):\n class Meta:\n model = Account\n fields = ('url', 'id', 'account_name', 'users', 'created')\n\n\n\nAbsolute and relative URLs\n\n\nWhen instantiating a \nHyperlinkedModelSerializer\n you must include the current\n\nrequest\n in the serializer context, for example:\n\n\nserializer = AccountSerializer(queryset, context={'request': request})\n\n\n\nDoing so will ensure that the hyperlinks can include an appropriate hostname,\nso that the resulting representation uses fully qualified URLs, such as:\n\n\nhttp://api.example.com/accounts/1/\n\n\n\nRather than relative URLs, such as:\n\n\n/accounts/1/\n\n\n\nIf you \ndo\n want to use relative URLs, you should explicitly pass \n{'request': None}\n\nin the serializer context.\n\n\nHow hyperlinked views are determined\n\n\nThere needs to be a way of determining which views should be used for hyperlinking to model instances.\n\n\nBy default hyperlinks are expected to correspond to a view name that matches the style \n'{model_name}-detail'\n, and looks up the instance by a \npk\n keyword argument.\n\n\nYou can override a URL field view name and lookup field by using either, or both of, the \nview_name\n and \nlookup_field\n options in the \nextra_kwargs\n setting, like so:\n\n\nclass AccountSerializer(serializers.HyperlinkedModelSerializer):\n class Meta:\n model = Account\n fields = ('account_url', 'account_name', 'users', 'created')\n extra_kwargs = {\n 'url': {'view_name': 'accounts', 'lookup_field': 'account_name'},\n 'users': {'lookup_field': 'username'}\n }\n\n\n\nAlternatively you can set the fields on the serializer explicitly. For example:\n\n\nclass AccountSerializer(serializers.HyperlinkedModelSerializer):\n url = serializers.HyperlinkedIdentityField(\n view_name='accounts',\n lookup_field='slug'\n )\n users = serializers.HyperlinkedRelatedField(\n view_name='user-detail',\n lookup_field='username',\n many=True,\n read_only=True\n )\n\n class Meta:\n model = Account\n fields = ('url', 'account_name', 'users', 'created')\n\n\n\n\n\nTip\n: Properly matching together hyperlinked representations and your URL conf can sometimes be a bit fiddly. Printing the \nrepr\n of a \nHyperlinkedModelSerializer\n instance is a particularly useful way to inspect exactly which view names and lookup fields the relationships are expected to map too.\n\n\n\n\nChanging the URL field name\n\n\nThe name of the URL field defaults to 'url'. You can override this globally, by using the \nURL_FIELD_NAME\n setting.\n\n\n\n\nListSerializer\n\n\nThe \nListSerializer\n class provides the behavior for serializing and validating multiple objects at once. You won't \ntypically\n need to use \nListSerializer\n directly, but should instead simply pass \nmany=True\n when instantiating a serializer.\n\n\nWhen a serializer is instantiated and \nmany=True\n is passed, a \nListSerializer\n instance will be created. The serializer class then becomes a child of the parent \nListSerializer\n\n\nThe following argument can also be passed to a \nListSerializer\n field or a serializer that is passed \nmany=True\n:\n\n\nallow_empty\n\n\nThis is \nTrue\n by default, but can be set to \nFalse\n if you want to disallow empty lists as valid input.\n\n\nCustomizing \nListSerializer\n behavior\n\n\nThere \nare\n a few use cases when you might want to customize the \nListSerializer\n behavior. For example:\n\n\n\n\nYou want to provide particular validation of the lists, such as checking that one element does not conflict with another element in a list.\n\n\nYou want to customize the create or update behavior of multiple objects.\n\n\n\n\nFor these cases you can modify the class that is used when \nmany=True\n is passed, by using the \nlist_serializer_class\n option on the serializer \nMeta\n class.\n\n\nFor example:\n\n\nclass CustomListSerializer(serializers.ListSerializer):\n ...\n\nclass CustomSerializer(serializers.Serializer):\n ...\n class Meta:\n list_serializer_class = CustomListSerializer\n\n\n\nCustomizing multiple create\n\n\nThe default implementation for multiple object creation is to simply call \n.create()\n for each item in the list. If you want to customize this behavior, you'll need to customize the \n.create()\n method on \nListSerializer\n class that is used when \nmany=True\n is passed.\n\n\nFor example:\n\n\nclass BookListSerializer(serializers.ListSerializer):\n def create(self, validated_data):\n books = [Book(**item) for item in validated_data]\n return Book.objects.bulk_create(books)\n\nclass BookSerializer(serializers.Serializer):\n ...\n class Meta:\n list_serializer_class = BookListSerializer\n\n\n\nCustomizing multiple update\n\n\nBy default the \nListSerializer\n class does not support multiple updates. This is because the behavior that should be expected for insertions and deletions is ambiguous.\n\n\nTo support multiple updates you'll need to do so explicitly. When writing your multiple update code make sure to keep the following in mind:\n\n\n\n\nHow do you determine which instance should be updated for each item in the list of data?\n\n\nHow should insertions be handled? Are they invalid, or do they create new objects?\n\n\nHow should removals be handled? Do they imply object deletion, or removing a relationship? Should they be silently ignored, or are they invalid?\n\n\nHow should ordering be handled? Does changing the position of two items imply any state change or is it ignored?\n\n\n\n\nYou will need to add an explicit \nid\n field to the instance serializer. The default implicitly-generated \nid\n field is marked as \nread_only\n. This causes it to be removed on updates. Once you declare it explicitly, it will be available in the list serializer's \nupdate\n method.\n\n\nHere's an example of how you might choose to implement multiple updates:\n\n\nclass BookListSerializer(serializers.ListSerializer):\n def update(self, instance, validated_data):\n # Maps for id->instance and id->data item.\n book_mapping = {book.id: book for book in instance}\n data_mapping = {item['id']: item for item in validated_data}\n\n # Perform creations and updates.\n ret = []\n for book_id, data in data_mapping.items():\n book = book_mapping.get(book_id, None)\n if book is None:\n ret.append(self.child.create(data))\n else:\n ret.append(self.child.update(book, data))\n\n # Perform deletions.\n for book_id, book in book_mapping.items():\n if book_id not in data_mapping:\n book.delete()\n\n return ret\n\nclass BookSerializer(serializers.Serializer):\n # We need to identify elements in the list using their primary key,\n # so use a writable field here, rather than the default which would be read-only.\n id = serializers.IntegerField()\n ...\n\n class Meta:\n list_serializer_class = BookListSerializer\n\n\n\nIt is possible that a third party package may be included alongside the 3.1 release that provides some automatic support for multiple update operations, similar to the \nallow_add_remove\n behavior that was present in REST framework 2.\n\n\nCustomizing ListSerializer initialization\n\n\nWhen a serializer with \nmany=True\n is instantiated, we need to determine which arguments and keyword arguments should be passed to the \n.__init__()\n method for both the child \nSerializer\n class, and for the parent \nListSerializer\n class.\n\n\nThe default implementation is to pass all arguments to both classes, except for \nvalidators\n, and any custom keyword arguments, both of which are assumed to be intended for the child serializer class.\n\n\nOccasionally you might need to explicitly specify how the child and parent classes should be instantiated when \nmany=True\n is passed. You can do so by using the \nmany_init\n class method.\n\n\n @classmethod\n def many_init(cls, *args, **kwargs):\n # Instantiate the child serializer.\n kwargs['child'] = cls()\n # Instantiate the parent list serializer.\n return CustomListSerializer(*args, **kwargs)\n\n\n\n\n\nBaseSerializer\n\n\nBaseSerializer\n class that can be used to easily support alternative serialization and deserialization styles.\n\n\nThis class implements the same basic API as the \nSerializer\n class:\n\n\n\n\n.data\n - Returns the outgoing primitive representation.\n\n\n.is_valid()\n - Deserializes and validates incoming data.\n\n\n.validated_data\n - Returns the validated incoming data.\n\n\n.errors\n - Returns any errors during validation.\n\n\n.save()\n - Persists the validated data into an object instance.\n\n\n\n\nThere are four methods that can be overridden, depending on what functionality you want the serializer class to support:\n\n\n\n\n.to_representation()\n - Override this to support serialization, for read operations.\n\n\n.to_internal_value()\n - Override this to support deserialization, for write operations.\n\n\n.create()\n and \n.update()\n - Override either or both of these to support saving instances.\n\n\n\n\nBecause this class provides the same interface as the \nSerializer\n class, you can use it with the existing generic class-based views exactly as you would for a regular \nSerializer\n or \nModelSerializer\n.\n\n\nThe only difference you'll notice when doing so is the \nBaseSerializer\n classes will not generate HTML forms in the browsable API. This is because the data they return does not include all the field information that would allow each field to be rendered into a suitable HTML input.\n\n\nRead-only \nBaseSerializer\n classes\n\n\nTo implement a read-only serializer using the \nBaseSerializer\n class, we just need to override the \n.to_representation()\n method. Let's take a look at an example using a simple Django model:\n\n\nclass HighScore(models.Model):\n created = models.DateTimeField(auto_now_add=True)\n player_name = models.CharField(max_length=10)\n score = models.IntegerField()\n\n\n\nIt's simple to create a read-only serializer for converting \nHighScore\n instances into primitive data types.\n\n\nclass HighScoreSerializer(serializers.BaseSerializer):\n def to_representation(self, obj):\n return {\n 'score': obj.score,\n 'player_name': obj.player_name\n }\n\n\n\nWe can now use this class to serialize single \nHighScore\n instances:\n\n\n@api_view(['GET'])\ndef high_score(request, pk):\n instance = HighScore.objects.get(pk=pk)\n serializer = HighScoreSerializer(instance)\n return Response(serializer.data)\n\n\n\nOr use it to serialize multiple instances:\n\n\n@api_view(['GET'])\ndef all_high_scores(request):\n queryset = HighScore.objects.order_by('-score')\n serializer = HighScoreSerializer(queryset, many=True)\n return Response(serializer.data)\n\n\n\nRead-write \nBaseSerializer\n classes\n\n\nTo create a read-write serializer we first need to implement a \n.to_internal_value()\n method. This method returns the validated values that will be used to construct the object instance, and may raise a \nserializers.ValidationError\n if the supplied data is in an incorrect format.\n\n\nOnce you've implemented \n.to_internal_value()\n, the basic validation API will be available on the serializer, and you will be able to use \n.is_valid()\n, \n.validated_data\n and \n.errors\n.\n\n\nIf you want to also support \n.save()\n you'll need to also implement either or both of the \n.create()\n and \n.update()\n methods.\n\n\nHere's a complete example of our previous \nHighScoreSerializer\n, that's been updated to support both read and write operations.\n\n\nclass HighScoreSerializer(serializers.BaseSerializer):\n def to_internal_value(self, data):\n score = data.get('score')\n player_name = data.get('player_name')\n\n # Perform the data validation.\n if not score:\n raise serializers.ValidationError({\n 'score': 'This field is required.'\n })\n if not player_name:\n raise serializers.ValidationError({\n 'player_name': 'This field is required.'\n })\n if len(player_name) > 10:\n raise serializers.ValidationError({\n 'player_name': 'May not be more than 10 characters.'\n })\n\n # Return the validated values. This will be available as\n # the `.validated_data` property.\n return {\n 'score': int(score),\n 'player_name': player_name\n }\n\n def to_representation(self, obj):\n return {\n 'score': obj.score,\n 'player_name': obj.player_name\n }\n\n def create(self, validated_data):\n return HighScore.objects.create(**validated_data)\n\n\n\nCreating new base classes\n\n\nThe \nBaseSerializer\n class is also useful if you want to implement new generic serializer classes for dealing with particular serialization styles, or for integrating with alternative storage backends.\n\n\nThe following class is an example of a generic serializer that can handle coercing arbitrary objects into primitive representations.\n\n\nclass ObjectSerializer(serializers.BaseSerializer):\n \"\"\"\n A read-only serializer that coerces arbitrary complex objects\n into primitive representations.\n \"\"\"\n def to_representation(self, obj):\n for attribute_name in dir(obj):\n attribute = getattr(obj, attribute_name)\n if attribute_name('_'):\n # Ignore private attributes.\n pass\n elif hasattr(attribute, '__call__'):\n # Ignore methods and other callables.\n pass\n elif isinstance(attribute, (str, int, bool, float, type(None))):\n # Primitive types can be passed through unmodified.\n output[attribute_name] = attribute\n elif isinstance(attribute, list):\n # Recursively deal with items in lists.\n output[attribute_name] = [\n self.to_representation(item) for item in attribute\n ]\n elif isinstance(attribute, dict):\n # Recursively deal with items in dictionaries.\n output[attribute_name] = {\n str(key): self.to_representation(value)\n for key, value in attribute.items()\n }\n else:\n # Force anything else to its string representation.\n output[attribute_name] = str(attribute)\n\n\n\n\n\nAdvanced serializer usage\n\n\nOverriding serialization and deserialization behavior\n\n\nIf you need to alter the serialization or deserialization behavior of a serializer class, you can do so by overriding the \n.to_representation()\n or \n.to_internal_value()\n methods.\n\n\nSome reasons this might be useful include...\n\n\n\n\nAdding new behavior for new serializer base classes.\n\n\nModifying the behavior slightly for an existing class.\n\n\nImproving serialization performance for a frequently accessed API endpoint that returns lots of data.\n\n\n\n\nThe signatures for these methods are as follows:\n\n\n.to_representation(self, obj)\n\n\nTakes the object instance that requires serialization, and should return a primitive representation. Typically this means returning a structure of built-in Python datatypes. The exact types that can be handled will depend on the render classes you have configured for your API.\n\n\nMay be overridden in order modify the representation style. For example:\n\n\ndef to_representation(self, instance):\n \"\"\"Convert `username` to lowercase.\"\"\"\n ret = super().to_representation(instance)\n ret['username'] = ret['username'].lower()\n return ret\n\n\n\n.to_internal_value(self, data)\n\n\nTakes the unvalidated incoming data as input and should return the validated data that will be made available as \nserializer.validated_data\n. The return value will also be passed to the \n.create()\n or \n.update()\n methods if \n.save()\n is called on the serializer class.\n\n\nIf any of the validation fails, then the method should raise a \nserializers.ValidationError(errors)\n. The \nerrors\n argument should be a dictionary mapping field names (or \nsettings.NON_FIELD_ERRORS_KEY\n) to a list of error messages. If you don't need to alter deserialization behavior and instead want to provide object-level validation, it's recommended that you instead override the \n.validate()\n method.\n\n\nThe \ndata\n argument passed to this method will normally be the value of \nrequest.data\n, so the datatype it provides will depend on the parser classes you have configured for your API.\n\n\nSerializer Inheritance\n\n\nSimilar to Django forms, you can extend and reuse serializers through inheritance. This allows you to declare a common set of fields or methods on a parent class that can then be used in a number of serializers. For example,\n\n\nclass MyBaseSerializer(Serializer):\n my_field = serializers.CharField()\n\n def validate_my_field(self):\n ...\n\nclass MySerializer(MyBaseSerializer):\n ...\n\n\n\nLike Django's \nModel\n and \nModelForm\n classes, the inner \nMeta\n class on serializers does not implicitly inherit from it's parents' inner \nMeta\n classes. If you want the \nMeta\n class to inherit from a parent class you must do so explicitly. For example:\n\n\nclass AccountSerializer(MyBaseSerializer):\n class Meta(MyBaseSerializer.Meta):\n model = Account\n\n\n\nTypically we would recommend \nnot\n using inheritance on inner Meta classes, but instead declaring all options explicitly.\n\n\nAdditionally, the following caveats apply to serializer inheritance:\n\n\n\n\nNormal Python name resolution rules apply. If you have multiple base classes that declare a \nMeta\n inner class, only the first one will be used. This means the child\u2019s \nMeta\n, if it exists, otherwise the \nMeta\n of the first parent, etc.\n\n\n\n\nIt\u2019s possible to declaratively remove a \nField\n inherited from a parent class by setting the name to be \nNone\n on the subclass.\n\n\nclass MyBaseSerializer(ModelSerializer):\n my_field = serializers.CharField()\n\nclass MySerializer(MyBaseSerializer):\n my_field = None\n\n\n\nHowever, you can only use this technique to opt out from a field defined declaratively by a parent class; it won\u2019t prevent the \nModelSerializer\n from generating a default field. To opt-out from default fields, see \nSpecifying which fields to include\n.\n\n\n\n\n\n\nDynamically modifying fields\n\n\nOnce a serializer has been initialized, the dictionary of fields that are set on the serializer may be accessed using the \n.fields\n attribute. Accessing and modifying this attribute allows you to dynamically modify the serializer.\n\n\nModifying the \nfields\n argument directly allows you to do interesting things such as changing the arguments on serializer fields at runtime, rather than at the point of declaring the serializer.\n\n\nExample\n\n\nFor example, if you wanted to be able to set which fields should be used by a serializer at the point of initializing it, you could create a serializer class like so:\n\n\nclass DynamicFieldsModelSerializer(serializers.ModelSerializer):\n \"\"\"\n A ModelSerializer that takes an additional `fields` argument that\n controls which fields should be displayed.\n \"\"\"\n\n def __init__(self, *args, **kwargs):\n # Don't pass the 'fields' arg up to the superclass\n fields = kwargs.pop('fields', None)\n\n # Instantiate the superclass normally\n super(DynamicFieldsModelSerializer, self).__init__(*args, **kwargs)\n\n if fields is not None:\n # Drop any fields that are not specified in the `fields` argument.\n allowed = set(fields)\n existing = set(self.fields)\n for field_name in existing - allowed:\n self.fields.pop(field_name)\n\n\n\nThis would then allow you to do the following:\n\n\n>>> class UserSerializer(DynamicFieldsModelSerializer):\n>>> class Meta:\n>>> model = User\n>>> fields = ('id', 'username', 'email')\n>>>\n>>> print UserSerializer(user)\n{'id': 2, 'username': 'jonwatts', 'email': 'jon@example.com'}\n>>>\n>>> print UserSerializer(user, fields=('id', 'email'))\n{'id': 2, 'email': 'jon@example.com'}\n\n\n\nCustomizing the default fields\n\n\nREST framework 2 provided an API to allow developers to override how a \nModelSerializer\n class would automatically generate the default set of fields.\n\n\nThis API included the \n.get_field()\n, \n.get_pk_field()\n and other methods.\n\n\nBecause the serializers have been fundamentally redesigned with 3.0 this API no longer exists. You can still modify the fields that get created but you'll need to refer to the source code, and be aware that if the changes you make are against private bits of API then they may be subject to change.\n\n\n\n\nThird party packages\n\n\nThe following third party packages are also available.\n\n\nDjango REST marshmallow\n\n\nThe \ndjango-rest-marshmallow\n package provides an alternative implementation for serializers, using the python \nmarshmallow\n library. It exposes the same API as the REST framework serializers, and can be used as a drop-in replacement in some use-cases.\n\n\nSerpy\n\n\nThe \nserpy\n package is an alternative implementation for serializers that is built for speed. \nSerpy\n serializes complex datatypes to simple native types. The native types can be easily converted to JSON or any other format needed.\n\n\nMongoengineModelSerializer\n\n\nThe \ndjango-rest-framework-mongoengine\n package provides a \nMongoEngineModelSerializer\n serializer class that supports using MongoDB as the storage layer for Django REST framework.\n\n\nGeoFeatureModelSerializer\n\n\nThe \ndjango-rest-framework-gis\n package provides a \nGeoFeatureModelSerializer\n serializer class that supports GeoJSON both for read and write operations.\n\n\nHStoreSerializer\n\n\nThe \ndjango-rest-framework-hstore\n package provides an \nHStoreSerializer\n to support \ndjango-hstore\n \nDictionaryField\n model field and its \nschema-mode\n feature.\n\n\nDynamic REST\n\n\nThe \ndynamic-rest\n package extends the ModelSerializer and ModelViewSet interfaces, adding API query parameters for filtering, sorting, and including / excluding all fields and relationships defined by your serializers.\n\n\nDynamic Fields Mixin\n\n\nThe \ndrf-dynamic-fields\n package provides a mixin to dynamically limit the fields per serializer to a subset specified by an URL parameter.\n\n\nDRF FlexFields\n\n\nThe \ndrf-flex-fields\n package extends the ModelSerializer and ModelViewSet to provide commonly used functionality for dynamically setting fields and expanding primitive fields to nested models, both from URL parameters and your serializer class definitions.\n\n\nSerializer Extensions\n\n\nThe \ndjango-rest-framework-serializer-extensions\n\npackage provides a collection of tools to DRY up your serializers, by allowing\nfields to be defined on a per-view/request basis. Fields can be whitelisted,\nblacklisted and child serializers can be optionally expanded.\n\n\nHTML JSON Forms\n\n\nThe \nhtml-json-forms\n package provides an algorithm and serializer for processing \n\n submissions per the (inactive) \nHTML JSON Form specification\n. The serializer facilitates processing of arbitrarily nested JSON structures within HTML. For example, \n\n will be interpreted as \n{\"items\": [{\"id\": \"5\"}]}\n.\n\n\nDRF-Base64\n\n\nDRF-Base64\n provides a set of field and model serializers that handles the upload of base64-encoded files.\n\n\nQueryFields\n\n\ndjangorestframework-queryfields\n allows API clients to specify which fields will be sent in the response via inclusion/exclusion query parameters.\n\n\nDRF Writable Nested\n\n\nThe \ndrf-writable-nested\n package provides writable nested model serializer which allows to create/update models with nested related data.", "title": "Serializers" }, { @@ -1407,7 +1412,7 @@ }, { "location": "/api-guide/serializers/#object-level-validation", - "text": "To do any other validation that requires access to multiple fields, add a method called .validate() to your Serializer subclass. This method takes a single argument, which is a dictionary of field values. It should raise a ValidationError if necessary, or just return the validated values. For example: from rest_framework import serializers\n\nclass EventSerializer(serializers.Serializer):\n description = serializers.CharField(max_length=100)\n start = serializers.DateTimeField()\n finish = serializers.DateTimeField()\n\n def validate(self, data):\n \"\"\"\n Check that the start is before the stop.\n \"\"\"\n if data['start'] > data['finish']:\n raise serializers.ValidationError(\"finish must occur after start\")\n return data", + "text": "To do any other validation that requires access to multiple fields, add a method called .validate() to your Serializer subclass. This method takes a single argument, which is a dictionary of field values. It should raise a serializers.ValidationError if necessary, or just return the validated values. For example: from rest_framework import serializers\n\nclass EventSerializer(serializers.Serializer):\n description = serializers.CharField(max_length=100)\n start = serializers.DateTimeField()\n finish = serializers.DateTimeField()\n\n def validate(self, data):\n \"\"\"\n Check that the start is before the stop.\n \"\"\"\n if data['start'] > data['finish']:\n raise serializers.ValidationError(\"finish must occur after start\")\n return data", "title": "Object-level validation" }, { @@ -1632,7 +1637,7 @@ }, { "location": "/api-guide/serializers/#read-write-baseserializer-classes", - "text": "To create a read-write serializer we first need to implement a .to_internal_value() method. This method returns the validated values that will be used to construct the object instance, and may raise a ValidationError if the supplied data is in an incorrect format. Once you've implemented .to_internal_value() , the basic validation API will be available on the serializer, and you will be able to use .is_valid() , .validated_data and .errors . If you want to also support .save() you'll need to also implement either or both of the .create() and .update() methods. Here's a complete example of our previous HighScoreSerializer , that's been updated to support both read and write operations. class HighScoreSerializer(serializers.BaseSerializer):\n def to_internal_value(self, data):\n score = data.get('score')\n player_name = data.get('player_name')\n\n # Perform the data validation.\n if not score:\n raise ValidationError({\n 'score': 'This field is required.'\n })\n if not player_name:\n raise ValidationError({\n 'player_name': 'This field is required.'\n })\n if len(player_name) > 10:\n raise ValidationError({\n 'player_name': 'May not be more than 10 characters.'\n })\n\n # Return the validated values. This will be available as\n # the `.validated_data` property.\n return {\n 'score': int(score),\n 'player_name': player_name\n }\n\n def to_representation(self, obj):\n return {\n 'score': obj.score,\n 'player_name': obj.player_name\n }\n\n def create(self, validated_data):\n return HighScore.objects.create(**validated_data)", + "text": "To create a read-write serializer we first need to implement a .to_internal_value() method. This method returns the validated values that will be used to construct the object instance, and may raise a serializers.ValidationError if the supplied data is in an incorrect format. Once you've implemented .to_internal_value() , the basic validation API will be available on the serializer, and you will be able to use .is_valid() , .validated_data and .errors . If you want to also support .save() you'll need to also implement either or both of the .create() and .update() methods. Here's a complete example of our previous HighScoreSerializer , that's been updated to support both read and write operations. class HighScoreSerializer(serializers.BaseSerializer):\n def to_internal_value(self, data):\n score = data.get('score')\n player_name = data.get('player_name')\n\n # Perform the data validation.\n if not score:\n raise serializers.ValidationError({\n 'score': 'This field is required.'\n })\n if not player_name:\n raise serializers.ValidationError({\n 'player_name': 'This field is required.'\n })\n if len(player_name) > 10:\n raise serializers.ValidationError({\n 'player_name': 'May not be more than 10 characters.'\n })\n\n # Return the validated values. This will be available as\n # the `.validated_data` property.\n return {\n 'score': int(score),\n 'player_name': player_name\n }\n\n def to_representation(self, obj):\n return {\n 'score': obj.score,\n 'player_name': obj.player_name\n }\n\n def create(self, validated_data):\n return HighScore.objects.create(**validated_data)", "title": "Read-write BaseSerializer classes" }, { @@ -1752,7 +1757,7 @@ }, { "location": "/api-guide/fields/", - "text": "Serializer fields\n\n\n\n\nEach field in a Form class is responsible not only for validating data, but also for \"cleaning\" it \u2014 normalizing it to a consistent format.\n\n\n\u2014 \nDjango documentation\n\n\n\n\nSerializer fields handle converting between primitive values and internal datatypes. They also deal with validating input values, as well as retrieving and setting the values from their parent objects.\n\n\n\n\nNote:\n The serializer fields are declared in \nfields.py\n, but by convention you should import them using \nfrom rest_framework import serializers\n and refer to fields as \nserializers.\n.\n\n\n\n\nCore arguments\n\n\nEach serializer field class constructor takes at least these arguments. Some Field classes take additional, field-specific arguments, but the following should always be accepted:\n\n\nread_only\n\n\nRead-only fields are included in the API output, but should not be included in the input during create or update operations. Any 'read_only' fields that are incorrectly included in the serializer input will be ignored.\n\n\nSet this to \nTrue\n to ensure that the field is used when serializing a representation, but is not used when creating or updating an instance during deserialization.\n\n\nDefaults to \nFalse\n\n\nwrite_only\n\n\nSet this to \nTrue\n to ensure that the field may be used when updating or creating an instance, but is not included when serializing the representation.\n\n\nDefaults to \nFalse\n\n\nrequired\n\n\nNormally an error will be raised if a field is not supplied during deserialization.\nSet to false if this field is not required to be present during deserialization.\n\n\nSetting this to \nFalse\n 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.\n\n\nDefaults to \nTrue\n.\n\n\nallow_null\n\n\nNormally an error will be raised if \nNone\n is passed to a serializer field. Set this keyword argument to \nTrue\n if \nNone\n should be considered a valid value.\n\n\nNote that setting this argument to \nTrue\n will imply a default value of \nnull\n for serialization output, but does not imply a default for input deserialization.\n\n\nDefaults to \nFalse\n\n\ndefault\n\n\nIf set, this gives the default value that will be used for the field if no input value is supplied. If not set the default behaviour is to not populate the attribute at all.\n\n\nThe \ndefault\n is not applied during partial update operations. In the partial update case only fields that are provided in the incoming data will have a validated value returned.\n\n\nMay be set to a function or other callable, in which case the value will be evaluated each time it is used. When called, it will receive no arguments. If the callable has a \nset_context\n method, that will be called each time before getting the value with the field instance as only argument. This works the same way as for \nvalidators\n.\n\n\nWhen serializing the instance, default will be used if the the object attribute or dictionary key is not present in the instance.\n\n\nNote that setting a \ndefault\n value implies that the field is not required. Including both the \ndefault\n and \nrequired\n keyword arguments is invalid and will raise an error.\n\n\nsource\n\n\nThe name of the attribute that will be used to populate the field. May be a method that only takes a \nself\n argument, such as \nURLField(source='get_absolute_url')\n, or may use dotted notation to traverse attributes, such as \nEmailField(source='user.email')\n. When serializing fields with dotted notation, it may be necessary to provide a \ndefault\n value if any object is not present or is empty during attribute traversal.\n\n\nThe value \nsource='*'\n has a special meaning, and is used to indicate that the entire object should be passed through to the field. This can be useful for creating nested representations, or for fields which require access to the complete object in order to determine the output representation.\n\n\nDefaults to the name of the field.\n\n\nvalidators\n\n\nA list of validator functions which should be applied to the incoming field input, and which either raise a validation error or simply return. Validator functions should typically raise \nserializers.ValidationError\n, but Django's built-in \nValidationError\n is also supported for compatibility with validators defined in the Django codebase or third party Django packages.\n\n\nerror_messages\n\n\nA dictionary of error codes to error messages.\n\n\nlabel\n\n\nA short text string that may be used as the name of the field in HTML form fields or other descriptive elements.\n\n\nhelp_text\n\n\nA text string that may be used as a description of the field in HTML form fields or other descriptive elements.\n\n\ninitial\n\n\nA value that should be used for pre-populating the value of HTML form fields. You may pass a callable to it, just as\nyou may do with any regular Django \nField\n:\n\n\nimport datetime\nfrom rest_framework import serializers\nclass ExampleSerializer(serializers.Serializer):\n day = serializers.DateField(initial=datetime.date.today)\n\n\n\nstyle\n\n\nA dictionary of key-value pairs that can be used to control how renderers should render the field.\n\n\nTwo examples here are \n'input_type'\n and \n'base_template'\n:\n\n\n# Use for the input.\npassword = serializers.CharField(\n style={'input_type': 'password'}\n)\n\n# Use a radio input instead of a select input.\ncolor_channel = serializers.ChoiceField(\n choices=['red', 'green', 'blue'],\n style={'base_template': 'radio.html'}\n)\n\n\n\nFor more details see the \nHTML & Forms\n documentation.\n\n\n\n\nBoolean fields\n\n\nBooleanField\n\n\nA boolean representation.\n\n\nWhen using HTML encoded form input be aware that omitting a value will always be treated as setting a field to \nFalse\n, even if it has a \ndefault=True\n option specified. This is because HTML checkbox inputs represent the unchecked state by omitting the value, so REST framework treats omission as if it is an empty checkbox input.\n\n\nNote that default \nBooleanField\n instances will be generated with a \nrequired=False\n option (since Django \nmodels.BooleanField\n is always \nblank=True\n). If you want to change this behaviour explicitly declare the \nBooleanField\n on the serializer class.\n\n\nCorresponds to \ndjango.db.models.fields.BooleanField\n.\n\n\nSignature:\n \nBooleanField()\n\n\nNullBooleanField\n\n\nA boolean representation that also accepts \nNone\n as a valid value.\n\n\nCorresponds to \ndjango.db.models.fields.NullBooleanField\n.\n\n\nSignature:\n \nNullBooleanField()\n\n\n\n\nString fields\n\n\nCharField\n\n\nA text representation. Optionally validates the text to be shorter than \nmax_length\n and longer than \nmin_length\n.\n\n\nCorresponds to \ndjango.db.models.fields.CharField\n or \ndjango.db.models.fields.TextField\n.\n\n\nSignature:\n \nCharField(max_length=None, min_length=None, allow_blank=False, trim_whitespace=True)\n\n\n\n\nmax_length\n - Validates that the input contains no more than this number of characters.\n\n\nmin_length\n - Validates that the input contains no fewer than this number of characters.\n\n\nallow_blank\n - If set to \nTrue\n then the empty string should be considered a valid value. If set to \nFalse\n then the empty string is considered invalid and will raise a validation error. Defaults to \nFalse\n.\n\n\ntrim_whitespace\n - If set to \nTrue\n then leading and trailing whitespace is trimmed. Defaults to \nTrue\n.\n\n\n\n\nThe \nallow_null\n option is also available for string fields, although its usage is discouraged in favor of \nallow_blank\n. It is valid to set both \nallow_blank=True\n and \nallow_null=True\n, but doing so means that there will be two differing types of empty value permissible for string representations, which can lead to data inconsistencies and subtle application bugs.\n\n\nEmailField\n\n\nA text representation, validates the text to be a valid e-mail address.\n\n\nCorresponds to \ndjango.db.models.fields.EmailField\n\n\nSignature:\n \nEmailField(max_length=None, min_length=None, allow_blank=False)\n\n\nRegexField\n\n\nA text representation, that validates the given value matches against a certain regular expression.\n\n\nCorresponds to \ndjango.forms.fields.RegexField\n.\n\n\nSignature:\n \nRegexField(regex, max_length=None, min_length=None, allow_blank=False)\n\n\nThe mandatory \nregex\n argument may either be a string, or a compiled python regular expression object.\n\n\nUses Django's \ndjango.core.validators.RegexValidator\n for validation.\n\n\nSlugField\n\n\nA \nRegexField\n that validates the input against the pattern \n[a-zA-Z0-9_-]+\n.\n\n\nCorresponds to \ndjango.db.models.fields.SlugField\n.\n\n\nSignature:\n \nSlugField(max_length=50, min_length=None, allow_blank=False)\n\n\nURLField\n\n\nA \nRegexField\n that validates the input against a URL matching pattern. Expects fully qualified URLs of the form \nhttp:///\n.\n\n\nCorresponds to \ndjango.db.models.fields.URLField\n. Uses Django's \ndjango.core.validators.URLValidator\n for validation.\n\n\nSignature:\n \nURLField(max_length=200, min_length=None, allow_blank=False)\n\n\nUUIDField\n\n\nA field that ensures the input is a valid UUID string. The \nto_internal_value\n method will return a \nuuid.UUID\n instance. On output the field will return a string in the canonical hyphenated format, for example:\n\n\n\"de305d54-75b4-431b-adb2-eb6b9e546013\"\n\n\n\nSignature:\n \nUUIDField(format='hex_verbose')\n\n\n\n\nformat\n: Determines the representation format of the uuid value\n\n\n'hex_verbose'\n - The cannoncical hex representation, including hyphens: \n\"5ce0e9a5-5ffa-654b-cee0-1238041fb31a\"\n\n\n'hex'\n - The compact hex representation of the UUID, not including hyphens: \n\"5ce0e9a55ffa654bcee01238041fb31a\"\n\n\n'int'\n - A 128 bit integer representation of the UUID: \n\"123456789012312313134124512351145145114\"\n\n\n'urn'\n - RFC 4122 URN representation of the UUID: \n\"urn:uuid:5ce0e9a5-5ffa-654b-cee0-1238041fb31a\"\n\n Changing the \nformat\n parameters only affects representation values. All formats are accepted by \nto_internal_value\n\n\n\n\n\n\n\n\nFilePathField\n\n\nA field whose choices are limited to the filenames in a certain directory on the filesystem\n\n\nCorresponds to \ndjango.forms.fields.FilePathField\n.\n\n\nSignature:\n \nFilePathField(path, match=None, recursive=False, allow_files=True, allow_folders=False, required=None, **kwargs)\n\n\n\n\npath\n - The absolute filesystem path to a directory from which this FilePathField should get its choice.\n\n\nmatch\n - A regular expression, as a string, that FilePathField will use to filter filenames.\n\n\nrecursive\n - Specifies whether all subdirectories of path should be included. Default is \nFalse\n.\n\n\nallow_files\n - Specifies whether files in the specified location should be included. Default is \nTrue\n. Either this or \nallow_folders\n must be \nTrue\n.\n\n\nallow_folders\n - Specifies whether folders in the specified location should be included. Default is \nFalse\n. Either this or \nallow_files\n must be \nTrue\n.\n\n\n\n\nIPAddressField\n\n\nA field that ensures the input is a valid IPv4 or IPv6 string.\n\n\nCorresponds to \ndjango.forms.fields.IPAddressField\n and \ndjango.forms.fields.GenericIPAddressField\n.\n\n\nSignature\n: \nIPAddressField(protocol='both', unpack_ipv4=False, **options)\n\n\n\n\nprotocol\n Limits valid inputs to the specified protocol. Accepted values are 'both' (default), 'IPv4' or 'IPv6'. Matching is case insensitive.\n\n\nunpack_ipv4\n Unpacks IPv4 mapped addresses like ::ffff:192.0.2.1. If this option is enabled that address would be unpacked to 192.0.2.1. Default is disabled. Can only be used when protocol is set to 'both'.\n\n\n\n\n\n\nNumeric fields\n\n\nIntegerField\n\n\nAn integer representation.\n\n\nCorresponds to \ndjango.db.models.fields.IntegerField\n, \ndjango.db.models.fields.SmallIntegerField\n, \ndjango.db.models.fields.PositiveIntegerField\n and \ndjango.db.models.fields.PositiveSmallIntegerField\n.\n\n\nSignature\n: \nIntegerField(max_value=None, min_value=None)\n\n\n\n\nmax_value\n Validate that the number provided is no greater than this value.\n\n\nmin_value\n Validate that the number provided is no less than this value.\n\n\n\n\nFloatField\n\n\nA floating point representation.\n\n\nCorresponds to \ndjango.db.models.fields.FloatField\n.\n\n\nSignature\n: \nFloatField(max_value=None, min_value=None)\n\n\n\n\nmax_value\n Validate that the number provided is no greater than this value.\n\n\nmin_value\n Validate that the number provided is no less than this value.\n\n\n\n\nDecimalField\n\n\nA decimal representation, represented in Python by a \nDecimal\n instance.\n\n\nCorresponds to \ndjango.db.models.fields.DecimalField\n.\n\n\nSignature\n: \nDecimalField(max_digits, decimal_places, coerce_to_string=None, max_value=None, min_value=None)\n\n\n\n\nmax_digits\n The maximum number of digits allowed in the number. It must be either \nNone\n or an integer greater than or equal to \ndecimal_places\n.\n\n\ndecimal_places\n The number of decimal places to store with the number.\n\n\ncoerce_to_string\n Set to \nTrue\n if string values should be returned for the representation, or \nFalse\n if \nDecimal\n objects should be returned. Defaults to the same value as the \nCOERCE_DECIMAL_TO_STRING\n settings key, which will be \nTrue\n unless overridden. If \nDecimal\n objects are returned by the serializer, then the final output format will be determined by the renderer. Note that setting \nlocalize\n will force the value to \nTrue\n.\n\n\nmax_value\n Validate that the number provided is no greater than this value.\n\n\nmin_value\n Validate that the number provided is no less than this value.\n\n\nlocalize\n Set to \nTrue\n to enable localization of input and output based on the current locale. This will also force \ncoerce_to_string\n to \nTrue\n. Defaults to \nFalse\n. Note that data formatting is enabled if you have set \nUSE_L10N=True\n in your settings file.\n\n\nrounding\n Sets the rounding mode used when quantising to the configured precision. Valid values are \ndecimal\n module rounding modes\n. Defaults to \nNone\n.\n\n\n\n\nExample usage\n\n\nTo validate numbers up to 999 with a resolution of 2 decimal places, you would use:\n\n\nserializers.DecimalField(max_digits=5, decimal_places=2)\n\n\n\nAnd to validate numbers up to anything less than one billion with a resolution of 10 decimal places:\n\n\nserializers.DecimalField(max_digits=19, decimal_places=10)\n\n\n\nThis field also takes an optional argument, \ncoerce_to_string\n. If set to \nTrue\n the representation will be output as a string. If set to \nFalse\n the representation will be left as a \nDecimal\n instance and the final representation will be determined by the renderer.\n\n\nIf unset, this will default to the same value as the \nCOERCE_DECIMAL_TO_STRING\n setting, which is \nTrue\n unless set otherwise.\n\n\n\n\nDate and time fields\n\n\nDateTimeField\n\n\nA date and time representation.\n\n\nCorresponds to \ndjango.db.models.fields.DateTimeField\n.\n\n\nSignature:\n \nDateTimeField(format=api_settings.DATETIME_FORMAT, input_formats=None)\n\n\n\n\nformat\n - A string representing the output format. If not specified, this defaults to the same value as the \nDATETIME_FORMAT\n settings key, which will be \n'iso-8601'\n unless set. Setting to a format string indicates that \nto_representation\n return values should be coerced to string output. Format strings are described below. Setting this value to \nNone\n indicates that Python \ndatetime\n objects should be returned by \nto_representation\n. In this case the datetime encoding will be determined by the renderer.\n\n\ninput_formats\n - A list of strings representing the input formats which may be used to parse the date. If not specified, the \nDATETIME_INPUT_FORMATS\n setting will be used, which defaults to \n['iso-8601']\n.\n\n\n\n\nDateTimeField\n format strings.\n\n\nFormat strings may either be \nPython strftime formats\n which explicitly specify the format, or the special string \n'iso-8601'\n, which indicates that \nISO 8601\n style datetimes should be used. (eg \n'2013-01-29T12:34:56.000000Z'\n)\n\n\nWhen a value of \nNone\n is used for the format \ndatetime\n objects will be returned by \nto_representation\n and the final output representation will determined by the renderer class.\n\n\nauto_now_add\n model fields.\nauto_now\n and \n\n\nWhen using \nModelSerializer\n or \nHyperlinkedModelSerializer\n, note that any model fields with \nauto_now=True\n or \nauto_now_add=True\n will use serializer fields that are \nread_only=True\n by default.\n\n\nIf you want to override this behavior, you'll need to declare the \nDateTimeField\n explicitly on the serializer. For example:\n\n\nclass CommentSerializer(serializers.ModelSerializer):\n created = serializers.DateTimeField()\n\n class Meta:\n model = Comment\n\n\n\nDateField\n\n\nA date representation.\n\n\nCorresponds to \ndjango.db.models.fields.DateField\n\n\nSignature:\n \nDateField(format=api_settings.DATE_FORMAT, input_formats=None)\n\n\n\n\nformat\n - A string representing the output format. If not specified, this defaults to the same value as the \nDATE_FORMAT\n settings key, which will be \n'iso-8601'\n unless set. Setting to a format string indicates that \nto_representation\n return values should be coerced to string output. Format strings are described below. Setting this value to \nNone\n indicates that Python \ndate\n objects should be returned by \nto_representation\n. In this case the date encoding will be determined by the renderer.\n\n\ninput_formats\n - A list of strings representing the input formats which may be used to parse the date. If not specified, the \nDATE_INPUT_FORMATS\n setting will be used, which defaults to \n['iso-8601']\n.\n\n\n\n\nDateField\n format strings\n\n\nFormat strings may either be \nPython strftime formats\n which explicitly specify the format, or the special string \n'iso-8601'\n, which indicates that \nISO 8601\n style dates should be used. (eg \n'2013-01-29'\n)\n\n\nTimeField\n\n\nA time representation.\n\n\nCorresponds to \ndjango.db.models.fields.TimeField\n\n\nSignature:\n \nTimeField(format=api_settings.TIME_FORMAT, input_formats=None)\n\n\n\n\nformat\n - A string representing the output format. If not specified, this defaults to the same value as the \nTIME_FORMAT\n settings key, which will be \n'iso-8601'\n unless set. Setting to a format string indicates that \nto_representation\n return values should be coerced to string output. Format strings are described below. Setting this value to \nNone\n indicates that Python \ntime\n objects should be returned by \nto_representation\n. In this case the time encoding will be determined by the renderer.\n\n\ninput_formats\n - A list of strings representing the input formats which may be used to parse the date. If not specified, the \nTIME_INPUT_FORMATS\n setting will be used, which defaults to \n['iso-8601']\n.\n\n\n\n\nTimeField\n format strings\n\n\nFormat strings may either be \nPython strftime formats\n which explicitly specify the format, or the special string \n'iso-8601'\n, which indicates that \nISO 8601\n style times should be used. (eg \n'12:34:56.000000'\n)\n\n\nDurationField\n\n\nA Duration representation.\nCorresponds to \ndjango.db.models.fields.DurationField\n\n\nThe \nvalidated_data\n for these fields will contain a \ndatetime.timedelta\n instance.\nThe representation is a string following this format \n'[DD] [HH:[MM:]]ss[.uuuuuu]'\n.\n\n\nSignature:\n \nDurationField()\n\n\n\n\nChoice selection fields\n\n\nChoiceField\n\n\nA field that can accept a value out of a limited set of choices.\n\n\nUsed by \nModelSerializer\n to automatically generate fields if the corresponding model field includes a \nchoices=\u2026\n argument.\n\n\nSignature:\n \nChoiceField(choices)\n\n\n\n\nchoices\n - A list of valid values, or a list of \n(key, display_name)\n tuples.\n\n\nallow_blank\n - If set to \nTrue\n then the empty string should be considered a valid value. If set to \nFalse\n then the empty string is considered invalid and will raise a validation error. Defaults to \nFalse\n.\n\n\nhtml_cutoff\n - If set this will be the maximum number of choices that will be displayed by a HTML select drop down. Can be used to ensure that automatically generated ChoiceFields with very large possible selections do not prevent a template from rendering. Defaults to \nNone\n.\n\n\nhtml_cutoff_text\n - If set this will display a textual indicator if the maximum number of items have been cutoff in an HTML select drop down. Defaults to \n\"More than {count} items\u2026\"\n\n\n\n\nBoth the \nallow_blank\n and \nallow_null\n are valid options on \nChoiceField\n, although it is highly recommended that you only use one and not both. \nallow_blank\n should be preferred for textual choices, and \nallow_null\n should be preferred for numeric or other non-textual choices.\n\n\nMultipleChoiceField\n\n\nA field that can accept a set of zero, one or many values, chosen from a limited set of choices. Takes a single mandatory argument. \nto_internal_value\n returns a \nset\n containing the selected values.\n\n\nSignature:\n \nMultipleChoiceField(choices)\n\n\n\n\nchoices\n - A list of valid values, or a list of \n(key, display_name)\n tuples.\n\n\nallow_blank\n - If set to \nTrue\n then the empty string should be considered a valid value. If set to \nFalse\n then the empty string is considered invalid and will raise a validation error. Defaults to \nFalse\n.\n\n\nhtml_cutoff\n - If set this will be the maximum number of choices that will be displayed by a HTML select drop down. Can be used to ensure that automatically generated ChoiceFields with very large possible selections do not prevent a template from rendering. Defaults to \nNone\n.\n\n\nhtml_cutoff_text\n - If set this will display a textual indicator if the maximum number of items have been cutoff in an HTML select drop down. Defaults to \n\"More than {count} items\u2026\"\n\n\n\n\nAs with \nChoiceField\n, both the \nallow_blank\n and \nallow_null\n options are valid, although it is highly recommended that you only use one and not both. \nallow_blank\n should be preferred for textual choices, and \nallow_null\n should be preferred for numeric or other non-textual choices.\n\n\n\n\nFile upload fields\n\n\nParsers and file uploads.\n\n\nThe \nFileField\n and \nImageField\n classes are only suitable for use with \nMultiPartParser\n or \nFileUploadParser\n. Most parsers, such as e.g. JSON don't support file uploads.\nDjango's regular \nFILE_UPLOAD_HANDLERS\n are used for handling uploaded files.\n\n\nFileField\n\n\nA file representation. Performs Django's standard FileField validation.\n\n\nCorresponds to \ndjango.forms.fields.FileField\n.\n\n\nSignature:\n \nFileField(max_length=None, allow_empty_file=False, use_url=UPLOADED_FILES_USE_URL)\n\n\n\n\nmax_length\n - Designates the maximum length for the file name.\n\n\nallow_empty_file\n - Designates if empty files are allowed.\n\n\nuse_url\n - If set to \nTrue\n then URL string values will be used for the output representation. If set to \nFalse\n then filename string values will be used for the output representation. Defaults to the value of the \nUPLOADED_FILES_USE_URL\n settings key, which is \nTrue\n unless set otherwise.\n\n\n\n\nImageField\n\n\nAn image representation. Validates the uploaded file content as matching a known image format.\n\n\nCorresponds to \ndjango.forms.fields.ImageField\n.\n\n\nSignature:\n \nImageField(max_length=None, allow_empty_file=False, use_url=UPLOADED_FILES_USE_URL)\n\n\n\n\nmax_length\n - Designates the maximum length for the file name.\n\n\nallow_empty_file\n - Designates if empty files are allowed.\n\n\nuse_url\n - If set to \nTrue\n then URL string values will be used for the output representation. If set to \nFalse\n then filename string values will be used for the output representation. Defaults to the value of the \nUPLOADED_FILES_USE_URL\n settings key, which is \nTrue\n unless set otherwise.\n\n\n\n\nRequires either the \nPillow\n package or \nPIL\n package. The \nPillow\n package is recommended, as \nPIL\n is no longer actively maintained.\n\n\n\n\nComposite fields\n\n\nListField\n\n\nA field class that validates a list of objects.\n\n\nSignature\n: \nListField(child=, min_length=None, max_length=None)\n\n\n\n\nchild\n - 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.\n\n\nmin_length\n - Validates that the list contains no fewer than this number of elements.\n\n\nmax_length\n - Validates that the list contains no more than this number of elements.\n\n\n\n\nFor example, to validate a list of integers you might use something like the following:\n\n\nscores = serializers.ListField(\n child=serializers.IntegerField(min_value=0, max_value=100)\n)\n\n\n\nThe \nListField\n class also supports a declarative style that allows you to write reusable list field classes.\n\n\nclass StringListField(serializers.ListField):\n child = serializers.CharField()\n\n\n\nWe can now reuse our custom \nStringListField\n class throughout our application, without having to provide a \nchild\n argument to it.\n\n\nDictField\n\n\nA field class that validates a dictionary of objects. The keys in \nDictField\n are always assumed to be string values.\n\n\nSignature\n: \nDictField(child=)\n\n\n\n\nchild\n - 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.\n\n\n\n\nFor example, to create a field that validates a mapping of strings to strings, you would write something like this:\n\n\ndocument = DictField(child=CharField())\n\n\n\nYou can also use the declarative style, as with \nListField\n. For example:\n\n\nclass DocumentField(DictField):\n child = CharField()\n\n\n\nJSONField\n\n\nA field class that validates that the incoming data structure consists of valid JSON primitives. In its alternate binary mode, it will represent and validate JSON-encoded binary strings.\n\n\nSignature\n: \nJSONField(binary)\n\n\n\n\nbinary\n - If set to \nTrue\n then the field will output and validate a JSON encoded string, rather than a primitive data structure. Defaults to \nFalse\n.\n\n\n\n\n\n\nMiscellaneous fields\n\n\nReadOnlyField\n\n\nA field class that simply returns the value of the field without modification.\n\n\nThis field is used by default with \nModelSerializer\n when including field names that relate to an attribute rather than a model field.\n\n\nSignature\n: \nReadOnlyField()\n\n\nFor example, if \nhas_expired\n was a property on the \nAccount\n model, then the following serializer would automatically generate it as a \nReadOnlyField\n:\n\n\nclass AccountSerializer(serializers.ModelSerializer):\n class Meta:\n model = Account\n fields = ('id', 'account_name', 'has_expired')\n\n\n\nHiddenField\n\n\nA field class that does not take a value based on user input, but instead takes its value from a default value or callable.\n\n\nSignature\n: \nHiddenField()\n\n\nFor example, to include a field that always provides the current time as part of the serializer validated data, you would use the following:\n\n\nmodified = serializers.HiddenField(default=timezone.now)\n\n\n\nThe \nHiddenField\n class is usually only needed if you have some validation that needs to run based on some pre-provided field values, but you do not want to expose all of those fields to the end user.\n\n\nFor further examples on \nHiddenField\n see the \nvalidators\n documentation.\n\n\nModelField\n\n\nA generic field that can be tied to any arbitrary model field. The \nModelField\n class delegates the task of serialization/deserialization to its associated model field. This field can be used to create serializer fields for custom model fields, without having to create a new custom serializer field.\n\n\nThis field is used by \nModelSerializer\n to correspond to custom model field classes.\n\n\nSignature:\n \nModelField(model_field=)\n\n\nThe \nModelField\n class is generally intended for internal use, but can be used by your API if needed. In order to properly instantiate a \nModelField\n, it must be passed a field that is attached to an instantiated model. For example: \nModelField(model_field=MyModel()._meta.get_field('custom_field'))\n\n\nSerializerMethodField\n\n\nThis is a read-only field. It gets its value by calling a method on the serializer class it is attached to. It can be used to add any sort of data to the serialized representation of your object.\n\n\nSignature\n: \nSerializerMethodField(method_name=None)\n\n\n\n\nmethod_name\n - The name of the method on the serializer to be called. If not included this defaults to \nget_\n.\n\n\n\n\nThe serializer method referred to by the \nmethod_name\n argument should accept a single argument (in addition to \nself\n), which is the object being serialized. It should return whatever you want to be included in the serialized representation of the object. For example:\n\n\nfrom django.contrib.auth.models import User\nfrom django.utils.timezone import now\nfrom rest_framework import serializers\n\nclass UserSerializer(serializers.ModelSerializer):\n days_since_joined = serializers.SerializerMethodField()\n\n class Meta:\n model = User\n\n def get_days_since_joined(self, obj):\n return (now() - obj.date_joined).days\n\n\n\n\n\nCustom fields\n\n\nIf you want to create a custom field, you'll need to subclass \nField\n and then override either one or both of the \n.to_representation()\n and \n.to_internal_value()\n methods. These two methods are used to convert between the initial datatype, and a primitive, serializable datatype. Primitive datatypes will typically be any of a number, string, boolean, \ndate\n/\ntime\n/\ndatetime\n or \nNone\n. They may also be any list or dictionary like object that only contains other primitive objects. Other types might be supported, depending on the renderer that you are using.\n\n\nThe \n.to_representation()\n method is called to convert the initial datatype into a primitive, serializable datatype.\n\n\nThe \nto_internal_value()\n method is called to restore a primitive datatype into its internal python representation. This method should raise a \nserializers.ValidationError\n if the data is invalid.\n\n\nNote that the \nWritableField\n class that was present in version 2.x no longer exists. You should subclass \nField\n and override \nto_internal_value()\n if the field supports data input.\n\n\nExamples\n\n\nA Basic Custom Field\n\n\nLet's look at an example of serializing a class that represents an RGB color value:\n\n\nclass Color(object):\n \"\"\"\n A color represented in the RGB colorspace.\n \"\"\"\n def __init__(self, red, green, blue):\n assert(red >= 0 and green >= 0 and blue >= 0)\n assert(red < 256 and green < 256 and blue < 256)\n self.red, self.green, self.blue = red, green, blue\n\nclass ColorField(serializers.Field):\n \"\"\"\n Color objects are serialized into 'rgb(#, #, #)' notation.\n \"\"\"\n def to_representation(self, obj):\n return \"rgb(%d, %d, %d)\" % (obj.red, obj.green, obj.blue)\n\n def to_internal_value(self, data):\n data = data.strip('rgb(').rstrip(')')\n red, green, blue = [int(col) for col in data.split(',')]\n return Color(red, green, blue)\n\n\n\nBy default field values are treated as mapping to an attribute on the object. If you need to customize how the field value is accessed and set you need to override \n.get_attribute()\n and/or \n.get_value()\n.\n\n\nAs an example, let's create a field that can be used to represent the class name of the object being serialized:\n\n\nclass ClassNameField(serializers.Field):\n def get_attribute(self, obj):\n # We pass the object instance onto `to_representation`,\n # not just the field attribute.\n return obj\n\n def to_representation(self, obj):\n \"\"\"\n Serialize the object's class name.\n \"\"\"\n return obj.__class__.__name__\n\n\n\nRaising validation errors\n\n\nOur \nColorField\n class above currently does not perform any data validation.\nTo indicate invalid data, we should raise a \nserializers.ValidationError\n, like so:\n\n\ndef to_internal_value(self, data):\n if not isinstance(data, six.text_type):\n msg = 'Incorrect type. Expected a string, but got %s'\n raise ValidationError(msg % type(data).__name__)\n\n if not re.match(r'^rgb\\([0-9]+,[0-9]+,[0-9]+\\)$', data):\n raise ValidationError('Incorrect format. Expected `rgb(#,#,#)`.')\n\n data = data.strip('rgb(').rstrip(')')\n red, green, blue = [int(col) for col in data.split(',')]\n\n if any([col > 255 or col < 0 for col in (red, green, blue)]):\n raise ValidationError('Value out of range. Must be between 0 and 255.')\n\n return Color(red, green, blue)\n\n\n\nThe \n.fail()\n method is a shortcut for raising \nValidationError\n that takes a message string from the \nerror_messages\n dictionary. For example:\n\n\ndefault_error_messages = {\n 'incorrect_type': 'Incorrect type. Expected a string, but got {input_type}',\n 'incorrect_format': 'Incorrect format. Expected `rgb(#,#,#)`.',\n 'out_of_range': 'Value out of range. Must be between 0 and 255.'\n}\n\ndef to_internal_value(self, data):\n if not isinstance(data, six.text_type):\n self.fail('incorrect_type', input_type=type(data).__name__)\n\n if not re.match(r'^rgb\\([0-9]+,[0-9]+,[0-9]+\\)$', data):\n self.fail('incorrect_format')\n\n data = data.strip('rgb(').rstrip(')')\n red, green, blue = [int(col) for col in data.split(',')]\n\n if any([col > 255 or col < 0 for col in (red, green, blue)]):\n self.fail('out_of_range')\n\n return Color(red, green, blue)\n\n\n\nThis style keeps your error messages cleaner and more separated from your code, and should be preferred.\n\n\nUsing \nsource='*'\n\n\nHere we'll take an example of a \nflat\n \nDataPoint\n model with \nx_coordinate\n and \ny_coordinate\n attributes.\n\n\nclass DataPoint(models.Model):\n label = models.CharField(max_length=50)\n x_coordinate = models.SmallIntegerField()\n y_coordinate = models.SmallIntegerField()\n\n\n\nUsing a custom field and \nsource='*'\n we can provide a nested representation of\nthe coordinate pair:\n\n\nclass CoordinateField(serializers.Field):\n\n def to_representation(self, obj):\n ret = {\n \"x\": obj.x_coordinate,\n \"y\": obj.y_coordinate\n }\n return ret\n\n def to_internal_value(self, data):\n ret = {\n \"x_coordinate\": data[\"x\"],\n \"y_coordinate\": data[\"y\"],\n }\n return ret\n\n\nclass DataPointSerializer(serializers.ModelSerializer):\n coordinates = CoordinateField(source='*')\n\n class Meta:\n model = DataPoint\n fields = ['label', 'coordinates']\n\n\n\nNote that this example doesn't handle validation. Partly for that reason, in a\nreal project, the coordinate nesting might be better handled with a nested serialiser\nusing \nsource='*'\n, with two \nIntegerField\n instances, each with their own \nsource\n\npointing to the relevant field.\n\n\nThe key points from the example, though, are:\n\n\n\n\n\n\nto_representation\n is passed the entire \nDataPoint\n object and must map from that\nto the desired output.\n\n\n>>> instance = DataPoint(label='Example', x_coordinate=1, y_coordinate=2)\n>>> out_serializer = DataPointSerializer(instance)\n>>> out_serializer.data\nReturnDict([('label', 'testing'), ('coordinates', {'x': 1, 'y': 2})])\n\n\n\n\n\n\n\nUnless our field is to be read-only, \nto_internal_value\n must map back to a dict\nsuitable for updating our target object. With \nsource='*'\n, the return from\n\nto_internal_value\n will update the root validated data dictionary, rather than a single key.\n\n\n>>> data = {\n... \"label\": \"Second Example\",\n... \"coordinates\": {\n... \"x\": 3,\n... \"y\": 4,\n... }\n... }\n>>> in_serializer = DataPointSerializer(data=data)\n>>> in_serializer.is_valid()\nTrue\n>>> in_serializer.validated_data\nOrderedDict([('label', 'Second Example'),\n ('y_coordinate', 4),\n ('x_coordinate', 3)])\n\n\n\n\n\n\n\nFor completeness lets do the same thing again but with the nested serialiser\napproach suggested above:\n\n\nclass NestedCoordinateSerializer(serializers.Serializer):\n x = serializers.IntegerField(source='x_coordinate')\n y = serializers.IntegerField(source='y_coordinate')\n\n\nclass DataPointSerializer(serializers.ModelSerializer):\n coordinates = NestedCoordinateSerializer(source='*')\n\n class Meta:\n model = DataPoint\n fields = ['label', 'coordinates']\n\n\n\nHere the mapping between the target and source attribute pairs (\nx\n and\n\nx_coordinate\n, \ny\n and \ny_coordinate\n) is handled in the \nIntegerField\n\ndeclarations. It's our \nNestedCoordinateSerializer\n that takes \nsource='*'\n.\n\n\nOur new \nDataPointSerializer\n exhibits the same behaviour as the custom field\napproach.\n\n\nSerialising:\n\n\n>>> out_serializer = DataPointSerializer(instance)\n>>> out_serializer.data\nReturnDict([('label', 'testing'),\n ('coordinates', OrderedDict([('x', 1), ('y', 2)]))])\n\n\n\nDeserialising:\n\n\n>>> in_serializer = DataPointSerializer(data=data)\n>>> in_serializer.is_valid()\nTrue\n>>> in_serializer.validated_data\nOrderedDict([('label', 'still testing'),\n ('x_coordinate', 3),\n ('y_coordinate', 4)])\n\n\n\nBut we also get the built-in validation for free:\n\n\n>>> invalid_data = {\n... \"label\": \"still testing\",\n... \"coordinates\": {\n... \"x\": 'a',\n... \"y\": 'b',\n... }\n... }\n>>> invalid_serializer = DataPointSerializer(data=invalid_data)\n>>> invalid_serializer.is_valid()\nFalse\n>>> invalid_serializer.errors\nReturnDict([('coordinates',\n {'x': ['A valid integer is required.'],\n 'y': ['A valid integer is required.']})])\n\n\n\nFor this reason, the nested serialiser approach would be the first to try. You\nwould use the custom field approach when the nested serialiser becomes infeasible\nor overly complex.\n\n\nThird party packages\n\n\nThe following third party packages are also available.\n\n\nDRF Compound Fields\n\n\nThe \ndrf-compound-fields\n package provides \"compound\" serializer fields, such as lists of simple values, which can be described by other fields rather than serializers with the \nmany=True\n option. Also provided are fields for typed dictionaries and values that can be either a specific type or a list of items of that type.\n\n\nDRF Extra Fields\n\n\nThe \ndrf-extra-fields\n package provides extra serializer fields for REST framework, including \nBase64ImageField\n and \nPointField\n classes.\n\n\ndjangrestframework-recursive\n\n\nthe \ndjangorestframework-recursive\n package provides a \nRecursiveField\n for serializing and deserializing recursive structures\n\n\ndjango-rest-framework-gis\n\n\nThe \ndjango-rest-framework-gis\n package provides geographic addons for django rest framework like a \nGeometryField\n field and a GeoJSON serializer.\n\n\ndjango-rest-framework-hstore\n\n\nThe \ndjango-rest-framework-hstore\n package provides an \nHStoreField\n to support \ndjango-hstore\n \nDictionaryField\n model field.", + "text": "Serializer fields\n\n\n\n\nEach field in a Form class is responsible not only for validating data, but also for \"cleaning\" it \u2014 normalizing it to a consistent format.\n\n\n\u2014 \nDjango documentation\n\n\n\n\nSerializer fields handle converting between primitive values and internal datatypes. They also deal with validating input values, as well as retrieving and setting the values from their parent objects.\n\n\n\n\nNote:\n The serializer fields are declared in \nfields.py\n, but by convention you should import them using \nfrom rest_framework import serializers\n and refer to fields as \nserializers.\n.\n\n\n\n\nCore arguments\n\n\nEach serializer field class constructor takes at least these arguments. Some Field classes take additional, field-specific arguments, but the following should always be accepted:\n\n\nread_only\n\n\nRead-only fields are included in the API output, but should not be included in the input during create or update operations. Any 'read_only' fields that are incorrectly included in the serializer input will be ignored.\n\n\nSet this to \nTrue\n to ensure that the field is used when serializing a representation, but is not used when creating or updating an instance during deserialization.\n\n\nDefaults to \nFalse\n\n\nwrite_only\n\n\nSet this to \nTrue\n to ensure that the field may be used when updating or creating an instance, but is not included when serializing the representation.\n\n\nDefaults to \nFalse\n\n\nrequired\n\n\nNormally an error will be raised if a field is not supplied during deserialization.\nSet to false if this field is not required to be present during deserialization.\n\n\nSetting this to \nFalse\n 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.\n\n\nDefaults to \nTrue\n.\n\n\ndefault\n\n\nIf set, this gives the default value that will be used for the field if no input value is supplied. If not set the default behaviour is to not populate the attribute at all.\n\n\nThe \ndefault\n is not applied during partial update operations. In the partial update case only fields that are provided in the incoming data will have a validated value returned.\n\n\nMay be set to a function or other callable, in which case the value will be evaluated each time it is used. When called, it will receive no arguments. If the callable has a \nset_context\n method, that will be called each time before getting the value with the field instance as only argument. This works the same way as for \nvalidators\n.\n\n\nWhen serializing the instance, default will be used if the the object attribute or dictionary key is not present in the instance.\n\n\nNote that setting a \ndefault\n value implies that the field is not required. Including both the \ndefault\n and \nrequired\n keyword arguments is invalid and will raise an error.\n\n\nallow_null\n\n\nNormally an error will be raised if \nNone\n is passed to a serializer field. Set this keyword argument to \nTrue\n if \nNone\n should be considered a valid value.\n\n\nNote that, without an explicit \ndefault\n, setting this argument to \nTrue\n will imply a \ndefault\n value of \nnull\n for serialization output, but does not imply a default for input deserialization.\n\n\nDefaults to \nFalse\n\n\nsource\n\n\nThe name of the attribute that will be used to populate the field. May be a method that only takes a \nself\n argument, such as \nURLField(source='get_absolute_url')\n, or may use dotted notation to traverse attributes, such as \nEmailField(source='user.email')\n. When serializing fields with dotted notation, it may be necessary to provide a \ndefault\n value if any object is not present or is empty during attribute traversal.\n\n\nThe value \nsource='*'\n has a special meaning, and is used to indicate that the entire object should be passed through to the field. This can be useful for creating nested representations, or for fields which require access to the complete object in order to determine the output representation.\n\n\nDefaults to the name of the field.\n\n\nvalidators\n\n\nA list of validator functions which should be applied to the incoming field input, and which either raise a validation error or simply return. Validator functions should typically raise \nserializers.ValidationError\n, but Django's built-in \nValidationError\n is also supported for compatibility with validators defined in the Django codebase or third party Django packages.\n\n\nerror_messages\n\n\nA dictionary of error codes to error messages.\n\n\nlabel\n\n\nA short text string that may be used as the name of the field in HTML form fields or other descriptive elements.\n\n\nhelp_text\n\n\nA text string that may be used as a description of the field in HTML form fields or other descriptive elements.\n\n\ninitial\n\n\nA value that should be used for pre-populating the value of HTML form fields. You may pass a callable to it, just as\nyou may do with any regular Django \nField\n:\n\n\nimport datetime\nfrom rest_framework import serializers\nclass ExampleSerializer(serializers.Serializer):\n day = serializers.DateField(initial=datetime.date.today)\n\n\n\nstyle\n\n\nA dictionary of key-value pairs that can be used to control how renderers should render the field.\n\n\nTwo examples here are \n'input_type'\n and \n'base_template'\n:\n\n\n# Use for the input.\npassword = serializers.CharField(\n style={'input_type': 'password'}\n)\n\n# Use a radio input instead of a select input.\ncolor_channel = serializers.ChoiceField(\n choices=['red', 'green', 'blue'],\n style={'base_template': 'radio.html'}\n)\n\n\n\nFor more details see the \nHTML & Forms\n documentation.\n\n\n\n\nBoolean fields\n\n\nBooleanField\n\n\nA boolean representation.\n\n\nWhen using HTML encoded form input be aware that omitting a value will always be treated as setting a field to \nFalse\n, even if it has a \ndefault=True\n option specified. This is because HTML checkbox inputs represent the unchecked state by omitting the value, so REST framework treats omission as if it is an empty checkbox input.\n\n\nNote that default \nBooleanField\n instances will be generated with a \nrequired=False\n option (since Django \nmodels.BooleanField\n is always \nblank=True\n). If you want to change this behaviour explicitly declare the \nBooleanField\n on the serializer class.\n\n\nCorresponds to \ndjango.db.models.fields.BooleanField\n.\n\n\nSignature:\n \nBooleanField()\n\n\nNullBooleanField\n\n\nA boolean representation that also accepts \nNone\n as a valid value.\n\n\nCorresponds to \ndjango.db.models.fields.NullBooleanField\n.\n\n\nSignature:\n \nNullBooleanField()\n\n\n\n\nString fields\n\n\nCharField\n\n\nA text representation. Optionally validates the text to be shorter than \nmax_length\n and longer than \nmin_length\n.\n\n\nCorresponds to \ndjango.db.models.fields.CharField\n or \ndjango.db.models.fields.TextField\n.\n\n\nSignature:\n \nCharField(max_length=None, min_length=None, allow_blank=False, trim_whitespace=True)\n\n\n\n\nmax_length\n - Validates that the input contains no more than this number of characters.\n\n\nmin_length\n - Validates that the input contains no fewer than this number of characters.\n\n\nallow_blank\n - If set to \nTrue\n then the empty string should be considered a valid value. If set to \nFalse\n then the empty string is considered invalid and will raise a validation error. Defaults to \nFalse\n.\n\n\ntrim_whitespace\n - If set to \nTrue\n then leading and trailing whitespace is trimmed. Defaults to \nTrue\n.\n\n\n\n\nThe \nallow_null\n option is also available for string fields, although its usage is discouraged in favor of \nallow_blank\n. It is valid to set both \nallow_blank=True\n and \nallow_null=True\n, but doing so means that there will be two differing types of empty value permissible for string representations, which can lead to data inconsistencies and subtle application bugs.\n\n\nEmailField\n\n\nA text representation, validates the text to be a valid e-mail address.\n\n\nCorresponds to \ndjango.db.models.fields.EmailField\n\n\nSignature:\n \nEmailField(max_length=None, min_length=None, allow_blank=False)\n\n\nRegexField\n\n\nA text representation, that validates the given value matches against a certain regular expression.\n\n\nCorresponds to \ndjango.forms.fields.RegexField\n.\n\n\nSignature:\n \nRegexField(regex, max_length=None, min_length=None, allow_blank=False)\n\n\nThe mandatory \nregex\n argument may either be a string, or a compiled python regular expression object.\n\n\nUses Django's \ndjango.core.validators.RegexValidator\n for validation.\n\n\nSlugField\n\n\nA \nRegexField\n that validates the input against the pattern \n[a-zA-Z0-9_-]+\n.\n\n\nCorresponds to \ndjango.db.models.fields.SlugField\n.\n\n\nSignature:\n \nSlugField(max_length=50, min_length=None, allow_blank=False)\n\n\nURLField\n\n\nA \nRegexField\n that validates the input against a URL matching pattern. Expects fully qualified URLs of the form \nhttp:///\n.\n\n\nCorresponds to \ndjango.db.models.fields.URLField\n. Uses Django's \ndjango.core.validators.URLValidator\n for validation.\n\n\nSignature:\n \nURLField(max_length=200, min_length=None, allow_blank=False)\n\n\nUUIDField\n\n\nA field that ensures the input is a valid UUID string. The \nto_internal_value\n method will return a \nuuid.UUID\n instance. On output the field will return a string in the canonical hyphenated format, for example:\n\n\n\"de305d54-75b4-431b-adb2-eb6b9e546013\"\n\n\n\nSignature:\n \nUUIDField(format='hex_verbose')\n\n\n\n\nformat\n: Determines the representation format of the uuid value\n\n\n'hex_verbose'\n - The cannoncical hex representation, including hyphens: \n\"5ce0e9a5-5ffa-654b-cee0-1238041fb31a\"\n\n\n'hex'\n - The compact hex representation of the UUID, not including hyphens: \n\"5ce0e9a55ffa654bcee01238041fb31a\"\n\n\n'int'\n - A 128 bit integer representation of the UUID: \n\"123456789012312313134124512351145145114\"\n\n\n'urn'\n - RFC 4122 URN representation of the UUID: \n\"urn:uuid:5ce0e9a5-5ffa-654b-cee0-1238041fb31a\"\n\n Changing the \nformat\n parameters only affects representation values. All formats are accepted by \nto_internal_value\n\n\n\n\n\n\n\n\nFilePathField\n\n\nA field whose choices are limited to the filenames in a certain directory on the filesystem\n\n\nCorresponds to \ndjango.forms.fields.FilePathField\n.\n\n\nSignature:\n \nFilePathField(path, match=None, recursive=False, allow_files=True, allow_folders=False, required=None, **kwargs)\n\n\n\n\npath\n - The absolute filesystem path to a directory from which this FilePathField should get its choice.\n\n\nmatch\n - A regular expression, as a string, that FilePathField will use to filter filenames.\n\n\nrecursive\n - Specifies whether all subdirectories of path should be included. Default is \nFalse\n.\n\n\nallow_files\n - Specifies whether files in the specified location should be included. Default is \nTrue\n. Either this or \nallow_folders\n must be \nTrue\n.\n\n\nallow_folders\n - Specifies whether folders in the specified location should be included. Default is \nFalse\n. Either this or \nallow_files\n must be \nTrue\n.\n\n\n\n\nIPAddressField\n\n\nA field that ensures the input is a valid IPv4 or IPv6 string.\n\n\nCorresponds to \ndjango.forms.fields.IPAddressField\n and \ndjango.forms.fields.GenericIPAddressField\n.\n\n\nSignature\n: \nIPAddressField(protocol='both', unpack_ipv4=False, **options)\n\n\n\n\nprotocol\n Limits valid inputs to the specified protocol. Accepted values are 'both' (default), 'IPv4' or 'IPv6'. Matching is case insensitive.\n\n\nunpack_ipv4\n Unpacks IPv4 mapped addresses like ::ffff:192.0.2.1. If this option is enabled that address would be unpacked to 192.0.2.1. Default is disabled. Can only be used when protocol is set to 'both'.\n\n\n\n\n\n\nNumeric fields\n\n\nIntegerField\n\n\nAn integer representation.\n\n\nCorresponds to \ndjango.db.models.fields.IntegerField\n, \ndjango.db.models.fields.SmallIntegerField\n, \ndjango.db.models.fields.PositiveIntegerField\n and \ndjango.db.models.fields.PositiveSmallIntegerField\n.\n\n\nSignature\n: \nIntegerField(max_value=None, min_value=None)\n\n\n\n\nmax_value\n Validate that the number provided is no greater than this value.\n\n\nmin_value\n Validate that the number provided is no less than this value.\n\n\n\n\nFloatField\n\n\nA floating point representation.\n\n\nCorresponds to \ndjango.db.models.fields.FloatField\n.\n\n\nSignature\n: \nFloatField(max_value=None, min_value=None)\n\n\n\n\nmax_value\n Validate that the number provided is no greater than this value.\n\n\nmin_value\n Validate that the number provided is no less than this value.\n\n\n\n\nDecimalField\n\n\nA decimal representation, represented in Python by a \nDecimal\n instance.\n\n\nCorresponds to \ndjango.db.models.fields.DecimalField\n.\n\n\nSignature\n: \nDecimalField(max_digits, decimal_places, coerce_to_string=None, max_value=None, min_value=None)\n\n\n\n\nmax_digits\n The maximum number of digits allowed in the number. It must be either \nNone\n or an integer greater than or equal to \ndecimal_places\n.\n\n\ndecimal_places\n The number of decimal places to store with the number.\n\n\ncoerce_to_string\n Set to \nTrue\n if string values should be returned for the representation, or \nFalse\n if \nDecimal\n objects should be returned. Defaults to the same value as the \nCOERCE_DECIMAL_TO_STRING\n settings key, which will be \nTrue\n unless overridden. If \nDecimal\n objects are returned by the serializer, then the final output format will be determined by the renderer. Note that setting \nlocalize\n will force the value to \nTrue\n.\n\n\nmax_value\n Validate that the number provided is no greater than this value.\n\n\nmin_value\n Validate that the number provided is no less than this value.\n\n\nlocalize\n Set to \nTrue\n to enable localization of input and output based on the current locale. This will also force \ncoerce_to_string\n to \nTrue\n. Defaults to \nFalse\n. Note that data formatting is enabled if you have set \nUSE_L10N=True\n in your settings file.\n\n\nrounding\n Sets the rounding mode used when quantising to the configured precision. Valid values are \ndecimal\n module rounding modes\n. Defaults to \nNone\n.\n\n\n\n\nExample usage\n\n\nTo validate numbers up to 999 with a resolution of 2 decimal places, you would use:\n\n\nserializers.DecimalField(max_digits=5, decimal_places=2)\n\n\n\nAnd to validate numbers up to anything less than one billion with a resolution of 10 decimal places:\n\n\nserializers.DecimalField(max_digits=19, decimal_places=10)\n\n\n\nThis field also takes an optional argument, \ncoerce_to_string\n. If set to \nTrue\n the representation will be output as a string. If set to \nFalse\n the representation will be left as a \nDecimal\n instance and the final representation will be determined by the renderer.\n\n\nIf unset, this will default to the same value as the \nCOERCE_DECIMAL_TO_STRING\n setting, which is \nTrue\n unless set otherwise.\n\n\n\n\nDate and time fields\n\n\nDateTimeField\n\n\nA date and time representation.\n\n\nCorresponds to \ndjango.db.models.fields.DateTimeField\n.\n\n\nSignature:\n \nDateTimeField(format=api_settings.DATETIME_FORMAT, input_formats=None)\n\n\n\n\nformat\n - A string representing the output format. If not specified, this defaults to the same value as the \nDATETIME_FORMAT\n settings key, which will be \n'iso-8601'\n unless set. Setting to a format string indicates that \nto_representation\n return values should be coerced to string output. Format strings are described below. Setting this value to \nNone\n indicates that Python \ndatetime\n objects should be returned by \nto_representation\n. In this case the datetime encoding will be determined by the renderer.\n\n\ninput_formats\n - A list of strings representing the input formats which may be used to parse the date. If not specified, the \nDATETIME_INPUT_FORMATS\n setting will be used, which defaults to \n['iso-8601']\n.\n\n\n\n\nDateTimeField\n format strings.\n\n\nFormat strings may either be \nPython strftime formats\n which explicitly specify the format, or the special string \n'iso-8601'\n, which indicates that \nISO 8601\n style datetimes should be used. (eg \n'2013-01-29T12:34:56.000000Z'\n)\n\n\nWhen a value of \nNone\n is used for the format \ndatetime\n objects will be returned by \nto_representation\n and the final output representation will determined by the renderer class.\n\n\nauto_now_add\n model fields.\nauto_now\n and \n\n\nWhen using \nModelSerializer\n or \nHyperlinkedModelSerializer\n, note that any model fields with \nauto_now=True\n or \nauto_now_add=True\n will use serializer fields that are \nread_only=True\n by default.\n\n\nIf you want to override this behavior, you'll need to declare the \nDateTimeField\n explicitly on the serializer. For example:\n\n\nclass CommentSerializer(serializers.ModelSerializer):\n created = serializers.DateTimeField()\n\n class Meta:\n model = Comment\n\n\n\nDateField\n\n\nA date representation.\n\n\nCorresponds to \ndjango.db.models.fields.DateField\n\n\nSignature:\n \nDateField(format=api_settings.DATE_FORMAT, input_formats=None)\n\n\n\n\nformat\n - A string representing the output format. If not specified, this defaults to the same value as the \nDATE_FORMAT\n settings key, which will be \n'iso-8601'\n unless set. Setting to a format string indicates that \nto_representation\n return values should be coerced to string output. Format strings are described below. Setting this value to \nNone\n indicates that Python \ndate\n objects should be returned by \nto_representation\n. In this case the date encoding will be determined by the renderer.\n\n\ninput_formats\n - A list of strings representing the input formats which may be used to parse the date. If not specified, the \nDATE_INPUT_FORMATS\n setting will be used, which defaults to \n['iso-8601']\n.\n\n\n\n\nDateField\n format strings\n\n\nFormat strings may either be \nPython strftime formats\n which explicitly specify the format, or the special string \n'iso-8601'\n, which indicates that \nISO 8601\n style dates should be used. (eg \n'2013-01-29'\n)\n\n\nTimeField\n\n\nA time representation.\n\n\nCorresponds to \ndjango.db.models.fields.TimeField\n\n\nSignature:\n \nTimeField(format=api_settings.TIME_FORMAT, input_formats=None)\n\n\n\n\nformat\n - A string representing the output format. If not specified, this defaults to the same value as the \nTIME_FORMAT\n settings key, which will be \n'iso-8601'\n unless set. Setting to a format string indicates that \nto_representation\n return values should be coerced to string output. Format strings are described below. Setting this value to \nNone\n indicates that Python \ntime\n objects should be returned by \nto_representation\n. In this case the time encoding will be determined by the renderer.\n\n\ninput_formats\n - A list of strings representing the input formats which may be used to parse the date. If not specified, the \nTIME_INPUT_FORMATS\n setting will be used, which defaults to \n['iso-8601']\n.\n\n\n\n\nTimeField\n format strings\n\n\nFormat strings may either be \nPython strftime formats\n which explicitly specify the format, or the special string \n'iso-8601'\n, which indicates that \nISO 8601\n style times should be used. (eg \n'12:34:56.000000'\n)\n\n\nDurationField\n\n\nA Duration representation.\nCorresponds to \ndjango.db.models.fields.DurationField\n\n\nThe \nvalidated_data\n for these fields will contain a \ndatetime.timedelta\n instance.\nThe representation is a string following this format \n'[DD] [HH:[MM:]]ss[.uuuuuu]'\n.\n\n\nSignature:\n \nDurationField()\n\n\n\n\nChoice selection fields\n\n\nChoiceField\n\n\nA field that can accept a value out of a limited set of choices.\n\n\nUsed by \nModelSerializer\n to automatically generate fields if the corresponding model field includes a \nchoices=\u2026\n argument.\n\n\nSignature:\n \nChoiceField(choices)\n\n\n\n\nchoices\n - A list of valid values, or a list of \n(key, display_name)\n tuples.\n\n\nallow_blank\n - If set to \nTrue\n then the empty string should be considered a valid value. If set to \nFalse\n then the empty string is considered invalid and will raise a validation error. Defaults to \nFalse\n.\n\n\nhtml_cutoff\n - If set this will be the maximum number of choices that will be displayed by a HTML select drop down. Can be used to ensure that automatically generated ChoiceFields with very large possible selections do not prevent a template from rendering. Defaults to \nNone\n.\n\n\nhtml_cutoff_text\n - If set this will display a textual indicator if the maximum number of items have been cutoff in an HTML select drop down. Defaults to \n\"More than {count} items\u2026\"\n\n\n\n\nBoth the \nallow_blank\n and \nallow_null\n are valid options on \nChoiceField\n, although it is highly recommended that you only use one and not both. \nallow_blank\n should be preferred for textual choices, and \nallow_null\n should be preferred for numeric or other non-textual choices.\n\n\nMultipleChoiceField\n\n\nA field that can accept a set of zero, one or many values, chosen from a limited set of choices. Takes a single mandatory argument. \nto_internal_value\n returns a \nset\n containing the selected values.\n\n\nSignature:\n \nMultipleChoiceField(choices)\n\n\n\n\nchoices\n - A list of valid values, or a list of \n(key, display_name)\n tuples.\n\n\nallow_blank\n - If set to \nTrue\n then the empty string should be considered a valid value. If set to \nFalse\n then the empty string is considered invalid and will raise a validation error. Defaults to \nFalse\n.\n\n\nhtml_cutoff\n - If set this will be the maximum number of choices that will be displayed by a HTML select drop down. Can be used to ensure that automatically generated ChoiceFields with very large possible selections do not prevent a template from rendering. Defaults to \nNone\n.\n\n\nhtml_cutoff_text\n - If set this will display a textual indicator if the maximum number of items have been cutoff in an HTML select drop down. Defaults to \n\"More than {count} items\u2026\"\n\n\n\n\nAs with \nChoiceField\n, both the \nallow_blank\n and \nallow_null\n options are valid, although it is highly recommended that you only use one and not both. \nallow_blank\n should be preferred for textual choices, and \nallow_null\n should be preferred for numeric or other non-textual choices.\n\n\n\n\nFile upload fields\n\n\nParsers and file uploads.\n\n\nThe \nFileField\n and \nImageField\n classes are only suitable for use with \nMultiPartParser\n or \nFileUploadParser\n. Most parsers, such as e.g. JSON don't support file uploads.\nDjango's regular \nFILE_UPLOAD_HANDLERS\n are used for handling uploaded files.\n\n\nFileField\n\n\nA file representation. Performs Django's standard FileField validation.\n\n\nCorresponds to \ndjango.forms.fields.FileField\n.\n\n\nSignature:\n \nFileField(max_length=None, allow_empty_file=False, use_url=UPLOADED_FILES_USE_URL)\n\n\n\n\nmax_length\n - Designates the maximum length for the file name.\n\n\nallow_empty_file\n - Designates if empty files are allowed.\n\n\nuse_url\n - If set to \nTrue\n then URL string values will be used for the output representation. If set to \nFalse\n then filename string values will be used for the output representation. Defaults to the value of the \nUPLOADED_FILES_USE_URL\n settings key, which is \nTrue\n unless set otherwise.\n\n\n\n\nImageField\n\n\nAn image representation. Validates the uploaded file content as matching a known image format.\n\n\nCorresponds to \ndjango.forms.fields.ImageField\n.\n\n\nSignature:\n \nImageField(max_length=None, allow_empty_file=False, use_url=UPLOADED_FILES_USE_URL)\n\n\n\n\nmax_length\n - Designates the maximum length for the file name.\n\n\nallow_empty_file\n - Designates if empty files are allowed.\n\n\nuse_url\n - If set to \nTrue\n then URL string values will be used for the output representation. If set to \nFalse\n then filename string values will be used for the output representation. Defaults to the value of the \nUPLOADED_FILES_USE_URL\n settings key, which is \nTrue\n unless set otherwise.\n\n\n\n\nRequires either the \nPillow\n package or \nPIL\n package. The \nPillow\n package is recommended, as \nPIL\n is no longer actively maintained.\n\n\n\n\nComposite fields\n\n\nListField\n\n\nA field class that validates a list of objects.\n\n\nSignature\n: \nListField(child=, min_length=None, max_length=None)\n\n\n\n\nchild\n - 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.\n\n\nmin_length\n - Validates that the list contains no fewer than this number of elements.\n\n\nmax_length\n - Validates that the list contains no more than this number of elements.\n\n\n\n\nFor example, to validate a list of integers you might use something like the following:\n\n\nscores = serializers.ListField(\n child=serializers.IntegerField(min_value=0, max_value=100)\n)\n\n\n\nThe \nListField\n class also supports a declarative style that allows you to write reusable list field classes.\n\n\nclass StringListField(serializers.ListField):\n child = serializers.CharField()\n\n\n\nWe can now reuse our custom \nStringListField\n class throughout our application, without having to provide a \nchild\n argument to it.\n\n\nDictField\n\n\nA field class that validates a dictionary of objects. The keys in \nDictField\n are always assumed to be string values.\n\n\nSignature\n: \nDictField(child=)\n\n\n\n\nchild\n - 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.\n\n\n\n\nFor example, to create a field that validates a mapping of strings to strings, you would write something like this:\n\n\ndocument = DictField(child=CharField())\n\n\n\nYou can also use the declarative style, as with \nListField\n. For example:\n\n\nclass DocumentField(DictField):\n child = CharField()\n\n\n\nHStoreField\n\n\nA preconfigured \nDictField\n that is compatible with Django's postgres \nHStoreField\n.\n\n\nSignature\n: \nHStoreField(child=)\n\n\n\n\nchild\n - A field instance that is used for validating the values in the dictionary. The default child field accepts both empty strings and null values.\n\n\n\n\nNote that the child field \nmust\n be an instance of \nCharField\n, as the hstore extension stores values as strings.\n\n\nJSONField\n\n\nA field class that validates that the incoming data structure consists of valid JSON primitives. In its alternate binary mode, it will represent and validate JSON-encoded binary strings.\n\n\nSignature\n: \nJSONField(binary)\n\n\n\n\nbinary\n - If set to \nTrue\n then the field will output and validate a JSON encoded string, rather than a primitive data structure. Defaults to \nFalse\n.\n\n\n\n\n\n\nMiscellaneous fields\n\n\nReadOnlyField\n\n\nA field class that simply returns the value of the field without modification.\n\n\nThis field is used by default with \nModelSerializer\n when including field names that relate to an attribute rather than a model field.\n\n\nSignature\n: \nReadOnlyField()\n\n\nFor example, if \nhas_expired\n was a property on the \nAccount\n model, then the following serializer would automatically generate it as a \nReadOnlyField\n:\n\n\nclass AccountSerializer(serializers.ModelSerializer):\n class Meta:\n model = Account\n fields = ('id', 'account_name', 'has_expired')\n\n\n\nHiddenField\n\n\nA field class that does not take a value based on user input, but instead takes its value from a default value or callable.\n\n\nSignature\n: \nHiddenField()\n\n\nFor example, to include a field that always provides the current time as part of the serializer validated data, you would use the following:\n\n\nmodified = serializers.HiddenField(default=timezone.now)\n\n\n\nThe \nHiddenField\n class is usually only needed if you have some validation that needs to run based on some pre-provided field values, but you do not want to expose all of those fields to the end user.\n\n\nFor further examples on \nHiddenField\n see the \nvalidators\n documentation.\n\n\nModelField\n\n\nA generic field that can be tied to any arbitrary model field. The \nModelField\n class delegates the task of serialization/deserialization to its associated model field. This field can be used to create serializer fields for custom model fields, without having to create a new custom serializer field.\n\n\nThis field is used by \nModelSerializer\n to correspond to custom model field classes.\n\n\nSignature:\n \nModelField(model_field=)\n\n\nThe \nModelField\n class is generally intended for internal use, but can be used by your API if needed. In order to properly instantiate a \nModelField\n, it must be passed a field that is attached to an instantiated model. For example: \nModelField(model_field=MyModel()._meta.get_field('custom_field'))\n\n\nSerializerMethodField\n\n\nThis is a read-only field. It gets its value by calling a method on the serializer class it is attached to. It can be used to add any sort of data to the serialized representation of your object.\n\n\nSignature\n: \nSerializerMethodField(method_name=None)\n\n\n\n\nmethod_name\n - The name of the method on the serializer to be called. If not included this defaults to \nget_\n.\n\n\n\n\nThe serializer method referred to by the \nmethod_name\n argument should accept a single argument (in addition to \nself\n), which is the object being serialized. It should return whatever you want to be included in the serialized representation of the object. For example:\n\n\nfrom django.contrib.auth.models import User\nfrom django.utils.timezone import now\nfrom rest_framework import serializers\n\nclass UserSerializer(serializers.ModelSerializer):\n days_since_joined = serializers.SerializerMethodField()\n\n class Meta:\n model = User\n\n def get_days_since_joined(self, obj):\n return (now() - obj.date_joined).days\n\n\n\n\n\nCustom fields\n\n\nIf you want to create a custom field, you'll need to subclass \nField\n and then override either one or both of the \n.to_representation()\n and \n.to_internal_value()\n methods. These two methods are used to convert between the initial datatype, and a primitive, serializable datatype. Primitive datatypes will typically be any of a number, string, boolean, \ndate\n/\ntime\n/\ndatetime\n or \nNone\n. They may also be any list or dictionary like object that only contains other primitive objects. Other types might be supported, depending on the renderer that you are using.\n\n\nThe \n.to_representation()\n method is called to convert the initial datatype into a primitive, serializable datatype.\n\n\nThe \nto_internal_value()\n method is called to restore a primitive datatype into its internal python representation. This method should raise a \nserializers.ValidationError\n if the data is invalid.\n\n\nNote that the \nWritableField\n class that was present in version 2.x no longer exists. You should subclass \nField\n and override \nto_internal_value()\n if the field supports data input.\n\n\nExamples\n\n\nA Basic Custom Field\n\n\nLet's look at an example of serializing a class that represents an RGB color value:\n\n\nclass Color(object):\n \"\"\"\n A color represented in the RGB colorspace.\n \"\"\"\n def __init__(self, red, green, blue):\n assert(red >= 0 and green >= 0 and blue >= 0)\n assert(red < 256 and green < 256 and blue < 256)\n self.red, self.green, self.blue = red, green, blue\n\nclass ColorField(serializers.Field):\n \"\"\"\n Color objects are serialized into 'rgb(#, #, #)' notation.\n \"\"\"\n def to_representation(self, obj):\n return \"rgb(%d, %d, %d)\" % (obj.red, obj.green, obj.blue)\n\n def to_internal_value(self, data):\n data = data.strip('rgb(').rstrip(')')\n red, green, blue = [int(col) for col in data.split(',')]\n return Color(red, green, blue)\n\n\n\nBy default field values are treated as mapping to an attribute on the object. If you need to customize how the field value is accessed and set you need to override \n.get_attribute()\n and/or \n.get_value()\n.\n\n\nAs an example, let's create a field that can be used to represent the class name of the object being serialized:\n\n\nclass ClassNameField(serializers.Field):\n def get_attribute(self, obj):\n # We pass the object instance onto `to_representation`,\n # not just the field attribute.\n return obj\n\n def to_representation(self, obj):\n \"\"\"\n Serialize the object's class name.\n \"\"\"\n return obj.__class__.__name__\n\n\n\nRaising validation errors\n\n\nOur \nColorField\n class above currently does not perform any data validation.\nTo indicate invalid data, we should raise a \nserializers.ValidationError\n, like so:\n\n\ndef to_internal_value(self, data):\n if not isinstance(data, six.text_type):\n msg = 'Incorrect type. Expected a string, but got %s'\n raise ValidationError(msg % type(data).__name__)\n\n if not re.match(r'^rgb\\([0-9]+,[0-9]+,[0-9]+\\)$', data):\n raise ValidationError('Incorrect format. Expected `rgb(#,#,#)`.')\n\n data = data.strip('rgb(').rstrip(')')\n red, green, blue = [int(col) for col in data.split(',')]\n\n if any([col > 255 or col < 0 for col in (red, green, blue)]):\n raise ValidationError('Value out of range. Must be between 0 and 255.')\n\n return Color(red, green, blue)\n\n\n\nThe \n.fail()\n method is a shortcut for raising \nValidationError\n that takes a message string from the \nerror_messages\n dictionary. For example:\n\n\ndefault_error_messages = {\n 'incorrect_type': 'Incorrect type. Expected a string, but got {input_type}',\n 'incorrect_format': 'Incorrect format. Expected `rgb(#,#,#)`.',\n 'out_of_range': 'Value out of range. Must be between 0 and 255.'\n}\n\ndef to_internal_value(self, data):\n if not isinstance(data, six.text_type):\n self.fail('incorrect_type', input_type=type(data).__name__)\n\n if not re.match(r'^rgb\\([0-9]+,[0-9]+,[0-9]+\\)$', data):\n self.fail('incorrect_format')\n\n data = data.strip('rgb(').rstrip(')')\n red, green, blue = [int(col) for col in data.split(',')]\n\n if any([col > 255 or col < 0 for col in (red, green, blue)]):\n self.fail('out_of_range')\n\n return Color(red, green, blue)\n\n\n\nThis style keeps your error messages cleaner and more separated from your code, and should be preferred.\n\n\nUsing \nsource='*'\n\n\nHere we'll take an example of a \nflat\n \nDataPoint\n model with \nx_coordinate\n and \ny_coordinate\n attributes.\n\n\nclass DataPoint(models.Model):\n label = models.CharField(max_length=50)\n x_coordinate = models.SmallIntegerField()\n y_coordinate = models.SmallIntegerField()\n\n\n\nUsing a custom field and \nsource='*'\n we can provide a nested representation of\nthe coordinate pair:\n\n\nclass CoordinateField(serializers.Field):\n\n def to_representation(self, obj):\n ret = {\n \"x\": obj.x_coordinate,\n \"y\": obj.y_coordinate\n }\n return ret\n\n def to_internal_value(self, data):\n ret = {\n \"x_coordinate\": data[\"x\"],\n \"y_coordinate\": data[\"y\"],\n }\n return ret\n\n\nclass DataPointSerializer(serializers.ModelSerializer):\n coordinates = CoordinateField(source='*')\n\n class Meta:\n model = DataPoint\n fields = ['label', 'coordinates']\n\n\n\nNote that this example doesn't handle validation. Partly for that reason, in a\nreal project, the coordinate nesting might be better handled with a nested serialiser\nusing \nsource='*'\n, with two \nIntegerField\n instances, each with their own \nsource\n\npointing to the relevant field.\n\n\nThe key points from the example, though, are:\n\n\n\n\n\n\nto_representation\n is passed the entire \nDataPoint\n object and must map from that\nto the desired output.\n\n\n>>> instance = DataPoint(label='Example', x_coordinate=1, y_coordinate=2)\n>>> out_serializer = DataPointSerializer(instance)\n>>> out_serializer.data\nReturnDict([('label', 'testing'), ('coordinates', {'x': 1, 'y': 2})])\n\n\n\n\n\n\n\nUnless our field is to be read-only, \nto_internal_value\n must map back to a dict\nsuitable for updating our target object. With \nsource='*'\n, the return from\n\nto_internal_value\n will update the root validated data dictionary, rather than a single key.\n\n\n>>> data = {\n... \"label\": \"Second Example\",\n... \"coordinates\": {\n... \"x\": 3,\n... \"y\": 4,\n... }\n... }\n>>> in_serializer = DataPointSerializer(data=data)\n>>> in_serializer.is_valid()\nTrue\n>>> in_serializer.validated_data\nOrderedDict([('label', 'Second Example'),\n ('y_coordinate', 4),\n ('x_coordinate', 3)])\n\n\n\n\n\n\n\nFor completeness lets do the same thing again but with the nested serialiser\napproach suggested above:\n\n\nclass NestedCoordinateSerializer(serializers.Serializer):\n x = serializers.IntegerField(source='x_coordinate')\n y = serializers.IntegerField(source='y_coordinate')\n\n\nclass DataPointSerializer(serializers.ModelSerializer):\n coordinates = NestedCoordinateSerializer(source='*')\n\n class Meta:\n model = DataPoint\n fields = ['label', 'coordinates']\n\n\n\nHere the mapping between the target and source attribute pairs (\nx\n and\n\nx_coordinate\n, \ny\n and \ny_coordinate\n) is handled in the \nIntegerField\n\ndeclarations. It's our \nNestedCoordinateSerializer\n that takes \nsource='*'\n.\n\n\nOur new \nDataPointSerializer\n exhibits the same behaviour as the custom field\napproach.\n\n\nSerialising:\n\n\n>>> out_serializer = DataPointSerializer(instance)\n>>> out_serializer.data\nReturnDict([('label', 'testing'),\n ('coordinates', OrderedDict([('x', 1), ('y', 2)]))])\n\n\n\nDeserialising:\n\n\n>>> in_serializer = DataPointSerializer(data=data)\n>>> in_serializer.is_valid()\nTrue\n>>> in_serializer.validated_data\nOrderedDict([('label', 'still testing'),\n ('x_coordinate', 3),\n ('y_coordinate', 4)])\n\n\n\nBut we also get the built-in validation for free:\n\n\n>>> invalid_data = {\n... \"label\": \"still testing\",\n... \"coordinates\": {\n... \"x\": 'a',\n... \"y\": 'b',\n... }\n... }\n>>> invalid_serializer = DataPointSerializer(data=invalid_data)\n>>> invalid_serializer.is_valid()\nFalse\n>>> invalid_serializer.errors\nReturnDict([('coordinates',\n {'x': ['A valid integer is required.'],\n 'y': ['A valid integer is required.']})])\n\n\n\nFor this reason, the nested serialiser approach would be the first to try. You\nwould use the custom field approach when the nested serialiser becomes infeasible\nor overly complex.\n\n\nThird party packages\n\n\nThe following third party packages are also available.\n\n\nDRF Compound Fields\n\n\nThe \ndrf-compound-fields\n package provides \"compound\" serializer fields, such as lists of simple values, which can be described by other fields rather than serializers with the \nmany=True\n option. Also provided are fields for typed dictionaries and values that can be either a specific type or a list of items of that type.\n\n\nDRF Extra Fields\n\n\nThe \ndrf-extra-fields\n package provides extra serializer fields for REST framework, including \nBase64ImageField\n and \nPointField\n classes.\n\n\ndjangorestframework-recursive\n\n\nthe \ndjangorestframework-recursive\n package provides a \nRecursiveField\n for serializing and deserializing recursive structures\n\n\ndjango-rest-framework-gis\n\n\nThe \ndjango-rest-framework-gis\n package provides geographic addons for django rest framework like a \nGeometryField\n field and a GeoJSON serializer.\n\n\ndjango-rest-framework-hstore\n\n\nThe \ndjango-rest-framework-hstore\n package provides an \nHStoreField\n to support \ndjango-hstore\n \nDictionaryField\n model field.", "title": "Serializer fields" }, { @@ -1780,16 +1785,16 @@ "text": "Normally an error will be raised if a field is not supplied during deserialization.\nSet 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 .", "title": "required" }, - { - "location": "/api-guide/fields/#allow_null", - "text": "Normally an error will be raised if None is passed to a serializer field. Set this keyword argument to True if None should be considered a valid value. Note that setting this argument to True will imply a default value of null for serialization output, but does not imply a default for input deserialization. Defaults to False", - "title": "allow_null" - }, { "location": "/api-guide/fields/#default", "text": "If set, this gives the default value that will be used for the field if no input value is supplied. If not set the default behaviour is to not populate the attribute at all. The default is not applied during partial update operations. In the partial update case only fields that are provided in the incoming data will have a validated value returned. May be set to a function or other callable, in which case the value will be evaluated each time it is used. When called, it will receive no arguments. If the callable has a set_context method, that will be called each time before getting the value with the field instance as only argument. This works the same way as for validators . When serializing the instance, default will be used if the the object attribute or dictionary key is not present in the instance. Note that setting a default value implies that the field is not required. Including both the default and required keyword arguments is invalid and will raise an error.", "title": "default" }, + { + "location": "/api-guide/fields/#allow_null", + "text": "Normally an error will be raised if None is passed to a serializer field. Set this keyword argument to True if None should be considered a valid value. Note that, without an explicit default , setting this argument to True will imply a default value of null for serialization output, but does not imply a default for input deserialization. Defaults to False", + "title": "allow_null" + }, { "location": "/api-guide/fields/#source", "text": "The name of the attribute that will be used to populate the field. May be a method that only takes a self argument, such as URLField(source='get_absolute_url') , or may use dotted notation to traverse attributes, such as EmailField(source='user.email') . When serializing fields with dotted notation, it may be necessary to provide a default value if any object is not present or is empty during attribute traversal. The value source='*' has a special meaning, and is used to indicate that the entire object should be passed through to the field. This can be useful for creating nested representations, or for fields which require access to the complete object in order to determine the output representation. Defaults to the name of the field.", @@ -2005,6 +2010,11 @@ "text": "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):\n child = CharField()", "title": "DictField" }, + { + "location": "/api-guide/fields/#hstorefield", + "text": "A preconfigured DictField that is compatible with Django's postgres HStoreField . Signature : HStoreField(child=) child - A field instance that is used for validating the values in the dictionary. The default child field accepts both empty strings and null values. Note that the child field must be an instance of CharField , as the hstore extension stores values as strings.", + "title": "HStoreField" + }, { "location": "/api-guide/fields/#jsonfield", "text": "A field class that validates that the incoming data structure consists of valid JSON primitives. In its alternate binary mode, it will represent and validate JSON-encoded binary strings. Signature : JSONField(binary) binary - If set to True then the field will output and validate a JSON encoded string, rather than a primitive data structure. Defaults to False .", @@ -2076,9 +2086,9 @@ "title": "DRF Extra Fields" }, { - "location": "/api-guide/fields/#djangrestframework-recursive", + "location": "/api-guide/fields/#djangorestframework-recursive", "text": "the djangorestframework-recursive package provides a RecursiveField for serializing and deserializing recursive structures", - "title": "djangrestframework-recursive" + "title": "djangorestframework-recursive" }, { "location": "/api-guide/fields/#django-rest-framework-gis", @@ -2222,7 +2232,7 @@ }, { "location": "/api-guide/validators/", - "text": "Validators\n\n\n\n\nValidators can be useful for re-using validation logic between different types of fields.\n\n\n\u2014 \nDjango documentation\n\n\n\n\nMost of the time you're dealing with validation in REST framework you'll simply be relying on the default field validation, or writing explicit validation methods on serializer or field classes.\n\n\nHowever, sometimes you'll want to place your validation logic into reusable components, so that it can easily be reused throughout your codebase. This can be achieved by using validator functions and validator classes.\n\n\nValidation in REST framework\n\n\nValidation in Django REST framework serializers is handled a little differently to how validation works in Django's \nModelForm\n class.\n\n\nWith \nModelForm\n the validation is performed partially on the form, and partially on the model instance. With REST framework the validation is performed entirely on the serializer class. This is advantageous for the following reasons:\n\n\n\n\nIt introduces a proper separation of concerns, making your code behavior more obvious.\n\n\nIt is easy to switch between using shortcut \nModelSerializer\n classes and using explicit \nSerializer\n classes. Any validation behavior being used for \nModelSerializer\n is simple to replicate.\n\n\nPrinting the \nrepr\n of a serializer instance will show you exactly what validation rules it applies. There's no extra hidden validation behavior being called on the model instance.\n\n\n\n\nWhen you're using \nModelSerializer\n all of this is handled automatically for you. If you want to drop down to using \nSerializer\n classes instead, then you need to define the validation rules explicitly.\n\n\nExample\n\n\nAs an example of how REST framework uses explicit validation, we'll take a simple model class that has a field with a uniqueness constraint.\n\n\nclass CustomerReportRecord(models.Model):\n time_raised = models.DateTimeField(default=timezone.now, editable=False)\n reference = models.CharField(unique=True, max_length=20)\n description = models.TextField()\n\n\n\nHere's a basic \nModelSerializer\n that we can use for creating or updating instances of \nCustomerReportRecord\n:\n\n\nclass CustomerReportSerializer(serializers.ModelSerializer):\n class Meta:\n model = CustomerReportRecord\n\n\n\nIf we open up the Django shell using \nmanage.py shell\n we can now\n\n\n>>> from project.example.serializers import CustomerReportSerializer\n>>> serializer = CustomerReportSerializer()\n>>> print(repr(serializer))\nCustomerReportSerializer():\n id = IntegerField(label='ID', read_only=True)\n time_raised = DateTimeField(read_only=True)\n reference = CharField(max_length=20, validators=[])\n description = CharField(style={'type': 'textarea'})\n\n\n\nThe interesting bit here is the \nreference\n field. We can see that the uniqueness constraint is being explicitly enforced by a validator on the serializer field.\n\n\nBecause of this more explicit style REST framework includes a few validator classes that are not available in core Django. These classes are detailed below.\n\n\n\n\nUniqueValidator\n\n\nThis validator can be used to enforce the \nunique=True\n constraint on model fields.\nIt takes a single required argument, and an optional \nmessages\n argument:\n\n\n\n\nqueryset\n \nrequired\n - This is the queryset against which uniqueness should be enforced.\n\n\nmessage\n - The error message that should be used when validation fails.\n\n\nlookup\n - The lookup used to find an existing instance with the value being validated. Defaults to \n'exact'\n.\n\n\n\n\nThis validator should be applied to \nserializer fields\n, like so:\n\n\nfrom rest_framework.validators import UniqueValidator\n\nslug = SlugField(\n max_length=100,\n validators=[UniqueValidator(queryset=BlogPost.objects.all())]\n)\n\n\n\nUniqueTogetherValidator\n\n\nThis validator can be used to enforce \nunique_together\n constraints on model instances.\nIt has two required arguments, and a single optional \nmessages\n argument:\n\n\n\n\nqueryset\n \nrequired\n - This is the queryset against which uniqueness should be enforced.\n\n\nfields\n \nrequired\n - A list or tuple of field names which should make a unique set. These must exist as fields on the serializer class.\n\n\nmessage\n - The error message that should be used when validation fails.\n\n\n\n\nThe validator should be applied to \nserializer classes\n, like so:\n\n\nfrom rest_framework.validators import UniqueTogetherValidator\n\nclass ExampleSerializer(serializers.Serializer):\n # ...\n class Meta:\n # ToDo items belong to a parent list, and have an ordering defined\n #\u00a0by the 'position' field. No two items in a given list may share\n # the same position.\n validators = [\n UniqueTogetherValidator(\n queryset=ToDoItem.objects.all(),\n fields=('list', 'position')\n )\n ]\n\n\n\n\n\nNote\n: The \nUniqueTogetherValidation\n class always imposes an implicit constraint that all the fields it applies to are always treated as required. Fields with \ndefault\n values are an exception to this as they always supply a value even when omitted from user input.\n\n\n\n\nUniqueForDateValidator\n\n\nUniqueForMonthValidator\n\n\nUniqueForYearValidator\n\n\nThese validators can be used to enforce the \nunique_for_date\n, \nunique_for_month\n and \nunique_for_year\n constraints on model instances. They take the following arguments:\n\n\n\n\nqueryset\n \nrequired\n - This is the queryset against which uniqueness should be enforced.\n\n\nfield\n \nrequired\n - A field name against which uniqueness in the given date range will be validated. This must exist as a field on the serializer class.\n\n\ndate_field\n \nrequired\n - A field name which will be used to determine date range for the uniqueness constrain. This must exist as a field on the serializer class.\n\n\nmessage\n - The error message that should be used when validation fails.\n\n\n\n\nThe validator should be applied to \nserializer classes\n, like so:\n\n\nfrom rest_framework.validators import UniqueForYearValidator\n\nclass ExampleSerializer(serializers.Serializer):\n # ...\n class Meta:\n # Blog posts should have a slug that is unique for the current year.\n validators = [\n UniqueForYearValidator(\n queryset=BlogPostItem.objects.all(),\n field='slug',\n date_field='published'\n )\n ]\n\n\n\nThe date field that is used for the validation is always required to be present on the serializer class. You can't simply rely on a model class \ndefault=...\n, because the value being used for the default wouldn't be generated until after the validation has run.\n\n\nThere are a couple of styles you may want to use for this depending on how you want your API to behave. If you're using \nModelSerializer\n you'll probably simply rely on the defaults that REST framework generates for you, but if you are using \nSerializer\n or simply want more explicit control, use on of the styles demonstrated below.\n\n\nUsing with a writable date field.\n\n\nIf you want the date field to be writable the only thing worth noting is that you should ensure that it is always available in the input data, either by setting a \ndefault\n argument, or by setting \nrequired=True\n.\n\n\npublished = serializers.DateTimeField(required=True)\n\n\n\nUsing with a read-only date field.\n\n\nIf you want the date field to be visible, but not editable by the user, then set \nread_only=True\n and additionally set a \ndefault=...\n argument.\n\n\npublished = serializers.DateTimeField(read_only=True, default=timezone.now)\n\n\n\nThe field will not be writable to the user, but the default value will still be passed through to the \nvalidated_data\n.\n\n\nUsing with a hidden date field.\n\n\nIf you want the date field to be entirely hidden from the user, then use \nHiddenField\n. This field type does not accept user input, but instead always returns its default value to the \nvalidated_data\n in the serializer.\n\n\npublished = serializers.HiddenField(default=timezone.now)\n\n\n\n\n\nNote\n: The \nUniqueForValidation\n classes impose an implicit constraint that the fields they are applied to are always treated as required. Fields with \ndefault\n values are an exception to this as they always supply a value even when omitted from user input.\n\n\n\n\nAdvanced field defaults\n\n\nValidators that are applied across multiple fields in the serializer can sometimes require a field input that should not be provided by the API client, but that \nis\n available as input to the validator.\n\n\nTwo patterns that you may want to use for this sort of validation include:\n\n\n\n\nUsing \nHiddenField\n. This field will be present in \nvalidated_data\n but \nwill not\n be used in the serializer output representation.\n\n\nUsing a standard field with \nread_only=True\n, but that also includes a \ndefault=\u2026\n argument. This field \nwill\n be used in the serializer output representation, but cannot be set directly by the user.\n\n\n\n\nREST framework includes a couple of defaults that may be useful in this context.\n\n\nCurrentUserDefault\n\n\nA default class that can be used to represent the current user. In order to use this, the 'request' must have been provided as part of the context dictionary when instantiating the serializer.\n\n\nowner = serializers.HiddenField(\n default=serializers.CurrentUserDefault()\n)\n\n\n\nCreateOnlyDefault\n\n\nA default class that can be used to \nonly set a default argument during create operations\n. During updates the field is omitted.\n\n\nIt takes a single argument, which is the default value or callable that should be used during create operations.\n\n\ncreated_at = serializers.DateTimeField(\n read_only=True,\n default=serializers.CreateOnlyDefault(timezone.now)\n)\n\n\n\n\n\nLimitations of validators\n\n\nThere are some ambiguous cases where you'll need to instead handle validation\nexplicitly, rather than relying on the default serializer classes that\n\nModelSerializer\n generates.\n\n\nIn these cases you may want to disable the automatically generated validators,\nby specifying an empty list for the serializer \nMeta.validators\n attribute.\n\n\nOptional fields\n\n\nBy default \"unique together\" validation enforces that all fields be\n\nrequired=True\n. In some cases, you might want to explicit apply\n\nrequired=False\n to one of the fields, in which case the desired behaviour\nof the validation is ambiguous.\n\n\nIn this case you will typically need to exclude the validator from the\nserializer class, and instead write any validation logic explicitly, either\nin the \n.validate()\n method, or else in the view.\n\n\nFor example:\n\n\nclass BillingRecordSerializer(serializers.ModelSerializer):\n def validate(self, data):\n # Apply custom validation either here, or in the view.\n\n class Meta:\n fields = ('client', 'date', 'amount')\n extra_kwargs = {'client': {'required': 'False'}}\n validators = [] # Remove a default \"unique together\" constraint.\n\n\n\nUpdating nested serializers\n\n\nWhen applying an update to an existing instance, uniqueness validators will\nexclude the current instance from the uniqueness check. The current instance\nis available in the context of the uniqueness check, because it exists as\nan attribute on the serializer, having initially been passed using\n\ninstance=...\n when instantiating the serializer.\n\n\nIn the case of update operations on \nnested\n serializers there's no way of\napplying this exclusion, because the instance is not available.\n\n\nAgain, you'll probably want to explicitly remove the validator from the\nserializer class, and write the code the for the validation constraint\nexplicitly, in a \n.validate()\n method, or in the view.\n\n\nDebugging complex cases\n\n\nIf you're not sure exactly what behavior a \nModelSerializer\n class will\ngenerate it is usually a good idea to run \nmanage.py shell\n, and print\nan instance of the serializer, so that you can inspect the fields and\nvalidators that it automatically generates for you.\n\n\n>>> serializer = MyComplexModelSerializer()\n>>> print(serializer)\nclass MyComplexModelSerializer:\n my_fields = ...\n\n\n\nAlso keep in mind that with complex cases it can often be better to explicitly\ndefine your serializer classes, rather than relying on the default\n\nModelSerializer\n behavior. This involves a little more code, but ensures\nthat the resulting behavior is more transparent.\n\n\n\n\nWriting custom validators\n\n\nYou can use any of Django's existing validators, or write your own custom validators.\n\n\nFunction based\n\n\nA validator may be any callable that raises a \nserializers.ValidationError\n on failure.\n\n\ndef even_number(value):\n if value % 2 != 0:\n raise serializers.ValidationError('This field must be an even number.')\n\n\n\nField-level validation\n\n\nYou can specify custom field-level validation by adding \n.validate_\n methods\nto your \nSerializer\n subclass. This is documented in the\n\nSerializer docs\n\n\nClass-based\n\n\nTo write a class-based validator, use the \n__call__\n method. Class-based validators are useful as they allow you to parameterize and reuse behavior.\n\n\nclass MultipleOf(object):\n def __init__(self, base):\n self.base = base\n\n def __call__(self, value):\n if value % self.base != 0:\n message = 'This field must be a multiple of %d.' % self.base\n raise serializers.ValidationError(message)\n\n\n\nUsing \nset_context()\n\n\nIn some advanced cases you might want a validator to be passed the serializer field it is being used with as additional context. You can do so by declaring a \nset_context\n method on a class-based validator.\n\n\ndef set_context(self, serializer_field):\n # Determine if this is an update or a create operation.\n # In `__call__` we can then use that information to modify the validation behavior.\n self.is_update = serializer_field.parent.instance is not None", + "text": "Validators\n\n\n\n\nValidators can be useful for re-using validation logic between different types of fields.\n\n\n\u2014 \nDjango documentation\n\n\n\n\nMost of the time you're dealing with validation in REST framework you'll simply be relying on the default field validation, or writing explicit validation methods on serializer or field classes.\n\n\nHowever, sometimes you'll want to place your validation logic into reusable components, so that it can easily be reused throughout your codebase. This can be achieved by using validator functions and validator classes.\n\n\nValidation in REST framework\n\n\nValidation in Django REST framework serializers is handled a little differently to how validation works in Django's \nModelForm\n class.\n\n\nWith \nModelForm\n the validation is performed partially on the form, and partially on the model instance. With REST framework the validation is performed entirely on the serializer class. This is advantageous for the following reasons:\n\n\n\n\nIt introduces a proper separation of concerns, making your code behavior more obvious.\n\n\nIt is easy to switch between using shortcut \nModelSerializer\n classes and using explicit \nSerializer\n classes. Any validation behavior being used for \nModelSerializer\n is simple to replicate.\n\n\nPrinting the \nrepr\n of a serializer instance will show you exactly what validation rules it applies. There's no extra hidden validation behavior being called on the model instance.\n\n\n\n\nWhen you're using \nModelSerializer\n all of this is handled automatically for you. If you want to drop down to using \nSerializer\n classes instead, then you need to define the validation rules explicitly.\n\n\nExample\n\n\nAs an example of how REST framework uses explicit validation, we'll take a simple model class that has a field with a uniqueness constraint.\n\n\nclass CustomerReportRecord(models.Model):\n time_raised = models.DateTimeField(default=timezone.now, editable=False)\n reference = models.CharField(unique=True, max_length=20)\n description = models.TextField()\n\n\n\nHere's a basic \nModelSerializer\n that we can use for creating or updating instances of \nCustomerReportRecord\n:\n\n\nclass CustomerReportSerializer(serializers.ModelSerializer):\n class Meta:\n model = CustomerReportRecord\n\n\n\nIf we open up the Django shell using \nmanage.py shell\n we can now\n\n\n>>> from project.example.serializers import CustomerReportSerializer\n>>> serializer = CustomerReportSerializer()\n>>> print(repr(serializer))\nCustomerReportSerializer():\n id = IntegerField(label='ID', read_only=True)\n time_raised = DateTimeField(read_only=True)\n reference = CharField(max_length=20, validators=[])\n description = CharField(style={'type': 'textarea'})\n\n\n\nThe interesting bit here is the \nreference\n field. We can see that the uniqueness constraint is being explicitly enforced by a validator on the serializer field.\n\n\nBecause of this more explicit style REST framework includes a few validator classes that are not available in core Django. These classes are detailed below.\n\n\n\n\nUniqueValidator\n\n\nThis validator can be used to enforce the \nunique=True\n constraint on model fields.\nIt takes a single required argument, and an optional \nmessages\n argument:\n\n\n\n\nqueryset\n \nrequired\n - This is the queryset against which uniqueness should be enforced.\n\n\nmessage\n - The error message that should be used when validation fails.\n\n\nlookup\n - The lookup used to find an existing instance with the value being validated. Defaults to \n'exact'\n.\n\n\n\n\nThis validator should be applied to \nserializer fields\n, like so:\n\n\nfrom rest_framework.validators import UniqueValidator\n\nslug = SlugField(\n max_length=100,\n validators=[UniqueValidator(queryset=BlogPost.objects.all())]\n)\n\n\n\nUniqueTogetherValidator\n\n\nThis validator can be used to enforce \nunique_together\n constraints on model instances.\nIt has two required arguments, and a single optional \nmessages\n argument:\n\n\n\n\nqueryset\n \nrequired\n - This is the queryset against which uniqueness should be enforced.\n\n\nfields\n \nrequired\n - A list or tuple of field names which should make a unique set. These must exist as fields on the serializer class.\n\n\nmessage\n - The error message that should be used when validation fails.\n\n\n\n\nThe validator should be applied to \nserializer classes\n, like so:\n\n\nfrom rest_framework.validators import UniqueTogetherValidator\n\nclass ExampleSerializer(serializers.Serializer):\n # ...\n class Meta:\n # ToDo items belong to a parent list, and have an ordering defined\n #\u00a0by the 'position' field. No two items in a given list may share\n # the same position.\n validators = [\n UniqueTogetherValidator(\n queryset=ToDoItem.objects.all(),\n fields=('list', 'position')\n )\n ]\n\n\n\n\n\nNote\n: The \nUniqueTogetherValidation\n class always imposes an implicit constraint that all the fields it applies to are always treated as required. Fields with \ndefault\n values are an exception to this as they always supply a value even when omitted from user input.\n\n\n\n\nUniqueForDateValidator\n\n\nUniqueForMonthValidator\n\n\nUniqueForYearValidator\n\n\nThese validators can be used to enforce the \nunique_for_date\n, \nunique_for_month\n and \nunique_for_year\n constraints on model instances. They take the following arguments:\n\n\n\n\nqueryset\n \nrequired\n - This is the queryset against which uniqueness should be enforced.\n\n\nfield\n \nrequired\n - A field name against which uniqueness in the given date range will be validated. This must exist as a field on the serializer class.\n\n\ndate_field\n \nrequired\n - A field name which will be used to determine date range for the uniqueness constrain. This must exist as a field on the serializer class.\n\n\nmessage\n - The error message that should be used when validation fails.\n\n\n\n\nThe validator should be applied to \nserializer classes\n, like so:\n\n\nfrom rest_framework.validators import UniqueForYearValidator\n\nclass ExampleSerializer(serializers.Serializer):\n # ...\n class Meta:\n # Blog posts should have a slug that is unique for the current year.\n validators = [\n UniqueForYearValidator(\n queryset=BlogPostItem.objects.all(),\n field='slug',\n date_field='published'\n )\n ]\n\n\n\nThe date field that is used for the validation is always required to be present on the serializer class. You can't simply rely on a model class \ndefault=...\n, because the value being used for the default wouldn't be generated until after the validation has run.\n\n\nThere are a couple of styles you may want to use for this depending on how you want your API to behave. If you're using \nModelSerializer\n you'll probably simply rely on the defaults that REST framework generates for you, but if you are using \nSerializer\n or simply want more explicit control, use on of the styles demonstrated below.\n\n\nUsing with a writable date field.\n\n\nIf you want the date field to be writable the only thing worth noting is that you should ensure that it is always available in the input data, either by setting a \ndefault\n argument, or by setting \nrequired=True\n.\n\n\npublished = serializers.DateTimeField(required=True)\n\n\n\nUsing with a read-only date field.\n\n\nIf you want the date field to be visible, but not editable by the user, then set \nread_only=True\n and additionally set a \ndefault=...\n argument.\n\n\npublished = serializers.DateTimeField(read_only=True, default=timezone.now)\n\n\n\nThe field will not be writable to the user, but the default value will still be passed through to the \nvalidated_data\n.\n\n\nUsing with a hidden date field.\n\n\nIf you want the date field to be entirely hidden from the user, then use \nHiddenField\n. This field type does not accept user input, but instead always returns its default value to the \nvalidated_data\n in the serializer.\n\n\npublished = serializers.HiddenField(default=timezone.now)\n\n\n\n\n\nNote\n: The \nUniqueForValidation\n classes impose an implicit constraint that the fields they are applied to are always treated as required. Fields with \ndefault\n values are an exception to this as they always supply a value even when omitted from user input.\n\n\n\n\nAdvanced field defaults\n\n\nValidators that are applied across multiple fields in the serializer can sometimes require a field input that should not be provided by the API client, but that \nis\n available as input to the validator.\n\n\nTwo patterns that you may want to use for this sort of validation include:\n\n\n\n\nUsing \nHiddenField\n. This field will be present in \nvalidated_data\n but \nwill not\n be used in the serializer output representation.\n\n\nUsing a standard field with \nread_only=True\n, but that also includes a \ndefault=\u2026\n argument. This field \nwill\n be used in the serializer output representation, but cannot be set directly by the user.\n\n\n\n\nREST framework includes a couple of defaults that may be useful in this context.\n\n\nCurrentUserDefault\n\n\nA default class that can be used to represent the current user. In order to use this, the 'request' must have been provided as part of the context dictionary when instantiating the serializer.\n\n\nowner = serializers.HiddenField(\n default=serializers.CurrentUserDefault()\n)\n\n\n\nCreateOnlyDefault\n\n\nA default class that can be used to \nonly set a default argument during create operations\n. During updates the field is omitted.\n\n\nIt takes a single argument, which is the default value or callable that should be used during create operations.\n\n\ncreated_at = serializers.DateTimeField(\n default=serializers.CreateOnlyDefault(timezone.now)\n)\n\n\n\n\n\nLimitations of validators\n\n\nThere are some ambiguous cases where you'll need to instead handle validation\nexplicitly, rather than relying on the default serializer classes that\n\nModelSerializer\n generates.\n\n\nIn these cases you may want to disable the automatically generated validators,\nby specifying an empty list for the serializer \nMeta.validators\n attribute.\n\n\nOptional fields\n\n\nBy default \"unique together\" validation enforces that all fields be\n\nrequired=True\n. In some cases, you might want to explicit apply\n\nrequired=False\n to one of the fields, in which case the desired behaviour\nof the validation is ambiguous.\n\n\nIn this case you will typically need to exclude the validator from the\nserializer class, and instead write any validation logic explicitly, either\nin the \n.validate()\n method, or else in the view.\n\n\nFor example:\n\n\nclass BillingRecordSerializer(serializers.ModelSerializer):\n def validate(self, data):\n # Apply custom validation either here, or in the view.\n\n class Meta:\n fields = ('client', 'date', 'amount')\n extra_kwargs = {'client': {'required': False}}\n validators = [] # Remove a default \"unique together\" constraint.\n\n\n\nUpdating nested serializers\n\n\nWhen applying an update to an existing instance, uniqueness validators will\nexclude the current instance from the uniqueness check. The current instance\nis available in the context of the uniqueness check, because it exists as\nan attribute on the serializer, having initially been passed using\n\ninstance=...\n when instantiating the serializer.\n\n\nIn the case of update operations on \nnested\n serializers there's no way of\napplying this exclusion, because the instance is not available.\n\n\nAgain, you'll probably want to explicitly remove the validator from the\nserializer class, and write the code the for the validation constraint\nexplicitly, in a \n.validate()\n method, or in the view.\n\n\nDebugging complex cases\n\n\nIf you're not sure exactly what behavior a \nModelSerializer\n class will\ngenerate it is usually a good idea to run \nmanage.py shell\n, and print\nan instance of the serializer, so that you can inspect the fields and\nvalidators that it automatically generates for you.\n\n\n>>> serializer = MyComplexModelSerializer()\n>>> print(serializer)\nclass MyComplexModelSerializer:\n my_fields = ...\n\n\n\nAlso keep in mind that with complex cases it can often be better to explicitly\ndefine your serializer classes, rather than relying on the default\n\nModelSerializer\n behavior. This involves a little more code, but ensures\nthat the resulting behavior is more transparent.\n\n\n\n\nWriting custom validators\n\n\nYou can use any of Django's existing validators, or write your own custom validators.\n\n\nFunction based\n\n\nA validator may be any callable that raises a \nserializers.ValidationError\n on failure.\n\n\ndef even_number(value):\n if value % 2 != 0:\n raise serializers.ValidationError('This field must be an even number.')\n\n\n\nField-level validation\n\n\nYou can specify custom field-level validation by adding \n.validate_\n methods\nto your \nSerializer\n subclass. This is documented in the\n\nSerializer docs\n\n\nClass-based\n\n\nTo write a class-based validator, use the \n__call__\n method. Class-based validators are useful as they allow you to parameterize and reuse behavior.\n\n\nclass MultipleOf(object):\n def __init__(self, base):\n self.base = base\n\n def __call__(self, value):\n if value % self.base != 0:\n message = 'This field must be a multiple of %d.' % self.base\n raise serializers.ValidationError(message)\n\n\n\nUsing \nset_context()\n\n\nIn some advanced cases you might want a validator to be passed the serializer field it is being used with as additional context. You can do so by declaring a \nset_context\n method on a class-based validator.\n\n\ndef set_context(self, serializer_field):\n # Determine if this is an update or a create operation.\n # In `__call__` we can then use that information to modify the validation behavior.\n self.is_update = serializer_field.parent.instance is not None", "title": "Validators" }, { @@ -2292,7 +2302,7 @@ }, { "location": "/api-guide/validators/#createonlydefault", - "text": "A default class that can be used to only set a default argument during create operations . During updates the field is omitted. It takes a single argument, which is the default value or callable that should be used during create operations. created_at = serializers.DateTimeField(\n read_only=True,\n default=serializers.CreateOnlyDefault(timezone.now)\n)", + "text": "A default class that can be used to only set a default argument during create operations . During updates the field is omitted. It takes a single argument, which is the default value or callable that should be used during create operations. created_at = serializers.DateTimeField(\n default=serializers.CreateOnlyDefault(timezone.now)\n)", "title": "CreateOnlyDefault" }, { @@ -2302,7 +2312,7 @@ }, { "location": "/api-guide/validators/#optional-fields", - "text": "By default \"unique together\" validation enforces that all fields be required=True . In some cases, you might want to explicit apply required=False to one of the fields, in which case the desired behaviour\nof the validation is ambiguous. In this case you will typically need to exclude the validator from the\nserializer class, and instead write any validation logic explicitly, either\nin the .validate() method, or else in the view. For example: class BillingRecordSerializer(serializers.ModelSerializer):\n def validate(self, data):\n # Apply custom validation either here, or in the view.\n\n class Meta:\n fields = ('client', 'date', 'amount')\n extra_kwargs = {'client': {'required': 'False'}}\n validators = [] # Remove a default \"unique together\" constraint.", + "text": "By default \"unique together\" validation enforces that all fields be required=True . In some cases, you might want to explicit apply required=False to one of the fields, in which case the desired behaviour\nof the validation is ambiguous. In this case you will typically need to exclude the validator from the\nserializer class, and instead write any validation logic explicitly, either\nin the .validate() method, or else in the view. For example: class BillingRecordSerializer(serializers.ModelSerializer):\n def validate(self, data):\n # Apply custom validation either here, or in the view.\n\n class Meta:\n fields = ('client', 'date', 'amount')\n extra_kwargs = {'client': {'required': False}}\n validators = [] # Remove a default \"unique together\" constraint.", "title": "Optional fields" }, { @@ -2342,7 +2352,7 @@ }, { "location": "/api-guide/authentication/", - "text": "Authentication\n\n\n\n\nAuth needs to be pluggable.\n\n\n\u2014 Jacob Kaplan-Moss, \n\"REST worst practices\"\n\n\n\n\nAuthentication is the mechanism of associating an incoming request with a set of identifying credentials, such as the user the request came from, or the token that it was signed with. The \npermission\n and \nthrottling\n policies can then use those credentials to determine if the request should be permitted.\n\n\nREST framework provides a number of authentication schemes out of the box, and also allows you to implement custom schemes.\n\n\nAuthentication is always run at the very start of the view, before the permission and throttling checks occur, and before any other code is allowed to proceed.\n\n\nThe \nrequest.user\n property will typically be set to an instance of the \ncontrib.auth\n package's \nUser\n class.\n\n\nThe \nrequest.auth\n property is used for any additional authentication information, for example, it may be used to represent an authentication token that the request was signed with.\n\n\n\n\nNote:\n Don't forget that \nauthentication by itself won't allow or disallow an incoming request\n, it simply identifies the credentials that the request was made with.\n\n\nFor information on how to setup the permission polices for your API please see the \npermissions documentation\n.\n\n\n\n\nHow authentication is determined\n\n\nThe authentication schemes are always defined as a list of classes. REST framework will attempt to authenticate with each class in the list, and will set \nrequest.user\n and \nrequest.auth\n using the return value of the first class that successfully authenticates.\n\n\nIf no class authenticates, \nrequest.user\n will be set to an instance of \ndjango.contrib.auth.models.AnonymousUser\n, and \nrequest.auth\n will be set to \nNone\n.\n\n\nThe value of \nrequest.user\n and \nrequest.auth\n for unauthenticated requests can be modified using the \nUNAUTHENTICATED_USER\n and \nUNAUTHENTICATED_TOKEN\n settings.\n\n\nSetting the authentication scheme\n\n\nThe default authentication schemes may be set globally, using the \nDEFAULT_AUTHENTICATION_CLASSES\n setting. For example.\n\n\nREST_FRAMEWORK = {\n 'DEFAULT_AUTHENTICATION_CLASSES': (\n 'rest_framework.authentication.BasicAuthentication',\n 'rest_framework.authentication.SessionAuthentication',\n )\n}\n\n\n\nYou can also set the authentication scheme on a per-view or per-viewset basis,\nusing the \nAPIView\n class-based views.\n\n\nfrom rest_framework.authentication import SessionAuthentication, BasicAuthentication\nfrom rest_framework.permissions import IsAuthenticated\nfrom rest_framework.response import Response\nfrom rest_framework.views import APIView\n\nclass ExampleView(APIView):\n authentication_classes = (SessionAuthentication, BasicAuthentication)\n permission_classes = (IsAuthenticated,)\n\n def get(self, request, format=None):\n content = {\n 'user': unicode(request.user), # `django.contrib.auth.User` instance.\n 'auth': unicode(request.auth), # None\n }\n return Response(content)\n\n\n\nOr, if you're using the \n@api_view\n decorator with function based views.\n\n\n@api_view(['GET'])\n@authentication_classes((SessionAuthentication, BasicAuthentication))\n@permission_classes((IsAuthenticated,))\ndef example_view(request, format=None):\n content = {\n 'user': unicode(request.user), # `django.contrib.auth.User` instance.\n 'auth': unicode(request.auth), # None\n }\n return Response(content)\n\n\n\nUnauthorized and Forbidden responses\n\n\nWhen an unauthenticated request is denied permission there are two different error codes that may be appropriate.\n\n\n\n\nHTTP 401 Unauthorized\n\n\nHTTP 403 Permission Denied\n\n\n\n\nHTTP 401 responses must always include a \nWWW-Authenticate\n header, that instructs the client how to authenticate. HTTP 403 responses do not include the \nWWW-Authenticate\n header.\n\n\nThe kind of response that will be used depends on the authentication scheme. Although multiple authentication schemes may be in use, only one scheme may be used to determine the type of response. \nThe first authentication class set on the view is used when determining the type of response\n.\n\n\nNote that when a request may successfully authenticate, but still be denied permission to perform the request, in which case a \n403 Permission Denied\n response will always be used, regardless of the authentication scheme.\n\n\nApache mod_wsgi specific configuration\n\n\nNote that if deploying to \nApache using mod_wsgi\n, the authorization header is not passed through to a WSGI application by default, as it is assumed that authentication will be handled by Apache, rather than at an application level.\n\n\nIf you are deploying to Apache, and using any non-session based authentication, you will need to explicitly configure mod_wsgi to pass the required headers through to the application. This can be done by specifying the \nWSGIPassAuthorization\n directive in the appropriate context and setting it to \n'On'\n.\n\n\n# this can go in either server config, virtual host, directory or .htaccess\nWSGIPassAuthorization On\n\n\n\n\n\nAPI Reference\n\n\nBasicAuthentication\n\n\nThis authentication scheme uses \nHTTP Basic Authentication\n, signed against a user's username and password. Basic authentication is generally only appropriate for testing.\n\n\nIf successfully authenticated, \nBasicAuthentication\n provides the following credentials.\n\n\n\n\nrequest.user\n will be a Django \nUser\n instance.\n\n\nrequest.auth\n will be \nNone\n.\n\n\n\n\nUnauthenticated responses that are denied permission will result in an \nHTTP 401 Unauthorized\n response with an appropriate WWW-Authenticate header. For example:\n\n\nWWW-Authenticate: Basic realm=\"api\"\n\n\n\nNote:\n If you use \nBasicAuthentication\n in production you must ensure that your API is only available over \nhttps\n. You should also ensure that your API clients will always re-request the username and password at login, and will never store those details to persistent storage.\n\n\nTokenAuthentication\n\n\nThis authentication scheme uses a simple token-based HTTP Authentication scheme. Token authentication is appropriate for client-server setups, such as native desktop and mobile clients.\n\n\nTo use the \nTokenAuthentication\n scheme you'll need to \nconfigure the authentication classes\n to include \nTokenAuthentication\n, and additionally include \nrest_framework.authtoken\n in your \nINSTALLED_APPS\n setting:\n\n\nINSTALLED_APPS = (\n ...\n 'rest_framework.authtoken'\n)\n\n\n\n\n\nNote:\n Make sure to run \nmanage.py migrate\n after changing your settings. The \nrest_framework.authtoken\n app provides Django database migrations.\n\n\n\n\nYou'll also need to create tokens for your users.\n\n\nfrom rest_framework.authtoken.models import Token\n\ntoken = Token.objects.create(user=...)\nprint token.key\n\n\n\nFor clients to authenticate, the token key should be included in the \nAuthorization\n HTTP header. The key should be prefixed by the string literal \"Token\", with whitespace separating the two strings. For example:\n\n\nAuthorization: Token 9944b09199c62bcf9418ad846dd0e4bbdfc6ee4b\n\n\n\nNote:\n If you want to use a different keyword in the header, such as \nBearer\n, simply subclass \nTokenAuthentication\n and set the \nkeyword\n class variable.\n\n\nIf successfully authenticated, \nTokenAuthentication\n provides the following credentials.\n\n\n\n\nrequest.user\n will be a Django \nUser\n instance.\n\n\nrequest.auth\n will be a \nrest_framework.authtoken.models.Token\n instance.\n\n\n\n\nUnauthenticated responses that are denied permission will result in an \nHTTP 401 Unauthorized\n response with an appropriate WWW-Authenticate header. For example:\n\n\nWWW-Authenticate: Token\n\n\n\nThe \ncurl\n command line tool may be useful for testing token authenticated APIs. For example:\n\n\ncurl -X GET http://127.0.0.1:8000/api/example/ -H 'Authorization: Token 9944b09199c62bcf9418ad846dd0e4bbdfc6ee4b'\n\n\n\n\n\nNote:\n If you use \nTokenAuthentication\n in production you must ensure that your API is only available over \nhttps\n.\n\n\n\n\nGenerating Tokens\n\n\nBy using signals\n\n\nIf you want every user to have an automatically generated Token, you can simply catch the User's \npost_save\n signal.\n\n\nfrom django.conf import settings\nfrom django.db.models.signals import post_save\nfrom django.dispatch import receiver\nfrom rest_framework.authtoken.models import Token\n\n@receiver(post_save, sender=settings.AUTH_USER_MODEL)\ndef create_auth_token(sender, instance=None, created=False, **kwargs):\n if created:\n Token.objects.create(user=instance)\n\n\n\nNote that you'll want to ensure you place this code snippet in an installed \nmodels.py\n module, or some other location that will be imported by Django on startup.\n\n\nIf you've already created some users, you can generate tokens for all existing users like this:\n\n\nfrom django.contrib.auth.models import User\nfrom rest_framework.authtoken.models import Token\n\nfor user in User.objects.all():\n Token.objects.get_or_create(user=user)\n\n\n\nBy exposing an api endpoint\n\n\nWhen using \nTokenAuthentication\n, you may want to provide a mechanism for clients to obtain a token given the username and password. REST framework provides a built-in view to provide this behavior. To use it, add the \nobtain_auth_token\n view to your URLconf:\n\n\nfrom rest_framework.authtoken import views\nurlpatterns += [\n url(r'^api-token-auth/', views.obtain_auth_token)\n]\n\n\n\nNote that the URL part of the pattern can be whatever you want to use.\n\n\nThe \nobtain_auth_token\n view will return a JSON response when valid \nusername\n and \npassword\n fields are POSTed to the view using form data or JSON:\n\n\n{ 'token' : '9944b09199c62bcf9418ad846dd0e4bbdfc6ee4b' }\n\n\n\nNote that the default \nobtain_auth_token\n view explicitly uses JSON requests and responses, rather than using default renderer and parser classes in your settings. If you need a customized version of the \nobtain_auth_token\n view, you can do so by overriding the \nObtainAuthToken\n view class, and using that in your url conf instead.\n\n\nBy default there are no permissions or throttling applied to the \nobtain_auth_token\n view. If you do wish to apply throttling you'll need to override the view class,\nand include them using the \nthrottle_classes\n attribute.\n\n\nWith Django admin\n\n\nIt is also possible to create Tokens manually through admin interface. In case you are using a large user base, we recommend that you monkey patch the \nTokenAdmin\n class to customize it to your needs, more specifically by declaring the \nuser\n field as \nraw_field\n.\n\n\nyour_app/admin.py\n:\n\n\nfrom rest_framework.authtoken.admin import TokenAdmin\n\nTokenAdmin.raw_id_fields = ('user',)\n\n\n\nUsing Django manage.py command\n\n\nSince version 3.6.4 it's possible to generate a user token using the following command:\n\n\n./manage.py drf_create_token \n\n\n\nthis command will return the API token for the given user, creating it if it doesn't exist:\n\n\nGenerated token 9944b09199c62bcf9418ad846dd0e4bbdfc6ee4b for user user1\n\n\n\nIn case you want to regenerate the token (for example if it has been compromised or leaked) you can pass an additional parameter:\n\n\n./manage.py drf_create_token -r \n\n\n\nSessionAuthentication\n\n\nThis authentication scheme uses Django's default session backend for authentication. Session authentication is appropriate for AJAX clients that are running in the same session context as your website.\n\n\nIf successfully authenticated, \nSessionAuthentication\n provides the following credentials.\n\n\n\n\nrequest.user\n will be a Django \nUser\n instance.\n\n\nrequest.auth\n will be \nNone\n.\n\n\n\n\nUnauthenticated responses that are denied permission will result in an \nHTTP 403 Forbidden\n response.\n\n\nIf 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 \nPUT\n, \nPATCH\n, \nPOST\n or \nDELETE\n requests. See the \nDjango CSRF documentation\n for more details.\n\n\nWarning\n: Always use Django's standard login view when creating login pages. This will ensure your login views are properly protected.\n\n\nCSRF validation in REST framework works slightly differently to standard Django due to the need to support both session and non-session based authentication to the same views. This means that only authenticated requests require CSRF tokens, and anonymous requests may be sent without CSRF tokens. This behaviour is not suitable for login views, which should always have CSRF validation applied.\n\n\nRemoteUserAuthentication\n\n\nThis authentication scheme allows you to delegate authentication to your web server, which sets the \nREMOTE_USER\n\nenvironment variable.\n\n\nTo use it, you must have \ndjango.contrib.auth.backends.RemoteUserBackend\n (or a subclass) in your\n\nAUTHENTICATION_BACKENDS\n setting. By default, \nRemoteUserBackend\n creates \nUser\n objects for usernames that don't\nalready exist. To change this and other behaviour, consult the\n\nDjango documentation\n.\n\n\nIf successfully authenticated, \nRemoteUserAuthentication\n provides the following credentials:\n\n\n\n\nrequest.user\n will be a Django \nUser\n instance.\n\n\nrequest.auth\n will be \nNone\n.\n\n\n\n\nConsult your web server's documentation for information about configuring an authentication method, e.g.:\n\n\n\n\nApache Authentication How-To\n\n\nNGINX (Restricting Access)\n\n\n\n\nCustom authentication\n\n\nTo implement a custom authentication scheme, subclass \nBaseAuthentication\n and override the \n.authenticate(self, request)\n method. The method should return a two-tuple of \n(user, auth)\n if authentication succeeds, or \nNone\n otherwise.\n\n\nIn some circumstances instead of returning \nNone\n, you may want to raise an \nAuthenticationFailed\n exception from the \n.authenticate()\n method.\n\n\nTypically the approach you should take is:\n\n\n\n\nIf authentication is not attempted, return \nNone\n. Any other authentication schemes also in use will still be checked.\n\n\nIf authentication is attempted but fails, raise a \nAuthenticationFailed\n exception. An error response will be returned immediately, regardless of any permissions checks, and without checking any other authentication schemes.\n\n\n\n\nYou \nmay\n also override the \n.authenticate_header(self, request)\n method. If implemented, it should return a string that will be used as the value of the \nWWW-Authenticate\n header in a \nHTTP 401 Unauthorized\n response.\n\n\nIf the \n.authenticate_header()\n method is not overridden, the authentication scheme will return \nHTTP 403 Forbidden\n responses when an unauthenticated request is denied access.\n\n\n\n\nNote:\n When your custom authenticator is invoked by the request object's \n.user\n or \n.auth\n properties, you may see an \nAttributeError\n re-raised as a \nWrappedAttributeError\n. This is necessary to prevent the original exception from being suppressed by the outer property access. Python will not recognize that the \nAttributeError\n orginates from your custom authenticator and will instead assume that the request object does not have a \n.user\n or \n.auth\n property. These errors should be fixed or otherwise handled by your authenticator.\n\n\n\n\nExample\n\n\nThe following example will authenticate any incoming request as the user given by the username in a custom request header named 'X_USERNAME'.\n\n\nfrom django.contrib.auth.models import User\nfrom rest_framework import authentication\nfrom rest_framework import exceptions\n\nclass ExampleAuthentication(authentication.BaseAuthentication):\n def authenticate(self, request):\n username = request.META.get('X_USERNAME')\n if not username:\n return None\n\n try:\n user = User.objects.get(username=username)\n except User.DoesNotExist:\n raise exceptions.AuthenticationFailed('No such user')\n\n return (user, None)\n\n\n\n\n\nThird party packages\n\n\nThe following third party packages are also available.\n\n\nDjango OAuth Toolkit\n\n\nThe \nDjango OAuth Toolkit\n package provides OAuth 2.0 support, and works with Python 2.7 and Python 3.3+. The package is maintained by \nEvonove\n and uses the excellent \nOAuthLib\n. The package is well documented, and well supported and is currently our \nrecommended package for OAuth 2.0 support\n.\n\n\nInstallation & configuration\n\n\nInstall using \npip\n.\n\n\npip install django-oauth-toolkit\n\n\n\nAdd the package to your \nINSTALLED_APPS\n and modify your REST framework settings.\n\n\nINSTALLED_APPS = (\n ...\n 'oauth2_provider',\n)\n\nREST_FRAMEWORK = {\n 'DEFAULT_AUTHENTICATION_CLASSES': (\n 'oauth2_provider.contrib.rest_framework.OAuth2Authentication',\n )\n}\n\n\n\nFor more details see the \nDjango REST framework - Getting started\n documentation.\n\n\nDjango REST framework OAuth\n\n\nThe \nDjango REST framework OAuth\n package provides both OAuth1 and OAuth2 support for REST framework.\n\n\nThis package was previously included directly in REST framework but is now supported and maintained as a third party package.\n\n\nInstallation & configuration\n\n\nInstall the package using \npip\n.\n\n\npip install djangorestframework-oauth\n\n\n\nFor details on configuration and usage see the Django REST framework OAuth documentation for \nauthentication\n and \npermissions\n.\n\n\nDigest Authentication\n\n\nHTTP digest authentication is a widely implemented scheme that was intended to replace HTTP basic authentication, and which provides a simple encrypted authentication mechanism. \nJuan Riaza\n maintains the \ndjangorestframework-digestauth\n package which provides HTTP digest authentication support for REST framework.\n\n\nDjango OAuth2 Consumer\n\n\nThe \nDjango OAuth2 Consumer\n library from \nRediker Software\n is another package that provides \nOAuth 2.0 support for REST framework\n. The package includes token scoping permissions on tokens, which allows finer-grained access to your API.\n\n\nJSON Web Token Authentication\n\n\nJSON Web Token is a fairly new standard which can be used for token-based authentication. Unlike the built-in TokenAuthentication scheme, JWT Authentication doesn't need to use a database to validate a token. \nBlimp\n maintains the \ndjangorestframework-jwt\n package which provides a JWT Authentication class as well as a mechanism for clients to obtain a JWT given the username and password. An alternative package for JWT authentication is \ndjangorestframework-simplejwt\n which provides different features as well as a pluggable token blacklist app.\n\n\nHawk HTTP Authentication\n\n\nThe \nHawkREST\n library builds on the \nMohawk\n library to let you work with \nHawk\n signed requests and responses in your API. \nHawk\n lets two parties securely communicate with each other using messages signed by a shared key. It is based on \nHTTP MAC access authentication\n (which was based on parts of \nOAuth 1.0\n).\n\n\nHTTP Signature Authentication\n\n\nHTTP Signature (currently a \nIETF draft\n) provides a way to achieve origin authentication and message integrity for HTTP messages. Similar to \nAmazon's HTTP Signature scheme\n, used by many of its services, it permits stateless, per-request authentication. \nElvio Toccalino\n maintains the \ndjangorestframework-httpsignature\n package which provides an easy to use HTTP Signature Authentication mechanism.\n\n\nDjoser\n\n\nDjoser\n library provides a set of views to handle basic actions such as registration, login, logout, password reset and account activation. The package works with a custom user model and it uses token based authentication. This is a ready to use REST implementation of Django authentication system.\n\n\ndjango-rest-auth\n\n\nDjango-rest-auth\n library provides a set of REST API endpoints for registration, authentication (including social media authentication), password reset, retrieve and update user details, etc. By having these API endpoints, your client apps such as AngularJS, iOS, Android, and others can communicate to your Django backend site independently via REST APIs for user management.\n\n\ndjango-rest-framework-social-oauth2\n\n\nDjango-rest-framework-social-oauth2\n library provides an easy way to integrate social plugins (facebook, twitter, google, etc.) to your authentication system and an easy oauth2 setup. With this library, you will be able to authenticate users based on external tokens (e.g. facebook access token), convert these tokens to \"in-house\" oauth2 tokens and use and generate oauth2 tokens to authenticate your users.\n\n\ndjango-rest-knox\n\n\nDjango-rest-knox\n library provides models and views to handle token based authentication in a more secure and extensible way than the built-in TokenAuthentication scheme - with Single Page Applications and Mobile clients in mind. It provides per-client tokens, and views to generate them when provided some other authentication (usually basic authentication), to delete the token (providing a server enforced logout) and to delete all tokens (logs out all clients that a user is logged into).\n\n\ndrfpasswordless\n\n\ndrfpasswordless\n adds (Medium, Square Cash inspired) passwordless support to Django REST Framework's own TokenAuthentication scheme. Users log in and sign up with a token sent to a contact point like an email address or a mobile number.", + "text": "Authentication\n\n\n\n\nAuth needs to be pluggable.\n\n\n\u2014 Jacob Kaplan-Moss, \n\"REST worst practices\"\n\n\n\n\nAuthentication is the mechanism of associating an incoming request with a set of identifying credentials, such as the user the request came from, or the token that it was signed with. The \npermission\n and \nthrottling\n policies can then use those credentials to determine if the request should be permitted.\n\n\nREST framework provides a number of authentication schemes out of the box, and also allows you to implement custom schemes.\n\n\nAuthentication is always run at the very start of the view, before the permission and throttling checks occur, and before any other code is allowed to proceed.\n\n\nThe \nrequest.user\n property will typically be set to an instance of the \ncontrib.auth\n package's \nUser\n class.\n\n\nThe \nrequest.auth\n property is used for any additional authentication information, for example, it may be used to represent an authentication token that the request was signed with.\n\n\n\n\nNote:\n Don't forget that \nauthentication by itself won't allow or disallow an incoming request\n, it simply identifies the credentials that the request was made with.\n\n\nFor information on how to setup the permission polices for your API please see the \npermissions documentation\n.\n\n\n\n\nHow authentication is determined\n\n\nThe authentication schemes are always defined as a list of classes. REST framework will attempt to authenticate with each class in the list, and will set \nrequest.user\n and \nrequest.auth\n using the return value of the first class that successfully authenticates.\n\n\nIf no class authenticates, \nrequest.user\n will be set to an instance of \ndjango.contrib.auth.models.AnonymousUser\n, and \nrequest.auth\n will be set to \nNone\n.\n\n\nThe value of \nrequest.user\n and \nrequest.auth\n for unauthenticated requests can be modified using the \nUNAUTHENTICATED_USER\n and \nUNAUTHENTICATED_TOKEN\n settings.\n\n\nSetting the authentication scheme\n\n\nThe default authentication schemes may be set globally, using the \nDEFAULT_AUTHENTICATION_CLASSES\n setting. For example.\n\n\nREST_FRAMEWORK = {\n 'DEFAULT_AUTHENTICATION_CLASSES': (\n 'rest_framework.authentication.BasicAuthentication',\n 'rest_framework.authentication.SessionAuthentication',\n )\n}\n\n\n\nYou can also set the authentication scheme on a per-view or per-viewset basis,\nusing the \nAPIView\n class-based views.\n\n\nfrom rest_framework.authentication import SessionAuthentication, BasicAuthentication\nfrom rest_framework.permissions import IsAuthenticated\nfrom rest_framework.response import Response\nfrom rest_framework.views import APIView\n\nclass ExampleView(APIView):\n authentication_classes = (SessionAuthentication, BasicAuthentication)\n permission_classes = (IsAuthenticated,)\n\n def get(self, request, format=None):\n content = {\n 'user': unicode(request.user), # `django.contrib.auth.User` instance.\n 'auth': unicode(request.auth), # None\n }\n return Response(content)\n\n\n\nOr, if you're using the \n@api_view\n decorator with function based views.\n\n\n@api_view(['GET'])\n@authentication_classes((SessionAuthentication, BasicAuthentication))\n@permission_classes((IsAuthenticated,))\ndef example_view(request, format=None):\n content = {\n 'user': unicode(request.user), # `django.contrib.auth.User` instance.\n 'auth': unicode(request.auth), # None\n }\n return Response(content)\n\n\n\nUnauthorized and Forbidden responses\n\n\nWhen an unauthenticated request is denied permission there are two different error codes that may be appropriate.\n\n\n\n\nHTTP 401 Unauthorized\n\n\nHTTP 403 Permission Denied\n\n\n\n\nHTTP 401 responses must always include a \nWWW-Authenticate\n header, that instructs the client how to authenticate. HTTP 403 responses do not include the \nWWW-Authenticate\n header.\n\n\nThe kind of response that will be used depends on the authentication scheme. Although multiple authentication schemes may be in use, only one scheme may be used to determine the type of response. \nThe first authentication class set on the view is used when determining the type of response\n.\n\n\nNote that when a request may successfully authenticate, but still be denied permission to perform the request, in which case a \n403 Permission Denied\n response will always be used, regardless of the authentication scheme.\n\n\nApache mod_wsgi specific configuration\n\n\nNote that if deploying to \nApache using mod_wsgi\n, the authorization header is not passed through to a WSGI application by default, as it is assumed that authentication will be handled by Apache, rather than at an application level.\n\n\nIf you are deploying to Apache, and using any non-session based authentication, you will need to explicitly configure mod_wsgi to pass the required headers through to the application. This can be done by specifying the \nWSGIPassAuthorization\n directive in the appropriate context and setting it to \n'On'\n.\n\n\n# this can go in either server config, virtual host, directory or .htaccess\nWSGIPassAuthorization On\n\n\n\n\n\nAPI Reference\n\n\nBasicAuthentication\n\n\nThis authentication scheme uses \nHTTP Basic Authentication\n, signed against a user's username and password. Basic authentication is generally only appropriate for testing.\n\n\nIf successfully authenticated, \nBasicAuthentication\n provides the following credentials.\n\n\n\n\nrequest.user\n will be a Django \nUser\n instance.\n\n\nrequest.auth\n will be \nNone\n.\n\n\n\n\nUnauthenticated responses that are denied permission will result in an \nHTTP 401 Unauthorized\n response with an appropriate WWW-Authenticate header. For example:\n\n\nWWW-Authenticate: Basic realm=\"api\"\n\n\n\nNote:\n If you use \nBasicAuthentication\n in production you must ensure that your API is only available over \nhttps\n. You should also ensure that your API clients will always re-request the username and password at login, and will never store those details to persistent storage.\n\n\nTokenAuthentication\n\n\nThis authentication scheme uses a simple token-based HTTP Authentication scheme. Token authentication is appropriate for client-server setups, such as native desktop and mobile clients.\n\n\nTo use the \nTokenAuthentication\n scheme you'll need to \nconfigure the authentication classes\n to include \nTokenAuthentication\n, and additionally include \nrest_framework.authtoken\n in your \nINSTALLED_APPS\n setting:\n\n\nINSTALLED_APPS = (\n ...\n 'rest_framework.authtoken'\n)\n\n\n\n\n\nNote:\n Make sure to run \nmanage.py migrate\n after changing your settings. The \nrest_framework.authtoken\n app provides Django database migrations.\n\n\n\n\nYou'll also need to create tokens for your users.\n\n\nfrom rest_framework.authtoken.models import Token\n\ntoken = Token.objects.create(user=...)\nprint token.key\n\n\n\nFor clients to authenticate, the token key should be included in the \nAuthorization\n HTTP header. The key should be prefixed by the string literal \"Token\", with whitespace separating the two strings. For example:\n\n\nAuthorization: Token 9944b09199c62bcf9418ad846dd0e4bbdfc6ee4b\n\n\n\nNote:\n If you want to use a different keyword in the header, such as \nBearer\n, simply subclass \nTokenAuthentication\n and set the \nkeyword\n class variable.\n\n\nIf successfully authenticated, \nTokenAuthentication\n provides the following credentials.\n\n\n\n\nrequest.user\n will be a Django \nUser\n instance.\n\n\nrequest.auth\n will be a \nrest_framework.authtoken.models.Token\n instance.\n\n\n\n\nUnauthenticated responses that are denied permission will result in an \nHTTP 401 Unauthorized\n response with an appropriate WWW-Authenticate header. For example:\n\n\nWWW-Authenticate: Token\n\n\n\nThe \ncurl\n command line tool may be useful for testing token authenticated APIs. For example:\n\n\ncurl -X GET http://127.0.0.1:8000/api/example/ -H 'Authorization: Token 9944b09199c62bcf9418ad846dd0e4bbdfc6ee4b'\n\n\n\n\n\nNote:\n If you use \nTokenAuthentication\n in production you must ensure that your API is only available over \nhttps\n.\n\n\n\n\nGenerating Tokens\n\n\nBy using signals\n\n\nIf you want every user to have an automatically generated Token, you can simply catch the User's \npost_save\n signal.\n\n\nfrom django.conf import settings\nfrom django.db.models.signals import post_save\nfrom django.dispatch import receiver\nfrom rest_framework.authtoken.models import Token\n\n@receiver(post_save, sender=settings.AUTH_USER_MODEL)\ndef create_auth_token(sender, instance=None, created=False, **kwargs):\n if created:\n Token.objects.create(user=instance)\n\n\n\nNote that you'll want to ensure you place this code snippet in an installed \nmodels.py\n module, or some other location that will be imported by Django on startup.\n\n\nIf you've already created some users, you can generate tokens for all existing users like this:\n\n\nfrom django.contrib.auth.models import User\nfrom rest_framework.authtoken.models import Token\n\nfor user in User.objects.all():\n Token.objects.get_or_create(user=user)\n\n\n\nBy exposing an api endpoint\n\n\nWhen using \nTokenAuthentication\n, you may want to provide a mechanism for clients to obtain a token given the username and password. REST framework provides a built-in view to provide this behavior. To use it, add the \nobtain_auth_token\n view to your URLconf:\n\n\nfrom rest_framework.authtoken import views\nurlpatterns += [\n url(r'^api-token-auth/', views.obtain_auth_token)\n]\n\n\n\nNote that the URL part of the pattern can be whatever you want to use.\n\n\nThe \nobtain_auth_token\n view will return a JSON response when valid \nusername\n and \npassword\n fields are POSTed to the view using form data or JSON:\n\n\n{ 'token' : '9944b09199c62bcf9418ad846dd0e4bbdfc6ee4b' }\n\n\n\nNote that the default \nobtain_auth_token\n view explicitly uses JSON requests and responses, rather than using default renderer and parser classes in your settings.\n\n\nBy default there are no permissions or throttling applied to the \nobtain_auth_token\n view. If you do wish to apply throttling you'll need to override the view class,\nand include them using the \nthrottle_classes\n attribute.\n\n\nIf you need a customized version of the \nobtain_auth_token\n view, you can do so by subclassing the \nObtainAuthToken\n view class, and using that in your url conf instead.\n\n\nFor example, you may return additional user information beyond the \ntoken\n value:\n\n\nfrom rest_framework.authtoken.views import ObtainAuthToken\nfrom rest_framework.authtoken.models import Token\nfrom rest_framework.response import Response\n\nclass CustomAuthToken(ObtainAuthToken):\n\n def post(self, request, *args, **kwargs):\n serializer = self.serializer_class(data=request.data,\n context={'request': request})\n serializer.is_valid(raise_exception=True)\n user = serializer.validated_data['user']\n token, created = Token.objects.get_or_create(user=user)\n return Response({\n 'token': token.key,\n 'user_id': user.pk,\n 'email': user.email\n })\n\n\n\nAnd in your \nurls.py\n:\n\n\nurlpatterns += [\n url(r'^api-token-auth/', CustomAuthToken.as_view())\n]\n\n\n\nWith Django admin\n\n\nIt is also possible to create Tokens manually through admin interface. In case you are using a large user base, we recommend that you monkey patch the \nTokenAdmin\n class to customize it to your needs, more specifically by declaring the \nuser\n field as \nraw_field\n.\n\n\nyour_app/admin.py\n:\n\n\nfrom rest_framework.authtoken.admin import TokenAdmin\n\nTokenAdmin.raw_id_fields = ('user',)\n\n\n\nUsing Django manage.py command\n\n\nSince version 3.6.4 it's possible to generate a user token using the following command:\n\n\n./manage.py drf_create_token \n\n\n\nthis command will return the API token for the given user, creating it if it doesn't exist:\n\n\nGenerated token 9944b09199c62bcf9418ad846dd0e4bbdfc6ee4b for user user1\n\n\n\nIn case you want to regenerate the token (for example if it has been compromised or leaked) you can pass an additional parameter:\n\n\n./manage.py drf_create_token -r \n\n\n\nSessionAuthentication\n\n\nThis authentication scheme uses Django's default session backend for authentication. Session authentication is appropriate for AJAX clients that are running in the same session context as your website.\n\n\nIf successfully authenticated, \nSessionAuthentication\n provides the following credentials.\n\n\n\n\nrequest.user\n will be a Django \nUser\n instance.\n\n\nrequest.auth\n will be \nNone\n.\n\n\n\n\nUnauthenticated responses that are denied permission will result in an \nHTTP 403 Forbidden\n response.\n\n\nIf 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 \nPUT\n, \nPATCH\n, \nPOST\n or \nDELETE\n requests. See the \nDjango CSRF documentation\n for more details.\n\n\nWarning\n: Always use Django's standard login view when creating login pages. This will ensure your login views are properly protected.\n\n\nCSRF validation in REST framework works slightly differently to standard Django due to the need to support both session and non-session based authentication to the same views. This means that only authenticated requests require CSRF tokens, and anonymous requests may be sent without CSRF tokens. This behaviour is not suitable for login views, which should always have CSRF validation applied.\n\n\nRemoteUserAuthentication\n\n\nThis authentication scheme allows you to delegate authentication to your web server, which sets the \nREMOTE_USER\n\nenvironment variable.\n\n\nTo use it, you must have \ndjango.contrib.auth.backends.RemoteUserBackend\n (or a subclass) in your\n\nAUTHENTICATION_BACKENDS\n setting. By default, \nRemoteUserBackend\n creates \nUser\n objects for usernames that don't\nalready exist. To change this and other behaviour, consult the\n\nDjango documentation\n.\n\n\nIf successfully authenticated, \nRemoteUserAuthentication\n provides the following credentials:\n\n\n\n\nrequest.user\n will be a Django \nUser\n instance.\n\n\nrequest.auth\n will be \nNone\n.\n\n\n\n\nConsult your web server's documentation for information about configuring an authentication method, e.g.:\n\n\n\n\nApache Authentication How-To\n\n\nNGINX (Restricting Access)\n\n\n\n\nCustom authentication\n\n\nTo implement a custom authentication scheme, subclass \nBaseAuthentication\n and override the \n.authenticate(self, request)\n method. The method should return a two-tuple of \n(user, auth)\n if authentication succeeds, or \nNone\n otherwise.\n\n\nIn some circumstances instead of returning \nNone\n, you may want to raise an \nAuthenticationFailed\n exception from the \n.authenticate()\n method.\n\n\nTypically the approach you should take is:\n\n\n\n\nIf authentication is not attempted, return \nNone\n. Any other authentication schemes also in use will still be checked.\n\n\nIf authentication is attempted but fails, raise a \nAuthenticationFailed\n exception. An error response will be returned immediately, regardless of any permissions checks, and without checking any other authentication schemes.\n\n\n\n\nYou \nmay\n also override the \n.authenticate_header(self, request)\n method. If implemented, it should return a string that will be used as the value of the \nWWW-Authenticate\n header in a \nHTTP 401 Unauthorized\n response.\n\n\nIf the \n.authenticate_header()\n method is not overridden, the authentication scheme will return \nHTTP 403 Forbidden\n responses when an unauthenticated request is denied access.\n\n\n\n\nNote:\n When your custom authenticator is invoked by the request object's \n.user\n or \n.auth\n properties, you may see an \nAttributeError\n re-raised as a \nWrappedAttributeError\n. This is necessary to prevent the original exception from being suppressed by the outer property access. Python will not recognize that the \nAttributeError\n orginates from your custom authenticator and will instead assume that the request object does not have a \n.user\n or \n.auth\n property. These errors should be fixed or otherwise handled by your authenticator.\n\n\n\n\nExample\n\n\nThe following example will authenticate any incoming request as the user given by the username in a custom request header named 'X_USERNAME'.\n\n\nfrom django.contrib.auth.models import User\nfrom rest_framework import authentication\nfrom rest_framework import exceptions\n\nclass ExampleAuthentication(authentication.BaseAuthentication):\n def authenticate(self, request):\n username = request.META.get('X_USERNAME')\n if not username:\n return None\n\n try:\n user = User.objects.get(username=username)\n except User.DoesNotExist:\n raise exceptions.AuthenticationFailed('No such user')\n\n return (user, None)\n\n\n\n\n\nThird party packages\n\n\nThe following third party packages are also available.\n\n\nDjango OAuth Toolkit\n\n\nThe \nDjango OAuth Toolkit\n package provides OAuth 2.0 support, and works with Python 2.7 and Python 3.3+. The package is maintained by \nEvonove\n and uses the excellent \nOAuthLib\n. The package is well documented, and well supported and is currently our \nrecommended package for OAuth 2.0 support\n.\n\n\nInstallation & configuration\n\n\nInstall using \npip\n.\n\n\npip install django-oauth-toolkit\n\n\n\nAdd the package to your \nINSTALLED_APPS\n and modify your REST framework settings.\n\n\nINSTALLED_APPS = (\n ...\n 'oauth2_provider',\n)\n\nREST_FRAMEWORK = {\n 'DEFAULT_AUTHENTICATION_CLASSES': (\n 'oauth2_provider.contrib.rest_framework.OAuth2Authentication',\n )\n}\n\n\n\nFor more details see the \nDjango REST framework - Getting started\n documentation.\n\n\nDjango REST framework OAuth\n\n\nThe \nDjango REST framework OAuth\n package provides both OAuth1 and OAuth2 support for REST framework.\n\n\nThis package was previously included directly in REST framework but is now supported and maintained as a third party package.\n\n\nInstallation & configuration\n\n\nInstall the package using \npip\n.\n\n\npip install djangorestframework-oauth\n\n\n\nFor details on configuration and usage see the Django REST framework OAuth documentation for \nauthentication\n and \npermissions\n.\n\n\nDigest Authentication\n\n\nHTTP digest authentication is a widely implemented scheme that was intended to replace HTTP basic authentication, and which provides a simple encrypted authentication mechanism. \nJuan Riaza\n maintains the \ndjangorestframework-digestauth\n package which provides HTTP digest authentication support for REST framework.\n\n\nDjango OAuth2 Consumer\n\n\nThe \nDjango OAuth2 Consumer\n library from \nRediker Software\n is another package that provides \nOAuth 2.0 support for REST framework\n. The package includes token scoping permissions on tokens, which allows finer-grained access to your API.\n\n\nJSON Web Token Authentication\n\n\nJSON Web Token is a fairly new standard which can be used for token-based authentication. Unlike the built-in TokenAuthentication scheme, JWT Authentication doesn't need to use a database to validate a token. \nBlimp\n maintains the \ndjangorestframework-jwt\n package which provides a JWT Authentication class as well as a mechanism for clients to obtain a JWT given the username and password. An alternative package for JWT authentication is \ndjangorestframework-simplejwt\n which provides different features as well as a pluggable token blacklist app.\n\n\nHawk HTTP Authentication\n\n\nThe \nHawkREST\n library builds on the \nMohawk\n library to let you work with \nHawk\n signed requests and responses in your API. \nHawk\n lets two parties securely communicate with each other using messages signed by a shared key. It is based on \nHTTP MAC access authentication\n (which was based on parts of \nOAuth 1.0\n).\n\n\nHTTP Signature Authentication\n\n\nHTTP Signature (currently a \nIETF draft\n) provides a way to achieve origin authentication and message integrity for HTTP messages. Similar to \nAmazon's HTTP Signature scheme\n, used by many of its services, it permits stateless, per-request authentication. \nElvio Toccalino\n maintains the \ndjangorestframework-httpsignature\n package which provides an easy to use HTTP Signature Authentication mechanism.\n\n\nDjoser\n\n\nDjoser\n library provides a set of views to handle basic actions such as registration, login, logout, password reset and account activation. The package works with a custom user model and it uses token based authentication. This is a ready to use REST implementation of Django authentication system.\n\n\ndjango-rest-auth\n\n\nDjango-rest-auth\n library provides a set of REST API endpoints for registration, authentication (including social media authentication), password reset, retrieve and update user details, etc. By having these API endpoints, your client apps such as AngularJS, iOS, Android, and others can communicate to your Django backend site independently via REST APIs for user management.\n\n\ndjango-rest-framework-social-oauth2\n\n\nDjango-rest-framework-social-oauth2\n library provides an easy way to integrate social plugins (facebook, twitter, google, etc.) to your authentication system and an easy oauth2 setup. With this library, you will be able to authenticate users based on external tokens (e.g. facebook access token), convert these tokens to \"in-house\" oauth2 tokens and use and generate oauth2 tokens to authenticate your users.\n\n\ndjango-rest-knox\n\n\nDjango-rest-knox\n library provides models and views to handle token based authentication in a more secure and extensible way than the built-in TokenAuthentication scheme - with Single Page Applications and Mobile clients in mind. It provides per-client tokens, and views to generate them when provided some other authentication (usually basic authentication), to delete the token (providing a server enforced logout) and to delete all tokens (logs out all clients that a user is logged into).\n\n\ndrfpasswordless\n\n\ndrfpasswordless\n adds (Medium, Square Cash inspired) passwordless support to Django REST Framework's own TokenAuthentication scheme. Users log in and sign up with a token sent to a contact point like an email address or a mobile number.", "title": "Authentication" }, { @@ -2397,7 +2407,7 @@ }, { "location": "/api-guide/authentication/#by-exposing-an-api-endpoint", - "text": "When using TokenAuthentication , you may want to provide a mechanism for clients to obtain a token given the username and password. REST framework provides a built-in view to provide this behavior. To use it, add the obtain_auth_token view to your URLconf: from rest_framework.authtoken import views\nurlpatterns += [\n url(r'^api-token-auth/', views.obtain_auth_token)\n] Note that the URL part of the pattern can be whatever you want to use. The obtain_auth_token view will return a JSON response when valid username and password fields are POSTed to the view using form data or JSON: { 'token' : '9944b09199c62bcf9418ad846dd0e4bbdfc6ee4b' } Note that the default obtain_auth_token view explicitly uses JSON requests and responses, rather than using default renderer and parser classes in your settings. If you need a customized version of the obtain_auth_token view, you can do so by overriding the ObtainAuthToken view class, and using that in your url conf instead. By default there are no permissions or throttling applied to the obtain_auth_token view. If you do wish to apply throttling you'll need to override the view class,\nand include them using the throttle_classes attribute.", + "text": "When using TokenAuthentication , you may want to provide a mechanism for clients to obtain a token given the username and password. REST framework provides a built-in view to provide this behavior. To use it, add the obtain_auth_token view to your URLconf: from rest_framework.authtoken import views\nurlpatterns += [\n url(r'^api-token-auth/', views.obtain_auth_token)\n] Note that the URL part of the pattern can be whatever you want to use. The obtain_auth_token view will return a JSON response when valid username and password fields are POSTed to the view using form data or JSON: { 'token' : '9944b09199c62bcf9418ad846dd0e4bbdfc6ee4b' } Note that the default obtain_auth_token view explicitly uses JSON requests and responses, rather than using default renderer and parser classes in your settings. By default there are no permissions or throttling applied to the obtain_auth_token view. If you do wish to apply throttling you'll need to override the view class,\nand include them using the throttle_classes attribute. If you need a customized version of the obtain_auth_token view, you can do so by subclassing the ObtainAuthToken view class, and using that in your url conf instead. For example, you may return additional user information beyond the token value: from rest_framework.authtoken.views import ObtainAuthToken\nfrom rest_framework.authtoken.models import Token\nfrom rest_framework.response import Response\n\nclass CustomAuthToken(ObtainAuthToken):\n\n def post(self, request, *args, **kwargs):\n serializer = self.serializer_class(data=request.data,\n context={'request': request})\n serializer.is_valid(raise_exception=True)\n user = serializer.validated_data['user']\n token, created = Token.objects.get_or_create(user=user)\n return Response({\n 'token': token.key,\n 'user_id': user.pk,\n 'email': user.email\n }) And in your urls.py : urlpatterns += [\n url(r'^api-token-auth/', CustomAuthToken.as_view())\n]", "title": "By exposing an api endpoint" }, { @@ -2507,7 +2517,7 @@ }, { "location": "/api-guide/permissions/", - "text": "Permissions\n\n\n\n\nAuthentication or identification by itself is not usually sufficient to gain access to information or code. For that, the entity requesting access must have authorization.\n\n\n\u2014 \nApple Developer Documentation\n\n\n\n\nTogether with \nauthentication\n and \nthrottling\n, permissions determine whether a request should be granted or denied access.\n\n\nPermission checks are always run at the very start of the view, before any other code is allowed to proceed. Permission checks will typically use the authentication information in the \nrequest.user\n and \nrequest.auth\n properties to determine if the incoming request should be permitted.\n\n\nPermissions are used to grant or deny access different classes of users to different parts of the API.\n\n\nThe simplest style of permission would be to allow access to any authenticated user, and deny access to any unauthenticated user. This corresponds the \nIsAuthenticated\n class in REST framework.\n\n\nA slightly less strict style of permission would be to allow full access to authenticated users, but allow read-only access to unauthenticated users. This corresponds to the \nIsAuthenticatedOrReadOnly\n class in REST framework.\n\n\nHow permissions are determined\n\n\nPermissions in REST framework are always defined as a list of permission classes.\n\n\nBefore running the main body of the view each permission in the list is checked.\nIf any permission check fails an \nexceptions.PermissionDenied\n or \nexceptions.NotAuthenticated\n exception will be raised, and the main body of the view will not run.\n\n\nWhen the permissions checks fail either a \"403 Forbidden\" or a \"401 Unauthorized\" response will be returned, according to the following rules:\n\n\n\n\nThe request was successfully authenticated, but permission was denied. \n\u2014 An HTTP 403 Forbidden response will be returned.\n\n\nThe request was not successfully authenticated, and the highest priority authentication class \ndoes not\n use \nWWW-Authenticate\n headers. \n\u2014 An HTTP 403 Forbidden response will be returned.\n\n\nThe request was not successfully authenticated, and the highest priority authentication class \ndoes\n use \nWWW-Authenticate\n headers. \n\u2014 An HTTP 401 Unauthorized response, with an appropriate \nWWW-Authenticate\n header will be returned.\n\n\n\n\nObject level permissions\n\n\nREST framework permissions also support object-level permissioning. Object level permissions are used to determine if a user should be allowed to act on a particular object, which will typically be a model instance.\n\n\nObject level permissions are run by REST framework's generic views when \n.get_object()\n is called.\nAs with view level permissions, an \nexceptions.PermissionDenied\n exception will be raised if the user is not allowed to act on the given object.\n\n\nIf you're writing your own views and want to enforce object level permissions,\nor if you override the \nget_object\n method on a generic view, then you'll need to explicitly call the \n.check_object_permissions(request, obj)\n method on the view at the point at which you've retrieved the object.\n\n\nThis will either raise a \nPermissionDenied\n or \nNotAuthenticated\n exception, or simply return if the view has the appropriate permissions.\n\n\nFor example:\n\n\ndef get_object(self):\n obj = get_object_or_404(self.get_queryset(), pk=self.kwargs[\"pk\"])\n self.check_object_permissions(self.request, obj)\n return obj\n\n\n\nLimitations of object level permissions\n\n\nFor performance reasons the generic views will not automatically apply object level permissions to each instance in a queryset when returning a list of objects.\n\n\nOften when you're using object level permissions you'll also want to \nfilter the queryset\n appropriately, to ensure that users only have visibility onto instances that they are permitted to view.\n\n\nSetting the permission policy\n\n\nThe default permission policy may be set globally, using the \nDEFAULT_PERMISSION_CLASSES\n setting. For example.\n\n\nREST_FRAMEWORK = {\n 'DEFAULT_PERMISSION_CLASSES': (\n 'rest_framework.permissions.IsAuthenticated',\n )\n}\n\n\n\nIf not specified, this setting defaults to allowing unrestricted access:\n\n\n'DEFAULT_PERMISSION_CLASSES': (\n 'rest_framework.permissions.AllowAny',\n)\n\n\n\nYou can also set the authentication policy on a per-view, or per-viewset basis,\nusing the \nAPIView\n class-based views.\n\n\nfrom rest_framework.permissions import IsAuthenticated\nfrom rest_framework.response import Response\nfrom rest_framework.views import APIView\n\nclass ExampleView(APIView):\n permission_classes = (IsAuthenticated,)\n\n def get(self, request, format=None):\n content = {\n 'status': 'request was permitted'\n }\n return Response(content)\n\n\n\nOr, if you're using the \n@api_view\n decorator with function based views.\n\n\nfrom rest_framework.decorators import api_view, permission_classes\nfrom rest_framework.permissions import IsAuthenticated\nfrom rest_framework.response import Response\n\n@api_view(['GET'])\n@permission_classes((IsAuthenticated, ))\ndef example_view(request, format=None):\n content = {\n 'status': 'request was permitted'\n }\n return Response(content)\n\n\n\nNote:\n when you set new permission classes through class attribute or decorators you're telling the view to ignore the default list set over the \nsettings.py\n file.\n\n\n\n\nAPI Reference\n\n\nAllowAny\n\n\nThe \nAllowAny\n permission class will allow unrestricted access, \nregardless of if the request was authenticated or unauthenticated\n.\n\n\nThis permission is not strictly required, since you can achieve the same result by using an empty list or tuple for the permissions setting, but you may find it useful to specify this class because it makes the intention explicit.\n\n\nIsAuthenticated\n\n\nThe \nIsAuthenticated\n permission class will deny permission to any unauthenticated user, and allow permission otherwise.\n\n\nThis permission is suitable if you want your API to only be accessible to registered users.\n\n\nIsAdminUser\n\n\nThe \nIsAdminUser\n permission class will deny permission to any user, unless \nuser.is_staff\n is \nTrue\n in which case permission will be allowed.\n\n\nThis permission is suitable if you want your API to only be accessible to a subset of trusted administrators.\n\n\nIsAuthenticatedOrReadOnly\n\n\nThe \nIsAuthenticatedOrReadOnly\n will allow authenticated users to perform any request. Requests for unauthorised users will only be permitted if the request method is one of the \"safe\" methods; \nGET\n, \nHEAD\n or \nOPTIONS\n.\n\n\nThis permission is suitable if you want to your API to allow read permissions to anonymous users, and only allow write permissions to authenticated users.\n\n\nDjangoModelPermissions\n\n\nThis permission class ties into Django's standard \ndjango.contrib.auth\n \nmodel permissions\n. This permission must only be applied to views that have a \n.queryset\n property set. Authorization will only be granted if the user \nis authenticated\n and has the \nrelevant model permissions\n assigned.\n\n\n\n\nPOST\n requests require the user to have the \nadd\n permission on the model.\n\n\nPUT\n and \nPATCH\n requests require the user to have the \nchange\n permission on the model.\n\n\nDELETE\n requests require the user to have the \ndelete\n permission on the model.\n\n\n\n\nThe default behaviour can also be overridden to support custom model permissions. For example, you might want to include a \nview\n model permission for \nGET\n requests.\n\n\nTo use custom model permissions, override \nDjangoModelPermissions\n and set the \n.perms_map\n property. Refer to the source code for details.\n\n\nUsing with views that do not include a \nqueryset\n attribute.\n\n\nIf you're using this permission with a view that uses an overridden \nget_queryset()\n method there may not be a \nqueryset\n attribute on the view. In this case we suggest also marking the view with a sentinel queryset, so that this class can determine the required permissions. For example:\n\n\nqueryset = User.objects.none() # Required for DjangoModelPermissions\n\n\n\nDjangoModelPermissionsOrAnonReadOnly\n\n\nSimilar to \nDjangoModelPermissions\n, but also allows unauthenticated users to have read-only access to the API.\n\n\nDjangoObjectPermissions\n\n\nThis permission class ties into Django's standard \nobject permissions framework\n that allows per-object permissions on models. In order to use this permission class, you'll also need to add a permission backend that supports object-level permissions, such as \ndjango-guardian\n.\n\n\nAs with \nDjangoModelPermissions\n, this permission must only be applied to views that have a \n.queryset\n property or \n.get_queryset()\n method. Authorization will only be granted if the user \nis authenticated\n and has the \nrelevant per-object permissions\n and \nrelevant model permissions\n assigned.\n\n\n\n\nPOST\n requests require the user to have the \nadd\n permission on the model instance.\n\n\nPUT\n and \nPATCH\n requests require the user to have the \nchange\n permission on the model instance.\n\n\nDELETE\n requests require the user to have the \ndelete\n permission on the model instance.\n\n\n\n\nNote that \nDjangoObjectPermissions\n \ndoes not\n require the \ndjango-guardian\n package, and should support other object-level backends equally well.\n\n\nAs with \nDjangoModelPermissions\n you can use custom model permissions by overriding \nDjangoObjectPermissions\n and setting the \n.perms_map\n property. Refer to the source code for details.\n\n\n\n\nNote\n: If you need object level \nview\n permissions for \nGET\n, \nHEAD\n and \nOPTIONS\n requests, you'll want to consider also adding the \nDjangoObjectPermissionsFilter\n class to ensure that list endpoints only return results including objects for which the user has appropriate view permissions.\n\n\n\n\n\n\nCustom permissions\n\n\nTo implement a custom permission, override \nBasePermission\n and implement either, or both, of the following methods:\n\n\n\n\n.has_permission(self, request, view)\n\n\n.has_object_permission(self, request, view, obj)\n\n\n\n\nThe methods should return \nTrue\n if the request should be granted access, and \nFalse\n otherwise.\n\n\nIf you need to test if a request is a read operation or a write operation, you should check the request method against the constant \nSAFE_METHODS\n, which is a tuple containing \n'GET'\n, \n'OPTIONS'\n and \n'HEAD'\n. For example:\n\n\nif request.method in permissions.SAFE_METHODS:\n # Check permissions for read-only request\nelse:\n # Check permissions for write request\n\n\n\n\n\nNote\n: The instance-level \nhas_object_permission\n method will only be called if the view-level \nhas_permission\n checks have already passed. Also note that in order for the instance-level checks to run, the view code should explicitly call \n.check_object_permissions(request, obj)\n. If you are using the generic views then this will be handled for you by default. (Function-based views will need to check object permissions explicitly, raising \nPermissionDenied\n on failure.)\n\n\n\n\nCustom permissions will raise a \nPermissionDenied\n exception if the test fails. To change the error message associated with the exception, implement a \nmessage\n attribute directly on your custom permission. Otherwise the \ndefault_detail\n attribute from \nPermissionDenied\n will be used.\n\n\nfrom rest_framework import permissions\n\nclass CustomerAccessPermission(permissions.BasePermission):\n message = 'Adding customers not allowed.'\n\n def has_permission(self, request, view):\n ...\n\n\n\nExamples\n\n\nThe following is an example of a permission class that checks the incoming request's IP address against a blacklist, and denies the request if the IP has been blacklisted.\n\n\nfrom rest_framework import permissions\n\nclass BlacklistPermission(permissions.BasePermission):\n \"\"\"\n Global permission check for blacklisted IPs.\n \"\"\"\n\n def has_permission(self, request, view):\n ip_addr = request.META['REMOTE_ADDR']\n blacklisted = Blacklist.objects.filter(ip_addr=ip_addr).exists()\n return not blacklisted\n\n\n\nAs well as global permissions, that are run against all incoming requests, you can also create object-level permissions, that are only run against operations that affect a particular object instance. For example:\n\n\nclass IsOwnerOrReadOnly(permissions.BasePermission):\n \"\"\"\n Object-level permission to only allow owners of an object to edit it.\n Assumes the model instance has an `owner` attribute.\n \"\"\"\n\n def has_object_permission(self, request, view, obj):\n # Read permissions are allowed to any request,\n # so we'll always allow GET, HEAD or OPTIONS requests.\n if request.method in permissions.SAFE_METHODS:\n return True\n\n # Instance must have an attribute named `owner`.\n return obj.owner == request.user\n\n\n\nNote that the generic views will check the appropriate object level permissions, but if you're writing your own custom views, you'll need to make sure you check the object level permission checks yourself. You can do so by calling \nself.check_object_permissions(request, obj)\n from the view once you have the object instance. This call will raise an appropriate \nAPIException\n if any object-level permission checks fail, and will otherwise simply return.\n\n\nAlso note that the generic views will only check the object-level permissions for views that retrieve a single model instance. If you require object-level filtering of list views, you'll need to filter the queryset separately. See the \nfiltering documentation\n for more details.\n\n\n\n\nThird party packages\n\n\nThe following third party packages are also available.\n\n\nComposed Permissions\n\n\nThe \nComposed Permissions\n package provides a simple way to define complex and multi-depth (with logic operators) permission objects, using small and reusable components.\n\n\nREST Condition\n\n\nThe \nREST Condition\n package is another extension for building complex permissions in a simple and convenient way. The extension allows you to combine permissions with logical operators.\n\n\nDRY Rest Permissions\n\n\nThe \nDRY Rest Permissions\n package provides the ability to define different permissions for individual default and custom actions. This package is made for apps with permissions that are derived from relationships defined in the app's data model. It also supports permission checks being returned to a client app through the API's serializer. Additionally it supports adding permissions to the default and custom list actions to restrict the data they retrieve per user.\n\n\nDjango Rest Framework Roles\n\n\nThe \nDjango Rest Framework Roles\n package makes it easier to parameterize your API over multiple types of users.\n\n\nDjango Rest Framework API Key\n\n\nThe \nDjango Rest Framework API Key\n package allows you to ensure that every request made to the server requires an API key header. You can generate one from the django admin interface.", + "text": "Permissions\n\n\n\n\nAuthentication or identification by itself is not usually sufficient to gain access to information or code. For that, the entity requesting access must have authorization.\n\n\n\u2014 \nApple Developer Documentation\n\n\n\n\nTogether with \nauthentication\n and \nthrottling\n, permissions determine whether a request should be granted or denied access.\n\n\nPermission checks are always run at the very start of the view, before any other code is allowed to proceed. Permission checks will typically use the authentication information in the \nrequest.user\n and \nrequest.auth\n properties to determine if the incoming request should be permitted.\n\n\nPermissions are used to grant or deny access different classes of users to different parts of the API.\n\n\nThe simplest style of permission would be to allow access to any authenticated user, and deny access to any unauthenticated user. This corresponds the \nIsAuthenticated\n class in REST framework.\n\n\nA slightly less strict style of permission would be to allow full access to authenticated users, but allow read-only access to unauthenticated users. This corresponds to the \nIsAuthenticatedOrReadOnly\n class in REST framework.\n\n\nHow permissions are determined\n\n\nPermissions in REST framework are always defined as a list of permission classes.\n\n\nBefore running the main body of the view each permission in the list is checked.\nIf any permission check fails an \nexceptions.PermissionDenied\n or \nexceptions.NotAuthenticated\n exception will be raised, and the main body of the view will not run.\n\n\nWhen the permissions checks fail either a \"403 Forbidden\" or a \"401 Unauthorized\" response will be returned, according to the following rules:\n\n\n\n\nThe request was successfully authenticated, but permission was denied. \n\u2014 An HTTP 403 Forbidden response will be returned.\n\n\nThe request was not successfully authenticated, and the highest priority authentication class \ndoes not\n use \nWWW-Authenticate\n headers. \n\u2014 An HTTP 403 Forbidden response will be returned.\n\n\nThe request was not successfully authenticated, and the highest priority authentication class \ndoes\n use \nWWW-Authenticate\n headers. \n\u2014 An HTTP 401 Unauthorized response, with an appropriate \nWWW-Authenticate\n header will be returned.\n\n\n\n\nObject level permissions\n\n\nREST framework permissions also support object-level permissioning. Object level permissions are used to determine if a user should be allowed to act on a particular object, which will typically be a model instance.\n\n\nObject level permissions are run by REST framework's generic views when \n.get_object()\n is called.\nAs with view level permissions, an \nexceptions.PermissionDenied\n exception will be raised if the user is not allowed to act on the given object.\n\n\nIf you're writing your own views and want to enforce object level permissions,\nor if you override the \nget_object\n method on a generic view, then you'll need to explicitly call the \n.check_object_permissions(request, obj)\n method on the view at the point at which you've retrieved the object.\n\n\nThis will either raise a \nPermissionDenied\n or \nNotAuthenticated\n exception, or simply return if the view has the appropriate permissions.\n\n\nFor example:\n\n\ndef get_object(self):\n obj = get_object_or_404(self.get_queryset(), pk=self.kwargs[\"pk\"])\n self.check_object_permissions(self.request, obj)\n return obj\n\n\n\nLimitations of object level permissions\n\n\nFor performance reasons the generic views will not automatically apply object level permissions to each instance in a queryset when returning a list of objects.\n\n\nOften when you're using object level permissions you'll also want to \nfilter the queryset\n appropriately, to ensure that users only have visibility onto instances that they are permitted to view.\n\n\nSetting the permission policy\n\n\nThe default permission policy may be set globally, using the \nDEFAULT_PERMISSION_CLASSES\n setting. For example.\n\n\nREST_FRAMEWORK = {\n 'DEFAULT_PERMISSION_CLASSES': (\n 'rest_framework.permissions.IsAuthenticated',\n )\n}\n\n\n\nIf not specified, this setting defaults to allowing unrestricted access:\n\n\n'DEFAULT_PERMISSION_CLASSES': (\n 'rest_framework.permissions.AllowAny',\n)\n\n\n\nYou can also set the authentication policy on a per-view, or per-viewset basis,\nusing the \nAPIView\n class-based views.\n\n\nfrom rest_framework.permissions import IsAuthenticated\nfrom rest_framework.response import Response\nfrom rest_framework.views import APIView\n\nclass ExampleView(APIView):\n permission_classes = (IsAuthenticated,)\n\n def get(self, request, format=None):\n content = {\n 'status': 'request was permitted'\n }\n return Response(content)\n\n\n\nOr, if you're using the \n@api_view\n decorator with function based views.\n\n\nfrom rest_framework.decorators import api_view, permission_classes\nfrom rest_framework.permissions import IsAuthenticated\nfrom rest_framework.response import Response\n\n@api_view(['GET'])\n@permission_classes((IsAuthenticated, ))\ndef example_view(request, format=None):\n content = {\n 'status': 'request was permitted'\n }\n return Response(content)\n\n\n\nNote:\n when you set new permission classes through class attribute or decorators you're telling the view to ignore the default list set over the \nsettings.py\n file.\n\n\n\n\nAPI Reference\n\n\nAllowAny\n\n\nThe \nAllowAny\n permission class will allow unrestricted access, \nregardless of if the request was authenticated or unauthenticated\n.\n\n\nThis permission is not strictly required, since you can achieve the same result by using an empty list or tuple for the permissions setting, but you may find it useful to specify this class because it makes the intention explicit.\n\n\nIsAuthenticated\n\n\nThe \nIsAuthenticated\n permission class will deny permission to any unauthenticated user, and allow permission otherwise.\n\n\nThis permission is suitable if you want your API to only be accessible to registered users.\n\n\nIsAdminUser\n\n\nThe \nIsAdminUser\n permission class will deny permission to any user, unless \nuser.is_staff\n is \nTrue\n in which case permission will be allowed.\n\n\nThis permission is suitable if you want your API to only be accessible to a subset of trusted administrators.\n\n\nIsAuthenticatedOrReadOnly\n\n\nThe \nIsAuthenticatedOrReadOnly\n will allow authenticated users to perform any request. Requests for unauthorised users will only be permitted if the request method is one of the \"safe\" methods; \nGET\n, \nHEAD\n or \nOPTIONS\n.\n\n\nThis permission is suitable if you want to your API to allow read permissions to anonymous users, and only allow write permissions to authenticated users.\n\n\nDjangoModelPermissions\n\n\nThis permission class ties into Django's standard \ndjango.contrib.auth\n \nmodel permissions\n. This permission must only be applied to views that have a \n.queryset\n property set. Authorization will only be granted if the user \nis authenticated\n and has the \nrelevant model permissions\n assigned.\n\n\n\n\nPOST\n requests require the user to have the \nadd\n permission on the model.\n\n\nPUT\n and \nPATCH\n requests require the user to have the \nchange\n permission on the model.\n\n\nDELETE\n requests require the user to have the \ndelete\n permission on the model.\n\n\n\n\nThe default behaviour can also be overridden to support custom model permissions. For example, you might want to include a \nview\n model permission for \nGET\n requests.\n\n\nTo use custom model permissions, override \nDjangoModelPermissions\n and set the \n.perms_map\n property. Refer to the source code for details.\n\n\nUsing with views that do not include a \nqueryset\n attribute.\n\n\nIf you're using this permission with a view that uses an overridden \nget_queryset()\n method there may not be a \nqueryset\n attribute on the view. In this case we suggest also marking the view with a sentinel queryset, so that this class can determine the required permissions. For example:\n\n\nqueryset = User.objects.none() # Required for DjangoModelPermissions\n\n\n\nDjangoModelPermissionsOrAnonReadOnly\n\n\nSimilar to \nDjangoModelPermissions\n, but also allows unauthenticated users to have read-only access to the API.\n\n\nDjangoObjectPermissions\n\n\nThis permission class ties into Django's standard \nobject permissions framework\n that allows per-object permissions on models. In order to use this permission class, you'll also need to add a permission backend that supports object-level permissions, such as \ndjango-guardian\n.\n\n\nAs with \nDjangoModelPermissions\n, this permission must only be applied to views that have a \n.queryset\n property or \n.get_queryset()\n method. Authorization will only be granted if the user \nis authenticated\n and has the \nrelevant per-object permissions\n and \nrelevant model permissions\n assigned.\n\n\n\n\nPOST\n requests require the user to have the \nadd\n permission on the model instance.\n\n\nPUT\n and \nPATCH\n requests require the user to have the \nchange\n permission on the model instance.\n\n\nDELETE\n requests require the user to have the \ndelete\n permission on the model instance.\n\n\n\n\nNote that \nDjangoObjectPermissions\n \ndoes not\n require the \ndjango-guardian\n package, and should support other object-level backends equally well.\n\n\nAs with \nDjangoModelPermissions\n you can use custom model permissions by overriding \nDjangoObjectPermissions\n and setting the \n.perms_map\n property. Refer to the source code for details.\n\n\n\n\nNote\n: If you need object level \nview\n permissions for \nGET\n, \nHEAD\n and \nOPTIONS\n requests, you'll want to consider also adding the \nDjangoObjectPermissionsFilter\n class to ensure that list endpoints only return results including objects for which the user has appropriate view permissions.\n\n\n\n\n\n\nCustom permissions\n\n\nTo implement a custom permission, override \nBasePermission\n and implement either, or both, of the following methods:\n\n\n\n\n.has_permission(self, request, view)\n\n\n.has_object_permission(self, request, view, obj)\n\n\n\n\nThe methods should return \nTrue\n if the request should be granted access, and \nFalse\n otherwise.\n\n\nIf you need to test if a request is a read operation or a write operation, you should check the request method against the constant \nSAFE_METHODS\n, which is a tuple containing \n'GET'\n, \n'OPTIONS'\n and \n'HEAD'\n. For example:\n\n\nif request.method in permissions.SAFE_METHODS:\n # Check permissions for read-only request\nelse:\n # Check permissions for write request\n\n\n\n\n\nNote\n: The instance-level \nhas_object_permission\n method will only be called if the view-level \nhas_permission\n checks have already passed. Also note that in order for the instance-level checks to run, the view code should explicitly call \n.check_object_permissions(request, obj)\n. If you are using the generic views then this will be handled for you by default. (Function-based views will need to check object permissions explicitly, raising \nPermissionDenied\n on failure.)\n\n\n\n\nCustom permissions will raise a \nPermissionDenied\n exception if the test fails. To change the error message associated with the exception, implement a \nmessage\n attribute directly on your custom permission. Otherwise the \ndefault_detail\n attribute from \nPermissionDenied\n will be used.\n\n\nfrom rest_framework import permissions\n\nclass CustomerAccessPermission(permissions.BasePermission):\n message = 'Adding customers not allowed.'\n\n def has_permission(self, request, view):\n ...\n\n\n\nExamples\n\n\nThe following is an example of a permission class that checks the incoming request's IP address against a blacklist, and denies the request if the IP has been blacklisted.\n\n\nfrom rest_framework import permissions\n\nclass BlacklistPermission(permissions.BasePermission):\n \"\"\"\n Global permission check for blacklisted IPs.\n \"\"\"\n\n def has_permission(self, request, view):\n ip_addr = request.META['REMOTE_ADDR']\n blacklisted = Blacklist.objects.filter(ip_addr=ip_addr).exists()\n return not blacklisted\n\n\n\nAs well as global permissions, that are run against all incoming requests, you can also create object-level permissions, that are only run against operations that affect a particular object instance. For example:\n\n\nclass IsOwnerOrReadOnly(permissions.BasePermission):\n \"\"\"\n Object-level permission to only allow owners of an object to edit it.\n Assumes the model instance has an `owner` attribute.\n \"\"\"\n\n def has_object_permission(self, request, view, obj):\n # Read permissions are allowed to any request,\n # so we'll always allow GET, HEAD or OPTIONS requests.\n if request.method in permissions.SAFE_METHODS:\n return True\n\n # Instance must have an attribute named `owner`.\n return obj.owner == request.user\n\n\n\nNote that the generic views will check the appropriate object level permissions, but if you're writing your own custom views, you'll need to make sure you check the object level permission checks yourself. You can do so by calling \nself.check_object_permissions(request, obj)\n from the view once you have the object instance. This call will raise an appropriate \nAPIException\n if any object-level permission checks fail, and will otherwise simply return.\n\n\nAlso note that the generic views will only check the object-level permissions for views that retrieve a single model instance. If you require object-level filtering of list views, you'll need to filter the queryset separately. See the \nfiltering documentation\n for more details.\n\n\n\n\nThird party packages\n\n\nThe following third party packages are also available.\n\n\nComposed Permissions\n\n\nThe \nComposed Permissions\n package provides a simple way to define complex and multi-depth (with logic operators) permission objects, using small and reusable components.\n\n\nREST Condition\n\n\nThe \nREST Condition\n package is another extension for building complex permissions in a simple and convenient way. The extension allows you to combine permissions with logical operators.\n\n\nDRY Rest Permissions\n\n\nThe \nDRY Rest Permissions\n package provides the ability to define different permissions for individual default and custom actions. This package is made for apps with permissions that are derived from relationships defined in the app's data model. It also supports permission checks being returned to a client app through the API's serializer. Additionally it supports adding permissions to the default and custom list actions to restrict the data they retrieve per user.\n\n\nDjango Rest Framework Roles\n\n\nThe \nDjango Rest Framework Roles\n package makes it easier to parameterize your API over multiple types of users.\n\n\nDjango Rest Framework API Key\n\n\nThe \nDjango Rest Framework API Key\n package allows you to ensure that every request made to the server requires an API key header. You can generate one from the django admin interface.\n\n\nDjango Rest Framework Role Filters\n\n\nThe \nDjango Rest Framework Role Filters\n package provides simple filtering over multiple types of roles.", "title": "Permissions" }, { @@ -2620,6 +2630,11 @@ "text": "The Django Rest Framework API Key package allows you to ensure that every request made to the server requires an API key header. You can generate one from the django admin interface.", "title": "Django Rest Framework API Key" }, + { + "location": "/api-guide/permissions/#django-rest-framework-role-filters", + "text": "The Django Rest Framework Role Filters package provides simple filtering over multiple types of roles.", + "title": "Django Rest Framework Role Filters" + }, { "location": "/api-guide/throttling/", "text": "Throttling\n\n\n\n\nHTTP/1.1 420 Enhance Your Calm\n\n\nTwitter API rate limiting response\n\n\n\n\nThrottling is similar to \npermissions\n, in that it determines if a request should be authorized. Throttles indicate a temporary state, and are used to control the rate of requests that clients can make to an API.\n\n\nAs with permissions, multiple throttles may be used. Your API might have a restrictive throttle for unauthenticated requests, and a less restrictive throttle for authenticated requests.\n\n\nAnother scenario where you might want to use multiple throttles would be if you need to impose different constraints on different parts of the API, due to some services being particularly resource-intensive.\n\n\nMultiple throttles can also be used if you want to impose both burst throttling rates, and sustained throttling rates. For example, you might want to limit a user to a maximum of 60 requests per minute, and 1000 requests per day.\n\n\nThrottles do not necessarily only refer to rate-limiting requests. For example a storage service might also need to throttle against bandwidth, and a paid data service might want to throttle against a certain number of a records being accessed.\n\n\nHow throttling is determined\n\n\nAs with permissions and authentication, throttling in REST framework is always defined as a list of classes.\n\n\nBefore running the main body of the view each throttle in the list is checked.\nIf any throttle check fails an \nexceptions.Throttled\n exception will be raised, and the main body of the view will not run.\n\n\nSetting the throttling policy\n\n\nThe default throttling policy may be set globally, using the \nDEFAULT_THROTTLE_CLASSES\n and \nDEFAULT_THROTTLE_RATES\n settings. For example.\n\n\nREST_FRAMEWORK = {\n 'DEFAULT_THROTTLE_CLASSES': (\n 'rest_framework.throttling.AnonRateThrottle',\n 'rest_framework.throttling.UserRateThrottle'\n ),\n 'DEFAULT_THROTTLE_RATES': {\n 'anon': '100/day',\n 'user': '1000/day'\n }\n}\n\n\n\nThe rate descriptions used in \nDEFAULT_THROTTLE_RATES\n may include \nsecond\n, \nminute\n, \nhour\n or \nday\n as the throttle period.\n\n\nYou can also set the throttling policy on a per-view or per-viewset basis,\nusing the \nAPIView\n class-based views.\n\n\nfrom rest_framework.response import Response\nfrom rest_framework.throttling import UserRateThrottle\nfrom rest_framework.views import APIView\n\nclass ExampleView(APIView):\n throttle_classes = (UserRateThrottle,)\n\n def get(self, request, format=None):\n content = {\n 'status': 'request was permitted'\n }\n return Response(content)\n\n\n\nOr, if you're using the \n@api_view\n decorator with function based views.\n\n\n@api_view(['GET'])\n@throttle_classes([UserRateThrottle])\ndef example_view(request, format=None):\n content = {\n 'status': 'request was permitted'\n }\n return Response(content)\n\n\n\nHow clients are identified\n\n\nThe \nX-Forwarded-For\n HTTP header and \nREMOTE_ADDR\n WSGI variable are used to uniquely identify client IP addresses for throttling. If the \nX-Forwarded-For\n header is present then it will be used, otherwise the value of the \nREMOTE_ADDR\n variable from the WSGI environment will be used.\n\n\nIf you need to strictly identify unique client IP addresses, you'll need to first configure the number of application proxies that the API runs behind by setting the \nNUM_PROXIES\n setting. This setting should be an integer of zero or more. If set to non-zero then the client IP will be identified as being the last IP address in the \nX-Forwarded-For\n header, once any application proxy IP addresses have first been excluded. If set to zero, then the \nREMOTE_ADDR\n value will always be used as the identifying IP address.\n\n\nIt is important to understand that if you configure the \nNUM_PROXIES\n setting, then all clients behind a unique \nNAT'd\n gateway will be treated as a single client.\n\n\nFurther context on how the \nX-Forwarded-For\n header works, and identifying a remote client IP can be \nfound here\n.\n\n\nSetting up the cache\n\n\nThe throttle classes provided by REST framework use Django's cache backend. You should make sure that you've set appropriate \ncache settings\n. The default value of \nLocMemCache\n backend should be okay for simple setups. See Django's \ncache documentation\n for more details.\n\n\nIf you need to use a cache other than \n'default'\n, you can do so by creating a custom throttle class and setting the \ncache\n attribute. For example:\n\n\nclass CustomAnonRateThrottle(AnonRateThrottle):\n cache = get_cache('alternate')\n\n\n\nYou'll need to remember to also set your custom throttle class in the \n'DEFAULT_THROTTLE_CLASSES'\n settings key, or using the \nthrottle_classes\n view attribute.\n\n\n\n\nAPI Reference\n\n\nAnonRateThrottle\n\n\nThe \nAnonRateThrottle\n will only ever throttle unauthenticated users. The IP address of the incoming request is used to generate a unique key to throttle against.\n\n\nThe allowed request rate is determined from one of the following (in order of preference).\n\n\n\n\nThe \nrate\n property on the class, which may be provided by overriding \nAnonRateThrottle\n and setting the property.\n\n\nThe \nDEFAULT_THROTTLE_RATES['anon']\n setting.\n\n\n\n\nAnonRateThrottle\n is suitable if you want to restrict the rate of requests from unknown sources.\n\n\nUserRateThrottle\n\n\nThe \nUserRateThrottle\n will throttle users to a given rate of requests across the API. The user id is used to generate a unique key to throttle against. Unauthenticated requests will fall back to using the IP address of the incoming request to generate a unique key to throttle against.\n\n\nThe allowed request rate is determined from one of the following (in order of preference).\n\n\n\n\nThe \nrate\n property on the class, which may be provided by overriding \nUserRateThrottle\n and setting the property.\n\n\nThe \nDEFAULT_THROTTLE_RATES['user']\n setting.\n\n\n\n\nAn API may have multiple \nUserRateThrottles\n in place at the same time. To do so, override \nUserRateThrottle\n and set a unique \"scope\" for each class.\n\n\nFor example, multiple user throttle rates could be implemented by using the following classes...\n\n\nclass BurstRateThrottle(UserRateThrottle):\n scope = 'burst'\n\nclass SustainedRateThrottle(UserRateThrottle):\n scope = 'sustained'\n\n\n\n...and the following settings.\n\n\nREST_FRAMEWORK = {\n 'DEFAULT_THROTTLE_CLASSES': (\n 'example.throttles.BurstRateThrottle',\n 'example.throttles.SustainedRateThrottle'\n ),\n 'DEFAULT_THROTTLE_RATES': {\n 'burst': '60/min',\n 'sustained': '1000/day'\n }\n}\n\n\n\nUserRateThrottle\n is suitable if you want simple global rate restrictions per-user.\n\n\nScopedRateThrottle\n\n\nThe \nScopedRateThrottle\n class can be used to restrict access to specific parts of the API. This throttle will only be applied if the view that is being accessed includes a \n.throttle_scope\n property. The unique throttle key will then be formed by concatenating the \"scope\" of the request with the unique user id or IP address.\n\n\nThe allowed request rate is determined by the \nDEFAULT_THROTTLE_RATES\n setting using a key from the request \"scope\".\n\n\nFor example, given the following views...\n\n\nclass ContactListView(APIView):\n throttle_scope = 'contacts'\n ...\n\nclass ContactDetailView(APIView):\n throttle_scope = 'contacts'\n ...\n\nclass UploadView(APIView):\n throttle_scope = 'uploads'\n ...\n\n\n\n...and the following settings.\n\n\nREST_FRAMEWORK = {\n 'DEFAULT_THROTTLE_CLASSES': (\n 'rest_framework.throttling.ScopedRateThrottle',\n ),\n 'DEFAULT_THROTTLE_RATES': {\n 'contacts': '1000/day',\n 'uploads': '20/day'\n }\n}\n\n\n\nUser requests to either \nContactListView\n or \nContactDetailView\n would be restricted to a total of 1000 requests per-day. User requests to \nUploadView\n would be restricted to 20 requests per day.\n\n\n\n\nCustom throttles\n\n\nTo create a custom throttle, override \nBaseThrottle\n and implement \n.allow_request(self, request, view)\n. The method should return \nTrue\n if the request should be allowed, and \nFalse\n otherwise.\n\n\nOptionally you may also override the \n.wait()\n method. If implemented, \n.wait()\n should return a recommended number of seconds to wait before attempting the next request, or \nNone\n. The \n.wait()\n method will only be called if \n.allow_request()\n has previously returned \nFalse\n.\n\n\nIf the \n.wait()\n method is implemented and the request is throttled, then a \nRetry-After\n header will be included in the response.\n\n\nExample\n\n\nThe following is an example of a rate throttle, that will randomly throttle 1 in every 10 requests.\n\n\nimport random\n\nclass RandomRateThrottle(throttling.BaseThrottle):\n def allow_request(self, request, view):\n return random.randint(1, 10) != 1", @@ -2937,7 +2952,7 @@ }, { "location": "/api-guide/versioning/", - "text": "Versioning\n\n\n\n\nVersioning an interface is just a \"polite\" way to kill deployed clients.\n\n\n\u2014 \nRoy Fielding\n.\n\n\n\n\nAPI versioning allows you to alter behavior between different clients. REST framework provides for a number of different versioning schemes.\n\n\nVersioning is determined by the incoming client request, and may either be based on the request URL, or based on the request headers.\n\n\nThere are a number of valid approaches to approaching versioning. \nNon-versioned systems can also be appropriate\n, particularly if you're engineering for very long-term systems with multiple clients outside of your control.\n\n\nVersioning with REST framework\n\n\nWhen API versioning is enabled, the \nrequest.version\n attribute will contain a string that corresponds to the version requested in the incoming client request.\n\n\nBy default, versioning is not enabled, and \nrequest.version\n will always return \nNone\n.\n\n\nVarying behavior based on the version\n\n\nHow you vary the API behavior is up to you, but one example you might typically want is to switch to a different serialization style in a newer version. For example:\n\n\ndef get_serializer_class(self):\n if self.request.version == 'v1':\n return AccountSerializerVersion1\n return AccountSerializer\n\n\n\nReversing URLs for versioned APIs\n\n\nThe \nreverse\n function included by REST framework ties in with the versioning scheme. You need to make sure to include the current \nrequest\n as a keyword argument, like so.\n\n\nfrom rest_framework.reverse import reverse\n\nreverse('bookings-list', request=request)\n\n\n\nThe above function will apply any URL transformations appropriate to the request version. For example:\n\n\n\n\nIf \nNamespacedVersioning\n was being used, and the API version was 'v1', then the URL lookup used would be \n'v1:bookings-list'\n, which might resolve to a URL like \nhttp://example.org/v1/bookings/\n.\n\n\nIf \nQueryParameterVersioning\n was being used, and the API version was \n1.0\n, then the returned URL might be something like \nhttp://example.org/bookings/?version=1.0\n\n\n\n\nVersioned APIs and hyperlinked serializers\n\n\nWhen using hyperlinked serialization styles together with a URL based versioning scheme make sure to include the request as context to the serializer.\n\n\ndef get(self, request):\n queryset = Booking.objects.all()\n serializer = BookingsSerializer(queryset, many=True, context={'request': request})\n return Response({'all_bookings': serializer.data})\n\n\n\nDoing so will allow any returned URLs to include the appropriate versioning.\n\n\nConfiguring the versioning scheme\n\n\nThe versioning scheme is defined by the \nDEFAULT_VERSIONING_CLASS\n settings key.\n\n\nREST_FRAMEWORK = {\n 'DEFAULT_VERSIONING_CLASS': 'rest_framework.versioning.NamespaceVersioning'\n}\n\n\n\nUnless it is explicitly set, the value for \nDEFAULT_VERSIONING_CLASS\n will be \nNone\n. In this case the \nrequest.version\n attribute will always return \nNone\n.\n\n\nYou can also set the versioning scheme on an individual view. Typically you won't need to do this, as it makes more sense to have a single versioning scheme used globally. If you do need to do so, use the \nversioning_class\n attribute.\n\n\nclass ProfileList(APIView):\n versioning_class = versioning.QueryParameterVersioning\n\n\n\nOther versioning settings\n\n\nThe following settings keys are also used to control versioning:\n\n\n\n\nDEFAULT_VERSION\n. The value that should be used for \nrequest.version\n when no versioning information is present. Defaults to \nNone\n.\n\n\nALLOWED_VERSIONS\n. If set, this value will restrict the set of versions that may be returned by the versioning scheme, and will raise an error if the provided version is not in this set. Note that the value used for the \nDEFAULT_VERSION\n setting is always considered to be part of the \nALLOWED_VERSIONS\n set (unless it is \nNone\n). Defaults to \nNone\n.\n\n\nVERSION_PARAM\n. The string that should be used for any versioning parameters, such as in the media type or URL query parameters. Defaults to \n'version'\n.\n\n\n\n\nYou can also set your versioning class plus those three values on a per-view or a per-viewset basis by defining your own versioning scheme and using the \ndefault_version\n, \nallowed_versions\n and \nversion_param\n class variables. For example, if you want to use \nURLPathVersioning\n:\n\n\nfrom rest_framework.versioning import URLPathVersioning\nfrom rest_framework.views import APIView\n\nclass ExampleVersioning(URLPathVersioning):\n default_version = ...\n allowed_versions = ...\n version_param = ...\n\nclass ExampleView(APIVIew):\n versioning_class = ExampleVersioning\n\n\n\n\n\nAPI Reference\n\n\nAcceptHeaderVersioning\n\n\nThis scheme requires the client to specify the version as part of the media type in the \nAccept\n header. The version is included as a media type parameter, that supplements the main media type.\n\n\nHere's an example HTTP request using the accept header versioning style.\n\n\nGET /bookings/ HTTP/1.1\nHost: example.com\nAccept: application/json; version=1.0\n\n\n\nIn the example request above \nrequest.version\n attribute would return the string \n'1.0'\n.\n\n\nVersioning based on accept headers is \ngenerally considered\n as \nbest practice\n, although other styles may be suitable depending on your client requirements.\n\n\nUsing accept headers with vendor media types\n\n\nStrictly speaking the \njson\n media type is not specified as \nincluding additional parameters\n. If you are building a well-specified public API you might consider using a \nvendor media type\n. To do so, configure your renderers to use a JSON based renderer with a custom media type:\n\n\nclass BookingsAPIRenderer(JSONRenderer):\n media_type = 'application/vnd.megacorp.bookings+json'\n\n\n\nYour client requests would now look like this:\n\n\nGET /bookings/ HTTP/1.1\nHost: example.com\nAccept: application/vnd.megacorp.bookings+json; version=1.0\n\n\n\nURLPathVersioning\n\n\nThis scheme requires the client to specify the version as part of the URL path.\n\n\nGET /v1/bookings/ HTTP/1.1\nHost: example.com\nAccept: application/json\n\n\n\nYour URL conf must include a pattern that matches the version with a \n'version'\n keyword argument, so that this information is available to the versioning scheme.\n\n\nurlpatterns = [\n url(\n r'^(?P(v1|v2))/bookings/$',\n bookings_list,\n name='bookings-list'\n ),\n url(\n r'^(?P(v1|v2))/bookings/(?P[0-9]+)/$',\n bookings_detail,\n name='bookings-detail'\n )\n]\n\n\n\nNamespaceVersioning\n\n\nTo the client, this scheme is the same as \nURLPathVersioning\n. The only difference is how it is configured in your Django application, as it uses URL namespacing, instead of URL keyword arguments.\n\n\nGET /v1/something/ HTTP/1.1\nHost: example.com\nAccept: application/json\n\n\n\nWith this scheme the \nrequest.version\n attribute is determined based on the \nnamespace\n that matches the incoming request path.\n\n\nIn the following example we're giving a set of views two different possible URL prefixes, each under a different namespace:\n\n\n# bookings/urls.py\nurlpatterns = [\n url(r'^$', bookings_list, name='bookings-list'),\n url(r'^(?P[0-9]+)/$', bookings_detail, name='bookings-detail')\n]\n\n# urls.py\nurlpatterns = [\n url(r'^v1/bookings/', include('bookings.urls', namespace='v1')),\n url(r'^v2/bookings/', include('bookings.urls', namespace='v2'))\n]\n\n\n\nBoth \nURLPathVersioning\n and \nNamespaceVersioning\n are reasonable if you just need a simple versioning scheme. The \nURLPathVersioning\n approach might be better suitable for small ad-hoc projects, and the \nNamespaceVersioning\n is probably easier to manage for larger projects.\n\n\nHostNameVersioning\n\n\nThe hostname versioning scheme requires the client to specify the requested version as part of the hostname in the URL.\n\n\nFor example the following is an HTTP request to the \nhttp://v1.example.com/bookings/\n URL:\n\n\nGET /bookings/ HTTP/1.1\nHost: v1.example.com\nAccept: application/json\n\n\n\nBy default this implementation expects the hostname to match this simple regular expression:\n\n\n^([a-zA-Z0-9]+)\\.[a-zA-Z0-9]+\\.[a-zA-Z0-9]+$\n\n\n\nNote that the first group is enclosed in brackets, indicating that this is the matched portion of the hostname.\n\n\nThe \nHostNameVersioning\n scheme can be awkward to use in debug mode as you will typically be accessing a raw IP address such as \n127.0.0.1\n. There are various online tutorials on how to \naccess localhost with a custom subdomain\n which you may find helpful in this case.\n\n\nHostname based versioning can be particularly useful if you have requirements to route incoming requests to different servers based on the version, as you can configure different DNS records for different API versions.\n\n\nQueryParameterVersioning\n\n\nThis scheme is a simple style that includes the version as a query parameter in the URL. For example:\n\n\nGET /something/?version=0.1 HTTP/1.1\nHost: example.com\nAccept: application/json\n\n\n\n\n\nCustom versioning schemes\n\n\nTo implement a custom versioning scheme, subclass \nBaseVersioning\n and override the \n.determine_version\n method.\n\n\nExample\n\n\nThe following example uses a custom \nX-API-Version\n header to determine the requested version.\n\n\nclass XAPIVersionScheme(versioning.BaseVersioning):\n def determine_version(self, request, *args, **kwargs):\n return request.META.get('HTTP_X_API_VERSION', None)\n\n\n\nIf 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 \n.reverse()\n method on the class. See the source code for examples.", + "text": "Versioning\n\n\n\n\nVersioning an interface is just a \"polite\" way to kill deployed clients.\n\n\n\u2014 \nRoy Fielding\n.\n\n\n\n\nAPI versioning allows you to alter behavior between different clients. REST framework provides for a number of different versioning schemes.\n\n\nVersioning is determined by the incoming client request, and may either be based on the request URL, or based on the request headers.\n\n\nThere are a number of valid approaches to approaching versioning. \nNon-versioned systems can also be appropriate\n, particularly if you're engineering for very long-term systems with multiple clients outside of your control.\n\n\nVersioning with REST framework\n\n\nWhen API versioning is enabled, the \nrequest.version\n attribute will contain a string that corresponds to the version requested in the incoming client request.\n\n\nBy default, versioning is not enabled, and \nrequest.version\n will always return \nNone\n.\n\n\nVarying behavior based on the version\n\n\nHow you vary the API behavior is up to you, but one example you might typically want is to switch to a different serialization style in a newer version. For example:\n\n\ndef get_serializer_class(self):\n if self.request.version == 'v1':\n return AccountSerializerVersion1\n return AccountSerializer\n\n\n\nReversing URLs for versioned APIs\n\n\nThe \nreverse\n function included by REST framework ties in with the versioning scheme. You need to make sure to include the current \nrequest\n as a keyword argument, like so.\n\n\nfrom rest_framework.reverse import reverse\n\nreverse('bookings-list', request=request)\n\n\n\nThe above function will apply any URL transformations appropriate to the request version. For example:\n\n\n\n\nIf \nNamespaceVersioning\n was being used, and the API version was 'v1', then the URL lookup used would be \n'v1:bookings-list'\n, which might resolve to a URL like \nhttp://example.org/v1/bookings/\n.\n\n\nIf \nQueryParameterVersioning\n was being used, and the API version was \n1.0\n, then the returned URL might be something like \nhttp://example.org/bookings/?version=1.0\n\n\n\n\nVersioned APIs and hyperlinked serializers\n\n\nWhen using hyperlinked serialization styles together with a URL based versioning scheme make sure to include the request as context to the serializer.\n\n\ndef get(self, request):\n queryset = Booking.objects.all()\n serializer = BookingsSerializer(queryset, many=True, context={'request': request})\n return Response({'all_bookings': serializer.data})\n\n\n\nDoing so will allow any returned URLs to include the appropriate versioning.\n\n\nConfiguring the versioning scheme\n\n\nThe versioning scheme is defined by the \nDEFAULT_VERSIONING_CLASS\n settings key.\n\n\nREST_FRAMEWORK = {\n 'DEFAULT_VERSIONING_CLASS': 'rest_framework.versioning.NamespaceVersioning'\n}\n\n\n\nUnless it is explicitly set, the value for \nDEFAULT_VERSIONING_CLASS\n will be \nNone\n. In this case the \nrequest.version\n attribute will always return \nNone\n.\n\n\nYou can also set the versioning scheme on an individual view. Typically you won't need to do this, as it makes more sense to have a single versioning scheme used globally. If you do need to do so, use the \nversioning_class\n attribute.\n\n\nclass ProfileList(APIView):\n versioning_class = versioning.QueryParameterVersioning\n\n\n\nOther versioning settings\n\n\nThe following settings keys are also used to control versioning:\n\n\n\n\nDEFAULT_VERSION\n. The value that should be used for \nrequest.version\n when no versioning information is present. Defaults to \nNone\n.\n\n\nALLOWED_VERSIONS\n. If set, this value will restrict the set of versions that may be returned by the versioning scheme, and will raise an error if the provided version is not in this set. Note that the value used for the \nDEFAULT_VERSION\n setting is always considered to be part of the \nALLOWED_VERSIONS\n set (unless it is \nNone\n). Defaults to \nNone\n.\n\n\nVERSION_PARAM\n. The string that should be used for any versioning parameters, such as in the media type or URL query parameters. Defaults to \n'version'\n.\n\n\n\n\nYou can also set your versioning class plus those three values on a per-view or a per-viewset basis by defining your own versioning scheme and using the \ndefault_version\n, \nallowed_versions\n and \nversion_param\n class variables. For example, if you want to use \nURLPathVersioning\n:\n\n\nfrom rest_framework.versioning import URLPathVersioning\nfrom rest_framework.views import APIView\n\nclass ExampleVersioning(URLPathVersioning):\n default_version = ...\n allowed_versions = ...\n version_param = ...\n\nclass ExampleView(APIVIew):\n versioning_class = ExampleVersioning\n\n\n\n\n\nAPI Reference\n\n\nAcceptHeaderVersioning\n\n\nThis scheme requires the client to specify the version as part of the media type in the \nAccept\n header. The version is included as a media type parameter, that supplements the main media type.\n\n\nHere's an example HTTP request using the accept header versioning style.\n\n\nGET /bookings/ HTTP/1.1\nHost: example.com\nAccept: application/json; version=1.0\n\n\n\nIn the example request above \nrequest.version\n attribute would return the string \n'1.0'\n.\n\n\nVersioning based on accept headers is \ngenerally considered\n as \nbest practice\n, although other styles may be suitable depending on your client requirements.\n\n\nUsing accept headers with vendor media types\n\n\nStrictly speaking the \njson\n media type is not specified as \nincluding additional parameters\n. If you are building a well-specified public API you might consider using a \nvendor media type\n. To do so, configure your renderers to use a JSON based renderer with a custom media type:\n\n\nclass BookingsAPIRenderer(JSONRenderer):\n media_type = 'application/vnd.megacorp.bookings+json'\n\n\n\nYour client requests would now look like this:\n\n\nGET /bookings/ HTTP/1.1\nHost: example.com\nAccept: application/vnd.megacorp.bookings+json; version=1.0\n\n\n\nURLPathVersioning\n\n\nThis scheme requires the client to specify the version as part of the URL path.\n\n\nGET /v1/bookings/ HTTP/1.1\nHost: example.com\nAccept: application/json\n\n\n\nYour URL conf must include a pattern that matches the version with a \n'version'\n keyword argument, so that this information is available to the versioning scheme.\n\n\nurlpatterns = [\n url(\n r'^(?P(v1|v2))/bookings/$',\n bookings_list,\n name='bookings-list'\n ),\n url(\n r'^(?P(v1|v2))/bookings/(?P[0-9]+)/$',\n bookings_detail,\n name='bookings-detail'\n )\n]\n\n\n\nNamespaceVersioning\n\n\nTo the client, this scheme is the same as \nURLPathVersioning\n. The only difference is how it is configured in your Django application, as it uses URL namespacing, instead of URL keyword arguments.\n\n\nGET /v1/something/ HTTP/1.1\nHost: example.com\nAccept: application/json\n\n\n\nWith this scheme the \nrequest.version\n attribute is determined based on the \nnamespace\n that matches the incoming request path.\n\n\nIn the following example we're giving a set of views two different possible URL prefixes, each under a different namespace:\n\n\n# bookings/urls.py\nurlpatterns = [\n url(r'^$', bookings_list, name='bookings-list'),\n url(r'^(?P[0-9]+)/$', bookings_detail, name='bookings-detail')\n]\n\n# urls.py\nurlpatterns = [\n url(r'^v1/bookings/', include('bookings.urls', namespace='v1')),\n url(r'^v2/bookings/', include('bookings.urls', namespace='v2'))\n]\n\n\n\nBoth \nURLPathVersioning\n and \nNamespaceVersioning\n are reasonable if you just need a simple versioning scheme. The \nURLPathVersioning\n approach might be better suitable for small ad-hoc projects, and the \nNamespaceVersioning\n is probably easier to manage for larger projects.\n\n\nHostNameVersioning\n\n\nThe hostname versioning scheme requires the client to specify the requested version as part of the hostname in the URL.\n\n\nFor example the following is an HTTP request to the \nhttp://v1.example.com/bookings/\n URL:\n\n\nGET /bookings/ HTTP/1.1\nHost: v1.example.com\nAccept: application/json\n\n\n\nBy default this implementation expects the hostname to match this simple regular expression:\n\n\n^([a-zA-Z0-9]+)\\.[a-zA-Z0-9]+\\.[a-zA-Z0-9]+$\n\n\n\nNote that the first group is enclosed in brackets, indicating that this is the matched portion of the hostname.\n\n\nThe \nHostNameVersioning\n scheme can be awkward to use in debug mode as you will typically be accessing a raw IP address such as \n127.0.0.1\n. There are various online tutorials on how to \naccess localhost with a custom subdomain\n which you may find helpful in this case.\n\n\nHostname based versioning can be particularly useful if you have requirements to route incoming requests to different servers based on the version, as you can configure different DNS records for different API versions.\n\n\nQueryParameterVersioning\n\n\nThis scheme is a simple style that includes the version as a query parameter in the URL. For example:\n\n\nGET /something/?version=0.1 HTTP/1.1\nHost: example.com\nAccept: application/json\n\n\n\n\n\nCustom versioning schemes\n\n\nTo implement a custom versioning scheme, subclass \nBaseVersioning\n and override the \n.determine_version\n method.\n\n\nExample\n\n\nThe following example uses a custom \nX-API-Version\n header to determine the requested version.\n\n\nclass XAPIVersionScheme(versioning.BaseVersioning):\n def determine_version(self, request, *args, **kwargs):\n return request.META.get('HTTP_X_API_VERSION', None)\n\n\n\nIf 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 \n.reverse()\n method on the class. See the source code for examples.", "title": "Versioning" }, { @@ -2957,7 +2972,7 @@ }, { "location": "/api-guide/versioning/#reversing-urls-for-versioned-apis", - "text": "The reverse function included by REST framework ties in with the versioning scheme. You need to make sure to include the current request as a keyword argument, like so. from rest_framework.reverse import reverse\n\nreverse('bookings-list', request=request) The above function will apply any URL transformations appropriate to the request version. For example: If NamespacedVersioning was being used, and the API version was 'v1', then the URL lookup used would be 'v1:bookings-list' , which might resolve to a URL like http://example.org/v1/bookings/ . If QueryParameterVersioning was being used, and the API version was 1.0 , then the returned URL might be something like http://example.org/bookings/?version=1.0", + "text": "The reverse function included by REST framework ties in with the versioning scheme. You need to make sure to include the current request as a keyword argument, like so. from rest_framework.reverse import reverse\n\nreverse('bookings-list', request=request) The above function will apply any URL transformations appropriate to the request version. For example: If NamespaceVersioning was being used, and the API version was 'v1', then the URL lookup used would be 'v1:bookings-list' , which might resolve to a URL like http://example.org/v1/bookings/ . If QueryParameterVersioning was being used, and the API version was 1.0 , then the returned URL might be something like http://example.org/bookings/?version=1.0", "title": "Reversing URLs for versioned APIs" }, { @@ -3052,7 +3067,7 @@ }, { "location": "/api-guide/metadata/", - "text": "Metadata\n\n\n\n\n[The \nOPTIONS\n] method allows a client to determine the options and/or requirements associated with a resource, or the capabilities of a server, without implying a resource action or initiating a resource retrieval.\n\n\n\u2014 \nRFC7231, Section 4.3.7.\n\n\n\n\nREST framework includes a configurable mechanism for determining how your API should respond to \nOPTIONS\n requests. This allows you to return API schema or other resource information.\n\n\nThere are not currently any widely adopted conventions for exactly what style of response should be returned for HTTP \nOPTIONS\n requests, so we provide an ad-hoc style that returns some useful information.\n\n\nHere's an example response that demonstrates the information that is returned by default.\n\n\nHTTP 200 OK\nAllow: GET, POST, HEAD, OPTIONS\nContent-Type: application/json\n\n{\n \"name\": \"To Do List\",\n \"description\": \"List existing 'To Do' items, or create a new item.\",\n \"renders\": [\n \"application/json\",\n \"text/html\"\n ],\n \"parses\": [\n \"application/json\",\n \"application/x-www-form-urlencoded\",\n \"multipart/form-data\"\n ],\n \"actions\": {\n \"POST\": {\n \"note\": {\n \"type\": \"string\",\n \"required\": false,\n \"read_only\": false,\n \"label\": \"title\",\n \"max_length\": 100\n }\n }\n }\n}\n\n\n\nSetting the metadata scheme\n\n\nYou can set the metadata class globally using the \n'DEFAULT_METADATA_CLASS'\n settings key:\n\n\nREST_FRAMEWORK = {\n 'DEFAULT_METADATA_CLASS': 'rest_framework.metadata.SimpleMetadata'\n}\n\n\n\nOr you can set the metadata class individually for a view:\n\n\nclass APIRoot(APIView):\n metadata_class = APIRootMetadata\n\n def get(self, request, format=None):\n return Response({\n ...\n })\n\n\n\nThe REST framework package only includes a single metadata class implementation, named \nSimpleMetadata\n. If you want to use an alternative style you'll need to implement a custom metadata class.\n\n\nCreating schema endpoints\n\n\nIf you have specific requirements for creating schema endpoints that are accessed with regular \nGET\n requests, you might consider re-using the metadata API for doing so.\n\n\nFor example, the following additional route could be used on a viewset to provide a linkable schema endpoint.\n\n\n@list_route(methods=['GET'])\ndef schema(self, request):\n meta = self.metadata_class()\n data = meta.determine_metadata(request, self)\n return Response(data)\n\n\n\nThere are a couple of reasons that you might choose to take this approach, including that \nOPTIONS\n responses \nare not cacheable\n.\n\n\n\n\nCustom metadata classes\n\n\nIf you want to provide a custom metadata class you should override \nBaseMetadata\n and implement the \ndetermine_metadata(self, request, view)\n method.\n\n\nUseful things that you might want to do could include returning schema information, using a format such as \nJSON schema\n, or returning debug information to admin users.\n\n\nExample\n\n\nThe following class could be used to limit the information that is returned to \nOPTIONS\n requests.\n\n\nclass MinimalMetadata(BaseMetadata):\n \"\"\"\n Don't include field and other information for `OPTIONS` requests.\n Just return the name and description.\n \"\"\"\n def determine_metadata(self, request, view):\n return {\n 'name': view.get_view_name(),\n 'description': view.get_view_description()\n }\n\n\n\nThen configure your settings to use this custom class:\n\n\nREST_FRAMEWORK = {\n 'DEFAULT_METADATA_CLASS': 'myproject.apps.core.MinimalMetadata'\n}\n\n\n\nThird party packages\n\n\nThe following third party packages provide additional metadata implementations.\n\n\nDRF-schema-adapter\n\n\ndrf-schema-adapter\n is a set of tools that makes it easier to provide schema information to frontend frameworks and libraries. It provides a metadata mixin as well as 2 metadata classes and several adapters suitable to generate \njson-schema\n as well as schema information readable by various libraries.\n\n\nYou can also write your own adapter to work with your specific frontend.\nIf you wish to do so, it also provides an exporter that can export those schema information to json files.", + "text": "Metadata\n\n\n\n\n[The \nOPTIONS\n] method allows a client to determine the options and/or requirements associated with a resource, or the capabilities of a server, without implying a resource action or initiating a resource retrieval.\n\n\n\u2014 \nRFC7231, Section 4.3.7.\n\n\n\n\nREST framework includes a configurable mechanism for determining how your API should respond to \nOPTIONS\n requests. This allows you to return API schema or other resource information.\n\n\nThere are not currently any widely adopted conventions for exactly what style of response should be returned for HTTP \nOPTIONS\n requests, so we provide an ad-hoc style that returns some useful information.\n\n\nHere's an example response that demonstrates the information that is returned by default.\n\n\nHTTP 200 OK\nAllow: GET, POST, HEAD, OPTIONS\nContent-Type: application/json\n\n{\n \"name\": \"To Do List\",\n \"description\": \"List existing 'To Do' items, or create a new item.\",\n \"renders\": [\n \"application/json\",\n \"text/html\"\n ],\n \"parses\": [\n \"application/json\",\n \"application/x-www-form-urlencoded\",\n \"multipart/form-data\"\n ],\n \"actions\": {\n \"POST\": {\n \"note\": {\n \"type\": \"string\",\n \"required\": false,\n \"read_only\": false,\n \"label\": \"title\",\n \"max_length\": 100\n }\n }\n }\n}\n\n\n\nSetting the metadata scheme\n\n\nYou can set the metadata class globally using the \n'DEFAULT_METADATA_CLASS'\n settings key:\n\n\nREST_FRAMEWORK = {\n 'DEFAULT_METADATA_CLASS': 'rest_framework.metadata.SimpleMetadata'\n}\n\n\n\nOr you can set the metadata class individually for a view:\n\n\nclass APIRoot(APIView):\n metadata_class = APIRootMetadata\n\n def get(self, request, format=None):\n return Response({\n ...\n })\n\n\n\nThe REST framework package only includes a single metadata class implementation, named \nSimpleMetadata\n. If you want to use an alternative style you'll need to implement a custom metadata class.\n\n\nCreating schema endpoints\n\n\nIf you have specific requirements for creating schema endpoints that are accessed with regular \nGET\n requests, you might consider re-using the metadata API for doing so.\n\n\nFor example, the following additional route could be used on a viewset to provide a linkable schema endpoint.\n\n\n@action(methods=['GET'], detail=False)\ndef schema(self, request):\n meta = self.metadata_class()\n data = meta.determine_metadata(request, self)\n return Response(data)\n\n\n\nThere are a couple of reasons that you might choose to take this approach, including that \nOPTIONS\n responses \nare not cacheable\n.\n\n\n\n\nCustom metadata classes\n\n\nIf you want to provide a custom metadata class you should override \nBaseMetadata\n and implement the \ndetermine_metadata(self, request, view)\n method.\n\n\nUseful things that you might want to do could include returning schema information, using a format such as \nJSON schema\n, or returning debug information to admin users.\n\n\nExample\n\n\nThe following class could be used to limit the information that is returned to \nOPTIONS\n requests.\n\n\nclass MinimalMetadata(BaseMetadata):\n \"\"\"\n Don't include field and other information for `OPTIONS` requests.\n Just return the name and description.\n \"\"\"\n def determine_metadata(self, request, view):\n return {\n 'name': view.get_view_name(),\n 'description': view.get_view_description()\n }\n\n\n\nThen configure your settings to use this custom class:\n\n\nREST_FRAMEWORK = {\n 'DEFAULT_METADATA_CLASS': 'myproject.apps.core.MinimalMetadata'\n}\n\n\n\nThird party packages\n\n\nThe following third party packages provide additional metadata implementations.\n\n\nDRF-schema-adapter\n\n\ndrf-schema-adapter\n is a set of tools that makes it easier to provide schema information to frontend frameworks and libraries. It provides a metadata mixin as well as 2 metadata classes and several adapters suitable to generate \njson-schema\n as well as schema information readable by various libraries.\n\n\nYou can also write your own adapter to work with your specific frontend.\nIf you wish to do so, it also provides an exporter that can export those schema information to json files.", "title": "Metadata" }, { @@ -3067,7 +3082,7 @@ }, { "location": "/api-guide/metadata/#creating-schema-endpoints", - "text": "If you have specific requirements for creating schema endpoints that are accessed with regular GET requests, you might consider re-using the metadata API for doing so. For example, the following additional route could be used on a viewset to provide a linkable schema endpoint. @list_route(methods=['GET'])\ndef schema(self, request):\n meta = self.metadata_class()\n data = meta.determine_metadata(request, self)\n return Response(data) There are a couple of reasons that you might choose to take this approach, including that OPTIONS responses are not cacheable .", + "text": "If you have specific requirements for creating schema endpoints that are accessed with regular GET requests, you might consider re-using the metadata API for doing so. For example, the following additional route could be used on a viewset to provide a linkable schema endpoint. @action(methods=['GET'], detail=False)\ndef schema(self, request):\n meta = self.metadata_class()\n data = meta.determine_metadata(request, self)\n return Response(data) There are a couple of reasons that you might choose to take this approach, including that OPTIONS responses are not cacheable .", "title": "Creating schema endpoints" }, { @@ -3092,7 +3107,7 @@ }, { "location": "/api-guide/schemas/", - "text": "Schemas\n\n\n\n\nA machine-readable [schema] describes what resources are available via the API, what their URLs are, how they are represented and what operations they support.\n\n\n\u2014 Heroku, \nJSON Schema for the Heroku Platform API\n\n\n\n\nAPI schemas are a useful tool that allow for a range of use cases, including\ngenerating reference documentation, or driving dynamic client libraries that\ncan interact with your API.\n\n\nInstall Core API\n\n\nYou'll need to install the \ncoreapi\n package in order to add schema support\nfor REST framework.\n\n\npip install coreapi\n\n\n\nInternal schema representation\n\n\nREST framework uses \nCore API\n in order to model schema information in\na format-independent representation. This information can then be rendered\ninto various different schema formats, or used to generate API documentation.\n\n\nWhen using Core API, a schema is represented as a \nDocument\n which is the\ntop-level container object for information about the API. Available API\ninteractions are represented using \nLink\n objects. Each link includes a URL,\nHTTP method, and may include a list of \nField\n instances, which describe any\nparameters that may be accepted by the API endpoint. The \nLink\n and \nField\n\ninstances may also include descriptions, that allow an API schema to be\nrendered into user documentation.\n\n\nHere's an example of an API description that includes a single \nsearch\n\nendpoint:\n\n\ncoreapi.Document(\n title='Flight Search API',\n url='https://api.example.org/',\n content={\n 'search': coreapi.Link(\n url='/search/',\n action='get',\n fields=[\n coreapi.Field(\n name='from',\n required=True,\n location='query',\n description='City name or airport code.'\n ),\n coreapi.Field(\n name='to',\n required=True,\n location='query',\n description='City name or airport code.'\n ),\n coreapi.Field(\n name='date',\n required=True,\n location='query',\n description='Flight date in \"YYYY-MM-DD\" format.'\n )\n ],\n description='Return flight availability and prices.'\n )\n }\n)\n\n\n\nSchema output formats\n\n\nIn order to be presented in an HTTP response, the internal representation\nhas to be rendered into the actual bytes that are used in the response.\n\n\nCore JSON\n is designed as a canonical format for use with Core API.\nREST framework includes a renderer class for handling this media type, which\nis available as \nrenderers.CoreJSONRenderer\n.\n\n\nAlternate schema formats\n\n\nOther schema formats such as \nOpen API\n (\"Swagger\"),\n\nJSON HyperSchema\n, or \nAPI Blueprint\n can also\nbe supported by implementing a custom renderer class that handles converting a\n\nDocument\n instance into a bytestring representation.\n\n\nIf there is a Core API codec package that supports encoding into the format you\nwant to use then implementing the renderer class can be done by using the codec.\n\n\nExample\n\n\nFor example, the \nopenapi_codec\n package provides support for encoding or decoding\nto the Open API (\"Swagger\") format:\n\n\nfrom rest_framework import renderers\nfrom openapi_codec import OpenAPICodec\n\nclass SwaggerRenderer(renderers.BaseRenderer):\n media_type = 'application/openapi+json'\n format = 'swagger'\n\n def render(self, data, media_type=None, renderer_context=None):\n codec = OpenAPICodec()\n return codec.dump(data)\n\n\n\nSchemas vs Hypermedia\n\n\nIt's worth pointing out here that Core API can also be used to model hypermedia\nresponses, which present an alternative interaction style to API schemas.\n\n\nWith an API schema, the entire available interface is presented up-front\nas a single endpoint. Responses to individual API endpoints are then typically\npresented as plain data, without any further interactions contained in each\nresponse.\n\n\nWith Hypermedia, the client is instead presented with a document containing\nboth data and available interactions. Each interaction results in a new\ndocument, detailing both the current state and the available interactions.\n\n\nFurther information and support on building Hypermedia APIs with REST framework\nis planned for a future version.\n\n\n\n\nCreating a schema\n\n\nREST framework includes functionality for auto-generating a schema,\nor allows you to specify one explicitly.\n\n\nManual Schema Specification\n\n\nTo manually specify a schema you create a Core API \nDocument\n, similar to the\nexample above.\n\n\nschema = coreapi.Document(\n title='Flight Search API',\n content={\n ...\n }\n)\n\n\n\nAutomatic Schema Generation\n\n\nAutomatic schema generation is provided by the \nSchemaGenerator\n class.\n\n\nSchemaGenerator\n processes a list of routed URL pattterns and compiles the\nappropriately structured Core API Document.\n\n\nBasic usage is just to provide the title for your schema and call\n\nget_schema()\n:\n\n\ngenerator = schemas.SchemaGenerator(title='Flight Search API')\nschema = generator.get_schema()\n\n\n\nPer-View Schema Customisation\n\n\nBy default, view introspection is performed by an \nAutoSchema\n instance\naccessible via the \nschema\n attribute on \nAPIView\n. This provides the\nappropriate Core API \nLink\n object for the view, request method and path:\n\n\nauto_schema = view.schema\ncoreapi_link = auto_schema.get_link(...)\n\n\n\n(In compiling the schema, \nSchemaGenerator\n calls \nview.schema.get_link()\n for\neach view, allowed method and path.)\n\n\n\n\nNote\n: For basic \nAPIView\n subclasses, default introspection is essentially\nlimited to the URL kwarg path parameters. For \nGenericAPIView\n\nsubclasses, which includes all the provided class based views, \nAutoSchema\n will\nattempt to introspect serialiser, pagination and filter fields, as well as\nprovide richer path field descriptions. (The key hooks here are the relevant\n\nGenericAPIView\n attributes and methods: \nget_serializer\n, \npagination_class\n,\n\nfilter_backends\n and so on.)\n\n\n\n\nTo customise the \nLink\n generation you may:\n\n\n\n\n\n\nInstantiate \nAutoSchema\n on your view with the \nmanual_fields\n kwarg:\n\n\nfrom rest_framework.views import APIView\nfrom rest_framework.schemas import AutoSchema\n\nclass CustomView(APIView):\n ...\n schema = AutoSchema(\n manual_fields=[\n coreapi.Field(\"extra_field\", ...),\n ]\n )\n\n\n\nThis allows extension for the most common case without subclassing.\n\n\n\n\n\n\nProvide an \nAutoSchema\n subclass with more complex customisation:\n\n\nfrom rest_framework.views import APIView\nfrom rest_framework.schemas import AutoSchema\n\nclass CustomSchema(AutoSchema):\n def get_link(...):\n # Implement custom introspection here (or in other sub-methods)\n\nclass CustomView(APIView):\n ...\n schema = CustomSchema()\n\n\n\nThis provides complete control over view introspection.\n\n\n\n\n\n\nInstantiate \nManualSchema\n on your view, providing the Core API \nFields\n for\n the view explicitly:\n\n\nfrom rest_framework.views import APIView\nfrom rest_framework.schemas import ManualSchema\n\nclass CustomView(APIView):\n ...\n schema = ManualSchema(fields=[\n coreapi.Field(\n \"first_field\",\n required=True,\n location=\"path\",\n schema=coreschema.String()\n ),\n coreapi.Field(\n \"second_field\",\n required=True,\n location=\"path\",\n schema=coreschema.String()\n ),\n ])\n\n\n\nThis allows manually specifying the schema for some views whilst maintaining\nautomatic generation elsewhere.\n\n\n\n\n\n\nYou may disable schema generation for a view by setting \nschema\n to \nNone\n:\n\n\n class CustomView(APIView):\n ...\n schema = None # Will not appear in schema\n\n\n\n\n\nNote\n: For full details on \nSchemaGenerator\n plus the \nAutoSchema\n and\n\nManualSchema\n descriptors see the \nAPI Reference below\n.\n\n\n\n\nAdding a schema view\n\n\nThere are a few different ways to add a schema view to your API, depending on\nexactly what you need.\n\n\nThe get_schema_view shortcut\n\n\nThe simplest way to include a schema in your project is to use the\n\nget_schema_view()\n function.\n\n\nfrom rest_framework.schemas import get_schema_view\n\nschema_view = get_schema_view(title=\"Server Monitoring API\")\n\nurlpatterns = [\n url('^$', schema_view),\n ...\n]\n\n\n\nOnce the view has been added, you'll be able to make API requests to retrieve\nthe auto-generated schema definition.\n\n\n$ http http://127.0.0.1:8000/ Accept:application/coreapi+json\nHTTP/1.0 200 OK\nAllow: GET, HEAD, OPTIONS\nContent-Type: application/vnd.coreapi+json\n\n{\n \"_meta\": {\n \"title\": \"Server Monitoring API\"\n },\n \"_type\": \"document\",\n ...\n}\n\n\n\nThe arguments to \nget_schema_view()\n are:\n\n\ntitle\n\n\nMay be used to provide a descriptive title for the schema definition.\n\n\nurl\n\n\nMay be used to pass a canonical URL for the schema.\n\n\nschema_view = get_schema_view(\n title='Server Monitoring API',\n url='https://www.example.org/api/'\n)\n\n\n\nurlconf\n\n\nA string representing the import path to the URL conf that you want\nto generate an API schema for. This defaults to the value of Django's\nROOT_URLCONF setting.\n\n\nschema_view = get_schema_view(\n title='Server Monitoring API',\n url='https://www.example.org/api/',\n urlconf='myproject.urls'\n)\n\n\n\nrenderer_classes\n\n\nMay be used to pass the set of renderer classes that can be used to render the API root endpoint.\n\n\nfrom rest_framework.schemas import get_schema_view\nfrom rest_framework.renderers import CoreJSONRenderer\nfrom my_custom_package import APIBlueprintRenderer\n\nschema_view = get_schema_view(\n title='Server Monitoring API',\n url='https://www.example.org/api/',\n renderer_classes=[CoreJSONRenderer, APIBlueprintRenderer]\n)\n\n\n\npatterns\n\n\nList of url patterns to limit the schema introspection to. If you only want the \nmyproject.api\n urls\nto be exposed in the schema:\n\n\nschema_url_patterns = [\n url(r'^api/', include('myproject.api.urls')),\n]\n\nschema_view = get_schema_view(\n title='Server Monitoring API',\n url='https://www.example.org/api/',\n patterns=schema_url_patterns,\n)\n\n\n\ngenerator_class\n\n\nMay be used to specify a \nSchemaGenerator\n subclass to be passed to the\n\nSchemaView\n.\n\n\nauthentication_classes\n\n\nMay be used to specify the list of authentication classes that will apply to the schema endpoint.\nDefaults to \nsettings.DEFAULT_AUTHENTICATION_CLASSES\n\n\npermission_classes\n\n\nMay be used to specify the list of permission classes that will apply to the schema endpoint.\nDefaults to \nsettings.DEFAULT_PERMISSION_CLASSES\n\n\nUsing an explicit schema view\n\n\nIf you need a little more control than the \nget_schema_view()\n shortcut gives you,\nthen you can use the \nSchemaGenerator\n class directly to auto-generate the\n\nDocument\n instance, and to return that from a view.\n\n\nThis option gives you the flexibility of setting up the schema endpoint\nwith whatever behaviour you want. For example, you can apply different\npermission, throttling, or authentication policies to the schema endpoint.\n\n\nHere's an example of using \nSchemaGenerator\n together with a view to\nreturn the schema.\n\n\nviews.py:\n\n\nfrom rest_framework.decorators import api_view, renderer_classes\nfrom rest_framework import renderers, response, schemas\n\ngenerator = schemas.SchemaGenerator(title='Bookings API')\n\n@api_view()\n@renderer_classes([renderers.CoreJSONRenderer])\ndef schema_view(request):\n schema = generator.get_schema(request)\n return response.Response(schema)\n\n\n\nurls.py:\n\n\nurlpatterns = [\n url('/', schema_view),\n ...\n]\n\n\n\nYou can also serve different schemas to different users, depending on the\npermissions they have available. This approach can be used to ensure that\nunauthenticated requests are presented with a different schema to\nauthenticated requests, or to ensure that different parts of the API are\nmade visible to different users depending on their role.\n\n\nIn order to present a schema with endpoints filtered by user permissions,\nyou need to pass the \nrequest\n argument to the \nget_schema()\n method, like so:\n\n\n@api_view()\n@renderer_classes([renderers.CoreJSONRenderer])\ndef schema_view(request):\n generator = schemas.SchemaGenerator(title='Bookings API')\n return response.Response(generator.get_schema(request=request))\n\n\n\nExplicit schema definition\n\n\nAn alternative to the auto-generated approach is to specify the API schema\nexplicitly, by declaring a \nDocument\n object in your codebase. Doing so is a\nlittle more work, but ensures that you have full control over the schema\nrepresentation.\n\n\nimport coreapi\nfrom rest_framework.decorators import api_view, renderer_classes\nfrom rest_framework import renderers, response\n\nschema = coreapi.Document(\n title='Bookings API',\n content={\n ...\n }\n)\n\n@api_view()\n@renderer_classes([renderers.CoreJSONRenderer])\ndef schema_view(request):\n return response.Response(schema)\n\n\n\nStatic schema file\n\n\nA final option is to write your API schema as a static file, using one\nof the available formats, such as Core JSON or Open API.\n\n\nYou could then either:\n\n\n\n\nWrite a schema definition as a static file, and \nserve the static file directly\n.\n\n\nWrite a schema definition that is loaded using \nCore API\n, and then\n rendered to one of many available formats, depending on the client request.\n\n\n\n\n\n\nSchemas as documentation\n\n\nOne common usage of API schemas is to use them to build documentation pages.\n\n\nThe schema generation in REST framework uses docstrings to automatically\npopulate descriptions in the schema document.\n\n\nThese descriptions will be based on:\n\n\n\n\nThe corresponding method docstring if one exists.\n\n\nA named section within the class docstring, which can be either single line or multi-line.\n\n\nThe class docstring.\n\n\n\n\nExamples\n\n\nAn \nAPIView\n, with an explicit method docstring.\n\n\nclass ListUsernames(APIView):\n def get(self, request):\n \"\"\"\n Return a list of all user names in the system.\n \"\"\"\n usernames = [user.username for user in User.objects.all()]\n return Response(usernames)\n\n\n\nA \nViewSet\n, with an explict action docstring.\n\n\nclass ListUsernames(ViewSet):\n def list(self, request):\n \"\"\"\n Return a list of all user names in the system.\n \"\"\"\n usernames = [user.username for user in User.objects.all()]\n return Response(usernames)\n\n\n\nA generic view with sections in the class docstring, using single-line style.\n\n\nclass UserList(generics.ListCreateAPIView):\n \"\"\"\n get: List all the users.\n post: Create a new user.\n \"\"\"\n queryset = User.objects.all()\n serializer_class = UserSerializer\n permission_classes = (IsAdminUser,)\n\n\n\nA generic viewset with sections in the class docstring, using multi-line style.\n\n\nclass UserViewSet(viewsets.ModelViewSet):\n \"\"\"\n API endpoint that allows users to be viewed or edited.\n\n retrieve:\n Return a user instance.\n\n list:\n Return all users, ordered by most recently joined.\n \"\"\"\n queryset = User.objects.all().order_by('-date_joined')\n serializer_class = UserSerializer\n\n\n\n\n\nAPI Reference\n\n\nSchemaGenerator\n\n\nA class that walks a list of routed URL patterns, requests the schema for each view,\nand collates the resulting CoreAPI Document.\n\n\nTypically you'll instantiate \nSchemaGenerator\n with a single argument, like so:\n\n\ngenerator = SchemaGenerator(title='Stock Prices API')\n\n\n\nArguments:\n\n\n\n\ntitle\n \nrequired\n - The name of the API.\n\n\nurl\n - The root URL of the API schema. This option is not required unless the schema is included under path prefix.\n\n\npatterns\n - A list of URLs to inspect when generating the schema. Defaults to the project's URL conf.\n\n\nurlconf\n - A URL conf module name to use when generating the schema. Defaults to \nsettings.ROOT_URLCONF\n.\n\n\n\n\nget_schema(self, request)\n\n\nReturns a \ncoreapi.Document\n instance that represents the API schema.\n\n\n@api_view\n@renderer_classes([renderers.CoreJSONRenderer])\ndef schema_view(request):\n generator = schemas.SchemaGenerator(title='Bookings API')\n return Response(generator.get_schema())\n\n\n\nThe \nrequest\n argument is optional, and may be used if you want to apply per-user\npermissions to the resulting schema generation.\n\n\nget_links(self, request)\n\n\nReturn a nested dictionary containing all the links that should be included in the API schema.\n\n\nThis is a good point to override if you want to modify the resulting structure of the generated schema,\nas you can build a new dictionary with a different layout.\n\n\nAutoSchema\n\n\nA class that deals with introspection of individual views for schema generation.\n\n\nAutoSchema\n is attached to \nAPIView\n via the \nschema\n attribute.\n\n\nThe \nAutoSchema\n constructor takes a single keyword argument \nmanual_fields\n.\n\n\nmanual_fields\n: a \nlist\n of \ncoreapi.Field\n instances that will be added to\nthe generated fields. Generated fields with a matching \nname\n will be overwritten.\n\n\nclass CustomView(APIView):\n schema = AutoSchema(manual_fields=[\n coreapi.Field(\n \"my_extra_field\",\n required=True,\n location=\"path\",\n schema=coreschema.String()\n ),\n ])\n\n\n\nFor more advanced customisation subclass \nAutoSchema\n to customise schema generation.\n\n\nclass CustomViewSchema(AutoSchema):\n \"\"\"\n Overrides `get_link()` to provide Custom Behavior X\n \"\"\"\n\n def get_link(self, path, method, base_url):\n link = super().get_link(path, method, base_url)\n # Do something to customize link here...\n return link\n\nclass MyView(APIView):\n schema = CustomViewSchema()\n\n\n\nThe following methods are available to override.\n\n\nget_link(self, path, method, base_url)\n\n\nReturns a \ncoreapi.Link\n instance corresponding to the given view.\n\n\nThis is the main entry point.\nYou can override this if you need to provide custom behaviors for particular views.\n\n\nget_description(self, path, method)\n\n\nReturns a string to use as the link description. By default this is based on the\nview docstring as described in the \"Schemas as Documentation\" section above.\n\n\nget_encoding(self, path, method)\n\n\nReturns a string to indicate the encoding for any request body, when interacting\nwith the given view. Eg. \n'application/json'\n. May return a blank string for views\nthat do not expect a request body.\n\n\nget_path_fields(self, path, method):\n\n\nReturn a list of \ncoreapi.Link()\n instances. One for each path parameter in the URL.\n\n\nget_serializer_fields(self, path, method)\n\n\nReturn a list of \ncoreapi.Link()\n instances. One for each field in the serializer class used by the view.\n\n\nget_pagination_fields(self, path, method)\n\n\nReturn a list of \ncoreapi.Link()\n instances, as returned by the \nget_schema_fields()\n method on any pagination class used by the view.\n\n\nget_filter_fields(self, path, method)\n\n\nReturn a list of \ncoreapi.Link()\n instances, as returned by the \nget_schema_fields()\n method of any filter classes used by the view.\n\n\nget_manual_fields(self, path, method)\n\n\nReturn a list of \ncoreapi.Field()\n instances to be added to or replace generated fields. Defaults to (optional) \nmanual_fields\n passed to \nAutoSchema\n constructor.\n\n\nMay be overridden to customise manual fields by \npath\n or \nmethod\n. For example, a per-method adjustment may look like this:\n\n\ndef get_manual_fields(self, path, method):\n \"\"\"Example adding per-method fields.\"\"\"\n\n extra_fields = []\n if method=='GET':\n extra_fields = # ... list of extra fields for GET ...\n if method=='POST':\n extra_fields = # ... list of extra fields for POST ...\n\n manual_fields = super().get_manual_fields()\n return manual_fields + extra_fields\n\n\n\n\nupdate_fields(fields, update_with)\n\n\nUtility \nstaticmethod\n. Encapsulates logic to add or replace fields from a list\nby \nField.name\n. May be overridden to adjust replacement criteria.\n\n\nManualSchema\n\n\nAllows manually providing a list of \ncoreapi.Field\n instances for the schema,\nplus an optional description.\n\n\nclass MyView(APIView):\n schema = ManualSchema(fields=[\n coreapi.Field(\n \"first_field\",\n required=True,\n location=\"path\",\n schema=coreschema.String()\n ),\n coreapi.Field(\n \"second_field\",\n required=True,\n location=\"path\",\n schema=coreschema.String()\n ),\n ]\n )\n\n\n\nThe \nManualSchema\n constructor takes two arguments:\n\n\nfields\n: A list of \ncoreapi.Field\n instances. Required.\n\n\ndescription\n: A string description. Optional.\n\n\n\n\nCore API\n\n\nThis documentation gives a brief overview of the components within the \ncoreapi\n\npackage that are used to represent an API schema.\n\n\nNote that these classes are imported from the \ncoreapi\n package, rather than\nfrom the \nrest_framework\n package.\n\n\nDocument\n\n\nRepresents a container for the API schema.\n\n\ntitle\n\n\nA name for the API.\n\n\nurl\n\n\nA canonical URL for the API.\n\n\ncontent\n\n\nA dictionary, containing the \nLink\n objects that the schema contains.\n\n\nIn order to provide more structure to the schema, the \ncontent\n dictionary\nmay be nested, typically to a second level. For example:\n\n\ncontent={\n \"bookings\": {\n \"list\": Link(...),\n \"create\": Link(...),\n ...\n },\n \"venues\": {\n \"list\": Link(...),\n ...\n },\n ...\n}\n\n\n\nLink\n\n\nRepresents an individual API endpoint.\n\n\nurl\n\n\nThe URL of the endpoint. May be a URI template, such as \n/users/{username}/\n.\n\n\naction\n\n\nThe HTTP method associated with the endpoint. Note that URLs that support\nmore than one HTTP method, should correspond to a single \nLink\n for each.\n\n\nfields\n\n\nA list of \nField\n instances, describing the available parameters on the input.\n\n\ndescription\n\n\nA short description of the meaning and intended usage of the endpoint.\n\n\nField\n\n\nRepresents a single input parameter on a given API endpoint.\n\n\nname\n\n\nA descriptive name for the input.\n\n\nrequired\n\n\nA boolean, indicated if the client is required to included a value, or if\nthe parameter can be omitted.\n\n\nlocation\n\n\nDetermines how the information is encoded into the request. Should be one of\nthe following strings:\n\n\n\"path\"\n\n\nIncluded in a templated URI. For example a \nurl\n value of \n/products/{product_code}/\n could be used together with a \n\"path\"\n field, to handle API inputs in a URL path such as \n/products/slim-fit-jeans/\n.\n\n\nThese fields will normally correspond with \nnamed arguments in the project URL conf\n.\n\n\n\"query\"\n\n\nIncluded as a URL query parameter. For example \n?search=sale\n. Typically for \nGET\n requests.\n\n\nThese fields will normally correspond with pagination and filtering controls on a view.\n\n\n\"form\"\n\n\nIncluded in the request body, as a single item of a JSON object or HTML form. For example \n{\"colour\": \"blue\", ...}\n. Typically for \nPOST\n, \nPUT\n and \nPATCH\n requests. Multiple \n\"form\"\n fields may be included on a single link.\n\n\nThese fields will normally correspond with serializer fields on a view.\n\n\n\"body\"\n\n\nIncluded as the complete request body. Typically for \nPOST\n, \nPUT\n and \nPATCH\n requests. No more than one \n\"body\"\n field may exist on a link. May not be used together with \n\"form\"\n fields.\n\n\nThese fields will normally correspond with views that use \nListSerializer\n to validate the request input, or with file upload views.\n\n\nencoding\n\n\n\"application/json\"\n\n\nJSON encoded request content. Corresponds to views using \nJSONParser\n.\nValid only if either one or more \nlocation=\"form\"\n fields, or a single\n\nlocation=\"body\"\n field is included on the \nLink\n.\n\n\n\"multipart/form-data\"\n\n\nMultipart encoded request content. Corresponds to views using \nMultiPartParser\n.\nValid only if one or more \nlocation=\"form\"\n fields is included on the \nLink\n.\n\n\n\"application/x-www-form-urlencoded\"\n\n\nURL encoded request content. Corresponds to views using \nFormParser\n. Valid\nonly if one or more \nlocation=\"form\"\n fields is included on the \nLink\n.\n\n\n\"application/octet-stream\"\n\n\nBinary upload request content. Corresponds to views using \nFileUploadParser\n.\nValid only if a \nlocation=\"body\"\n field is included on the \nLink\n.\n\n\ndescription\n\n\nA short description of the meaning and intended usage of the input field.\n\n\n\n\nThird party packages\n\n\ndrf-yasg - Yet Another Swagger Generator\n\n\ndrf-yasg\n generates \nOpenAPI\n documents suitable for code generation - nested schemas, \nnamed models, response bodies, enum/pattern/min/max validators, form parameters, etc.\n\n\nDRF OpenAPI\n\n\nDRF OpenAPI\n renders the schema generated by Django Rest Framework\nin \nOpenAPI\n format.", + "text": "Schemas\n\n\n\n\nA machine-readable [schema] describes what resources are available via the API, what their URLs are, how they are represented and what operations they support.\n\n\n\u2014 Heroku, \nJSON Schema for the Heroku Platform API\n\n\n\n\nAPI schemas are a useful tool that allow for a range of use cases, including\ngenerating reference documentation, or driving dynamic client libraries that\ncan interact with your API.\n\n\nInstall Core API\n\n\nYou'll need to install the \ncoreapi\n package in order to add schema support\nfor REST framework.\n\n\npip install coreapi\n\n\n\nInternal schema representation\n\n\nREST framework uses \nCore API\n in order to model schema information in\na format-independent representation. This information can then be rendered\ninto various different schema formats, or used to generate API documentation.\n\n\nWhen using Core API, a schema is represented as a \nDocument\n which is the\ntop-level container object for information about the API. Available API\ninteractions are represented using \nLink\n objects. Each link includes a URL,\nHTTP method, and may include a list of \nField\n instances, which describe any\nparameters that may be accepted by the API endpoint. The \nLink\n and \nField\n\ninstances may also include descriptions, that allow an API schema to be\nrendered into user documentation.\n\n\nHere's an example of an API description that includes a single \nsearch\n\nendpoint:\n\n\ncoreapi.Document(\n title='Flight Search API',\n url='https://api.example.org/',\n content={\n 'search': coreapi.Link(\n url='/search/',\n action='get',\n fields=[\n coreapi.Field(\n name='from',\n required=True,\n location='query',\n description='City name or airport code.'\n ),\n coreapi.Field(\n name='to',\n required=True,\n location='query',\n description='City name or airport code.'\n ),\n coreapi.Field(\n name='date',\n required=True,\n location='query',\n description='Flight date in \"YYYY-MM-DD\" format.'\n )\n ],\n description='Return flight availability and prices.'\n )\n }\n)\n\n\n\nSchema output formats\n\n\nIn order to be presented in an HTTP response, the internal representation\nhas to be rendered into the actual bytes that are used in the response.\n\n\nCore JSON\n is designed as a canonical format for use with Core API.\nREST framework includes a renderer class for handling this media type, which\nis available as \nrenderers.CoreJSONRenderer\n.\n\n\nAlternate schema formats\n\n\nOther schema formats such as \nOpen API\n (\"Swagger\"),\n\nJSON HyperSchema\n, or \nAPI Blueprint\n can also\nbe supported by implementing a custom renderer class that handles converting a\n\nDocument\n instance into a bytestring representation.\n\n\nIf there is a Core API codec package that supports encoding into the format you\nwant to use then implementing the renderer class can be done by using the codec.\n\n\nExample\n\n\nFor example, the \nopenapi_codec\n package provides support for encoding or decoding\nto the Open API (\"Swagger\") format:\n\n\nfrom rest_framework import renderers\nfrom openapi_codec import OpenAPICodec\n\nclass SwaggerRenderer(renderers.BaseRenderer):\n media_type = 'application/openapi+json'\n format = 'swagger'\n\n def render(self, data, media_type=None, renderer_context=None):\n codec = OpenAPICodec()\n return codec.dump(data)\n\n\n\nSchemas vs Hypermedia\n\n\nIt's worth pointing out here that Core API can also be used to model hypermedia\nresponses, which present an alternative interaction style to API schemas.\n\n\nWith an API schema, the entire available interface is presented up-front\nas a single endpoint. Responses to individual API endpoints are then typically\npresented as plain data, without any further interactions contained in each\nresponse.\n\n\nWith Hypermedia, the client is instead presented with a document containing\nboth data and available interactions. Each interaction results in a new\ndocument, detailing both the current state and the available interactions.\n\n\nFurther information and support on building Hypermedia APIs with REST framework\nis planned for a future version.\n\n\n\n\nCreating a schema\n\n\nREST framework includes functionality for auto-generating a schema,\nor allows you to specify one explicitly.\n\n\nManual Schema Specification\n\n\nTo manually specify a schema you create a Core API \nDocument\n, similar to the\nexample above.\n\n\nschema = coreapi.Document(\n title='Flight Search API',\n content={\n ...\n }\n)\n\n\n\nAutomatic Schema Generation\n\n\nAutomatic schema generation is provided by the \nSchemaGenerator\n class.\n\n\nSchemaGenerator\n processes a list of routed URL pattterns and compiles the\nappropriately structured Core API Document.\n\n\nBasic usage is just to provide the title for your schema and call\n\nget_schema()\n:\n\n\ngenerator = schemas.SchemaGenerator(title='Flight Search API')\nschema = generator.get_schema()\n\n\n\nPer-View Schema Customisation\n\n\nBy default, view introspection is performed by an \nAutoSchema\n instance\naccessible via the \nschema\n attribute on \nAPIView\n. This provides the\nappropriate Core API \nLink\n object for the view, request method and path:\n\n\nauto_schema = view.schema\ncoreapi_link = auto_schema.get_link(...)\n\n\n\n(In compiling the schema, \nSchemaGenerator\n calls \nview.schema.get_link()\n for\neach view, allowed method and path.)\n\n\n\n\nNote\n: For basic \nAPIView\n subclasses, default introspection is essentially\nlimited to the URL kwarg path parameters. For \nGenericAPIView\n\nsubclasses, which includes all the provided class based views, \nAutoSchema\n will\nattempt to introspect serialiser, pagination and filter fields, as well as\nprovide richer path field descriptions. (The key hooks here are the relevant\n\nGenericAPIView\n attributes and methods: \nget_serializer\n, \npagination_class\n,\n\nfilter_backends\n and so on.)\n\n\n\n\nTo customise the \nLink\n generation you may:\n\n\n\n\n\n\nInstantiate \nAutoSchema\n on your view with the \nmanual_fields\n kwarg:\n\n\nfrom rest_framework.views import APIView\nfrom rest_framework.schemas import AutoSchema\n\nclass CustomView(APIView):\n ...\n schema = AutoSchema(\n manual_fields=[\n coreapi.Field(\"extra_field\", ...),\n ]\n )\n\n\n\nThis allows extension for the most common case without subclassing.\n\n\n\n\n\n\nProvide an \nAutoSchema\n subclass with more complex customisation:\n\n\nfrom rest_framework.views import APIView\nfrom rest_framework.schemas import AutoSchema\n\nclass CustomSchema(AutoSchema):\n def get_link(...):\n # Implement custom introspection here (or in other sub-methods)\n\nclass CustomView(APIView):\n ...\n schema = CustomSchema()\n\n\n\nThis provides complete control over view introspection.\n\n\n\n\n\n\nInstantiate \nManualSchema\n on your view, providing the Core API \nFields\n for\n the view explicitly:\n\n\nfrom rest_framework.views import APIView\nfrom rest_framework.schemas import ManualSchema\n\nclass CustomView(APIView):\n ...\n schema = ManualSchema(fields=[\n coreapi.Field(\n \"first_field\",\n required=True,\n location=\"path\",\n schema=coreschema.String()\n ),\n coreapi.Field(\n \"second_field\",\n required=True,\n location=\"path\",\n schema=coreschema.String()\n ),\n ])\n\n\n\nThis allows manually specifying the schema for some views whilst maintaining\nautomatic generation elsewhere.\n\n\n\n\n\n\nYou may disable schema generation for a view by setting \nschema\n to \nNone\n:\n\n\n class CustomView(APIView):\n ...\n schema = None # Will not appear in schema\n\n\n\n\n\nNote\n: For full details on \nSchemaGenerator\n plus the \nAutoSchema\n and\n\nManualSchema\n descriptors see the \nAPI Reference below\n.\n\n\n\n\nAdding a schema view\n\n\nThere are a few different ways to add a schema view to your API, depending on\nexactly what you need.\n\n\nThe get_schema_view shortcut\n\n\nThe simplest way to include a schema in your project is to use the\n\nget_schema_view()\n function.\n\n\nfrom rest_framework.schemas import get_schema_view\n\nschema_view = get_schema_view(title=\"Server Monitoring API\")\n\nurlpatterns = [\n url('^$', schema_view),\n ...\n]\n\n\n\nOnce the view has been added, you'll be able to make API requests to retrieve\nthe auto-generated schema definition.\n\n\n$ http http://127.0.0.1:8000/ Accept:application/coreapi+json\nHTTP/1.0 200 OK\nAllow: GET, HEAD, OPTIONS\nContent-Type: application/vnd.coreapi+json\n\n{\n \"_meta\": {\n \"title\": \"Server Monitoring API\"\n },\n \"_type\": \"document\",\n ...\n}\n\n\n\nThe arguments to \nget_schema_view()\n are:\n\n\ntitle\n\n\nMay be used to provide a descriptive title for the schema definition.\n\n\nurl\n\n\nMay be used to pass a canonical URL for the schema.\n\n\nschema_view = get_schema_view(\n title='Server Monitoring API',\n url='https://www.example.org/api/'\n)\n\n\n\nurlconf\n\n\nA string representing the import path to the URL conf that you want\nto generate an API schema for. This defaults to the value of Django's\nROOT_URLCONF setting.\n\n\nschema_view = get_schema_view(\n title='Server Monitoring API',\n url='https://www.example.org/api/',\n urlconf='myproject.urls'\n)\n\n\n\nrenderer_classes\n\n\nMay be used to pass the set of renderer classes that can be used to render the API root endpoint.\n\n\nfrom rest_framework.schemas import get_schema_view\nfrom rest_framework.renderers import CoreJSONRenderer\nfrom my_custom_package import APIBlueprintRenderer\n\nschema_view = get_schema_view(\n title='Server Monitoring API',\n url='https://www.example.org/api/',\n renderer_classes=[CoreJSONRenderer, APIBlueprintRenderer]\n)\n\n\n\npatterns\n\n\nList of url patterns to limit the schema introspection to. If you only want the \nmyproject.api\n urls\nto be exposed in the schema:\n\n\nschema_url_patterns = [\n url(r'^api/', include('myproject.api.urls')),\n]\n\nschema_view = get_schema_view(\n title='Server Monitoring API',\n url='https://www.example.org/api/',\n patterns=schema_url_patterns,\n)\n\n\n\ngenerator_class\n\n\nMay be used to specify a \nSchemaGenerator\n subclass to be passed to the\n\nSchemaView\n.\n\n\nauthentication_classes\n\n\nMay be used to specify the list of authentication classes that will apply to the schema endpoint.\nDefaults to \nsettings.DEFAULT_AUTHENTICATION_CLASSES\n\n\npermission_classes\n\n\nMay be used to specify the list of permission classes that will apply to the schema endpoint.\nDefaults to \nsettings.DEFAULT_PERMISSION_CLASSES\n\n\nUsing an explicit schema view\n\n\nIf you need a little more control than the \nget_schema_view()\n shortcut gives you,\nthen you can use the \nSchemaGenerator\n class directly to auto-generate the\n\nDocument\n instance, and to return that from a view.\n\n\nThis option gives you the flexibility of setting up the schema endpoint\nwith whatever behaviour you want. For example, you can apply different\npermission, throttling, or authentication policies to the schema endpoint.\n\n\nHere's an example of using \nSchemaGenerator\n together with a view to\nreturn the schema.\n\n\nviews.py:\n\n\nfrom rest_framework.decorators import api_view, renderer_classes\nfrom rest_framework import renderers, response, schemas\n\ngenerator = schemas.SchemaGenerator(title='Bookings API')\n\n@api_view()\n@renderer_classes([renderers.CoreJSONRenderer])\ndef schema_view(request):\n schema = generator.get_schema(request)\n return response.Response(schema)\n\n\n\nurls.py:\n\n\nurlpatterns = [\n url('/', schema_view),\n ...\n]\n\n\n\nYou can also serve different schemas to different users, depending on the\npermissions they have available. This approach can be used to ensure that\nunauthenticated requests are presented with a different schema to\nauthenticated requests, or to ensure that different parts of the API are\nmade visible to different users depending on their role.\n\n\nIn order to present a schema with endpoints filtered by user permissions,\nyou need to pass the \nrequest\n argument to the \nget_schema()\n method, like so:\n\n\n@api_view()\n@renderer_classes([renderers.CoreJSONRenderer])\ndef schema_view(request):\n generator = schemas.SchemaGenerator(title='Bookings API')\n return response.Response(generator.get_schema(request=request))\n\n\n\nExplicit schema definition\n\n\nAn alternative to the auto-generated approach is to specify the API schema\nexplicitly, by declaring a \nDocument\n object in your codebase. Doing so is a\nlittle more work, but ensures that you have full control over the schema\nrepresentation.\n\n\nimport coreapi\nfrom rest_framework.decorators import api_view, renderer_classes\nfrom rest_framework import renderers, response\n\nschema = coreapi.Document(\n title='Bookings API',\n content={\n ...\n }\n)\n\n@api_view()\n@renderer_classes([renderers.CoreJSONRenderer])\ndef schema_view(request):\n return response.Response(schema)\n\n\n\nStatic schema file\n\n\nA final option is to write your API schema as a static file, using one\nof the available formats, such as Core JSON or Open API.\n\n\nYou could then either:\n\n\n\n\nWrite a schema definition as a static file, and \nserve the static file directly\n.\n\n\nWrite a schema definition that is loaded using \nCore API\n, and then\n rendered to one of many available formats, depending on the client request.\n\n\n\n\n\n\nSchemas as documentation\n\n\nOne common usage of API schemas is to use them to build documentation pages.\n\n\nThe schema generation in REST framework uses docstrings to automatically\npopulate descriptions in the schema document.\n\n\nThese descriptions will be based on:\n\n\n\n\nThe corresponding method docstring if one exists.\n\n\nA named section within the class docstring, which can be either single line or multi-line.\n\n\nThe class docstring.\n\n\n\n\nExamples\n\n\nAn \nAPIView\n, with an explicit method docstring.\n\n\nclass ListUsernames(APIView):\n def get(self, request):\n \"\"\"\n Return a list of all user names in the system.\n \"\"\"\n usernames = [user.username for user in User.objects.all()]\n return Response(usernames)\n\n\n\nA \nViewSet\n, with an explict action docstring.\n\n\nclass ListUsernames(ViewSet):\n def list(self, request):\n \"\"\"\n Return a list of all user names in the system.\n \"\"\"\n usernames = [user.username for user in User.objects.all()]\n return Response(usernames)\n\n\n\nA generic view with sections in the class docstring, using single-line style.\n\n\nclass UserList(generics.ListCreateAPIView):\n \"\"\"\n get: List all the users.\n post: Create a new user.\n \"\"\"\n queryset = User.objects.all()\n serializer_class = UserSerializer\n permission_classes = (IsAdminUser,)\n\n\n\nA generic viewset with sections in the class docstring, using multi-line style.\n\n\nclass UserViewSet(viewsets.ModelViewSet):\n \"\"\"\n API endpoint that allows users to be viewed or edited.\n\n retrieve:\n Return a user instance.\n\n list:\n Return all users, ordered by most recently joined.\n \"\"\"\n queryset = User.objects.all().order_by('-date_joined')\n serializer_class = UserSerializer\n\n\n\n\n\nAPI Reference\n\n\nSchemaGenerator\n\n\nA class that walks a list of routed URL patterns, requests the schema for each view,\nand collates the resulting CoreAPI Document.\n\n\nTypically you'll instantiate \nSchemaGenerator\n with a single argument, like so:\n\n\ngenerator = SchemaGenerator(title='Stock Prices API')\n\n\n\nArguments:\n\n\n\n\ntitle\n \nrequired\n - The name of the API.\n\n\nurl\n - The root URL of the API schema. This option is not required unless the schema is included under path prefix.\n\n\npatterns\n - A list of URLs to inspect when generating the schema. Defaults to the project's URL conf.\n\n\nurlconf\n - A URL conf module name to use when generating the schema. Defaults to \nsettings.ROOT_URLCONF\n.\n\n\n\n\nget_schema(self, request)\n\n\nReturns a \ncoreapi.Document\n instance that represents the API schema.\n\n\n@api_view\n@renderer_classes([renderers.CoreJSONRenderer])\ndef schema_view(request):\n generator = schemas.SchemaGenerator(title='Bookings API')\n return Response(generator.get_schema())\n\n\n\nThe \nrequest\n argument is optional, and may be used if you want to apply per-user\npermissions to the resulting schema generation.\n\n\nget_links(self, request)\n\n\nReturn a nested dictionary containing all the links that should be included in the API schema.\n\n\nThis is a good point to override if you want to modify the resulting structure of the generated schema,\nas you can build a new dictionary with a different layout.\n\n\nAutoSchema\n\n\nA class that deals with introspection of individual views for schema generation.\n\n\nAutoSchema\n is attached to \nAPIView\n via the \nschema\n attribute.\n\n\nThe \nAutoSchema\n constructor takes a single keyword argument \nmanual_fields\n.\n\n\nmanual_fields\n: a \nlist\n of \ncoreapi.Field\n instances that will be added to\nthe generated fields. Generated fields with a matching \nname\n will be overwritten.\n\n\nclass CustomView(APIView):\n schema = AutoSchema(manual_fields=[\n coreapi.Field(\n \"my_extra_field\",\n required=True,\n location=\"path\",\n schema=coreschema.String()\n ),\n ])\n\n\n\nFor more advanced customisation subclass \nAutoSchema\n to customise schema generation.\n\n\nclass CustomViewSchema(AutoSchema):\n \"\"\"\n Overrides `get_link()` to provide Custom Behavior X\n \"\"\"\n\n def get_link(self, path, method, base_url):\n link = super().get_link(path, method, base_url)\n # Do something to customize link here...\n return link\n\nclass MyView(APIView):\n schema = CustomViewSchema()\n\n\n\nThe following methods are available to override.\n\n\nget_link(self, path, method, base_url)\n\n\nReturns a \ncoreapi.Link\n instance corresponding to the given view.\n\n\nThis is the main entry point.\nYou can override this if you need to provide custom behaviors for particular views.\n\n\nget_description(self, path, method)\n\n\nReturns a string to use as the link description. By default this is based on the\nview docstring as described in the \"Schemas as Documentation\" section above.\n\n\nget_encoding(self, path, method)\n\n\nReturns a string to indicate the encoding for any request body, when interacting\nwith the given view. Eg. \n'application/json'\n. May return a blank string for views\nthat do not expect a request body.\n\n\nget_path_fields(self, path, method):\n\n\nReturn a list of \ncoreapi.Link()\n instances. One for each path parameter in the URL.\n\n\nget_serializer_fields(self, path, method)\n\n\nReturn a list of \ncoreapi.Link()\n instances. One for each field in the serializer class used by the view.\n\n\nget_pagination_fields(self, path, method)\n\n\nReturn a list of \ncoreapi.Link()\n instances, as returned by the \nget_schema_fields()\n method on any pagination class used by the view.\n\n\nget_filter_fields(self, path, method)\n\n\nReturn a list of \ncoreapi.Link()\n instances, as returned by the \nget_schema_fields()\n method of any filter classes used by the view.\n\n\nget_manual_fields(self, path, method)\n\n\nReturn a list of \ncoreapi.Field()\n instances to be added to or replace generated fields. Defaults to (optional) \nmanual_fields\n passed to \nAutoSchema\n constructor.\n\n\nMay be overridden to customise manual fields by \npath\n or \nmethod\n. For example, a per-method adjustment may look like this:\n\n\ndef get_manual_fields(self, path, method):\n \"\"\"Example adding per-method fields.\"\"\"\n\n extra_fields = []\n if method=='GET':\n extra_fields = # ... list of extra fields for GET ...\n if method=='POST':\n extra_fields = # ... list of extra fields for POST ...\n\n manual_fields = super().get_manual_fields(path, method)\n return manual_fields + extra_fields\n\n\n\n\nupdate_fields(fields, update_with)\n\n\nUtility \nstaticmethod\n. Encapsulates logic to add or replace fields from a list\nby \nField.name\n. May be overridden to adjust replacement criteria.\n\n\nManualSchema\n\n\nAllows manually providing a list of \ncoreapi.Field\n instances for the schema,\nplus an optional description.\n\n\nclass MyView(APIView):\n schema = ManualSchema(fields=[\n coreapi.Field(\n \"first_field\",\n required=True,\n location=\"path\",\n schema=coreschema.String()\n ),\n coreapi.Field(\n \"second_field\",\n required=True,\n location=\"path\",\n schema=coreschema.String()\n ),\n ]\n )\n\n\n\nThe \nManualSchema\n constructor takes two arguments:\n\n\nfields\n: A list of \ncoreapi.Field\n instances. Required.\n\n\ndescription\n: A string description. Optional.\n\n\nencoding\n: Default \nNone\n. A string encoding, e.g \napplication/json\n. Optional.\n\n\n\n\nCore API\n\n\nThis documentation gives a brief overview of the components within the \ncoreapi\n\npackage that are used to represent an API schema.\n\n\nNote that these classes are imported from the \ncoreapi\n package, rather than\nfrom the \nrest_framework\n package.\n\n\nDocument\n\n\nRepresents a container for the API schema.\n\n\ntitle\n\n\nA name for the API.\n\n\nurl\n\n\nA canonical URL for the API.\n\n\ncontent\n\n\nA dictionary, containing the \nLink\n objects that the schema contains.\n\n\nIn order to provide more structure to the schema, the \ncontent\n dictionary\nmay be nested, typically to a second level. For example:\n\n\ncontent={\n \"bookings\": {\n \"list\": Link(...),\n \"create\": Link(...),\n ...\n },\n \"venues\": {\n \"list\": Link(...),\n ...\n },\n ...\n}\n\n\n\nLink\n\n\nRepresents an individual API endpoint.\n\n\nurl\n\n\nThe URL of the endpoint. May be a URI template, such as \n/users/{username}/\n.\n\n\naction\n\n\nThe HTTP method associated with the endpoint. Note that URLs that support\nmore than one HTTP method, should correspond to a single \nLink\n for each.\n\n\nfields\n\n\nA list of \nField\n instances, describing the available parameters on the input.\n\n\ndescription\n\n\nA short description of the meaning and intended usage of the endpoint.\n\n\nField\n\n\nRepresents a single input parameter on a given API endpoint.\n\n\nname\n\n\nA descriptive name for the input.\n\n\nrequired\n\n\nA boolean, indicated if the client is required to included a value, or if\nthe parameter can be omitted.\n\n\nlocation\n\n\nDetermines how the information is encoded into the request. Should be one of\nthe following strings:\n\n\n\"path\"\n\n\nIncluded in a templated URI. For example a \nurl\n value of \n/products/{product_code}/\n could be used together with a \n\"path\"\n field, to handle API inputs in a URL path such as \n/products/slim-fit-jeans/\n.\n\n\nThese fields will normally correspond with \nnamed arguments in the project URL conf\n.\n\n\n\"query\"\n\n\nIncluded as a URL query parameter. For example \n?search=sale\n. Typically for \nGET\n requests.\n\n\nThese fields will normally correspond with pagination and filtering controls on a view.\n\n\n\"form\"\n\n\nIncluded in the request body, as a single item of a JSON object or HTML form. For example \n{\"colour\": \"blue\", ...}\n. Typically for \nPOST\n, \nPUT\n and \nPATCH\n requests. Multiple \n\"form\"\n fields may be included on a single link.\n\n\nThese fields will normally correspond with serializer fields on a view.\n\n\n\"body\"\n\n\nIncluded as the complete request body. Typically for \nPOST\n, \nPUT\n and \nPATCH\n requests. No more than one \n\"body\"\n field may exist on a link. May not be used together with \n\"form\"\n fields.\n\n\nThese fields will normally correspond with views that use \nListSerializer\n to validate the request input, or with file upload views.\n\n\nencoding\n\n\n\"application/json\"\n\n\nJSON encoded request content. Corresponds to views using \nJSONParser\n.\nValid only if either one or more \nlocation=\"form\"\n fields, or a single\n\nlocation=\"body\"\n field is included on the \nLink\n.\n\n\n\"multipart/form-data\"\n\n\nMultipart encoded request content. Corresponds to views using \nMultiPartParser\n.\nValid only if one or more \nlocation=\"form\"\n fields is included on the \nLink\n.\n\n\n\"application/x-www-form-urlencoded\"\n\n\nURL encoded request content. Corresponds to views using \nFormParser\n. Valid\nonly if one or more \nlocation=\"form\"\n fields is included on the \nLink\n.\n\n\n\"application/octet-stream\"\n\n\nBinary upload request content. Corresponds to views using \nFileUploadParser\n.\nValid only if a \nlocation=\"body\"\n field is included on the \nLink\n.\n\n\ndescription\n\n\nA short description of the meaning and intended usage of the input field.\n\n\n\n\nThird party packages\n\n\ndrf-yasg - Yet Another Swagger Generator\n\n\ndrf-yasg\n generates \nOpenAPI\n documents suitable for code generation - nested schemas, \nnamed models, response bodies, enum/pattern/min/max validators, form parameters, etc.\n\n\nDRF OpenAPI\n\n\nDRF OpenAPI\n renders the schema generated by Django Rest Framework\nin \nOpenAPI\n format.", "title": "Schemas" }, { @@ -3287,7 +3302,7 @@ }, { "location": "/api-guide/schemas/#get_manual_fieldsself-path-method", - "text": "Return a list of coreapi.Field() instances to be added to or replace generated fields. Defaults to (optional) manual_fields passed to AutoSchema constructor. May be overridden to customise manual fields by path or method . For example, a per-method adjustment may look like this: def get_manual_fields(self, path, method):\n \"\"\"Example adding per-method fields.\"\"\"\n\n extra_fields = []\n if method=='GET':\n extra_fields = # ... list of extra fields for GET ...\n if method=='POST':\n extra_fields = # ... list of extra fields for POST ...\n\n manual_fields = super().get_manual_fields()\n return manual_fields + extra_fields", + "text": "Return a list of coreapi.Field() instances to be added to or replace generated fields. Defaults to (optional) manual_fields passed to AutoSchema constructor. May be overridden to customise manual fields by path or method . For example, a per-method adjustment may look like this: def get_manual_fields(self, path, method):\n \"\"\"Example adding per-method fields.\"\"\"\n\n extra_fields = []\n if method=='GET':\n extra_fields = # ... list of extra fields for GET ...\n if method=='POST':\n extra_fields = # ... list of extra fields for POST ...\n\n manual_fields = super().get_manual_fields(path, method)\n return manual_fields + extra_fields", "title": "get_manual_fields(self, path, method)" }, { @@ -3297,7 +3312,7 @@ }, { "location": "/api-guide/schemas/#manualschema", - "text": "Allows manually providing a list of coreapi.Field instances for the schema,\nplus an optional description. class MyView(APIView):\n schema = ManualSchema(fields=[\n coreapi.Field(\n \"first_field\",\n required=True,\n location=\"path\",\n schema=coreschema.String()\n ),\n coreapi.Field(\n \"second_field\",\n required=True,\n location=\"path\",\n schema=coreschema.String()\n ),\n ]\n ) The ManualSchema constructor takes two arguments: fields : A list of coreapi.Field instances. Required. description : A string description. Optional.", + "text": "Allows manually providing a list of coreapi.Field instances for the schema,\nplus an optional description. class MyView(APIView):\n schema = ManualSchema(fields=[\n coreapi.Field(\n \"first_field\",\n required=True,\n location=\"path\",\n schema=coreschema.String()\n ),\n coreapi.Field(\n \"second_field\",\n required=True,\n location=\"path\",\n schema=coreschema.String()\n ),\n ]\n ) The ManualSchema constructor takes two arguments: fields : A list of coreapi.Field instances. Required. description : A string description. Optional. encoding : Default None . A string encoding, e.g application/json . Optional.", "title": "ManualSchema" }, { @@ -3447,7 +3462,7 @@ }, { "location": "/api-guide/exceptions/", - "text": "Exceptions\n\n\n\n\nExceptions\u2026 allow error handling to be organized cleanly in a central or high-level place within the program structure.\n\n\n\u2014 Doug Hellmann, \nPython Exception Handling Techniques\n\n\n\n\nException handling in REST framework views\n\n\nREST framework's views handle various exceptions, and deal with returning appropriate error responses.\n\n\nThe handled exceptions are:\n\n\n\n\nSubclasses of \nAPIException\n raised inside REST framework.\n\n\nDjango's \nHttp404\n exception.\n\n\nDjango's \nPermissionDenied\n exception.\n\n\n\n\nIn 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.\n\n\nMost error responses will include a key \ndetail\n in the body of the response.\n\n\nFor example, the following request:\n\n\nDELETE http://api.example.com/foo/bar HTTP/1.1\nAccept: application/json\n\n\n\nMight receive an error response indicating that the \nDELETE\n method is not allowed on that resource:\n\n\nHTTP/1.1 405 Method Not Allowed\nContent-Type: application/json\nContent-Length: 42\n\n{\"detail\": \"Method 'DELETE' not allowed.\"}\n\n\n\nValidation 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 \nNON_FIELD_ERRORS_KEY\n setting.\n\n\nAny example validation error might look like this:\n\n\nHTTP/1.1 400 Bad Request\nContent-Type: application/json\nContent-Length: 94\n\n{\"amount\": [\"A valid integer is required.\"], \"description\": [\"This field may not be blank.\"]}\n\n\n\nCustom exception handling\n\n\nYou 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.\n\n\nThe function must take a pair of arguments, the first is the exception to be handled, and the second is a dictionary containing any extra context such as the view currently being handled. The exception handler function should either return a \nResponse\n object, or return \nNone\n if the exception cannot be handled. If the handler returns \nNone\n then the exception will be re-raised and Django will return a standard HTTP 500 'server error' response.\n\n\nFor example, you might want to ensure that all error responses include the HTTP status code in the body of the response, like so:\n\n\nHTTP/1.1 405 Method Not Allowed\nContent-Type: application/json\nContent-Length: 62\n\n{\"status_code\": 405, \"detail\": \"Method 'DELETE' not allowed.\"}\n\n\n\nIn order to alter the style of the response, you could write the following custom exception handler:\n\n\nfrom rest_framework.views import exception_handler\n\ndef custom_exception_handler(exc, context):\n # Call REST framework's default exception handler first,\n # to get the standard error response.\n response = exception_handler(exc, context)\n\n #\u00a0Now add the HTTP status code to the response.\n if response is not None:\n response.data['status_code'] = response.status_code\n\n return response\n\n\n\nThe context argument is not used by the default handler, but can be useful if the exception handler needs further information such as the view currently being handled, which can be accessed as \ncontext['view']\n.\n\n\nThe exception handler must also be configured in your settings, using the \nEXCEPTION_HANDLER\n setting key. For example:\n\n\nREST_FRAMEWORK = {\n 'EXCEPTION_HANDLER': 'my_project.my_app.utils.custom_exception_handler'\n}\n\n\n\nIf not specified, the \n'EXCEPTION_HANDLER'\n setting defaults to the standard exception handler provided by REST framework:\n\n\nREST_FRAMEWORK = {\n 'EXCEPTION_HANDLER': 'rest_framework.views.exception_handler'\n}\n\n\n\nNote that the exception handler will only be called for responses generated by raised exceptions. It will not be used for any responses returned directly by the view, such as the \nHTTP_400_BAD_REQUEST\n responses that are returned by the generic views when serializer validation fails.\n\n\n\n\nAPI Reference\n\n\nAPIException\n\n\nSignature:\n \nAPIException()\n\n\nThe \nbase class\n for all exceptions raised inside an \nAPIView\n class or \n@api_view\n.\n\n\nTo provide a custom exception, subclass \nAPIException\n and set the \n.status_code\n, \n.default_detail\n, and \ndefault_code\n attributes on the class.\n\n\nFor example, if your API relies on a third party service that may sometimes be unreachable, you might want to implement an exception for the \"503 Service Unavailable\" HTTP response code. You could do this like so:\n\n\nfrom rest_framework.exceptions import APIException\n\nclass ServiceUnavailable(APIException):\n status_code = 503\n default_detail = 'Service temporarily unavailable, try again later.'\n default_code = 'service_unavailable'\n\n\n\nInspecting API exceptions\n\n\nThere are a number of different properties available for inspecting the status\nof an API exception. You can use these to build custom exception handling\nfor your project.\n\n\nThe available attributes and methods are:\n\n\n\n\n.detail\n - Return the textual description of the error.\n\n\n.get_codes()\n - Return the code identifier of the error.\n\n\n.get_full_details()\n - Return both the textual description and the code identifier.\n\n\n\n\nIn most cases the error detail will be a simple item:\n\n\n>>> print(exc.detail)\nYou do not have permission to perform this action.\n>>> print(exc.get_codes())\npermission_denied\n>>> print(exc.get_full_details())\n{'message':'You do not have permission to perform this action.','code':'permission_denied'}\n\n\n\nIn the case of validation errors the error detail will be either a list or\ndictionary of items:\n\n\n>>> print(exc.detail)\n{\"name\":\"This field is required.\",\"age\":\"A valid integer is required.\"}\n>>> print(exc.get_codes())\n{\"name\":\"required\",\"age\":\"invalid\"}\n>>> print(exc.get_full_details())\n{\"name\":{\"message\":\"This field is required.\",\"code\":\"required\"},\"age\":{\"message\":\"A valid integer is required.\",\"code\":\"invalid\"}}\n\n\n\nParseError\n\n\nSignature:\n \nParseError(detail=None, code=None)\n\n\nRaised if the request contains malformed data when accessing \nrequest.data\n.\n\n\nBy default this exception results in a response with the HTTP status code \"400 Bad Request\".\n\n\nAuthenticationFailed\n\n\nSignature:\n \nAuthenticationFailed(detail=None, code=None)\n\n\nRaised when an incoming request includes incorrect authentication.\n\n\nBy default this exception results in a response with the HTTP status code \"401 Unauthenticated\", but it may also result in a \"403 Forbidden\" response, depending on the authentication scheme in use. See the \nauthentication documentation\n for more details.\n\n\nNotAuthenticated\n\n\nSignature:\n \nNotAuthenticated(detail=None, code=None)\n\n\nRaised when an unauthenticated request fails the permission checks.\n\n\nBy default this exception results in a response with the HTTP status code \"401 Unauthenticated\", but it may also result in a \"403 Forbidden\" response, depending on the authentication scheme in use. See the \nauthentication documentation\n for more details.\n\n\nPermissionDenied\n\n\nSignature:\n \nPermissionDenied(detail=None, code=None)\n\n\nRaised when an authenticated request fails the permission checks.\n\n\nBy default this exception results in a response with the HTTP status code \"403 Forbidden\".\n\n\nNotFound\n\n\nSignature:\n \nNotFound(detail=None, code=None)\n\n\nRaised when a resource does not exists at the given URL. This exception is equivalent to the standard \nHttp404\n Django exception.\n\n\nBy default this exception results in a response with the HTTP status code \"404 Not Found\".\n\n\nMethodNotAllowed\n\n\nSignature:\n \nMethodNotAllowed(method, detail=None, code=None)\n\n\nRaised when an incoming request occurs that does not map to a handler method on the view.\n\n\nBy default this exception results in a response with the HTTP status code \"405 Method Not Allowed\".\n\n\nNotAcceptable\n\n\nSignature:\n \nNotAcceptable(detail=None, code=None)\n\n\nRaised when an incoming request occurs with an \nAccept\n header that cannot be satisfied by any of the available renderers.\n\n\nBy default this exception results in a response with the HTTP status code \"406 Not Acceptable\".\n\n\nUnsupportedMediaType\n\n\nSignature:\n \nUnsupportedMediaType(media_type, detail=None, code=None)\n\n\nRaised if there are no parsers that can handle the content type of the request data when accessing \nrequest.data\n.\n\n\nBy default this exception results in a response with the HTTP status code \"415 Unsupported Media Type\".\n\n\nThrottled\n\n\nSignature:\n \nThrottled(wait=None, detail=None, code=None)\n\n\nRaised when an incoming request fails the throttling checks.\n\n\nBy default this exception results in a response with the HTTP status code \"429 Too Many Requests\".\n\n\nValidationError\n\n\nSignature:\n \nValidationError(detail, code=None)\n\n\nThe \nValidationError\n exception is slightly different from the other \nAPIException\n classes:\n\n\n\n\nThe \ndetail\n argument is mandatory, not optional.\n\n\nThe \ndetail\n argument may be a list or dictionary of error details, and may also be a nested data structure.\n\n\nBy convention you should import the serializers module and use a fully qualified \nValidationError\n style, in order to differentiate it from Django's built-in validation error. For example. \nraise serializers.ValidationError('This field must be an integer value.')\n\n\n\n\nThe \nValidationError\n class should be used for serializer and field validation, and by validator classes. It is also raised when calling \nserializer.is_valid\n with the \nraise_exception\n keyword argument:\n\n\nserializer.is_valid(raise_exception=True)\n\n\n\nThe generic views use the \nraise_exception=True\n flag, which means that you can override the style of validation error responses globally in your API. To do so, use a custom exception handler, as described above.\n\n\nBy default this exception results in a response with the HTTP status code \"400 Bad Request\".", + "text": "Exceptions\n\n\n\n\nExceptions\u2026 allow error handling to be organized cleanly in a central or high-level place within the program structure.\n\n\n\u2014 Doug Hellmann, \nPython Exception Handling Techniques\n\n\n\n\nException handling in REST framework views\n\n\nREST framework's views handle various exceptions, and deal with returning appropriate error responses.\n\n\nThe handled exceptions are:\n\n\n\n\nSubclasses of \nAPIException\n raised inside REST framework.\n\n\nDjango's \nHttp404\n exception.\n\n\nDjango's \nPermissionDenied\n exception.\n\n\n\n\nIn 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.\n\n\nMost error responses will include a key \ndetail\n in the body of the response.\n\n\nFor example, the following request:\n\n\nDELETE http://api.example.com/foo/bar HTTP/1.1\nAccept: application/json\n\n\n\nMight receive an error response indicating that the \nDELETE\n method is not allowed on that resource:\n\n\nHTTP/1.1 405 Method Not Allowed\nContent-Type: application/json\nContent-Length: 42\n\n{\"detail\": \"Method 'DELETE' not allowed.\"}\n\n\n\nValidation 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 \nNON_FIELD_ERRORS_KEY\n setting.\n\n\nAny example validation error might look like this:\n\n\nHTTP/1.1 400 Bad Request\nContent-Type: application/json\nContent-Length: 94\n\n{\"amount\": [\"A valid integer is required.\"], \"description\": [\"This field may not be blank.\"]}\n\n\n\nCustom exception handling\n\n\nYou 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.\n\n\nThe function must take a pair of arguments, the first is the exception to be handled, and the second is a dictionary containing any extra context such as the view currently being handled. The exception handler function should either return a \nResponse\n object, or return \nNone\n if the exception cannot be handled. If the handler returns \nNone\n then the exception will be re-raised and Django will return a standard HTTP 500 'server error' response.\n\n\nFor example, you might want to ensure that all error responses include the HTTP status code in the body of the response, like so:\n\n\nHTTP/1.1 405 Method Not Allowed\nContent-Type: application/json\nContent-Length: 62\n\n{\"status_code\": 405, \"detail\": \"Method 'DELETE' not allowed.\"}\n\n\n\nIn order to alter the style of the response, you could write the following custom exception handler:\n\n\nfrom rest_framework.views import exception_handler\n\ndef custom_exception_handler(exc, context):\n # Call REST framework's default exception handler first,\n # to get the standard error response.\n response = exception_handler(exc, context)\n\n #\u00a0Now add the HTTP status code to the response.\n if response is not None:\n response.data['status_code'] = response.status_code\n\n return response\n\n\n\nThe context argument is not used by the default handler, but can be useful if the exception handler needs further information such as the view currently being handled, which can be accessed as \ncontext['view']\n.\n\n\nThe exception handler must also be configured in your settings, using the \nEXCEPTION_HANDLER\n setting key. For example:\n\n\nREST_FRAMEWORK = {\n 'EXCEPTION_HANDLER': 'my_project.my_app.utils.custom_exception_handler'\n}\n\n\n\nIf not specified, the \n'EXCEPTION_HANDLER'\n setting defaults to the standard exception handler provided by REST framework:\n\n\nREST_FRAMEWORK = {\n 'EXCEPTION_HANDLER': 'rest_framework.views.exception_handler'\n}\n\n\n\nNote that the exception handler will only be called for responses generated by raised exceptions. It will not be used for any responses returned directly by the view, such as the \nHTTP_400_BAD_REQUEST\n responses that are returned by the generic views when serializer validation fails.\n\n\n\n\nAPI Reference\n\n\nAPIException\n\n\nSignature:\n \nAPIException()\n\n\nThe \nbase class\n for all exceptions raised inside an \nAPIView\n class or \n@api_view\n.\n\n\nTo provide a custom exception, subclass \nAPIException\n and set the \n.status_code\n, \n.default_detail\n, and \ndefault_code\n attributes on the class.\n\n\nFor example, if your API relies on a third party service that may sometimes be unreachable, you might want to implement an exception for the \"503 Service Unavailable\" HTTP response code. You could do this like so:\n\n\nfrom rest_framework.exceptions import APIException\n\nclass ServiceUnavailable(APIException):\n status_code = 503\n default_detail = 'Service temporarily unavailable, try again later.'\n default_code = 'service_unavailable'\n\n\n\nInspecting API exceptions\n\n\nThere are a number of different properties available for inspecting the status\nof an API exception. You can use these to build custom exception handling\nfor your project.\n\n\nThe available attributes and methods are:\n\n\n\n\n.detail\n - Return the textual description of the error.\n\n\n.get_codes()\n - Return the code identifier of the error.\n\n\n.get_full_details()\n - Return both the textual description and the code identifier.\n\n\n\n\nIn most cases the error detail will be a simple item:\n\n\n>>> print(exc.detail)\nYou do not have permission to perform this action.\n>>> print(exc.get_codes())\npermission_denied\n>>> print(exc.get_full_details())\n{'message':'You do not have permission to perform this action.','code':'permission_denied'}\n\n\n\nIn the case of validation errors the error detail will be either a list or\ndictionary of items:\n\n\n>>> print(exc.detail)\n{\"name\":\"This field is required.\",\"age\":\"A valid integer is required.\"}\n>>> print(exc.get_codes())\n{\"name\":\"required\",\"age\":\"invalid\"}\n>>> print(exc.get_full_details())\n{\"name\":{\"message\":\"This field is required.\",\"code\":\"required\"},\"age\":{\"message\":\"A valid integer is required.\",\"code\":\"invalid\"}}\n\n\n\nParseError\n\n\nSignature:\n \nParseError(detail=None, code=None)\n\n\nRaised if the request contains malformed data when accessing \nrequest.data\n.\n\n\nBy default this exception results in a response with the HTTP status code \"400 Bad Request\".\n\n\nAuthenticationFailed\n\n\nSignature:\n \nAuthenticationFailed(detail=None, code=None)\n\n\nRaised when an incoming request includes incorrect authentication.\n\n\nBy default this exception results in a response with the HTTP status code \"401 Unauthenticated\", but it may also result in a \"403 Forbidden\" response, depending on the authentication scheme in use. See the \nauthentication documentation\n for more details.\n\n\nNotAuthenticated\n\n\nSignature:\n \nNotAuthenticated(detail=None, code=None)\n\n\nRaised when an unauthenticated request fails the permission checks.\n\n\nBy default this exception results in a response with the HTTP status code \"401 Unauthenticated\", but it may also result in a \"403 Forbidden\" response, depending on the authentication scheme in use. See the \nauthentication documentation\n for more details.\n\n\nPermissionDenied\n\n\nSignature:\n \nPermissionDenied(detail=None, code=None)\n\n\nRaised when an authenticated request fails the permission checks.\n\n\nBy default this exception results in a response with the HTTP status code \"403 Forbidden\".\n\n\nNotFound\n\n\nSignature:\n \nNotFound(detail=None, code=None)\n\n\nRaised when a resource does not exists at the given URL. This exception is equivalent to the standard \nHttp404\n Django exception.\n\n\nBy default this exception results in a response with the HTTP status code \"404 Not Found\".\n\n\nMethodNotAllowed\n\n\nSignature:\n \nMethodNotAllowed(method, detail=None, code=None)\n\n\nRaised when an incoming request occurs that does not map to a handler method on the view.\n\n\nBy default this exception results in a response with the HTTP status code \"405 Method Not Allowed\".\n\n\nNotAcceptable\n\n\nSignature:\n \nNotAcceptable(detail=None, code=None)\n\n\nRaised when an incoming request occurs with an \nAccept\n header that cannot be satisfied by any of the available renderers.\n\n\nBy default this exception results in a response with the HTTP status code \"406 Not Acceptable\".\n\n\nUnsupportedMediaType\n\n\nSignature:\n \nUnsupportedMediaType(media_type, detail=None, code=None)\n\n\nRaised if there are no parsers that can handle the content type of the request data when accessing \nrequest.data\n.\n\n\nBy default this exception results in a response with the HTTP status code \"415 Unsupported Media Type\".\n\n\nThrottled\n\n\nSignature:\n \nThrottled(wait=None, detail=None, code=None)\n\n\nRaised when an incoming request fails the throttling checks.\n\n\nBy default this exception results in a response with the HTTP status code \"429 Too Many Requests\".\n\n\nValidationError\n\n\nSignature:\n \nValidationError(detail, code=None)\n\n\nThe \nValidationError\n exception is slightly different from the other \nAPIException\n classes:\n\n\n\n\nThe \ndetail\n argument is mandatory, not optional.\n\n\nThe \ndetail\n argument may be a list or dictionary of error details, and may also be a nested data structure.\n\n\nBy convention you should import the serializers module and use a fully qualified \nValidationError\n style, in order to differentiate it from Django's built-in validation error. For example. \nraise serializers.ValidationError('This field must be an integer value.')\n\n\n\n\nThe \nValidationError\n class should be used for serializer and field validation, and by validator classes. It is also raised when calling \nserializer.is_valid\n with the \nraise_exception\n keyword argument:\n\n\nserializer.is_valid(raise_exception=True)\n\n\n\nThe generic views use the \nraise_exception=True\n flag, which means that you can override the style of validation error responses globally in your API. To do so, use a custom exception handler, as described above.\n\n\nBy default this exception results in a response with the HTTP status code \"400 Bad Request\".\n\n\n\n\nGeneric Error Views\n\n\nDjango REST Framework provides two error views suitable for providing generic JSON \n500\n Server Error and\n\n400\n Bad Request responses. (Django's default error views provide HTML responses, which may not be appropriate for an\nAPI-only application.)\n\n\nUse these as per \nDjango's Customizing error views documentation\n.\n\n\nrest_framework.exceptions.server_error\n\n\nReturns a response with status code \n500\n and \napplication/json\n content type.\n\n\nSet as \nhandler500\n:\n\n\nhandler500 = 'rest_framework.exceptions.server_error'\n\n\n\nrest_framework.exceptions.server_error\n\n\nReturns a response with status code \n400\n and \napplication/json\n content type.\n\n\nSet as \nhandler400\n:\n\n\nhandler400 = 'rest_framework.exceptions.bad_request'", "title": "Exceptions" }, { @@ -3530,6 +3545,21 @@ "text": "Signature: ValidationError(detail, code=None) The ValidationError exception is slightly different from the other APIException classes: The detail argument is mandatory, not optional. The detail argument may be a list or dictionary of error details, and may also be a nested data structure. By convention you should import the serializers module and use a fully qualified ValidationError style, in order to differentiate it from Django's built-in validation error. For example. raise serializers.ValidationError('This field must be an integer value.') The ValidationError class should be used for serializer and field validation, and by validator classes. It is also raised when calling serializer.is_valid with the raise_exception keyword argument: serializer.is_valid(raise_exception=True) The generic views use the raise_exception=True flag, which means that you can override the style of validation error responses globally in your API. To do so, use a custom exception handler, as described above. By default this exception results in a response with the HTTP status code \"400 Bad Request\".", "title": "ValidationError" }, + { + "location": "/api-guide/exceptions/#generic-error-views", + "text": "Django REST Framework provides two error views suitable for providing generic JSON 500 Server Error and 400 Bad Request responses. (Django's default error views provide HTML responses, which may not be appropriate for an\nAPI-only application.) Use these as per Django's Customizing error views documentation .", + "title": "Generic Error Views" + }, + { + "location": "/api-guide/exceptions/#rest_frameworkexceptionsserver_error", + "text": "Returns a response with status code 500 and application/json content type. Set as handler500 : handler500 = 'rest_framework.exceptions.server_error'", + "title": "rest_framework.exceptions.server_error" + }, + { + "location": "/api-guide/exceptions/#rest_frameworkexceptionsserver_error_1", + "text": "Returns a response with status code 400 and application/json content type. Set as handler400 : handler400 = 'rest_framework.exceptions.bad_request'", + "title": "rest_framework.exceptions.server_error" + }, { "location": "/api-guide/status-codes/", "text": "Status Codes\n\n\n\n\n418 I'm a teapot - Any attempt to brew coffee with a teapot should result in the error code \"418 I'm a teapot\". The resulting entity body MAY be short and stout.\n\n\n\u2014 \nRFC 2324\n, Hyper Text Coffee Pot Control Protocol\n\n\n\n\nUsing bare status codes in your responses isn't recommended. REST framework includes a set of named constants that you can use to make your code more obvious and readable.\n\n\nfrom rest_framework import status\nfrom rest_framework.response import Response\n\ndef empty_view(self):\n content = {'please move along': 'nothing to see here'}\n return Response(content, status=status.HTTP_404_NOT_FOUND)\n\n\n\nThe full set of HTTP status codes included in the \nstatus\n module is listed below.\n\n\nThe module also includes a set of helper functions for testing if a status code is in a given range.\n\n\nfrom rest_framework import status\nfrom rest_framework.test import APITestCase\n\nclass ExampleTestCase(APITestCase):\n def test_url_root(self):\n url = reverse('index')\n response = self.client.get(url)\n self.assertTrue(status.is_success(response.status_code))\n\n\n\nFor more information on proper usage of HTTP status codes see \nRFC 2616\n\nand \nRFC 6585\n.\n\n\nInformational - 1xx\n\n\nThis class of status code indicates a provisional response. There are no 1xx status codes used in REST framework by default.\n\n\nHTTP_100_CONTINUE\nHTTP_101_SWITCHING_PROTOCOLS\n\n\n\nSuccessful - 2xx\n\n\nThis class of status code indicates that the client's request was successfully received, understood, and accepted.\n\n\nHTTP_200_OK\nHTTP_201_CREATED\nHTTP_202_ACCEPTED\nHTTP_203_NON_AUTHORITATIVE_INFORMATION\nHTTP_204_NO_CONTENT\nHTTP_205_RESET_CONTENT\nHTTP_206_PARTIAL_CONTENT\nHTTP_207_MULTI_STATUS\n\n\n\nRedirection - 3xx\n\n\nThis class of status code indicates that further action needs to be taken by the user agent in order to fulfill the request.\n\n\nHTTP_300_MULTIPLE_CHOICES\nHTTP_301_MOVED_PERMANENTLY\nHTTP_302_FOUND\nHTTP_303_SEE_OTHER\nHTTP_304_NOT_MODIFIED\nHTTP_305_USE_PROXY\nHTTP_306_RESERVED\nHTTP_307_TEMPORARY_REDIRECT\n\n\n\nClient Error - 4xx\n\n\nThe 4xx class of status code is intended for cases in which the client seems to have erred. Except when responding to a HEAD request, the server SHOULD include an entity containing an explanation of the error situation, and whether it is a temporary or permanent condition.\n\n\nHTTP_400_BAD_REQUEST\nHTTP_401_UNAUTHORIZED\nHTTP_402_PAYMENT_REQUIRED\nHTTP_403_FORBIDDEN\nHTTP_404_NOT_FOUND\nHTTP_405_METHOD_NOT_ALLOWED\nHTTP_406_NOT_ACCEPTABLE\nHTTP_407_PROXY_AUTHENTICATION_REQUIRED\nHTTP_408_REQUEST_TIMEOUT\nHTTP_409_CONFLICT\nHTTP_410_GONE\nHTTP_411_LENGTH_REQUIRED\nHTTP_412_PRECONDITION_FAILED\nHTTP_413_REQUEST_ENTITY_TOO_LARGE\nHTTP_414_REQUEST_URI_TOO_LONG\nHTTP_415_UNSUPPORTED_MEDIA_TYPE\nHTTP_416_REQUESTED_RANGE_NOT_SATISFIABLE\nHTTP_417_EXPECTATION_FAILED\nHTTP_422_UNPROCESSABLE_ENTITY\nHTTP_423_LOCKED\nHTTP_424_FAILED_DEPENDENCY\nHTTP_428_PRECONDITION_REQUIRED\nHTTP_429_TOO_MANY_REQUESTS\nHTTP_431_REQUEST_HEADER_FIELDS_TOO_LARGE\nHTTP_451_UNAVAILABLE_FOR_LEGAL_REASONS\n\n\n\nServer Error - 5xx\n\n\nResponse status codes beginning with the digit \"5\" indicate cases in which the server is aware that it has erred or is incapable of performing the request. Except when responding to a HEAD request, the server SHOULD include an entity containing an explanation of the error situation, and whether it is a temporary or permanent condition.\n\n\nHTTP_500_INTERNAL_SERVER_ERROR\nHTTP_501_NOT_IMPLEMENTED\nHTTP_502_BAD_GATEWAY\nHTTP_503_SERVICE_UNAVAILABLE\nHTTP_504_GATEWAY_TIMEOUT\nHTTP_505_HTTP_VERSION_NOT_SUPPORTED\nHTTP_507_INSUFFICIENT_STORAGE\nHTTP_511_NETWORK_AUTHENTICATION_REQUIRED\n\n\n\nHelper functions\n\n\nThe following helper functions are available for identifying the category of the response code.\n\n\nis_informational() # 1xx\nis_success() #\u00a02xx\nis_redirect() # 3xx\nis_client_error() # 4xx\nis_server_error() # 5xx", @@ -3737,7 +3767,7 @@ }, { "location": "/api-guide/settings/", - "text": "Settings\n\n\n\n\nNamespaces are one honking great idea - let's do more of those!\n\n\n\u2014 \nThe Zen of Python\n\n\n\n\nConfiguration for REST framework is all namespaced inside a single Django setting, named \nREST_FRAMEWORK\n.\n\n\nFor example your project's \nsettings.py\n file might include something like this:\n\n\nREST_FRAMEWORK = {\n 'DEFAULT_RENDERER_CLASSES': (\n 'rest_framework.renderers.JSONRenderer',\n ),\n 'DEFAULT_PARSER_CLASSES': (\n 'rest_framework.parsers.JSONParser',\n )\n}\n\n\n\nAccessing settings\n\n\nIf you need to access the values of REST framework's API settings in your project,\nyou should use the \napi_settings\n object. For example.\n\n\nfrom rest_framework.settings import api_settings\n\nprint api_settings.DEFAULT_AUTHENTICATION_CLASSES\n\n\n\nThe \napi_settings\n object will check for any user-defined settings, and otherwise fall back to the default values. Any setting that uses string import paths to refer to a class will automatically import and return the referenced class, instead of the string literal.\n\n\n\n\nAPI Reference\n\n\nAPI policy settings\n\n\nThe following settings control the basic API policies, and are applied to every \nAPIView\n class-based view, or \n@api_view\n function based view.\n\n\nDEFAULT_RENDERER_CLASSES\n\n\nA list or tuple of renderer classes, that determines the default set of renderers that may be used when returning a \nResponse\n object.\n\n\nDefault:\n\n\n(\n 'rest_framework.renderers.JSONRenderer',\n 'rest_framework.renderers.BrowsableAPIRenderer',\n)\n\n\n\nDEFAULT_PARSER_CLASSES\n\n\nA list or tuple of parser classes, that determines the default set of parsers used when accessing the \nrequest.data\n property.\n\n\nDefault:\n\n\n(\n 'rest_framework.parsers.JSONParser',\n 'rest_framework.parsers.FormParser',\n 'rest_framework.parsers.MultiPartParser'\n)\n\n\n\nDEFAULT_AUTHENTICATION_CLASSES\n\n\nA list or tuple of authentication classes, that determines the default set of authenticators used when accessing the \nrequest.user\n or \nrequest.auth\n properties.\n\n\nDefault:\n\n\n(\n 'rest_framework.authentication.SessionAuthentication',\n 'rest_framework.authentication.BasicAuthentication'\n)\n\n\n\nDEFAULT_PERMISSION_CLASSES\n\n\nA list or tuple of permission classes, that determines the default set of permissions checked at the start of a view. Permission must be granted by every class in the list.\n\n\nDefault:\n\n\n(\n 'rest_framework.permissions.AllowAny',\n)\n\n\n\nDEFAULT_THROTTLE_CLASSES\n\n\nA list or tuple of throttle classes, that determines the default set of throttles checked at the start of a view.\n\n\nDefault: \n()\n\n\nDEFAULT_CONTENT_NEGOTIATION_CLASS\n\n\nA content negotiation class, that determines how a renderer is selected for the response, given an incoming request.\n\n\nDefault: \n'rest_framework.negotiation.DefaultContentNegotiation'\n\n\nDEFAULT_SCHEMA_CLASS\n\n\nA view inspector class that will be used for schema generation.\n\n\nDefault: \n'rest_framework.schemas.AutoSchema'\n\n\n\n\nGeneric view settings\n\n\nThe following settings control the behavior of the generic class-based views.\n\n\nDEFAULT_PAGINATION_SERIALIZER_CLASS\n\n\n\n\nThis setting has been removed.\n\n\nThe pagination API does not use serializers to determine the output format, and\nyou'll need to instead override the `get_paginated_response method on a\npagination class in order to specify how the output format is controlled.\n\n\n\n\nDEFAULT_FILTER_BACKENDS\n\n\nA list of filter backend classes that should be used for generic filtering.\nIf set to \nNone\n then generic filtering is disabled.\n\n\nPAGINATE_BY\n\n\n\n\nThis setting has been removed.\n\n\nSee the pagination documentation for further guidance on \nsetting the pagination style\n.\n\n\n\n\nPAGE_SIZE\n\n\nThe default page size to use for pagination. If set to \nNone\n, pagination is disabled by default.\n\n\nDefault: \nNone\n\n\nPAGINATE_BY_PARAM\n\n\n\n\nThis setting has been removed.\n\n\nSee the pagination documentation for further guidance on \nsetting the pagination style\n.\n\n\n\n\nMAX_PAGINATE_BY\n\n\n\n\nThis setting is pending deprecation.\n\n\nSee the pagination documentation for further guidance on \nsetting the pagination style\n.\n\n\n\n\nSEARCH_PARAM\n\n\nThe name of a query parameter, which can be used to specify the search term used by \nSearchFilter\n.\n\n\nDefault: \nsearch\n\n\nORDERING_PARAM\n\n\nThe name of a query parameter, which can be used to specify the ordering of results returned by \nOrderingFilter\n.\n\n\nDefault: \nordering\n\n\n\n\nVersioning settings\n\n\nDEFAULT_VERSION\n\n\nThe value that should be used for \nrequest.version\n when no versioning information is present.\n\n\nDefault: \nNone\n\n\nALLOWED_VERSIONS\n\n\nIf set, this value will restrict the set of versions that may be returned by the versioning scheme, and will raise an error if the provided version if not in this set.\n\n\nDefault: \nNone\n\n\nVERSION_PARAM\n\n\nThe string that should used for any versioning parameters, such as in the media type or URL query parameters.\n\n\nDefault: \n'version'\n\n\n\n\nAuthentication settings\n\n\nThe following settings control the behavior of unauthenticated requests.\n\n\nUNAUTHENTICATED_USER\n\n\nThe class that should be used to initialize \nrequest.user\n for unauthenticated requests.\n(If removing authentication entirely, e.g. by removing \ndjango.contrib.auth\n from\n\nINSTALLED_APPS\n, set \nUNAUTHENTICATED_USER\n to \nNone\n.)\n\n\nDefault: \ndjango.contrib.auth.models.AnonymousUser\n\n\nUNAUTHENTICATED_TOKEN\n\n\nThe class that should be used to initialize \nrequest.auth\n for unauthenticated requests.\n\n\nDefault: \nNone\n\n\n\n\nTest settings\n\n\nThe following settings control the behavior of APIRequestFactory and APIClient\n\n\nTEST_REQUEST_DEFAULT_FORMAT\n\n\nThe default format that should be used when making test requests.\n\n\nThis should match up with the format of one of the renderer classes in the \nTEST_REQUEST_RENDERER_CLASSES\n setting.\n\n\nDefault: \n'multipart'\n\n\nTEST_REQUEST_RENDERER_CLASSES\n\n\nThe renderer classes that are supported when building test requests.\n\n\nThe format of any of these renderer classes may be used when constructing a test request, for example: \nclient.post('/users', {'username': 'jamie'}, format='json')\n\n\nDefault:\n\n\n(\n 'rest_framework.renderers.MultiPartRenderer',\n 'rest_framework.renderers.JSONRenderer'\n)\n\n\n\n\n\nSchema generation controls\n\n\nSCHEMA_COERCE_PATH_PK\n\n\nIf set, this maps the \n'pk'\n identifier in the URL conf onto the actual field\nname when generating a schema path parameter. Typically this will be \n'id'\n.\nThis gives a more suitable representation as \"primary key\" is an implementation\ndetail, whereas \"identifier\" is a more general concept.\n\n\nDefault: \nTrue\n\n\nSCHEMA_COERCE_METHOD_NAMES\n\n\nIf set, this is used to map internal viewset method names onto external action\nnames used in the schema generation. This allows us to generate names that\nare more suitable for an external representation than those that are used\ninternally in the codebase.\n\n\nDefault: \n{'retrieve': 'read', 'destroy': 'delete'}\n\n\n\n\nContent type controls\n\n\nURL_FORMAT_OVERRIDE\n\n\nThe name of a URL parameter that may be used to override the default content negotiation \nAccept\n header behavior, by using a \nformat=\u2026\n query parameter in the request URL.\n\n\nFor example: \nhttp://example.com/organizations/?format=csv\n\n\nIf the value of this setting is \nNone\n then URL format overrides will be disabled.\n\n\nDefault: \n'format'\n\n\nFORMAT_SUFFIX_KWARG\n\n\nThe name of a parameter in the URL conf that may be used to provide a format suffix. This setting is applied when using \nformat_suffix_patterns\n to include suffixed URL patterns.\n\n\nFor example: \nhttp://example.com/organizations.csv/\n\n\nDefault: \n'format'\n\n\n\n\nDate and time formatting\n\n\nThe following settings are used to control how date and time representations may be parsed and rendered.\n\n\nDATETIME_FORMAT\n\n\nA format string that should be used by default for rendering the output of \nDateTimeField\n serializer fields. If \nNone\n, then \nDateTimeField\n serializer fields will return Python \ndatetime\n objects, and the datetime encoding will be determined by the renderer.\n\n\nMay be any of \nNone\n, \n'iso-8601'\n or a Python \nstrftime format\n string.\n\n\nDefault: \n'iso-8601'\n\n\nDATETIME_INPUT_FORMATS\n\n\nA list of format strings that should be used by default for parsing inputs to \nDateTimeField\n serializer fields.\n\n\nMay be a list including the string \n'iso-8601'\n or Python \nstrftime format\n strings.\n\n\nDefault: \n['iso-8601']\n\n\nDATE_FORMAT\n\n\nA format string that should be used by default for rendering the output of \nDateField\n serializer fields. If \nNone\n, then \nDateField\n serializer fields will return Python \ndate\n objects, and the date encoding will be determined by the renderer.\n\n\nMay be any of \nNone\n, \n'iso-8601'\n or a Python \nstrftime format\n string.\n\n\nDefault: \n'iso-8601'\n\n\nDATE_INPUT_FORMATS\n\n\nA list of format strings that should be used by default for parsing inputs to \nDateField\n serializer fields.\n\n\nMay be a list including the string \n'iso-8601'\n or Python \nstrftime format\n strings.\n\n\nDefault: \n['iso-8601']\n\n\nTIME_FORMAT\n\n\nA format string that should be used by default for rendering the output of \nTimeField\n serializer fields. If \nNone\n, then \nTimeField\n serializer fields will return Python \ntime\n objects, and the time encoding will be determined by the renderer.\n\n\nMay be any of \nNone\n, \n'iso-8601'\n or a Python \nstrftime format\n string.\n\n\nDefault: \n'iso-8601'\n\n\nTIME_INPUT_FORMATS\n\n\nA list of format strings that should be used by default for parsing inputs to \nTimeField\n serializer fields.\n\n\nMay be a list including the string \n'iso-8601'\n or Python \nstrftime format\n strings.\n\n\nDefault: \n['iso-8601']\n\n\n\n\nEncodings\n\n\nUNICODE_JSON\n\n\nWhen set to \nTrue\n, JSON responses will allow unicode characters in responses. For example:\n\n\n{\"unicode black star\":\"\u2605\"}\n\n\n\nWhen set to \nFalse\n, JSON responses will escape non-ascii characters, like so:\n\n\n{\"unicode black star\":\"\\u2605\"}\n\n\n\nBoth styles conform to \nRFC 4627\n, and are syntactically valid JSON. The unicode style is preferred as being more user-friendly when inspecting API responses.\n\n\nDefault: \nTrue\n\n\nCOMPACT_JSON\n\n\nWhen set to \nTrue\n, JSON responses will return compact representations, with no spacing after \n':'\n and \n','\n characters. For example:\n\n\n{\"is_admin\":false,\"email\":\"jane@example\"}\n\n\n\nWhen set to \nFalse\n, JSON responses will return slightly more verbose representations, like so:\n\n\n{\"is_admin\": false, \"email\": \"jane@example\"}\n\n\n\nThe default style is to return minified responses, in line with \nHeroku's API design guidelines\n.\n\n\nDefault: \nTrue\n\n\nSTRICT_JSON\n\n\nWhen set to \nTrue\n, JSON rendering and parsing will only observe syntactically valid JSON, raising an exception for the extended float values (\nnan\n, \ninf\n, \n-inf\n) accepted by Python's \njson\n module. This is the recommended setting, as these values are not generally supported. e.g., neither Javascript's \nJSON.Parse\n nor PostgreSQL's JSON data type accept these values.\n\n\nWhen set to \nFalse\n, JSON rendering and parsing will be permissive. However, these values are still invalid and will need to be specially handled in your code.\n\n\nDefault: \nTrue\n\n\nCOERCE_DECIMAL_TO_STRING\n\n\nWhen returning decimal objects in API representations that do not support a native decimal type, it is normally best to return the value as a string. This avoids the loss of precision that occurs with binary floating point implementations.\n\n\nWhen set to \nTrue\n, the serializer \nDecimalField\n class will return strings instead of \nDecimal\n objects. When set to \nFalse\n, serializers will return \nDecimal\n objects, which the default JSON encoder will return as floats.\n\n\nDefault: \nTrue\n\n\n\n\nView names and descriptions\n\n\nThe following settings are used to generate the view names and descriptions, as used in responses to \nOPTIONS\n requests, and as used in the browsable API.\n\n\nVIEW_NAME_FUNCTION\n\n\nA string representing the function that should be used when generating view names.\n\n\nThis should be a function with the following signature:\n\n\nview_name(cls, suffix=None)\n\n\n\n\n\ncls\n: The view class. Typically the name function would inspect the name of the class when generating a descriptive name, by accessing \ncls.__name__\n.\n\n\nsuffix\n: The optional suffix used when differentiating individual views in a viewset.\n\n\n\n\nDefault: \n'rest_framework.views.get_view_name'\n\n\nVIEW_DESCRIPTION_FUNCTION\n\n\nA string representing the function that should be used when generating view descriptions.\n\n\nThis setting can be changed to support markup styles other than the default markdown. For example, you can use it to support \nrst\n markup in your view docstrings being output in the browsable API.\n\n\nThis should be a function with the following signature:\n\n\nview_description(cls, html=False)\n\n\n\n\n\ncls\n: The view class. Typically the description function would inspect the docstring of the class when generating a description, by accessing \ncls.__doc__\n\n\nhtml\n: A boolean indicating if HTML output is required. \nTrue\n when used in the browsable API, and \nFalse\n when used in generating \nOPTIONS\n responses.\n\n\n\n\nDefault: \n'rest_framework.views.get_view_description'\n\n\nHTML Select Field cutoffs\n\n\nGlobal settings for \nselect field cutoffs for rendering relational fields\n in the browsable API.\n\n\nHTML_SELECT_CUTOFF\n\n\nGlobal setting for the \nhtml_cutoff\n value. Must be an integer.\n\n\nDefault: 1000\n\n\nHTML_SELECT_CUTOFF_TEXT\n\n\nA string representing a global setting for \nhtml_cutoff_text\n.\n\n\nDefault: \n\"More than {count} items...\"\n\n\n\n\nMiscellaneous settings\n\n\nEXCEPTION_HANDLER\n\n\nA string representing the function that should be used when returning a response for any given exception. If the function returns \nNone\n, a 500 error will be raised.\n\n\nThis setting can be changed to support error responses other than the default \n{\"detail\": \"Failure...\"}\n responses. For example, you can use it to provide API responses like \n{\"errors\": [{\"message\": \"Failure...\", \"code\": \"\"} ...]}\n.\n\n\nThis should be a function with the following signature:\n\n\nexception_handler(exc, context)\n\n\n\n\n\nexc\n: The exception.\n\n\n\n\nDefault: \n'rest_framework.views.exception_handler'\n\n\nNON_FIELD_ERRORS_KEY\n\n\nA string representing the key that should be used for serializer errors that do not refer to a specific field, but are instead general errors.\n\n\nDefault: \n'non_field_errors'\n\n\nURL_FIELD_NAME\n\n\nA string representing the key that should be used for the URL fields generated by \nHyperlinkedModelSerializer\n.\n\n\nDefault: \n'url'\n\n\nNUM_PROXIES\n\n\nAn integer of 0 or more, that may be used to specify the number of application proxies that the API runs behind. This allows throttling to more accurately identify client IP addresses. If set to \nNone\n then less strict IP matching will be used by the throttle classes.\n\n\nDefault: \nNone", + "text": "Settings\n\n\n\n\nNamespaces are one honking great idea - let's do more of those!\n\n\n\u2014 \nThe Zen of Python\n\n\n\n\nConfiguration for REST framework is all namespaced inside a single Django setting, named \nREST_FRAMEWORK\n.\n\n\nFor example your project's \nsettings.py\n file might include something like this:\n\n\nREST_FRAMEWORK = {\n 'DEFAULT_RENDERER_CLASSES': (\n 'rest_framework.renderers.JSONRenderer',\n ),\n 'DEFAULT_PARSER_CLASSES': (\n 'rest_framework.parsers.JSONParser',\n )\n}\n\n\n\nAccessing settings\n\n\nIf you need to access the values of REST framework's API settings in your project,\nyou should use the \napi_settings\n object. For example.\n\n\nfrom rest_framework.settings import api_settings\n\nprint api_settings.DEFAULT_AUTHENTICATION_CLASSES\n\n\n\nThe \napi_settings\n object will check for any user-defined settings, and otherwise fall back to the default values. Any setting that uses string import paths to refer to a class will automatically import and return the referenced class, instead of the string literal.\n\n\n\n\nAPI Reference\n\n\nAPI policy settings\n\n\nThe following settings control the basic API policies, and are applied to every \nAPIView\n class-based view, or \n@api_view\n function based view.\n\n\nDEFAULT_RENDERER_CLASSES\n\n\nA list or tuple of renderer classes, that determines the default set of renderers that may be used when returning a \nResponse\n object.\n\n\nDefault:\n\n\n(\n 'rest_framework.renderers.JSONRenderer',\n 'rest_framework.renderers.BrowsableAPIRenderer',\n)\n\n\n\nDEFAULT_PARSER_CLASSES\n\n\nA list or tuple of parser classes, that determines the default set of parsers used when accessing the \nrequest.data\n property.\n\n\nDefault:\n\n\n(\n 'rest_framework.parsers.JSONParser',\n 'rest_framework.parsers.FormParser',\n 'rest_framework.parsers.MultiPartParser'\n)\n\n\n\nDEFAULT_AUTHENTICATION_CLASSES\n\n\nA list or tuple of authentication classes, that determines the default set of authenticators used when accessing the \nrequest.user\n or \nrequest.auth\n properties.\n\n\nDefault:\n\n\n(\n 'rest_framework.authentication.SessionAuthentication',\n 'rest_framework.authentication.BasicAuthentication'\n)\n\n\n\nDEFAULT_PERMISSION_CLASSES\n\n\nA list or tuple of permission classes, that determines the default set of permissions checked at the start of a view. Permission must be granted by every class in the list.\n\n\nDefault:\n\n\n(\n 'rest_framework.permissions.AllowAny',\n)\n\n\n\nDEFAULT_THROTTLE_CLASSES\n\n\nA list or tuple of throttle classes, that determines the default set of throttles checked at the start of a view.\n\n\nDefault: \n()\n\n\nDEFAULT_CONTENT_NEGOTIATION_CLASS\n\n\nA content negotiation class, that determines how a renderer is selected for the response, given an incoming request.\n\n\nDefault: \n'rest_framework.negotiation.DefaultContentNegotiation'\n\n\nDEFAULT_SCHEMA_CLASS\n\n\nA view inspector class that will be used for schema generation.\n\n\nDefault: \n'rest_framework.schemas.AutoSchema'\n\n\n\n\nGeneric view settings\n\n\nThe following settings control the behavior of the generic class-based views.\n\n\nDEFAULT_PAGINATION_SERIALIZER_CLASS\n\n\n\n\nThis setting has been removed.\n\n\nThe pagination API does not use serializers to determine the output format, and\nyou'll need to instead override the `get_paginated_response method on a\npagination class in order to specify how the output format is controlled.\n\n\n\n\nDEFAULT_FILTER_BACKENDS\n\n\nA list of filter backend classes that should be used for generic filtering.\nIf set to \nNone\n then generic filtering is disabled.\n\n\nPAGINATE_BY\n\n\n\n\nThis setting has been removed.\n\n\nSee the pagination documentation for further guidance on \nsetting the pagination style\n.\n\n\n\n\nPAGE_SIZE\n\n\nThe default page size to use for pagination. If set to \nNone\n, pagination is disabled by default.\n\n\nDefault: \nNone\n\n\nPAGINATE_BY_PARAM\n\n\n\n\nThis setting has been removed.\n\n\nSee the pagination documentation for further guidance on \nsetting the pagination style\n.\n\n\n\n\nMAX_PAGINATE_BY\n\n\n\n\nThis setting has been removed.\n\n\nSee the pagination documentation for further guidance on \nsetting the pagination style\n.\n\n\n\n\nSEARCH_PARAM\n\n\nThe name of a query parameter, which can be used to specify the search term used by \nSearchFilter\n.\n\n\nDefault: \nsearch\n\n\nORDERING_PARAM\n\n\nThe name of a query parameter, which can be used to specify the ordering of results returned by \nOrderingFilter\n.\n\n\nDefault: \nordering\n\n\n\n\nVersioning settings\n\n\nDEFAULT_VERSION\n\n\nThe value that should be used for \nrequest.version\n when no versioning information is present.\n\n\nDefault: \nNone\n\n\nALLOWED_VERSIONS\n\n\nIf set, this value will restrict the set of versions that may be returned by the versioning scheme, and will raise an error if the provided version if not in this set.\n\n\nDefault: \nNone\n\n\nVERSION_PARAM\n\n\nThe string that should used for any versioning parameters, such as in the media type or URL query parameters.\n\n\nDefault: \n'version'\n\n\n\n\nAuthentication settings\n\n\nThe following settings control the behavior of unauthenticated requests.\n\n\nUNAUTHENTICATED_USER\n\n\nThe class that should be used to initialize \nrequest.user\n for unauthenticated requests.\n(If removing authentication entirely, e.g. by removing \ndjango.contrib.auth\n from\n\nINSTALLED_APPS\n, set \nUNAUTHENTICATED_USER\n to \nNone\n.)\n\n\nDefault: \ndjango.contrib.auth.models.AnonymousUser\n\n\nUNAUTHENTICATED_TOKEN\n\n\nThe class that should be used to initialize \nrequest.auth\n for unauthenticated requests.\n\n\nDefault: \nNone\n\n\n\n\nTest settings\n\n\nThe following settings control the behavior of APIRequestFactory and APIClient\n\n\nTEST_REQUEST_DEFAULT_FORMAT\n\n\nThe default format that should be used when making test requests.\n\n\nThis should match up with the format of one of the renderer classes in the \nTEST_REQUEST_RENDERER_CLASSES\n setting.\n\n\nDefault: \n'multipart'\n\n\nTEST_REQUEST_RENDERER_CLASSES\n\n\nThe renderer classes that are supported when building test requests.\n\n\nThe format of any of these renderer classes may be used when constructing a test request, for example: \nclient.post('/users', {'username': 'jamie'}, format='json')\n\n\nDefault:\n\n\n(\n 'rest_framework.renderers.MultiPartRenderer',\n 'rest_framework.renderers.JSONRenderer'\n)\n\n\n\n\n\nSchema generation controls\n\n\nSCHEMA_COERCE_PATH_PK\n\n\nIf set, this maps the \n'pk'\n identifier in the URL conf onto the actual field\nname when generating a schema path parameter. Typically this will be \n'id'\n.\nThis gives a more suitable representation as \"primary key\" is an implementation\ndetail, whereas \"identifier\" is a more general concept.\n\n\nDefault: \nTrue\n\n\nSCHEMA_COERCE_METHOD_NAMES\n\n\nIf set, this is used to map internal viewset method names onto external action\nnames used in the schema generation. This allows us to generate names that\nare more suitable for an external representation than those that are used\ninternally in the codebase.\n\n\nDefault: \n{'retrieve': 'read', 'destroy': 'delete'}\n\n\n\n\nContent type controls\n\n\nURL_FORMAT_OVERRIDE\n\n\nThe name of a URL parameter that may be used to override the default content negotiation \nAccept\n header behavior, by using a \nformat=\u2026\n query parameter in the request URL.\n\n\nFor example: \nhttp://example.com/organizations/?format=csv\n\n\nIf the value of this setting is \nNone\n then URL format overrides will be disabled.\n\n\nDefault: \n'format'\n\n\nFORMAT_SUFFIX_KWARG\n\n\nThe name of a parameter in the URL conf that may be used to provide a format suffix. This setting is applied when using \nformat_suffix_patterns\n to include suffixed URL patterns.\n\n\nFor example: \nhttp://example.com/organizations.csv/\n\n\nDefault: \n'format'\n\n\n\n\nDate and time formatting\n\n\nThe following settings are used to control how date and time representations may be parsed and rendered.\n\n\nDATETIME_FORMAT\n\n\nA format string that should be used by default for rendering the output of \nDateTimeField\n serializer fields. If \nNone\n, then \nDateTimeField\n serializer fields will return Python \ndatetime\n objects, and the datetime encoding will be determined by the renderer.\n\n\nMay be any of \nNone\n, \n'iso-8601'\n or a Python \nstrftime format\n string.\n\n\nDefault: \n'iso-8601'\n\n\nDATETIME_INPUT_FORMATS\n\n\nA list of format strings that should be used by default for parsing inputs to \nDateTimeField\n serializer fields.\n\n\nMay be a list including the string \n'iso-8601'\n or Python \nstrftime format\n strings.\n\n\nDefault: \n['iso-8601']\n\n\nDATE_FORMAT\n\n\nA format string that should be used by default for rendering the output of \nDateField\n serializer fields. If \nNone\n, then \nDateField\n serializer fields will return Python \ndate\n objects, and the date encoding will be determined by the renderer.\n\n\nMay be any of \nNone\n, \n'iso-8601'\n or a Python \nstrftime format\n string.\n\n\nDefault: \n'iso-8601'\n\n\nDATE_INPUT_FORMATS\n\n\nA list of format strings that should be used by default for parsing inputs to \nDateField\n serializer fields.\n\n\nMay be a list including the string \n'iso-8601'\n or Python \nstrftime format\n strings.\n\n\nDefault: \n['iso-8601']\n\n\nTIME_FORMAT\n\n\nA format string that should be used by default for rendering the output of \nTimeField\n serializer fields. If \nNone\n, then \nTimeField\n serializer fields will return Python \ntime\n objects, and the time encoding will be determined by the renderer.\n\n\nMay be any of \nNone\n, \n'iso-8601'\n or a Python \nstrftime format\n string.\n\n\nDefault: \n'iso-8601'\n\n\nTIME_INPUT_FORMATS\n\n\nA list of format strings that should be used by default for parsing inputs to \nTimeField\n serializer fields.\n\n\nMay be a list including the string \n'iso-8601'\n or Python \nstrftime format\n strings.\n\n\nDefault: \n['iso-8601']\n\n\n\n\nEncodings\n\n\nUNICODE_JSON\n\n\nWhen set to \nTrue\n, JSON responses will allow unicode characters in responses. For example:\n\n\n{\"unicode black star\":\"\u2605\"}\n\n\n\nWhen set to \nFalse\n, JSON responses will escape non-ascii characters, like so:\n\n\n{\"unicode black star\":\"\\u2605\"}\n\n\n\nBoth styles conform to \nRFC 4627\n, and are syntactically valid JSON. The unicode style is preferred as being more user-friendly when inspecting API responses.\n\n\nDefault: \nTrue\n\n\nCOMPACT_JSON\n\n\nWhen set to \nTrue\n, JSON responses will return compact representations, with no spacing after \n':'\n and \n','\n characters. For example:\n\n\n{\"is_admin\":false,\"email\":\"jane@example\"}\n\n\n\nWhen set to \nFalse\n, JSON responses will return slightly more verbose representations, like so:\n\n\n{\"is_admin\": false, \"email\": \"jane@example\"}\n\n\n\nThe default style is to return minified responses, in line with \nHeroku's API design guidelines\n.\n\n\nDefault: \nTrue\n\n\nSTRICT_JSON\n\n\nWhen set to \nTrue\n, JSON rendering and parsing will only observe syntactically valid JSON, raising an exception for the extended float values (\nnan\n, \ninf\n, \n-inf\n) accepted by Python's \njson\n module. This is the recommended setting, as these values are not generally supported. e.g., neither Javascript's \nJSON.Parse\n nor PostgreSQL's JSON data type accept these values.\n\n\nWhen set to \nFalse\n, JSON rendering and parsing will be permissive. However, these values are still invalid and will need to be specially handled in your code.\n\n\nDefault: \nTrue\n\n\nCOERCE_DECIMAL_TO_STRING\n\n\nWhen returning decimal objects in API representations that do not support a native decimal type, it is normally best to return the value as a string. This avoids the loss of precision that occurs with binary floating point implementations.\n\n\nWhen set to \nTrue\n, the serializer \nDecimalField\n class will return strings instead of \nDecimal\n objects. When set to \nFalse\n, serializers will return \nDecimal\n objects, which the default JSON encoder will return as floats.\n\n\nDefault: \nTrue\n\n\n\n\nView names and descriptions\n\n\nThe following settings are used to generate the view names and descriptions, as used in responses to \nOPTIONS\n requests, and as used in the browsable API.\n\n\nVIEW_NAME_FUNCTION\n\n\nA string representing the function that should be used when generating view names.\n\n\nThis should be a function with the following signature:\n\n\nview_name(cls, suffix=None)\n\n\n\n\n\ncls\n: The view class. Typically the name function would inspect the name of the class when generating a descriptive name, by accessing \ncls.__name__\n.\n\n\nsuffix\n: The optional suffix used when differentiating individual views in a viewset.\n\n\n\n\nDefault: \n'rest_framework.views.get_view_name'\n\n\nVIEW_DESCRIPTION_FUNCTION\n\n\nA string representing the function that should be used when generating view descriptions.\n\n\nThis setting can be changed to support markup styles other than the default markdown. For example, you can use it to support \nrst\n markup in your view docstrings being output in the browsable API.\n\n\nThis should be a function with the following signature:\n\n\nview_description(cls, html=False)\n\n\n\n\n\ncls\n: The view class. Typically the description function would inspect the docstring of the class when generating a description, by accessing \ncls.__doc__\n\n\nhtml\n: A boolean indicating if HTML output is required. \nTrue\n when used in the browsable API, and \nFalse\n when used in generating \nOPTIONS\n responses.\n\n\n\n\nDefault: \n'rest_framework.views.get_view_description'\n\n\nHTML Select Field cutoffs\n\n\nGlobal settings for \nselect field cutoffs for rendering relational fields\n in the browsable API.\n\n\nHTML_SELECT_CUTOFF\n\n\nGlobal setting for the \nhtml_cutoff\n value. Must be an integer.\n\n\nDefault: 1000\n\n\nHTML_SELECT_CUTOFF_TEXT\n\n\nA string representing a global setting for \nhtml_cutoff_text\n.\n\n\nDefault: \n\"More than {count} items...\"\n\n\n\n\nMiscellaneous settings\n\n\nEXCEPTION_HANDLER\n\n\nA string representing the function that should be used when returning a response for any given exception. If the function returns \nNone\n, a 500 error will be raised.\n\n\nThis setting can be changed to support error responses other than the default \n{\"detail\": \"Failure...\"}\n responses. For example, you can use it to provide API responses like \n{\"errors\": [{\"message\": \"Failure...\", \"code\": \"\"} ...]}\n.\n\n\nThis should be a function with the following signature:\n\n\nexception_handler(exc, context)\n\n\n\n\n\nexc\n: The exception.\n\n\n\n\nDefault: \n'rest_framework.views.exception_handler'\n\n\nNON_FIELD_ERRORS_KEY\n\n\nA string representing the key that should be used for serializer errors that do not refer to a specific field, but are instead general errors.\n\n\nDefault: \n'non_field_errors'\n\n\nURL_FIELD_NAME\n\n\nA string representing the key that should be used for the URL fields generated by \nHyperlinkedModelSerializer\n.\n\n\nDefault: \n'url'\n\n\nNUM_PROXIES\n\n\nAn integer of 0 or more, that may be used to specify the number of application proxies that the API runs behind. This allows throttling to more accurately identify client IP addresses. If set to \nNone\n then less strict IP matching will be used by the throttle classes.\n\n\nDefault: \nNone", "title": "Settings" }, { @@ -3827,7 +3857,7 @@ }, { "location": "/api-guide/settings/#max_paginate_by", - "text": "This setting is pending deprecation. See the pagination documentation for further guidance on setting the pagination style .", + "text": "This setting has been removed. See the pagination documentation for further guidance on setting the pagination style .", "title": "MAX_PAGINATE_BY" }, { @@ -4037,7 +4067,7 @@ }, { "location": "/topics/documenting-your-api/", - "text": "Documenting your API\n\n\n\n\nA REST API should spend almost all of its descriptive effort in defining the media type(s) used for representing resources and driving application state.\n\n\n\u2014 Roy Fielding, \nREST APIs must be hypertext driven\n\n\n\n\nREST framework provides built-in support for API documentation. There are also a number of great third-party documentation tools available.\n\n\nBuilt-in API documentation\n\n\nThe built-in API documentation includes:\n\n\n\n\nDocumentation of API endpoints.\n\n\nAutomatically generated code samples for each of the available API client libraries.\n\n\nSupport for API interaction.\n\n\n\n\nInstallation\n\n\nThe \ncoreapi\n library is required as a dependancy for the API docs. Make sure\nto install the latest version. The \npygments\n and \nmarkdown\n libraries\nare optional but recommended.\n\n\nTo install the API documentation, you'll need to include it in your projects URLconf:\n\n\nfrom rest_framework.documentation import include_docs_urls\n\nurlpatterns = [\n ...\n url(r'^docs/', include_docs_urls(title='My API title'))\n]\n\n\n\nThis will include two different views:\n\n\n\n\n/docs/\n - The documentation page itself.\n\n\n/docs/schema.js\n - A JavaScript resource that exposes the API schema.\n\n\n\n\n\n\nNote\n: By default \ninclude_docs_urls\n configures the underlying \nSchemaView\n to generate \npublic\n schemas.\nThis means that views will not be instantiated with a \nrequest\n instance. i.e. Inside the view \nself.request\n will be \nNone\n.\n\n\nTo be compatible with this behaviour methods (such as \nget_serializer\n or \nget_serializer_class\n etc.) which inspect \nself.request\n or, particularly, \nself.request.user\n may need to be adjusted to handle this case.\n\n\nYou may ensure views are given a \nrequest\n instance by calling \ninclude_docs_urls\n with \npublic=False\n:\n\n\nfrom rest_framework.documentation import include_docs_urls\n\nurlpatterns = [\n ...\n # Generate schema with valid `request` instance:\n url(r'^docs/', include_docs_urls(title='My API title', public=False))\n]\n\n\n\n\n\nDocumenting your views\n\n\nYou can document your views by including docstrings that describe each of the available actions.\nFor example:\n\n\nclass UserList(generics.ListAPIView):\n \"\"\"\n Return a list of all the existing users.\n \"\"\"\n\n\n\nIf a view supports multiple methods, you should split your documentation using \nmethod:\n style delimiters.\n\n\nclass UserList(generics.ListCreateAPIView):\n \"\"\"\n get:\n Return a list of all the existing users.\n\n post:\n Create a new user instance.\n \"\"\"\n\n\n\nWhen using viewsets, you should use the relevant action names as delimiters.\n\n\nclass UserViewSet(viewsets.ModelViewSet):\n \"\"\"\n retrieve:\n Return the given user.\n\n list:\n Return a list of all the existing users.\n\n create:\n Create a new user instance.\n \"\"\"\n\n\n\ndocumentation\n API Reference\n\n\nThe \nrest_framework.documentation\n module provides three helper functions to help configure the interactive API documentation, \ninclude_docs_urls\n (usage shown above), \nget_docs_view\n and \nget_schemajs_view\n.\n\n\ninclude_docs_urls\n employs \nget_docs_view\n and \nget_schemajs_view\n to generate the url patterns for the documentation page and JavaScript resource that exposes the API schema respectively. They expose the following options for customisation. (\nget_docs_view\n and \nget_schemajs_view\n ultimately call \nrest_frameworks.schemas.get_schema_view()\n, see the Schemas docs for more options there.)\n\n\ninclude_docs_urls\n\n\n\n\ntitle\n: Default \nNone\n. May be used to provide a descriptive title for the schema definition.\n\n\ndescription\n: Default \nNone\n. May be used to provide a description for the schema definition.\n\n\nschema_url\n: Default \nNone\n. May be used to pass a canonical base URL for the schema.\n\n\npublic\n: Default \nTrue\n. Should the schema be considered \npublic\n? If \nTrue\n schema is generated without a \nrequest\n instance being passed to views.\n\n\npatterns\n: Default \nNone\n. A list of URLs to inspect when generating the schema. If \nNone\n project's URL conf will be used.\n\n\ngenerator_class\n: Default \nrest_framework.schemas.SchemaGenerator\n. May be used to specify a \nSchemaGenerator\n subclass to be passed to the \nSchemaView\n.\n\n\nauthentication_classes\n: Default \napi_settings.DEFAULT_AUTHENTICATION_CLASSES\n. May be used to pass custom authentication classes to the \nSchemaView\n.\n\n\npermission_classes\n: Default \napi_settings.DEFAULT_PERMISSION_CLASSES\n May be used to pass custom permission classes to the \nSchemaView\n.\n\n\n\n\nget_docs_view\n\n\n\n\ntitle\n: Default \nNone\n. May be used to provide a descriptive title for the schema definition.\n\n\ndescription\n: Default \nNone\n. May be used to provide a description for the schema definition.\n\n\nschema_url\n: Default \nNone\n. May be used to pass a canonical base URL for the schema.\n\n\npublic\n: Default \nTrue\n. If \nTrue\n schema is generated without a \nrequest\n instance being passed to views.\n\n\npatterns\n: Default \nNone\n. A list of URLs to inspect when generating the schema. If \nNone\n project's URL conf will be used.\n\n\ngenerator_class\n: Default \nrest_framework.schemas.SchemaGenerator\n. May be used to specify a \nSchemaGenerator\n subclass to be passed to the \nSchemaView\n.\n\n\nauthentication_classes\n: Default \napi_settings.DEFAULT_AUTHENTICATION_CLASSES\n. May be used to pass custom authentication classes to the \nSchemaView\n.\n\n\npermission_classes\n: Default \napi_settings.DEFAULT_PERMISSION_CLASSES\n May be used to pass custom permission classes to the \nSchemaView\n.\n\n\n\n\nget_schemajs_view\n\n\n\n\ntitle\n: Default \nNone\n. May be used to provide a descriptive title for the schema definition.\n\n\ndescription\n: Default \nNone\n. May be used to provide a description for the schema definition.\n\n\nschema_url\n: Default \nNone\n. May be used to pass a canonical base URL for the schema.\n\n\npublic\n: Default \nTrue\n. If \nTrue\n schema is generated without a \nrequest\n instance being passed to views.\n\n\npatterns\n: Default \nNone\n. A list of URLs to inspect when generating the schema. If \nNone\n project's URL conf will be used.\n\n\ngenerator_class\n: Default \nrest_framework.schemas.SchemaGenerator\n. May be used to specify a \nSchemaGenerator\n subclass to be passed to the \nSchemaView\n.\n\n\nauthentication_classes\n: Default \napi_settings.DEFAULT_AUTHENTICATION_CLASSES\n. May be used to pass custom authentication classes to the \nSchemaView\n.\n\n\npermission_classes\n: Default \napi_settings.DEFAULT_PERMISSION_CLASSES\n May be used to pass custom permission classes to the \nSchemaView\n.\n\n\n\n\n\n\nThird party packages\n\n\nThere are a number of mature third-party packages for providing API documentation.\n\n\ndrf-yasg - Yet Another Swagger Generator\n\n\ndrf-yasg\n is a \nSwagger\n generation tool implemented without using the schema generation provided \nby Django Rest Framework.\n\n\nIt aims to implement as much of the \nOpenAPI\n specification as possible - nested schemas, named models, \nresponse bodies, enum/pattern/min/max validators, form parameters, etc. - and to generate documents usable with code \ngeneration tools like \nswagger-codegen\n.\n\n\nThis also translates into a very useful interactive documentation viewer in the form of \nswagger-ui\n:\n\n\n\n\nDRF OpenAPI\n\n\nDRF OpenAPI\n bridges the gap between OpenAPI specification and tool chain with the schema exposed\nout-of-the-box by Django Rest Framework. Its goals are:\n\n\n\n\nTo be dropped into any existing DRF project without any code change necessary.\n\n\nProvide clear disctinction between request schema and response schema.\n\n\nProvide a versioning mechanism for each schema. Support defining schema by version range syntax, e.g. >1.0, <=2.0\n\n\nSupport multiple response codes, not just 200\n\n\nAll this information should be bound to view methods, not view classes.\n\n\n\n\nIt also tries to stay current with the maturing schema generation mechanism provided by DRF.\n\n\n\n\n\n\nDRF Docs\n\n\nDRF Docs\n allows you to document Web APIs made with Django REST Framework and it is authored by Emmanouil Konstantinidis. It's made to work out of the box and its setup should not take more than a couple of minutes. Complete documentation can be found on the \nwebsite\n while there is also a \ndemo\n available for people to see what it looks like. \nLive API Endpoints\n allow you to utilize the endpoints from within the documentation in a neat way.\n\n\nFeatures include customizing the template with your branding, settings for hiding the docs depending on the environment and more.\n\n\nBoth this package and Django REST Swagger are fully documented, well supported, and come highly recommended.\n\n\n\n\n\n\nDjango REST Swagger\n\n\nMarc Gibbons' \nDjango REST Swagger\n integrates REST framework with the \nSwagger\n API documentation tool. The package produces well presented API documentation, and includes interactive tools for testing API endpoints.\n\n\nDjango REST Swagger supports REST framework versions 2.3 and above.\n\n\nMark is also the author of the \nREST Framework Docs\n package which offers clean, simple autogenerated documentation for your API but is deprecated and has moved to Django REST Swagger.\n\n\nBoth this package and DRF docs are fully documented, well supported, and come highly recommended.\n\n\n\n\n\n\nDRF AutoDocs\n\n\nOleksander Mashianovs' \nDRF Auto Docs\n automated api renderer.\n\n\nCollects almost all the code you written into documentation effortlessly.\n\n\nSupports:\n\n\n\n\nfunctional view docs\n\n\ntree-like structure\n\n\nDocstrings:\n\n\nmarkdown\n\n\npreserve space & newlines\n\n\nformatting with nice syntax\n\n\nFields:\n\n\nchoices rendering\n\n\nhelp_text (to specify SerializerMethodField output, etc)\n\n\nsmart read_only/required rendering\n\n\nEndpoint properties:\n\n\nfilter_backends\n\n\nauthentication_classes\n\n\npermission_classes\n\n\nextra url params(GET params)\n\n\n\n\n\n\n\n\nApiary\n\n\nThere are various other online tools and services for providing API documentation. One notable service is \nApiary\n. With Apiary, you describe your API using a simple markdown-like syntax. The generated documentation includes API interaction, a mock server for testing & prototyping, and various other tools.\n\n\n\n\n\n\nSelf describing APIs\n\n\nThe browsable API that REST framework provides makes it possible for your API to be entirely self describing. The documentation for each API endpoint can be provided simply by visiting the URL in your browser.\n\n\n\n\n\n\nSetting the title\n\n\nThe title that is used in the browsable API is generated from the view class name or function name. Any trailing \nView\n or \nViewSet\n suffix is stripped, and the string is whitespace separated on uppercase/lowercase boundaries or underscores.\n\n\nFor example, the view \nUserListView\n, will be named \nUser List\n when presented in the browsable API.\n\n\nWhen working with viewsets, an appropriate suffix is appended to each generated view. For example, the view set \nUserViewSet\n will generate views named \nUser List\n and \nUser Instance\n.\n\n\nSetting the description\n\n\nThe description in the browsable API is generated from the docstring of the view or viewset.\n\n\nIf the python \nmarkdown\n library is installed, then \nmarkdown syntax\n may be used in the docstring, and will be converted to HTML in the browsable API. For example:\n\n\nclass AccountListView(views.APIView):\n \"\"\"\n Returns a list of all **active** accounts in the system.\n\n For more details on how accounts are activated please [see here][ref].\n\n [ref]: http://example.com/activating-accounts\n \"\"\"\n\n\n\nNote that when using viewsets the basic docstring is used for all generated views. To provide descriptions for each view, such as for the the list and retrieve views, use docstring sections as described in \nSchemas as documentation: Examples\n.\n\n\nThe \nOPTIONS\n method\n\n\nREST framework APIs also support programmatically accessible descriptions, using the \nOPTIONS\n HTTP method. A view will respond to an \nOPTIONS\n request with metadata including the name, description, and the various media types it accepts and responds with.\n\n\nWhen using the generic views, any \nOPTIONS\n requests will additionally respond with metadata regarding any \nPOST\n or \nPUT\n actions available, describing which fields are on the serializer.\n\n\nYou can modify the response behavior to \nOPTIONS\n requests by overriding the \noptions\n view method and/or by providing a custom Metadata class. For example:\n\n\ndef options(self, request, *args, **kwargs):\n \"\"\"\n Don't include the view description in OPTIONS responses.\n \"\"\"\n meta = self.metadata_class()\n data = meta.determine_metadata(request, self)\n data.pop('description')\n return data\n\n\n\nSee \nthe Metadata docs\n for more details.\n\n\n\n\nThe hypermedia approach\n\n\nTo be fully RESTful an API should present its available actions as hypermedia controls in the responses that it sends.\n\n\nIn this approach, rather than documenting the available API endpoints up front, the description instead concentrates on the \nmedia types\n that are used. The available actions that may be taken on any given URL are not strictly fixed, but are instead made available by the presence of link and form controls in the returned document.\n\n\nTo implement a hypermedia API you'll need to decide on an appropriate media type for the API, and implement a custom renderer and parser for that media type. The \nREST, Hypermedia & HATEOAS\n section of the documentation includes pointers to background reading, as well as links to various hypermedia formats.", + "text": "Documenting your API\n\n\n\n\nA REST API should spend almost all of its descriptive effort in defining the media type(s) used for representing resources and driving application state.\n\n\n\u2014 Roy Fielding, \nREST APIs must be hypertext driven\n\n\n\n\nREST framework provides built-in support for API documentation. There are also a number of great third-party documentation tools available.\n\n\nBuilt-in API documentation\n\n\nThe built-in API documentation includes:\n\n\n\n\nDocumentation of API endpoints.\n\n\nAutomatically generated code samples for each of the available API client libraries.\n\n\nSupport for API interaction.\n\n\n\n\nInstallation\n\n\nThe \ncoreapi\n library is required as a dependancy for the API docs. Make sure\nto install the latest version. The \npygments\n and \nmarkdown\n libraries\nare optional but recommended.\n\n\nTo install the API documentation, you'll need to include it in your projects URLconf:\n\n\nfrom rest_framework.documentation import include_docs_urls\n\nurlpatterns = [\n ...\n url(r'^docs/', include_docs_urls(title='My API title'))\n]\n\n\n\nThis will include two different views:\n\n\n\n\n/docs/\n - The documentation page itself.\n\n\n/docs/schema.js\n - A JavaScript resource that exposes the API schema.\n\n\n\n\n\n\nNote\n: By default \ninclude_docs_urls\n configures the underlying \nSchemaView\n to generate \npublic\n schemas.\nThis means that views will not be instantiated with a \nrequest\n instance. i.e. Inside the view \nself.request\n will be \nNone\n.\n\n\nTo be compatible with this behaviour methods (such as \nget_serializer\n or \nget_serializer_class\n etc.) which inspect \nself.request\n or, particularly, \nself.request.user\n may need to be adjusted to handle this case.\n\n\nYou may ensure views are given a \nrequest\n instance by calling \ninclude_docs_urls\n with \npublic=False\n:\n\n\nfrom rest_framework.documentation import include_docs_urls\n\nurlpatterns = [\n ...\n # Generate schema with valid `request` instance:\n url(r'^docs/', include_docs_urls(title='My API title', public=False))\n]\n\n\n\n\n\nDocumenting your views\n\n\nYou can document your views by including docstrings that describe each of the available actions.\nFor example:\n\n\nclass UserList(generics.ListAPIView):\n \"\"\"\n Return a list of all the existing users.\n \"\"\"\n\n\n\nIf a view supports multiple methods, you should split your documentation using \nmethod:\n style delimiters.\n\n\nclass UserList(generics.ListCreateAPIView):\n \"\"\"\n get:\n Return a list of all the existing users.\n\n post:\n Create a new user instance.\n \"\"\"\n\n\n\nWhen using viewsets, you should use the relevant action names as delimiters.\n\n\nclass UserViewSet(viewsets.ModelViewSet):\n \"\"\"\n retrieve:\n Return the given user.\n\n list:\n Return a list of all the existing users.\n\n create:\n Create a new user instance.\n \"\"\"\n\n\n\ndocumentation\n API Reference\n\n\nThe \nrest_framework.documentation\n module provides three helper functions to help configure the interactive API documentation, \ninclude_docs_urls\n (usage shown above), \nget_docs_view\n and \nget_schemajs_view\n.\n\n\ninclude_docs_urls\n employs \nget_docs_view\n and \nget_schemajs_view\n to generate the url patterns for the documentation page and JavaScript resource that exposes the API schema respectively. They expose the following options for customisation. (\nget_docs_view\n and \nget_schemajs_view\n ultimately call \nrest_frameworks.schemas.get_schema_view()\n, see the Schemas docs for more options there.)\n\n\ninclude_docs_urls\n\n\n\n\ntitle\n: Default \nNone\n. May be used to provide a descriptive title for the schema definition.\n\n\ndescription\n: Default \nNone\n. May be used to provide a description for the schema definition.\n\n\nschema_url\n: Default \nNone\n. May be used to pass a canonical base URL for the schema.\n\n\npublic\n: Default \nTrue\n. Should the schema be considered \npublic\n? If \nTrue\n schema is generated without a \nrequest\n instance being passed to views.\n\n\npatterns\n: Default \nNone\n. A list of URLs to inspect when generating the schema. If \nNone\n project's URL conf will be used.\n\n\ngenerator_class\n: Default \nrest_framework.schemas.SchemaGenerator\n. May be used to specify a \nSchemaGenerator\n subclass to be passed to the \nSchemaView\n.\n\n\nauthentication_classes\n: Default \napi_settings.DEFAULT_AUTHENTICATION_CLASSES\n. May be used to pass custom authentication classes to the \nSchemaView\n.\n\n\npermission_classes\n: Default \napi_settings.DEFAULT_PERMISSION_CLASSES\n May be used to pass custom permission classes to the \nSchemaView\n.\n\n\nrenderer_classes\n: Default \nNone\n. May be used to pass custom renderer classes to the \nSchemaView\n.\n\n\n\n\nget_docs_view\n\n\n\n\ntitle\n: Default \nNone\n. May be used to provide a descriptive title for the schema definition.\n\n\ndescription\n: Default \nNone\n. May be used to provide a description for the schema definition.\n\n\nschema_url\n: Default \nNone\n. May be used to pass a canonical base URL for the schema.\n\n\npublic\n: Default \nTrue\n. If \nTrue\n schema is generated without a \nrequest\n instance being passed to views.\n\n\npatterns\n: Default \nNone\n. A list of URLs to inspect when generating the schema. If \nNone\n project's URL conf will be used.\n\n\ngenerator_class\n: Default \nrest_framework.schemas.SchemaGenerator\n. May be used to specify a \nSchemaGenerator\n subclass to be passed to the \nSchemaView\n.\n\n\nauthentication_classes\n: Default \napi_settings.DEFAULT_AUTHENTICATION_CLASSES\n. May be used to pass custom authentication classes to the \nSchemaView\n.\n\n\npermission_classes\n: Default \napi_settings.DEFAULT_PERMISSION_CLASSES\n. May be used to pass custom permission classes to the \nSchemaView\n.\n\n\nrenderer_classes\n: Default \nNone\n. May be used to pass custom renderer classes to the \nSchemaView\n. If \nNone\n the \nSchemaView\n will be configured with \nDocumentationRenderer\n and \nCoreJSONRenderer\n renderers, corresponding to the (default) \nhtml\n and \ncorejson\n formats.\n\n\n\n\nget_schemajs_view\n\n\n\n\ntitle\n: Default \nNone\n. May be used to provide a descriptive title for the schema definition.\n\n\ndescription\n: Default \nNone\n. May be used to provide a description for the schema definition.\n\n\nschema_url\n: Default \nNone\n. May be used to pass a canonical base URL for the schema.\n\n\npublic\n: Default \nTrue\n. If \nTrue\n schema is generated without a \nrequest\n instance being passed to views.\n\n\npatterns\n: Default \nNone\n. A list of URLs to inspect when generating the schema. If \nNone\n project's URL conf will be used.\n\n\ngenerator_class\n: Default \nrest_framework.schemas.SchemaGenerator\n. May be used to specify a \nSchemaGenerator\n subclass to be passed to the \nSchemaView\n.\n\n\nauthentication_classes\n: Default \napi_settings.DEFAULT_AUTHENTICATION_CLASSES\n. May be used to pass custom authentication classes to the \nSchemaView\n.\n\n\npermission_classes\n: Default \napi_settings.DEFAULT_PERMISSION_CLASSES\n May be used to pass custom permission classes to the \nSchemaView\n.\n\n\n\n\nCustomising code samples\n\n\nThe built-in API documentation includes automatically generated code samples for\neach of the available API client libraries.\n\n\nYou may customise these samples by subclassing \nDocumentationRenderer\n, setting\n\nlanguages\n to the list of languages you wish to support:\n\n\nfrom rest_framework.renderers import DocumentationRenderer\n\n\nclass CustomRenderer(DocumentationRenderer):\n languages = ['ruby', 'go']\n\n\n\nFor each language you need to provide an \nintro\n template, detailing installation instructions and such,\nplus a generic template for making API requests, that can be filled with individual request details.\nSee the \ntemplates for the bundled languages\n for examples.\n\n\n\n\nThird party packages\n\n\nThere are a number of mature third-party packages for providing API documentation.\n\n\ndrf-yasg - Yet Another Swagger Generator\n\n\ndrf-yasg\n is a \nSwagger\n generation tool implemented without using the schema generation provided\nby Django Rest Framework.\n\n\nIt aims to implement as much of the \nOpenAPI\n specification as possible - nested schemas, named models,\nresponse bodies, enum/pattern/min/max validators, form parameters, etc. - and to generate documents usable with code\ngeneration tools like \nswagger-codegen\n.\n\n\nThis also translates into a very useful interactive documentation viewer in the form of \nswagger-ui\n:\n\n\n\n\nDRF OpenAPI\n\n\nDRF OpenAPI\n bridges the gap between OpenAPI specification and tool chain with the schema exposed\nout-of-the-box by Django Rest Framework. Its goals are:\n\n\n\n\nTo be dropped into any existing DRF project without any code change necessary.\n\n\nProvide clear disctinction between request schema and response schema.\n\n\nProvide a versioning mechanism for each schema. Support defining schema by version range syntax, e.g. >1.0, <=2.0\n\n\nSupport multiple response codes, not just 200\n\n\nAll this information should be bound to view methods, not view classes.\n\n\n\n\nIt also tries to stay current with the maturing schema generation mechanism provided by DRF.\n\n\n\n\n\n\nDRF Docs\n\n\nDRF Docs\n allows you to document Web APIs made with Django REST Framework and it is authored by Emmanouil Konstantinidis. It's made to work out of the box and its setup should not take more than a couple of minutes. Complete documentation can be found on the \nwebsite\n while there is also a \ndemo\n available for people to see what it looks like. \nLive API Endpoints\n allow you to utilize the endpoints from within the documentation in a neat way.\n\n\nFeatures include customizing the template with your branding, settings for hiding the docs depending on the environment and more.\n\n\nBoth this package and Django REST Swagger are fully documented, well supported, and come highly recommended.\n\n\n\n\n\n\nDjango REST Swagger\n\n\nMarc Gibbons' \nDjango REST Swagger\n integrates REST framework with the \nSwagger\n API documentation tool. The package produces well presented API documentation, and includes interactive tools for testing API endpoints.\n\n\nDjango REST Swagger supports REST framework versions 2.3 and above.\n\n\nMark is also the author of the \nREST Framework Docs\n package which offers clean, simple autogenerated documentation for your API but is deprecated and has moved to Django REST Swagger.\n\n\nBoth this package and DRF docs are fully documented, well supported, and come highly recommended.\n\n\n\n\n\n\nDRF AutoDocs\n\n\nOleksander Mashianovs' \nDRF Auto Docs\n automated api renderer.\n\n\nCollects almost all the code you written into documentation effortlessly.\n\n\nSupports:\n\n\n\n\nfunctional view docs\n\n\ntree-like structure\n\n\nDocstrings:\n\n\nmarkdown\n\n\npreserve space & newlines\n\n\nformatting with nice syntax\n\n\nFields:\n\n\nchoices rendering\n\n\nhelp_text (to specify SerializerMethodField output, etc)\n\n\nsmart read_only/required rendering\n\n\nEndpoint properties:\n\n\nfilter_backends\n\n\nauthentication_classes\n\n\npermission_classes\n\n\nextra url params(GET params)\n\n\n\n\n\n\n\n\nApiary\n\n\nThere are various other online tools and services for providing API documentation. One notable service is \nApiary\n. With Apiary, you describe your API using a simple markdown-like syntax. The generated documentation includes API interaction, a mock server for testing & prototyping, and various other tools.\n\n\n\n\n\n\nSelf describing APIs\n\n\nThe browsable API that REST framework provides makes it possible for your API to be entirely self describing. The documentation for each API endpoint can be provided simply by visiting the URL in your browser.\n\n\n\n\n\n\nSetting the title\n\n\nThe title that is used in the browsable API is generated from the view class name or function name. Any trailing \nView\n or \nViewSet\n suffix is stripped, and the string is whitespace separated on uppercase/lowercase boundaries or underscores.\n\n\nFor example, the view \nUserListView\n, will be named \nUser List\n when presented in the browsable API.\n\n\nWhen working with viewsets, an appropriate suffix is appended to each generated view. For example, the view set \nUserViewSet\n will generate views named \nUser List\n and \nUser Instance\n.\n\n\nSetting the description\n\n\nThe description in the browsable API is generated from the docstring of the view or viewset.\n\n\nIf the python \nmarkdown\n library is installed, then \nmarkdown syntax\n may be used in the docstring, and will be converted to HTML in the browsable API. For example:\n\n\nclass AccountListView(views.APIView):\n \"\"\"\n Returns a list of all **active** accounts in the system.\n\n For more details on how accounts are activated please [see here][ref].\n\n [ref]: http://example.com/activating-accounts\n \"\"\"\n\n\n\nNote that when using viewsets the basic docstring is used for all generated views. To provide descriptions for each view, such as for the the list and retrieve views, use docstring sections as described in \nSchemas as documentation: Examples\n.\n\n\nThe \nOPTIONS\n method\n\n\nREST framework APIs also support programmatically accessible descriptions, using the \nOPTIONS\n HTTP method. A view will respond to an \nOPTIONS\n request with metadata including the name, description, and the various media types it accepts and responds with.\n\n\nWhen using the generic views, any \nOPTIONS\n requests will additionally respond with metadata regarding any \nPOST\n or \nPUT\n actions available, describing which fields are on the serializer.\n\n\nYou can modify the response behavior to \nOPTIONS\n requests by overriding the \noptions\n view method and/or by providing a custom Metadata class. For example:\n\n\ndef options(self, request, *args, **kwargs):\n \"\"\"\n Don't include the view description in OPTIONS responses.\n \"\"\"\n meta = self.metadata_class()\n data = meta.determine_metadata(request, self)\n data.pop('description')\n return data\n\n\n\nSee \nthe Metadata docs\n for more details.\n\n\n\n\nThe hypermedia approach\n\n\nTo be fully RESTful an API should present its available actions as hypermedia controls in the responses that it sends.\n\n\nIn this approach, rather than documenting the available API endpoints up front, the description instead concentrates on the \nmedia types\n that are used. The available actions that may be taken on any given URL are not strictly fixed, but are instead made available by the presence of link and form controls in the returned document.\n\n\nTo implement a hypermedia API you'll need to decide on an appropriate media type for the API, and implement a custom renderer and parser for that media type. The \nREST, Hypermedia & HATEOAS\n section of the documentation includes pointers to background reading, as well as links to various hypermedia formats.", "title": "Documenting your API" }, { @@ -4067,12 +4097,12 @@ }, { "location": "/topics/documenting-your-api/#include_docs_urls", - "text": "title : Default None . May be used to provide a descriptive title for the schema definition. description : Default None . May be used to provide a description for the schema definition. schema_url : Default None . May be used to pass a canonical base URL for the schema. public : Default True . Should the schema be considered public ? If True schema is generated without a request instance being passed to views. patterns : Default None . A list of URLs to inspect when generating the schema. If None project's URL conf will be used. generator_class : Default rest_framework.schemas.SchemaGenerator . May be used to specify a SchemaGenerator subclass to be passed to the SchemaView . authentication_classes : Default api_settings.DEFAULT_AUTHENTICATION_CLASSES . May be used to pass custom authentication classes to the SchemaView . permission_classes : Default api_settings.DEFAULT_PERMISSION_CLASSES May be used to pass custom permission classes to the SchemaView .", + "text": "title : Default None . May be used to provide a descriptive title for the schema definition. description : Default None . May be used to provide a description for the schema definition. schema_url : Default None . May be used to pass a canonical base URL for the schema. public : Default True . Should the schema be considered public ? If True schema is generated without a request instance being passed to views. patterns : Default None . A list of URLs to inspect when generating the schema. If None project's URL conf will be used. generator_class : Default rest_framework.schemas.SchemaGenerator . May be used to specify a SchemaGenerator subclass to be passed to the SchemaView . authentication_classes : Default api_settings.DEFAULT_AUTHENTICATION_CLASSES . May be used to pass custom authentication classes to the SchemaView . permission_classes : Default api_settings.DEFAULT_PERMISSION_CLASSES May be used to pass custom permission classes to the SchemaView . renderer_classes : Default None . May be used to pass custom renderer classes to the SchemaView .", "title": "include_docs_urls" }, { "location": "/topics/documenting-your-api/#get_docs_view", - "text": "title : Default None . May be used to provide a descriptive title for the schema definition. description : Default None . May be used to provide a description for the schema definition. schema_url : Default None . May be used to pass a canonical base URL for the schema. public : Default True . If True schema is generated without a request instance being passed to views. patterns : Default None . A list of URLs to inspect when generating the schema. If None project's URL conf will be used. generator_class : Default rest_framework.schemas.SchemaGenerator . May be used to specify a SchemaGenerator subclass to be passed to the SchemaView . authentication_classes : Default api_settings.DEFAULT_AUTHENTICATION_CLASSES . May be used to pass custom authentication classes to the SchemaView . permission_classes : Default api_settings.DEFAULT_PERMISSION_CLASSES May be used to pass custom permission classes to the SchemaView .", + "text": "title : Default None . May be used to provide a descriptive title for the schema definition. description : Default None . May be used to provide a description for the schema definition. schema_url : Default None . May be used to pass a canonical base URL for the schema. public : Default True . If True schema is generated without a request instance being passed to views. patterns : Default None . A list of URLs to inspect when generating the schema. If None project's URL conf will be used. generator_class : Default rest_framework.schemas.SchemaGenerator . May be used to specify a SchemaGenerator subclass to be passed to the SchemaView . authentication_classes : Default api_settings.DEFAULT_AUTHENTICATION_CLASSES . May be used to pass custom authentication classes to the SchemaView . permission_classes : Default api_settings.DEFAULT_PERMISSION_CLASSES . May be used to pass custom permission classes to the SchemaView . renderer_classes : Default None . May be used to pass custom renderer classes to the SchemaView . If None the SchemaView will be configured with DocumentationRenderer and CoreJSONRenderer renderers, corresponding to the (default) html and corejson formats.", "title": "get_docs_view" }, { @@ -4080,6 +4110,11 @@ "text": "title : Default None . May be used to provide a descriptive title for the schema definition. description : Default None . May be used to provide a description for the schema definition. schema_url : Default None . May be used to pass a canonical base URL for the schema. public : Default True . If True schema is generated without a request instance being passed to views. patterns : Default None . A list of URLs to inspect when generating the schema. If None project's URL conf will be used. generator_class : Default rest_framework.schemas.SchemaGenerator . May be used to specify a SchemaGenerator subclass to be passed to the SchemaView . authentication_classes : Default api_settings.DEFAULT_AUTHENTICATION_CLASSES . May be used to pass custom authentication classes to the SchemaView . permission_classes : Default api_settings.DEFAULT_PERMISSION_CLASSES May be used to pass custom permission classes to the SchemaView .", "title": "get_schemajs_view" }, + { + "location": "/topics/documenting-your-api/#customising-code-samples", + "text": "The built-in API documentation includes automatically generated code samples for\neach of the available API client libraries. You may customise these samples by subclassing DocumentationRenderer , setting languages to the list of languages you wish to support: from rest_framework.renderers import DocumentationRenderer\n\n\nclass CustomRenderer(DocumentationRenderer):\n languages = ['ruby', 'go'] For each language you need to provide an intro template, detailing installation instructions and such,\nplus a generic template for making API requests, that can be filled with individual request details.\nSee the templates for the bundled languages for examples.", + "title": "Customising code samples" + }, { "location": "/topics/documenting-your-api/#third-party-packages", "text": "There are a number of mature third-party packages for providing API documentation.", @@ -4087,7 +4122,7 @@ }, { "location": "/topics/documenting-your-api/#drf-yasg-yet-another-swagger-generator", - "text": "drf-yasg is a Swagger generation tool implemented without using the schema generation provided \nby Django Rest Framework. It aims to implement as much of the OpenAPI specification as possible - nested schemas, named models, \nresponse bodies, enum/pattern/min/max validators, form parameters, etc. - and to generate documents usable with code \ngeneration tools like swagger-codegen . This also translates into a very useful interactive documentation viewer in the form of swagger-ui :", + "text": "drf-yasg is a Swagger generation tool implemented without using the schema generation provided\nby Django Rest Framework. It aims to implement as much of the OpenAPI specification as possible - nested schemas, named models,\nresponse bodies, enum/pattern/min/max validators, form parameters, etc. - and to generate documents usable with code\ngeneration tools like swagger-codegen . This also translates into a very useful interactive documentation viewer in the form of swagger-ui :", "title": "drf-yasg - Yet Another Swagger Generator" }, { @@ -4142,7 +4177,7 @@ }, { "location": "/topics/api-clients/", - "text": "API Clients\n\n\nAn API client handles the underlying details of how network requests are made\nand how responses are decoded. They present the developer with an application\ninterface to work against, rather than working directly with the network interface.\n\n\nThe API clients documented here are not restricted to APIs built with Django REST framework.\n They can be used with any API that exposes a supported schema format.\n\n\nFor example, \nthe Heroku platform API\n exposes a schema in the JSON\nHyperschema format. As a result, the Core API command line client and Python\nclient library can be \nused to interact with the Heroku API\n.\n\n\nClient-side Core API\n\n\nCore API\n is a document specification that can be used to describe APIs. It can\nbe used either server-side, as is done with REST framework's \nschema generation\n,\nor used client-side, as described here.\n\n\nWhen used client-side, Core API allows for \ndynamically driven client libraries\n\nthat can interact with any API that exposes a supported schema or hypermedia\nformat.\n\n\nUsing a dynamically driven client has a number of advantages over interacting\nwith an API by building HTTP requests directly.\n\n\nMore meaningful interaction\n\n\nAPI interactions are presented in a more meaningful way. You're working at\nthe application interface layer, rather than the network interface layer.\n\n\nResilience & evolvability\n\n\nThe client determines what endpoints are available, what parameters exist\nagainst each particular endpoint, and how HTTP requests are formed.\n\n\nThis also allows for a degree of API evolvability. URLs can be modified\nwithout breaking existing clients, or more efficient encodings can be used\non-the-wire, with clients transparently upgrading.\n\n\nSelf-descriptive APIs\n\n\nA dynamically driven client is able to present documentation on the API to the\nend user. This documentation allows the user to discover the available endpoints\nand parameters, and better understand the API they are working with.\n\n\nBecause this documentation is driven by the API schema it will always be fully\nup to date with the most recently deployed version of the service.\n\n\n\n\nCommand line client\n\n\nThe command line client allows you to inspect and interact with any API that\nexposes a supported schema format.\n\n\nGetting started\n\n\nTo install the Core API command line client, use \npip\n.\n\n\nNote that the command-line client is a separate package to the\npython client library. Make sure to install \ncoreapi-cli\n.\n\n\n$ pip install coreapi-cli\n\n\n\nTo start inspecting and interacting with an API the schema must first be loaded\nfrom the network.\n\n\n$ coreapi get http://api.example.org/\n\nsnippets: {\n create(code, [title], [linenos], [language], [style])\n destroy(pk)\n highlight(pk)\n list([page])\n partial_update(pk, [title], [code], [linenos], [language], [style])\n retrieve(pk)\n update(pk, code, [title], [linenos], [language], [style])\n}\nusers: {\n list([page])\n retrieve(pk)\n}\n\n\n\nThis will then load the schema, displaying the resulting \nDocument\n. This\n\nDocument\n includes all the available interactions that may be made against the API.\n\n\nTo interact with the API, use the \naction\n command. This command requires a list\nof keys that are used to index into the link.\n\n\n$ coreapi action users list\n[\n {\n \"url\": \"http://127.0.0.1:8000/users/2/\",\n \"id\": 2,\n \"username\": \"aziz\",\n \"snippets\": []\n },\n ...\n]\n\n\n\nTo inspect the underlying HTTP request and response, use the \n--debug\n flag.\n\n\n$ coreapi action users list --debug\n> GET /users/ HTTP/1.1\n> Accept: application/vnd.coreapi+json, */*\n> Authorization: Basic bWF4Om1heA==\n> Host: 127.0.0.1\n> User-Agent: coreapi\n< 200 OK\n< Allow: GET, HEAD, OPTIONS\n< Content-Type: application/json\n< Date: Thu, 30 Jun 2016 10:51:46 GMT\n< Server: WSGIServer/0.1 Python/2.7.10\n< Vary: Accept, Cookie\n<\n< [{\"url\":\"http://127.0.0.1/users/2/\",\"id\":2,\"username\":\"aziz\",\"snippets\":[]},{\"url\":\"http://127.0.0.1/users/3/\",\"id\":3,\"username\":\"amy\",\"snippets\":[\"http://127.0.0.1/snippets/3/\"]},{\"url\":\"http://127.0.0.1/users/4/\",\"id\":4,\"username\":\"max\",\"snippets\":[\"http://127.0.0.1/snippets/4/\",\"http://127.0.0.1/snippets/5/\",\"http://127.0.0.1/snippets/6/\",\"http://127.0.0.1/snippets/7/\"]},{\"url\":\"http://127.0.0.1/users/5/\",\"id\":5,\"username\":\"jose\",\"snippets\":[]},{\"url\":\"http://127.0.0.1/users/6/\",\"id\":6,\"username\":\"admin\",\"snippets\":[\"http://127.0.0.1/snippets/1/\",\"http://127.0.0.1/snippets/2/\"]}]\n\n[\n ...\n]\n\n\n\nSome actions may include optional or required parameters.\n\n\n$ coreapi action users create --param username=example\n\n\n\nWhen using \n--param\n, the type of the input will be determined automatically.\n\n\nIf you want to be more explicit about the parameter type then use \n--data\n for\nany null, numeric, boolean, list, or object inputs, and use \n--string\n for string inputs.\n\n\n$ coreapi action users edit --string username=tomchristie --data is_admin=true\n\n\n\nAuthentication & headers\n\n\nThe \ncredentials\n command is used to manage the request \nAuthentication:\n header.\nAny credentials added are always linked to a particular domain, so as to ensure\nthat credentials are not leaked across differing APIs.\n\n\nThe format for adding a new credential is:\n\n\n$ coreapi credentials add \n\n\n\nFor instance:\n\n\n$ coreapi credentials add api.example.org \"Token 9944b09199c62bcf9418ad846dd0e4bbdfc6ee4b\"\n\n\n\nThe optional \n--auth\n flag also allows you to add specific types of authentication,\nhandling the encoding for you. Currently only \n\"basic\"\n is supported as an option here.\nFor example:\n\n\n$ coreapi credentials add api.example.org tomchristie:foobar --auth basic\n\n\n\nYou can also add specific request headers, using the \nheaders\n command:\n\n\n$ coreapi headers add api.example.org x-api-version 2\n\n\n\nFor more information and a listing of the available subcommands use \ncoreapi\ncredentials --help\n or \ncoreapi headers --help\n.\n\n\nCodecs\n\n\nBy default the command line client only includes support for reading Core JSON\nschemas, however it includes a plugin system for installing additional codecs.\n\n\n$ pip install openapi-codec jsonhyperschema-codec hal-codec\n$ coreapi codecs show\nCodecs\ncorejson application/vnd.coreapi+json encoding, decoding\nhal application/hal+json encoding, decoding\nopenapi application/openapi+json encoding, decoding\njsonhyperschema application/schema+json decoding\njson application/json data\ntext text/* data\n\n\n\nUtilities\n\n\nThe command line client includes functionality for bookmarking API URLs\nunder a memorable name. For example, you can add a bookmark for the\nexisting API, like so...\n\n\n$ coreapi bookmarks add accountmanagement\n\n\n\nThere is also functionality for navigating forward or backward through the\nhistory of which API URLs have been accessed.\n\n\n$ coreapi history show\n$ coreapi history back\n\n\n\nFor more information and a listing of the available subcommands use\n\ncoreapi bookmarks --help\n or \ncoreapi history --help\n.\n\n\nOther commands\n\n\nTo display the current \nDocument\n:\n\n\n$ coreapi show\n\n\n\nTo reload the current \nDocument\n from the network:\n\n\n$ coreapi reload\n\n\n\nTo load a schema file from disk:\n\n\n$ coreapi load my-api-schema.json --format corejson\n\n\n\nTo dump the current document to console in a given format:\n\n\n$ coreapi dump --format openapi\n\n\n\nTo remove the current document, along with all currently saved history,\ncredentials, headers and bookmarks:\n\n\n$ coreapi clear\n\n\n\n\n\nPython client library\n\n\nThe \ncoreapi\n Python package allows you to programmatically interact with any\nAPI that exposes a supported schema format.\n\n\nGetting started\n\n\nYou'll need to install the \ncoreapi\n package using \npip\n before you can get\nstarted.\n\n\n$ pip install coreapi\n\n\n\nIn order to start working with an API, we first need a \nClient\n instance. The\nclient holds any configuration around which codecs and transports are supported\nwhen interacting with an API, which allows you to provide for more advanced\nkinds of behaviour.\n\n\nimport coreapi\nclient = coreapi.Client()\n\n\n\nOnce we have a \nClient\n instance, we can fetch an API schema from the network.\n\n\nschema = client.get('https://api.example.org/')\n\n\n\nThe object returned from this call will be a \nDocument\n instance, which is\na representation of the API schema.\n\n\nAuthentication\n\n\nTypically you'll also want to provide some authentication credentials when\ninstantiating the client.\n\n\nToken authentication\n\n\nThe \nTokenAuthentication\n class can be used to support REST framework's built-in\n\nTokenAuthentication\n, as well as OAuth and JWT schemes.\n\n\nauth = coreapi.auth.TokenAuthentication(\n scheme='JWT'\n token=''\n)\nclient = coreapi.Client(auth=auth)\n\n\n\nWhen using TokenAuthentication you'll probably need to implement a login flow\nusing the CoreAPI client.\n\n\nA suggested pattern for this would be to initially make an unauthenticated client\nrequest to an \"obtain token\" endpoint\n\n\nFor example, using the \"Django REST framework JWT\" package\n\n\nclient = coreapi.Client()\nschema = client.get('https://api.example.org/')\n\naction = ['api-token-auth', 'obtain-token']\nparams = {username: \"example\", email: \"example@example.com\"}\nresult = client.action(schema, action, params)\n\nauth = coreapi.auth.TokenAuthentication(\n scheme='JWT',\n token=result['token']\n)\nclient = coreapi.Client(auth=auth)\n\n\n\nBasic authentication\n\n\nThe \nBasicAuthentication\n class can be used to support HTTP Basic Authentication.\n\n\nauth = coreapi.auth.BasicAuthentication(\n username='',\n password=''\n)\nclient = coreapi.Client(auth=auth)\n\n\n\nInteracting with the API\n\n\nNow that we have a client and have fetched our schema \nDocument\n, we can now\nstart to interact with the API:\n\n\nusers = client.action(schema, ['users', 'list'])\n\n\n\nSome endpoints may include named parameters, which might be either optional or required:\n\n\nnew_user = client.action(schema, ['users', 'create'], params={\"username\": \"max\"})\n\n\n\nCodecs\n\n\nCodecs are responsible for encoding or decoding Documents.\n\n\nThe decoding process is used by a client to take a bytestring of an API schema\ndefinition, and returning the Core API \nDocument\n that represents that interface.\n\n\nA codec should be associated with a particular media type, such as \n'application/coreapi+json'\n.\n\n\nThis media type is used by the server in the response \nContent-Type\n header,\nin order to indicate what kind of data is being returned in the response.\n\n\nConfiguring codecs\n\n\nThe codecs that are available can be configured when instantiating a client.\nThe keyword argument used here is \ndecoders\n, because in the context of a\nclient the codecs are only for \ndecoding\n responses.\n\n\nIn the following example we'll configure a client to only accept \nCore JSON\n\nand \nJSON\n responses. This will allow us to receive and decode a Core JSON schema,\nand subsequently to receive JSON responses made against the API.\n\n\nfrom coreapi import codecs, Client\n\ndecoders = [codecs.CoreJSONCodec(), codecs.JSONCodec()]\nclient = Client(decoders=decoders)\n\n\n\nLoading and saving schemas\n\n\nYou can use a codec directly, in order to load an existing schema definition,\nand return the resulting \nDocument\n.\n\n\ninput_file = open('my-api-schema.json', 'rb')\nschema_definition = input_file.read()\ncodec = codecs.CoreJSONCodec()\nschema = codec.load(schema_definition)\n\n\n\nYou can also use a codec directly to generate a schema definition given a \nDocument\n instance:\n\n\nschema_definition = codec.dump(schema)\noutput_file = open('my-api-schema.json', 'rb')\noutput_file.write(schema_definition)\n\n\n\nTransports\n\n\nTransports are responsible for making network requests. The set of transports\nthat a client has installed determines which network protocols it is able to\nsupport.\n\n\nCurrently the \ncoreapi\n library only includes an HTTP/HTTPS transport, but\nother protocols can also be supported.\n\n\nConfiguring transports\n\n\nThe behavior of the network layer can be customized by configuring the\ntransports that the client is instantiated with.\n\n\nimport requests\nfrom coreapi import transports, Client\n\ncredentials = {'api.example.org': 'Token 3bd44a009d16ff'}\ntransports = transports.HTTPTransport(credentials=credentials)\nclient = Client(transports=transports)\n\n\n\nMore complex customizations can also be achieved, for example modifying the\nunderlying \nrequests.Session\n instance to \nattach transport adaptors\n\nthat modify the outgoing requests.\n\n\n\n\nJavaScript Client Library\n\n\nThe JavaScript client library allows you to interact with your API either from a browser, or using node.\n\n\nInstalling the JavaScript client\n\n\nThere are two separate JavaScript resources that you need to include in your HTML pages in order to use the JavaScript client library. These are a static \ncoreapi.js\n file, which contains the code for the dynamic client library, and a templated \nschema.js\n resource, which exposes your API schema.\n\n\nFirst, install the API documentation views. These will include the schema resource that'll allow you to load the schema directly from an HTML page, without having to make an asynchronous AJAX call.\n\n\nfrom rest_framework.documentation import include_docs_urls\n\nurlpatterns = [\n ...\n url(r'^docs/', include_docs_urls(title='My API service'))\n]\n\n\n\nOnce the API documentation URLs are installed, you'll be able to include both the required JavaScript resources. Note that the ordering of these two lines is important, as the schema loading requires CoreAPI to already be installed.\n\n\n\n{% load staticfiles %}\n\n\n\n\n\nThe \ncoreapi\n library, and the \nschema\n object will now both be available on the \nwindow\n instance.\n\n\nconst coreapi = window.coreapi\nconst schema = window.schema\n\n\n\nInstantiating a client\n\n\nIn order to interact with the API you'll need a client instance.\n\n\nvar client = new coreapi.Client()\n\n\n\nTypically you'll also want to provide some authentication credentials when\ninstantiating the client.\n\n\nSession authentication\n\n\nThe \nSessionAuthentication\n class allows session cookies to provide the user\nauthentication. You'll want to provide a standard HTML login flow, to allow\nthe user to login, and then instantiate a client using session authentication:\n\n\nlet auth = new coreapi.auth.SessionAuthentication({\n csrfCookieName: 'csrftoken',\n csrfHeaderName: 'X-CSRFToken'\n})\nlet client = new coreapi.Client({auth: auth})\n\n\n\nThe authentication scheme will handle including a CSRF header in any outgoing\nrequests for unsafe HTTP methods.\n\n\nToken authentication\n\n\nThe \nTokenAuthentication\n class can be used to support REST framework's built-in\n\nTokenAuthentication\n, as well as OAuth and JWT schemes.\n\n\nlet auth = new coreapi.auth.TokenAuthentication({\n scheme: 'JWT'\n token: ''\n})\nlet client = new coreapi.Client({auth: auth})\n\n\n\nWhen using TokenAuthentication you'll probably need to implement a login flow\nusing the CoreAPI client.\n\n\nA suggested pattern for this would be to initially make an unauthenticated client\nrequest to an \"obtain token\" endpoint\n\n\nFor example, using the \"Django REST framework JWT\" package\n\n\n// Setup some globally accessible state\nwindow.client = new coreapi.Client()\nwindow.loggedIn = false\n\nfunction loginUser(username, password) {\n let action = [\"api-token-auth\", \"obtain-token\"]\n let params = {username: \"example\", email: \"example@example.com\"}\n client.action(schema, action, params).then(function(result) {\n // On success, instantiate an authenticated client.\n let auth = window.coreapi.auth.TokenAuthentication({\n scheme: 'JWT',\n token: result['token']\n })\n window.client = coreapi.Client({auth: auth})\n window.loggedIn = true\n }).catch(function (error) {\n // Handle error case where eg. user provides incorrect credentials.\n })\n}\n\n\n\nBasic authentication\n\n\nThe \nBasicAuthentication\n class can be used to support HTTP Basic Authentication.\n\n\nlet auth = new coreapi.auth.BasicAuthentication({\n username: '',\n password: ''\n})\nlet client = new coreapi.Client({auth: auth})\n\n\n\nUsing the client\n\n\nMaking requests:\n\n\nlet action = [\"users\", \"list\"]\nclient.action(schema, action).then(function(result) {\n // Return value is in 'result'\n})\n\n\n\nIncluding parameters:\n\n\nlet action = [\"users\", \"create\"]\nlet params = {username: \"example\", email: \"example@example.com\"}\nclient.action(schema, action, params).then(function(result) {\n // Return value is in 'result'\n})\n\n\n\nHandling errors:\n\n\nclient.action(schema, action, params).then(function(result) {\n // Return value is in 'result'\n}).catch(function (error) {\n // Error value is in 'error'\n})\n\n\n\nInstallation with node\n\n\nThe coreapi package is available on NPM.\n\n\n$ npm install coreapi\n$ node\nconst coreapi = require('coreapi')\n\n\n\nYou'll either want to include the API schema in your codebase directly, by copying it from the \nschema.js\n resource, or else load the schema asynchronously. For example:\n\n\nlet client = new coreapi.Client()\nlet schema = null\nclient.get(\"https://api.example.org/\").then(function(data) {\n // Load a CoreJSON API schema.\n schema = data\n console.log('schema loaded')\n})", + "text": "API Clients\n\n\nAn API client handles the underlying details of how network requests are made\nand how responses are decoded. They present the developer with an application\ninterface to work against, rather than working directly with the network interface.\n\n\nThe API clients documented here are not restricted to APIs built with Django REST framework.\n They can be used with any API that exposes a supported schema format.\n\n\nFor example, \nthe Heroku platform API\n exposes a schema in the JSON\nHyperschema format. As a result, the Core API command line client and Python\nclient library can be \nused to interact with the Heroku API\n.\n\n\nClient-side Core API\n\n\nCore API\n is a document specification that can be used to describe APIs. It can\nbe used either server-side, as is done with REST framework's \nschema generation\n,\nor used client-side, as described here.\n\n\nWhen used client-side, Core API allows for \ndynamically driven client libraries\n\nthat can interact with any API that exposes a supported schema or hypermedia\nformat.\n\n\nUsing a dynamically driven client has a number of advantages over interacting\nwith an API by building HTTP requests directly.\n\n\nMore meaningful interaction\n\n\nAPI interactions are presented in a more meaningful way. You're working at\nthe application interface layer, rather than the network interface layer.\n\n\nResilience & evolvability\n\n\nThe client determines what endpoints are available, what parameters exist\nagainst each particular endpoint, and how HTTP requests are formed.\n\n\nThis also allows for a degree of API evolvability. URLs can be modified\nwithout breaking existing clients, or more efficient encodings can be used\non-the-wire, with clients transparently upgrading.\n\n\nSelf-descriptive APIs\n\n\nA dynamically driven client is able to present documentation on the API to the\nend user. This documentation allows the user to discover the available endpoints\nand parameters, and better understand the API they are working with.\n\n\nBecause this documentation is driven by the API schema it will always be fully\nup to date with the most recently deployed version of the service.\n\n\n\n\nCommand line client\n\n\nThe command line client allows you to inspect and interact with any API that\nexposes a supported schema format.\n\n\nGetting started\n\n\nTo install the Core API command line client, use \npip\n.\n\n\nNote that the command-line client is a separate package to the\npython client library. Make sure to install \ncoreapi-cli\n.\n\n\n$ pip install coreapi-cli\n\n\n\nTo start inspecting and interacting with an API the schema must first be loaded\nfrom the network.\n\n\n$ coreapi get http://api.example.org/\n\nsnippets: {\n create(code, [title], [linenos], [language], [style])\n destroy(pk)\n highlight(pk)\n list([page])\n partial_update(pk, [title], [code], [linenos], [language], [style])\n retrieve(pk)\n update(pk, code, [title], [linenos], [language], [style])\n}\nusers: {\n list([page])\n retrieve(pk)\n}\n\n\n\nThis will then load the schema, displaying the resulting \nDocument\n. This\n\nDocument\n includes all the available interactions that may be made against the API.\n\n\nTo interact with the API, use the \naction\n command. This command requires a list\nof keys that are used to index into the link.\n\n\n$ coreapi action users list\n[\n {\n \"url\": \"http://127.0.0.1:8000/users/2/\",\n \"id\": 2,\n \"username\": \"aziz\",\n \"snippets\": []\n },\n ...\n]\n\n\n\nTo inspect the underlying HTTP request and response, use the \n--debug\n flag.\n\n\n$ coreapi action users list --debug\n> GET /users/ HTTP/1.1\n> Accept: application/vnd.coreapi+json, */*\n> Authorization: Basic bWF4Om1heA==\n> Host: 127.0.0.1\n> User-Agent: coreapi\n< 200 OK\n< Allow: GET, HEAD, OPTIONS\n< Content-Type: application/json\n< Date: Thu, 30 Jun 2016 10:51:46 GMT\n< Server: WSGIServer/0.1 Python/2.7.10\n< Vary: Accept, Cookie\n<\n< [{\"url\":\"http://127.0.0.1/users/2/\",\"id\":2,\"username\":\"aziz\",\"snippets\":[]},{\"url\":\"http://127.0.0.1/users/3/\",\"id\":3,\"username\":\"amy\",\"snippets\":[\"http://127.0.0.1/snippets/3/\"]},{\"url\":\"http://127.0.0.1/users/4/\",\"id\":4,\"username\":\"max\",\"snippets\":[\"http://127.0.0.1/snippets/4/\",\"http://127.0.0.1/snippets/5/\",\"http://127.0.0.1/snippets/6/\",\"http://127.0.0.1/snippets/7/\"]},{\"url\":\"http://127.0.0.1/users/5/\",\"id\":5,\"username\":\"jose\",\"snippets\":[]},{\"url\":\"http://127.0.0.1/users/6/\",\"id\":6,\"username\":\"admin\",\"snippets\":[\"http://127.0.0.1/snippets/1/\",\"http://127.0.0.1/snippets/2/\"]}]\n\n[\n ...\n]\n\n\n\nSome actions may include optional or required parameters.\n\n\n$ coreapi action users create --param username=example\n\n\n\nWhen using \n--param\n, the type of the input will be determined automatically.\n\n\nIf you want to be more explicit about the parameter type then use \n--data\n for\nany null, numeric, boolean, list, or object inputs, and use \n--string\n for string inputs.\n\n\n$ coreapi action users edit --string username=tomchristie --data is_admin=true\n\n\n\nAuthentication & headers\n\n\nThe \ncredentials\n command is used to manage the request \nAuthentication:\n header.\nAny credentials added are always linked to a particular domain, so as to ensure\nthat credentials are not leaked across differing APIs.\n\n\nThe format for adding a new credential is:\n\n\n$ coreapi credentials add \n\n\n\nFor instance:\n\n\n$ coreapi credentials add api.example.org \"Token 9944b09199c62bcf9418ad846dd0e4bbdfc6ee4b\"\n\n\n\nThe optional \n--auth\n flag also allows you to add specific types of authentication,\nhandling the encoding for you. Currently only \n\"basic\"\n is supported as an option here.\nFor example:\n\n\n$ coreapi credentials add api.example.org tomchristie:foobar --auth basic\n\n\n\nYou can also add specific request headers, using the \nheaders\n command:\n\n\n$ coreapi headers add api.example.org x-api-version 2\n\n\n\nFor more information and a listing of the available subcommands use \ncoreapi\ncredentials --help\n or \ncoreapi headers --help\n.\n\n\nCodecs\n\n\nBy default the command line client only includes support for reading Core JSON\nschemas, however it includes a plugin system for installing additional codecs.\n\n\n$ pip install openapi-codec jsonhyperschema-codec hal-codec\n$ coreapi codecs show\nCodecs\ncorejson application/vnd.coreapi+json encoding, decoding\nhal application/hal+json encoding, decoding\nopenapi application/openapi+json encoding, decoding\njsonhyperschema application/schema+json decoding\njson application/json data\ntext text/* data\n\n\n\nUtilities\n\n\nThe command line client includes functionality for bookmarking API URLs\nunder a memorable name. For example, you can add a bookmark for the\nexisting API, like so...\n\n\n$ coreapi bookmarks add accountmanagement\n\n\n\nThere is also functionality for navigating forward or backward through the\nhistory of which API URLs have been accessed.\n\n\n$ coreapi history show\n$ coreapi history back\n\n\n\nFor more information and a listing of the available subcommands use\n\ncoreapi bookmarks --help\n or \ncoreapi history --help\n.\n\n\nOther commands\n\n\nTo display the current \nDocument\n:\n\n\n$ coreapi show\n\n\n\nTo reload the current \nDocument\n from the network:\n\n\n$ coreapi reload\n\n\n\nTo load a schema file from disk:\n\n\n$ coreapi load my-api-schema.json --format corejson\n\n\n\nTo dump the current document to console in a given format:\n\n\n$ coreapi dump --format openapi\n\n\n\nTo remove the current document, along with all currently saved history,\ncredentials, headers and bookmarks:\n\n\n$ coreapi clear\n\n\n\n\n\nPython client library\n\n\nThe \ncoreapi\n Python package allows you to programmatically interact with any\nAPI that exposes a supported schema format.\n\n\nGetting started\n\n\nYou'll need to install the \ncoreapi\n package using \npip\n before you can get\nstarted.\n\n\n$ pip install coreapi\n\n\n\nIn order to start working with an API, we first need a \nClient\n instance. The\nclient holds any configuration around which codecs and transports are supported\nwhen interacting with an API, which allows you to provide for more advanced\nkinds of behaviour.\n\n\nimport coreapi\nclient = coreapi.Client()\n\n\n\nOnce we have a \nClient\n instance, we can fetch an API schema from the network.\n\n\nschema = client.get('https://api.example.org/')\n\n\n\nThe object returned from this call will be a \nDocument\n instance, which is\na representation of the API schema.\n\n\nAuthentication\n\n\nTypically you'll also want to provide some authentication credentials when\ninstantiating the client.\n\n\nToken authentication\n\n\nThe \nTokenAuthentication\n class can be used to support REST framework's built-in\n\nTokenAuthentication\n, as well as OAuth and JWT schemes.\n\n\nauth = coreapi.auth.TokenAuthentication(\n scheme='JWT'\n token=''\n)\nclient = coreapi.Client(auth=auth)\n\n\n\nWhen using TokenAuthentication you'll probably need to implement a login flow\nusing the CoreAPI client.\n\n\nA suggested pattern for this would be to initially make an unauthenticated client\nrequest to an \"obtain token\" endpoint\n\n\nFor example, using the \"Django REST framework JWT\" package\n\n\nclient = coreapi.Client()\nschema = client.get('https://api.example.org/')\n\naction = ['api-token-auth', 'obtain-token']\nparams = {username: \"example\", email: \"example@example.com\"}\nresult = client.action(schema, action, params)\n\nauth = coreapi.auth.TokenAuthentication(\n scheme='JWT',\n token=result['token']\n)\nclient = coreapi.Client(auth=auth)\n\n\n\nBasic authentication\n\n\nThe \nBasicAuthentication\n class can be used to support HTTP Basic Authentication.\n\n\nauth = coreapi.auth.BasicAuthentication(\n username='',\n password=''\n)\nclient = coreapi.Client(auth=auth)\n\n\n\nInteracting with the API\n\n\nNow that we have a client and have fetched our schema \nDocument\n, we can now\nstart to interact with the API:\n\n\nusers = client.action(schema, ['users', 'list'])\n\n\n\nSome endpoints may include named parameters, which might be either optional or required:\n\n\nnew_user = client.action(schema, ['users', 'create'], params={\"username\": \"max\"})\n\n\n\nCodecs\n\n\nCodecs are responsible for encoding or decoding Documents.\n\n\nThe decoding process is used by a client to take a bytestring of an API schema\ndefinition, and returning the Core API \nDocument\n that represents that interface.\n\n\nA codec should be associated with a particular media type, such as \n'application/coreapi+json'\n.\n\n\nThis media type is used by the server in the response \nContent-Type\n header,\nin order to indicate what kind of data is being returned in the response.\n\n\nConfiguring codecs\n\n\nThe codecs that are available can be configured when instantiating a client.\nThe keyword argument used here is \ndecoders\n, because in the context of a\nclient the codecs are only for \ndecoding\n responses.\n\n\nIn the following example we'll configure a client to only accept \nCore JSON\n\nand \nJSON\n responses. This will allow us to receive and decode a Core JSON schema,\nand subsequently to receive JSON responses made against the API.\n\n\nfrom coreapi import codecs, Client\n\ndecoders = [codecs.CoreJSONCodec(), codecs.JSONCodec()]\nclient = Client(decoders=decoders)\n\n\n\nLoading and saving schemas\n\n\nYou can use a codec directly, in order to load an existing schema definition,\nand return the resulting \nDocument\n.\n\n\ninput_file = open('my-api-schema.json', 'rb')\nschema_definition = input_file.read()\ncodec = codecs.CoreJSONCodec()\nschema = codec.load(schema_definition)\n\n\n\nYou can also use a codec directly to generate a schema definition given a \nDocument\n instance:\n\n\nschema_definition = codec.dump(schema)\noutput_file = open('my-api-schema.json', 'rb')\noutput_file.write(schema_definition)\n\n\n\nTransports\n\n\nTransports are responsible for making network requests. The set of transports\nthat a client has installed determines which network protocols it is able to\nsupport.\n\n\nCurrently the \ncoreapi\n library only includes an HTTP/HTTPS transport, but\nother protocols can also be supported.\n\n\nConfiguring transports\n\n\nThe behavior of the network layer can be customized by configuring the\ntransports that the client is instantiated with.\n\n\nimport requests\nfrom coreapi import transports, Client\n\ncredentials = {'api.example.org': 'Token 3bd44a009d16ff'}\ntransports = transports.HTTPTransport(credentials=credentials)\nclient = Client(transports=transports)\n\n\n\nMore complex customizations can also be achieved, for example modifying the\nunderlying \nrequests.Session\n instance to \nattach transport adaptors\n\nthat modify the outgoing requests.\n\n\n\n\nJavaScript Client Library\n\n\nThe JavaScript client library allows you to interact with your API either from a browser, or using node.\n\n\nInstalling the JavaScript client\n\n\nThere are two separate JavaScript resources that you need to include in your HTML pages in order to use the JavaScript client library. These are a static \ncoreapi.js\n file, which contains the code for the dynamic client library, and a templated \nschema.js\n resource, which exposes your API schema.\n\n\nFirst, install the API documentation views. These will include the schema resource that'll allow you to load the schema directly from an HTML page, without having to make an asynchronous AJAX call.\n\n\nfrom rest_framework.documentation import include_docs_urls\n\nurlpatterns = [\n ...\n url(r'^docs/', include_docs_urls(title='My API service'))\n]\n\n\n\nOnce the API documentation URLs are installed, you'll be able to include both the required JavaScript resources. Note that the ordering of these two lines is important, as the schema loading requires CoreAPI to already be installed.\n\n\n\n{% load static %}\n\n\n\n\n\nThe \ncoreapi\n library, and the \nschema\n object will now both be available on the \nwindow\n instance.\n\n\nconst coreapi = window.coreapi\nconst schema = window.schema\n\n\n\nInstantiating a client\n\n\nIn order to interact with the API you'll need a client instance.\n\n\nvar client = new coreapi.Client()\n\n\n\nTypically you'll also want to provide some authentication credentials when\ninstantiating the client.\n\n\nSession authentication\n\n\nThe \nSessionAuthentication\n class allows session cookies to provide the user\nauthentication. You'll want to provide a standard HTML login flow, to allow\nthe user to login, and then instantiate a client using session authentication:\n\n\nlet auth = new coreapi.auth.SessionAuthentication({\n csrfCookieName: 'csrftoken',\n csrfHeaderName: 'X-CSRFToken'\n})\nlet client = new coreapi.Client({auth: auth})\n\n\n\nThe authentication scheme will handle including a CSRF header in any outgoing\nrequests for unsafe HTTP methods.\n\n\nToken authentication\n\n\nThe \nTokenAuthentication\n class can be used to support REST framework's built-in\n\nTokenAuthentication\n, as well as OAuth and JWT schemes.\n\n\nlet auth = new coreapi.auth.TokenAuthentication({\n scheme: 'JWT'\n token: ''\n})\nlet client = new coreapi.Client({auth: auth})\n\n\n\nWhen using TokenAuthentication you'll probably need to implement a login flow\nusing the CoreAPI client.\n\n\nA suggested pattern for this would be to initially make an unauthenticated client\nrequest to an \"obtain token\" endpoint\n\n\nFor example, using the \"Django REST framework JWT\" package\n\n\n// Setup some globally accessible state\nwindow.client = new coreapi.Client()\nwindow.loggedIn = false\n\nfunction loginUser(username, password) {\n let action = [\"api-token-auth\", \"obtain-token\"]\n let params = {username: \"example\", email: \"example@example.com\"}\n client.action(schema, action, params).then(function(result) {\n // On success, instantiate an authenticated client.\n let auth = window.coreapi.auth.TokenAuthentication({\n scheme: 'JWT',\n token: result['token']\n })\n window.client = coreapi.Client({auth: auth})\n window.loggedIn = true\n }).catch(function (error) {\n // Handle error case where eg. user provides incorrect credentials.\n })\n}\n\n\n\nBasic authentication\n\n\nThe \nBasicAuthentication\n class can be used to support HTTP Basic Authentication.\n\n\nlet auth = new coreapi.auth.BasicAuthentication({\n username: '',\n password: ''\n})\nlet client = new coreapi.Client({auth: auth})\n\n\n\nUsing the client\n\n\nMaking requests:\n\n\nlet action = [\"users\", \"list\"]\nclient.action(schema, action).then(function(result) {\n // Return value is in 'result'\n})\n\n\n\nIncluding parameters:\n\n\nlet action = [\"users\", \"create\"]\nlet params = {username: \"example\", email: \"example@example.com\"}\nclient.action(schema, action, params).then(function(result) {\n // Return value is in 'result'\n})\n\n\n\nHandling errors:\n\n\nclient.action(schema, action, params).then(function(result) {\n // Return value is in 'result'\n}).catch(function (error) {\n // Error value is in 'error'\n})\n\n\n\nInstallation with node\n\n\nThe coreapi package is available on NPM.\n\n\n$ npm install coreapi\n$ node\nconst coreapi = require('coreapi')\n\n\n\nYou'll either want to include the API schema in your codebase directly, by copying it from the \nschema.js\n resource, or else load the schema asynchronously. For example:\n\n\nlet client = new coreapi.Client()\nlet schema = null\nclient.get(\"https://api.example.org/\").then(function(data) {\n // Load a CoreJSON API schema.\n schema = data\n console.log('schema loaded')\n})", "title": "API Clients" }, { @@ -4262,7 +4297,7 @@ }, { "location": "/topics/api-clients/#installing-the-javascript-client", - "text": "There are two separate JavaScript resources that you need to include in your HTML pages in order to use the JavaScript client library. These are a static coreapi.js file, which contains the code for the dynamic client library, and a templated schema.js resource, which exposes your API schema. First, install the API documentation views. These will include the schema resource that'll allow you to load the schema directly from an HTML page, without having to make an asynchronous AJAX call. from rest_framework.documentation import include_docs_urls\n\nurlpatterns = [\n ...\n url(r'^docs/', include_docs_urls(title='My API service'))\n] Once the API documentation URLs are installed, you'll be able to include both the required JavaScript resources. Note that the ordering of these two lines is important, as the schema loading requires CoreAPI to already be installed. \n{% load staticfiles %}\n\n The coreapi library, and the schema object will now both be available on the window instance. const coreapi = window.coreapi\nconst schema = window.schema", + "text": "There are two separate JavaScript resources that you need to include in your HTML pages in order to use the JavaScript client library. These are a static coreapi.js file, which contains the code for the dynamic client library, and a templated schema.js resource, which exposes your API schema. First, install the API documentation views. These will include the schema resource that'll allow you to load the schema directly from an HTML page, without having to make an asynchronous AJAX call. from rest_framework.documentation import include_docs_urls\n\nurlpatterns = [\n ...\n url(r'^docs/', include_docs_urls(title='My API service'))\n] Once the API documentation URLs are installed, you'll be able to include both the required JavaScript resources. Note that the ordering of these two lines is important, as the schema loading requires CoreAPI to already be installed. \n{% load static %}\n\n The coreapi library, and the schema object will now both be available on the window instance. const coreapi = window.coreapi\nconst schema = window.schema", "title": "Installing the JavaScript client" }, { @@ -4682,7 +4717,7 @@ }, { "location": "/topics/tutorials-and-resources/", - "text": "Tutorials and Resources\n\n\nThere are a wide range of resources available for learning and using Django REST framework. We try to keep a comprehensive list available here.\n\n\nBooks\n\n\n\n \n\n \n\n \n\n \n\n \n\n \n\n\n\n\n\nTutorials\n\n\n\n\nBeginner's Guide to the Django REST Framework\n\n\nDjango REST Framework - An Introduction\n\n\nDjango REST Framework Tutorial\n\n\nDjango REST Framework Course\n\n\nBuilding a RESTful API with Django REST Framework\n\n\nGetting Started with Django REST Framework and AngularJS\n\n\nEnd to End Web App with Django REST Framework & AngularJS\n\n\nStart Your API - Django REST Framework Part 1\n\n\nPermissions & Authentication - Django REST Framework Part 2\n\n\nViewSets and Routers - Django REST Framework Part 3\n\n\nDjango REST Framework User Endpoint\n\n\nCheck Credentials Using Django REST Framework\n\n\nCreating a Production Ready API with Python and Django REST Framework \u2013 Part 1\n\n\nCreating a Production Ready API with Python and Django REST Framework \u2013 Part 2\n\n\n\n\nVideos\n\n\nTalks\n\n\n\n\nLevel Up! Rethinking the Web API Framework\n\n\nHow to Make a Full Fledged REST API with Django OAuth Toolkit\n\n\nDjango REST API - So Easy You Can Learn It in 25 Minutes\n\n\nTom Christie about Django Rest Framework at Django: Under The Hood\n\n\nDjango REST Framework: Schemas, Hypermedia & Client Libraries\n\n\n\n\nTutorials\n\n\n\n\nDjango REST Framework Part 1\n\n\nDjango REST Framework in Your PJ's!\n\n\nBuilding a REST API Using Django & Django REST Framework\n\n\nBlog API with Django REST Framework\n\n\nEmber and Django Part 1\n\n\nDjango REST Framework Image Upload Tutorial (with AngularJS)\n\n\nDjango REST Framework Tutorials\n\n\n\n\nArticles\n\n\n\n\nWeb API performance: Profiling Django REST Framework\n\n\nAPI Development with Django and Django REST Framework\n\n\nIntegrating Pandas, Django REST Framework and Bokeh\n\n\nControlling Uncertainty on Web Applications and APIs\n\n\nFull Text Search in Django REST Framework with Database Backends\n\n\nOAuth2 Authentication with Django REST Framework and Custom Third-Party OAuth2 Backends\n\n\nNested Resources with Django REST Framework\n\n\nImage Fields with Django REST Framework\n\n\nChatbot Using Django REST Framework + api.ai + Slack\u200a\u2014\u200aPart 1/3\n\n\nNew Django Admin with DRF and EmberJS... What are the News?\n\n\nBlog posts about Django REST Framework\n\n\n\n\nDocumentations\n\n\n\n\nClassy Django REST Framework\n\n\nDRF-schema-adapter\n\n\n\n\nWant your Django REST Framework talk/tutorial/article to be added to our website? Or know of a resource that's not yet included here? Please \nsubmit a pull request\n or \nemail us\n!", + "text": "Tutorials and Resources\n\n\nThere are a wide range of resources available for learning and using Django REST framework. We try to keep a comprehensive list available here.\n\n\nBooks\n\n\n\n \n\n \n\n \n\n \n\n \n\n \n\n\n\n\n\nTutorials\n\n\n\n\nBeginner's Guide to the Django REST Framework\n\n\nDjango REST Framework - An Introduction\n\n\nDjango REST Framework Tutorial\n\n\nDjango REST Framework Course\n\n\nBuilding a RESTful API with Django REST Framework\n\n\nGetting Started with Django REST Framework and AngularJS\n\n\nEnd to End Web App with Django REST Framework & AngularJS\n\n\nStart Your API - Django REST Framework Part 1\n\n\nPermissions & Authentication - Django REST Framework Part 2\n\n\nViewSets and Routers - Django REST Framework Part 3\n\n\nDjango REST Framework User Endpoint\n\n\nCheck Credentials Using Django REST Framework\n\n\nCreating a Production Ready API with Python and Django REST Framework \u2013 Part 1\n\n\nCreating a Production Ready API with Python and Django REST Framework \u2013 Part 2\n\n\nDjango REST Framework Tutorial - Build a Blog API\n\n\nDjango REST Framework & React Tutorial - Build a Todo List API\n\n\nTutorial: Django REST with React (Django 2.0)\n\n\n\n\nVideos\n\n\nTalks\n\n\n\n\nLevel Up! Rethinking the Web API Framework\n\n\nHow to Make a Full Fledged REST API with Django OAuth Toolkit\n\n\nDjango REST API - So Easy You Can Learn It in 25 Minutes\n\n\nTom Christie about Django Rest Framework at Django: Under The Hood\n\n\nDjango REST Framework: Schemas, Hypermedia & Client Libraries\n\n\n\n\nTutorials\n\n\n\n\nDjango REST Framework Part 1\n\n\nDjango REST Framework in Your PJ's!\n\n\nBuilding a REST API Using Django & Django REST Framework\n\n\nBlog API with Django REST Framework\n\n\nEmber and Django Part 1\n\n\nDjango REST Framework Image Upload Tutorial (with AngularJS)\n\n\nDjango REST Framework Tutorials\n\n\n\n\nArticles\n\n\n\n\nWeb API performance: Profiling Django REST Framework\n\n\nAPI Development with Django and Django REST Framework\n\n\nIntegrating Pandas, Django REST Framework and Bokeh\n\n\nControlling Uncertainty on Web Applications and APIs\n\n\nFull Text Search in Django REST Framework with Database Backends\n\n\nOAuth2 Authentication with Django REST Framework and Custom Third-Party OAuth2 Backends\n\n\nNested Resources with Django REST Framework\n\n\nImage Fields with Django REST Framework\n\n\nChatbot Using Django REST Framework + api.ai + Slack\u200a\u2014\u200aPart 1/3\n\n\nNew Django Admin with DRF and EmberJS... What are the News?\n\n\nBlog posts about Django REST Framework\n\n\n\n\nDocumentations\n\n\n\n\nClassy Django REST Framework\n\n\nDRF-schema-adapter\n\n\n\n\nWant your Django REST Framework talk/tutorial/article to be added to our website? Or know of a resource that's not yet included here? Please \nsubmit a pull request\n or \nemail us\n!", "title": "Tutorials and Resources" }, { @@ -4697,7 +4732,7 @@ }, { "location": "/topics/tutorials-and-resources/#tutorials", - "text": "Beginner's Guide to the Django REST Framework Django REST Framework - An Introduction Django REST Framework Tutorial Django REST Framework Course Building a RESTful API with Django REST Framework Getting Started with Django REST Framework and AngularJS End to End Web App with Django REST Framework & AngularJS Start Your API - Django REST Framework Part 1 Permissions & Authentication - Django REST Framework Part 2 ViewSets and Routers - Django REST Framework Part 3 Django REST Framework User Endpoint Check Credentials Using Django REST Framework Creating a Production Ready API with Python and Django REST Framework \u2013 Part 1 Creating a Production Ready API with Python and Django REST Framework \u2013 Part 2", + "text": "Beginner's Guide to the Django REST Framework Django REST Framework - An Introduction Django REST Framework Tutorial Django REST Framework Course Building a RESTful API with Django REST Framework Getting Started with Django REST Framework and AngularJS End to End Web App with Django REST Framework & AngularJS Start Your API - Django REST Framework Part 1 Permissions & Authentication - Django REST Framework Part 2 ViewSets and Routers - Django REST Framework Part 3 Django REST Framework User Endpoint Check Credentials Using Django REST Framework Creating a Production Ready API with Python and Django REST Framework \u2013 Part 1 Creating a Production Ready API with Python and Django REST Framework \u2013 Part 2 Django REST Framework Tutorial - Build a Blog API Django REST Framework & React Tutorial - Build a Todo List API Tutorial: Django REST with React (Django 2.0)", "title": "Tutorials" }, { @@ -4727,7 +4762,7 @@ }, { "location": "/topics/contributing/", - "text": "Contributing to REST framework\n\n\n\n\nThe world can only really be changed one piece at a time. The art is picking that piece.\n\n\n\u2014 \nTim Berners-Lee\n\n\n\n\nThere are many ways you can contribute to Django REST framework. We'd like it to be a community-led project, so please get involved and help shape the future of the project.\n\n\nCommunity\n\n\nThe most important thing you can do to help push the REST framework project forward is to be actively involved wherever possible. Code contributions are often overvalued as being the primary way to get involved in a project, we don't believe that needs to be the case.\n\n\nIf you use REST framework, we'd love you to be vocal about your experiences with it - you might consider writing a blog post about using REST framework, or publishing a tutorial about building a project with a particular JavaScript framework. Experiences from beginners can be particularly helpful because you'll be in the best position to assess which bits of REST framework are more difficult to understand and work with.\n\n\nOther really great ways you can help move the community forward include helping to answer questions on the \ndiscussion group\n, or setting up an \nemail alert on StackOverflow\n so that you get notified of any new questions with the \ndjango-rest-framework\n tag.\n\n\nWhen answering questions make sure to help future contributors find their way around by hyperlinking wherever possible to related threads and tickets, and include backlinks from those items if relevant.\n\n\nCode of conduct\n\n\nPlease keep the tone polite & professional. For some users a discussion on the REST framework mailing list or ticket tracker may be their first engagement with the open source community. First impressions count, so let's try to make everyone feel welcome.\n\n\nBe mindful in the language you choose. As an example, in an environment that is heavily male-dominated, posts that start 'Hey guys,' can come across as unintentionally exclusive. It's just as easy, and more inclusive to use gender neutral language in those situations.\n\n\nThe \nDjango code of conduct\n gives a fuller set of guidelines for participating in community forums.\n\n\nIssues\n\n\nIt's really helpful if you can make sure to address issues on the correct channel. Usage questions should be directed to the \ndiscussion group\n. Feature requests, bug reports and other issues should be raised on the GitHub \nissue tracker\n.\n\n\nSome tips on good issue reporting:\n\n\n\n\nWhen describing issues try to phrase your ticket in terms of the \nbehavior\n you think needs changing rather than the \ncode\n you think need changing.\n\n\nSearch the issue list first for related items, and make sure you're running the latest version of REST framework before reporting an issue.\n\n\nIf reporting a bug, then try to include a pull request with a failing test case. This will help us quickly identify if there is a valid issue, and make sure that it gets fixed more quickly if there is one.\n\n\nFeature requests will often be closed with a recommendation that they be implemented outside of the core REST framework library. Keeping new feature requests implemented as third party libraries allows us to keep down the maintenance overhead of REST framework, so that the focus can be on continued stability, bugfixes, and great documentation.\n\n\nClosing an issue doesn't necessarily mean the end of a discussion. If you believe your issue has been closed incorrectly, explain why and we'll consider if it needs to be reopened.\n\n\n\n\nTriaging issues\n\n\nGetting involved in triaging incoming issues is a good way to start contributing. Every single ticket that comes into the ticket tracker needs to be reviewed in order to determine what the next steps should be. Anyone can help out with this, you just need to be willing to\n\n\n\n\nRead through the ticket - does it make sense, is it missing any context that would help explain it better?\n\n\nIs the ticket reported in the correct place, would it be better suited as a discussion on the discussion group?\n\n\nIf the ticket is a bug report, can you reproduce it? Are you able to write a failing test case that demonstrates the issue and that can be submitted as a pull request?\n\n\nIf the ticket is a feature request, do you agree with it, and could the feature request instead be implemented as a third party package?\n\n\nIf a ticket hasn't had much activity and it addresses something you need, then comment on the ticket and try to find out what's needed to get it moving again.\n\n\n\n\nDevelopment\n\n\nTo start developing on Django REST framework, clone the repo:\n\n\ngit clone git@github.com:encode/django-rest-framework.git\n\n\n\nChanges should broadly follow the \nPEP 8\n style conventions, and we recommend you set up your editor to automatically indicate non-conforming styles.\n\n\nTesting\n\n\nTo run the tests, clone the repository, and then:\n\n\n# Setup the virtual environment\nvirtualenv env\nsource env/bin/activate\npip install django\npip install -r requirements.txt\n\n# Run the tests\n./runtests.py\n\n\n\nTest options\n\n\nRun using a more concise output style.\n\n\n./runtests.py -q\n\n\n\nRun the tests using a more concise output style, no coverage, no flake8.\n\n\n./runtests.py --fast\n\n\n\nDon't run the flake8 code linting.\n\n\n./runtests.py --nolint\n\n\n\nOnly run the flake8 code linting, don't run the tests.\n\n\n./runtests.py --lintonly\n\n\n\nRun the tests for a given test case.\n\n\n./runtests.py MyTestCase\n\n\n\nRun the tests for a given test method.\n\n\n./runtests.py MyTestCase.test_this_method\n\n\n\nShorter form to run the tests for a given test method.\n\n\n./runtests.py test_this_method\n\n\n\nNote: The test case and test method matching is fuzzy and will sometimes run other tests that contain a partial string match to the given command line input.\n\n\nRunning against multiple environments\n\n\nYou can also use the excellent \ntox\n testing tool to run the tests against all supported versions of Python and Django. Install \ntox\n globally, and then simply run:\n\n\ntox\n\n\n\nPull requests\n\n\nIt's a good idea to make pull requests early on. A pull request represents the start of a discussion, and doesn't necessarily need to be the final, finished submission.\n\n\nIt's also always best to make a new branch before starting work on a pull request. This means that you'll be able to later switch back to working on another separate issue without interfering with an ongoing pull requests.\n\n\nIt's also useful to remember that if you have an outstanding pull request then pushing new commits to your GitHub repo will also automatically update the pull requests.\n\n\nGitHub's documentation for working on pull requests is \navailable here\n.\n\n\nAlways run the tests before submitting pull requests, and ideally run \ntox\n in order to check that your modifications are compatible with both Python 2 and Python 3, and that they run properly on all supported versions of Django.\n\n\nOnce you've made a pull request take a look at the Travis build status in the GitHub interface and make sure the tests are running as you'd expect.\n\n\n\n\nAbove: Travis build notifications\n\n\nManaging compatibility issues\n\n\nSometimes, in order to ensure your code works on various different versions of Django, Python or third party libraries, you'll need to run slightly different code depending on the environment. Any code that branches in this way should be isolated into the \ncompat.py\n module, and should provide a single common interface that the rest of the codebase can use.\n\n\nDocumentation\n\n\nThe documentation for REST framework is built from the \nMarkdown\n source files in \nthe docs directory\n.\n\n\nThere are many great Markdown editors that make working with the documentation really easy. The \nMou editor for Mac\n is one such editor that comes highly recommended.\n\n\nBuilding the documentation\n\n\nTo build the documentation, install MkDocs with \npip install mkdocs\n and then run the following command.\n\n\nmkdocs build\n\n\n\nThis will build the documentation into the \nsite\n directory.\n\n\nYou can build the documentation and open a preview in a browser window by using the \nserve\n command.\n\n\nmkdocs serve\n\n\n\nLanguage style\n\n\nDocumentation should be in American English. The tone of the documentation is very important - try to stick to a simple, plain, objective and well-balanced style where possible.\n\n\nSome other tips:\n\n\n\n\nKeep paragraphs reasonably short.\n\n\nDon't use abbreviations such as 'e.g.' but instead use the long form, such as 'For example'.\n\n\n\n\nMarkdown style\n\n\nThere are a couple of conventions you should follow when working on the documentation.\n\n\n1. Headers\n\n\nHeaders should use the hash style. For example:\n\n\n### Some important topic\n\n\n\nThe underline style should not be used. \nDon't do this:\n\n\nSome important topic\n====================\n\n\n\n2. Links\n\n\nLinks should always use the reference style, with the referenced hyperlinks kept at the end of the document.\n\n\nHere is a link to [some other thing][other-thing].\n\nMore text...\n\n[other-thing]: http://example.com/other/thing\n\n\n\nThis style helps keep the documentation source consistent and readable.\n\n\nIf you are hyperlinking to another REST framework document, you should use a relative link, and link to the \n.md\n suffix. For example:\n\n\n[authentication]: ../api-guide/authentication.md\n\n\n\nLinking in this style means you'll be able to click the hyperlink in your Markdown editor to open the referenced document. When the documentation is built, these links will be converted into regular links to HTML pages.\n\n\n3. Notes\n\n\nIf you want to draw attention to a note or warning, use a pair of enclosing lines, like so:\n\n\n---\n\n**Note:** A useful documentation note.\n\n---", + "text": "Contributing to REST framework\n\n\n\n\nThe world can only really be changed one piece at a time. The art is picking that piece.\n\n\n\u2014 \nTim Berners-Lee\n\n\n\n\nThere are many ways you can contribute to Django REST framework. We'd like it to be a community-led project, so please get involved and help shape the future of the project.\n\n\nCommunity\n\n\nThe most important thing you can do to help push the REST framework project forward is to be actively involved wherever possible. Code contributions are often overvalued as being the primary way to get involved in a project, we don't believe that needs to be the case.\n\n\nIf you use REST framework, we'd love you to be vocal about your experiences with it - you might consider writing a blog post about using REST framework, or publishing a tutorial about building a project with a particular JavaScript framework. Experiences from beginners can be particularly helpful because you'll be in the best position to assess which bits of REST framework are more difficult to understand and work with.\n\n\nOther really great ways you can help move the community forward include helping to answer questions on the \ndiscussion group\n, or setting up an \nemail alert on StackOverflow\n so that you get notified of any new questions with the \ndjango-rest-framework\n tag.\n\n\nWhen answering questions make sure to help future contributors find their way around by hyperlinking wherever possible to related threads and tickets, and include backlinks from those items if relevant.\n\n\nCode of conduct\n\n\nPlease keep the tone polite & professional. For some users a discussion on the REST framework mailing list or ticket tracker may be their first engagement with the open source community. First impressions count, so let's try to make everyone feel welcome.\n\n\nBe mindful in the language you choose. As an example, in an environment that is heavily male-dominated, posts that start 'Hey guys,' can come across as unintentionally exclusive. It's just as easy, and more inclusive to use gender neutral language in those situations.\n\n\nThe \nDjango code of conduct\n gives a fuller set of guidelines for participating in community forums.\n\n\nIssues\n\n\nIt's really helpful if you can make sure to address issues on the correct channel. Usage questions should be directed to the \ndiscussion group\n. Feature requests, bug reports and other issues should be raised on the GitHub \nissue tracker\n.\n\n\nSome tips on good issue reporting:\n\n\n\n\nWhen describing issues try to phrase your ticket in terms of the \nbehavior\n you think needs changing rather than the \ncode\n you think need changing.\n\n\nSearch the issue list first for related items, and make sure you're running the latest version of REST framework before reporting an issue.\n\n\nIf reporting a bug, then try to include a pull request with a failing test case. This will help us quickly identify if there is a valid issue, and make sure that it gets fixed more quickly if there is one.\n\n\nFeature requests will often be closed with a recommendation that they be implemented outside of the core REST framework library. Keeping new feature requests implemented as third party libraries allows us to keep down the maintenance overhead of REST framework, so that the focus can be on continued stability, bugfixes, and great documentation.\n\n\nClosing an issue doesn't necessarily mean the end of a discussion. If you believe your issue has been closed incorrectly, explain why and we'll consider if it needs to be reopened.\n\n\n\n\nTriaging issues\n\n\nGetting involved in triaging incoming issues is a good way to start contributing. Every single ticket that comes into the ticket tracker needs to be reviewed in order to determine what the next steps should be. Anyone can help out with this, you just need to be willing to\n\n\n\n\nRead through the ticket - does it make sense, is it missing any context that would help explain it better?\n\n\nIs the ticket reported in the correct place, would it be better suited as a discussion on the discussion group?\n\n\nIf the ticket is a bug report, can you reproduce it? Are you able to write a failing test case that demonstrates the issue and that can be submitted as a pull request?\n\n\nIf the ticket is a feature request, do you agree with it, and could the feature request instead be implemented as a third party package?\n\n\nIf a ticket hasn't had much activity and it addresses something you need, then comment on the ticket and try to find out what's needed to get it moving again.\n\n\n\n\nDevelopment\n\n\nTo start developing on Django REST framework, first create a Fork from the\n\nDjango REST Framework repo\n on GitHub.\n\n\nThen clone your fork. The clone command will look like this, with your GitHub\nusername instead of YOUR-USERNAME:\n\n\ngit clone https://github.com/YOUR-USERNAME/Spoon-Knife\n\n\n\nSee GitHub's \nFork a Repo\n Guide for more help.\n\n\nChanges should broadly follow the \nPEP 8\n style conventions, and we recommend you set up your editor to automatically indicate non-conforming styles.\n\n\nTesting\n\n\nTo run the tests, clone the repository, and then:\n\n\n# Setup the virtual environment\nvirtualenv env\nsource env/bin/activate\npip install django\npip install -r requirements.txt\n\n# Run the tests\n./runtests.py\n\n\n\nTest options\n\n\nRun using a more concise output style.\n\n\n./runtests.py -q\n\n\n\nRun the tests using a more concise output style, no coverage, no flake8.\n\n\n./runtests.py --fast\n\n\n\nDon't run the flake8 code linting.\n\n\n./runtests.py --nolint\n\n\n\nOnly run the flake8 code linting, don't run the tests.\n\n\n./runtests.py --lintonly\n\n\n\nRun the tests for a given test case.\n\n\n./runtests.py MyTestCase\n\n\n\nRun the tests for a given test method.\n\n\n./runtests.py MyTestCase.test_this_method\n\n\n\nShorter form to run the tests for a given test method.\n\n\n./runtests.py test_this_method\n\n\n\nNote: The test case and test method matching is fuzzy and will sometimes run other tests that contain a partial string match to the given command line input.\n\n\nRunning against multiple environments\n\n\nYou can also use the excellent \ntox\n testing tool to run the tests against all supported versions of Python and Django. Install \ntox\n globally, and then simply run:\n\n\ntox\n\n\n\nPull requests\n\n\nIt's a good idea to make pull requests early on. A pull request represents the start of a discussion, and doesn't necessarily need to be the final, finished submission.\n\n\nIt's also always best to make a new branch before starting work on a pull request. This means that you'll be able to later switch back to working on another separate issue without interfering with an ongoing pull requests.\n\n\nIt's also useful to remember that if you have an outstanding pull request then pushing new commits to your GitHub repo will also automatically update the pull requests.\n\n\nGitHub's documentation for working on pull requests is \navailable here\n.\n\n\nAlways run the tests before submitting pull requests, and ideally run \ntox\n in order to check that your modifications are compatible with both Python 2 and Python 3, and that they run properly on all supported versions of Django.\n\n\nOnce you've made a pull request take a look at the Travis build status in the GitHub interface and make sure the tests are running as you'd expect.\n\n\n\n\nAbove: Travis build notifications\n\n\nManaging compatibility issues\n\n\nSometimes, in order to ensure your code works on various different versions of Django, Python or third party libraries, you'll need to run slightly different code depending on the environment. Any code that branches in this way should be isolated into the \ncompat.py\n module, and should provide a single common interface that the rest of the codebase can use.\n\n\nDocumentation\n\n\nThe documentation for REST framework is built from the \nMarkdown\n source files in \nthe docs directory\n.\n\n\nThere are many great Markdown editors that make working with the documentation really easy. The \nMou editor for Mac\n is one such editor that comes highly recommended.\n\n\nBuilding the documentation\n\n\nTo build the documentation, install MkDocs with \npip install mkdocs\n and then run the following command.\n\n\nmkdocs build\n\n\n\nThis will build the documentation into the \nsite\n directory.\n\n\nYou can build the documentation and open a preview in a browser window by using the \nserve\n command.\n\n\nmkdocs serve\n\n\n\nLanguage style\n\n\nDocumentation should be in American English. The tone of the documentation is very important - try to stick to a simple, plain, objective and well-balanced style where possible.\n\n\nSome other tips:\n\n\n\n\nKeep paragraphs reasonably short.\n\n\nDon't use abbreviations such as 'e.g.' but instead use the long form, such as 'For example'.\n\n\n\n\nMarkdown style\n\n\nThere are a couple of conventions you should follow when working on the documentation.\n\n\n1. Headers\n\n\nHeaders should use the hash style. For example:\n\n\n### Some important topic\n\n\n\nThe underline style should not be used. \nDon't do this:\n\n\nSome important topic\n====================\n\n\n\n2. Links\n\n\nLinks should always use the reference style, with the referenced hyperlinks kept at the end of the document.\n\n\nHere is a link to [some other thing][other-thing].\n\nMore text...\n\n[other-thing]: http://example.com/other/thing\n\n\n\nThis style helps keep the documentation source consistent and readable.\n\n\nIf you are hyperlinking to another REST framework document, you should use a relative link, and link to the \n.md\n suffix. For example:\n\n\n[authentication]: ../api-guide/authentication.md\n\n\n\nLinking in this style means you'll be able to click the hyperlink in your Markdown editor to open the referenced document. When the documentation is built, these links will be converted into regular links to HTML pages.\n\n\n3. Notes\n\n\nIf you want to draw attention to a note or warning, use a pair of enclosing lines, like so:\n\n\n---\n\n**Note:** A useful documentation note.\n\n---", "title": "Contributing to REST framework" }, { @@ -4757,7 +4792,7 @@ }, { "location": "/topics/contributing/#development", - "text": "To start developing on Django REST framework, clone the repo: git clone git@github.com:encode/django-rest-framework.git Changes should broadly follow the PEP 8 style conventions, and we recommend you set up your editor to automatically indicate non-conforming styles.", + "text": "To start developing on Django REST framework, first create a Fork from the Django REST Framework repo on GitHub. Then clone your fork. The clone command will look like this, with your GitHub\nusername instead of YOUR-USERNAME: git clone https://github.com/YOUR-USERNAME/Spoon-Knife See GitHub's Fork a Repo Guide for more help. Changes should broadly follow the PEP 8 style conventions, and we recommend you set up your editor to automatically indicate non-conforming styles.", "title": "Development" }, { @@ -4892,7 +4927,7 @@ }, { "location": "/topics/jobs/", - "text": "Jobs\n\n\nLooking for a new Django REST Framework related role? On this site we provide a list of job resources that may be helpful. It's also worth checking out if any of \nour sponsors are hiring\n.\n\n\nPlaces to look for Django REST Framework Jobs\n\n\n\n\nhttps://www.djangoproject.com/community/jobs/\n\n\nhttps://www.python.org/jobs/\n\n\nhttps://djangogigs.com\n\n\nhttps://djangojobs.net/jobs/\n\n\nhttp://djangojobbers.com\n\n\nhttps://www.indeed.com/q-Django-jobs.html\n\n\nhttps://stackoverflow.com/jobs/developer-jobs-using-django\n\n\nhttps://www.upwork.com/o/jobs/browse/skill/django-framework/\n\n\nhttps://www.technojobs.co.uk/django-jobs\n\n\nhttps://remoteok.io/remote-django-jobs\n\n\nhttps://www.remotepython.com/jobs/\n\n\n\n\nKnow of any other great resources for Django REST Framework jobs that are missing in our list? Please \nsubmit a pull request\n or \nemail us\n.\n\n\nWonder how else you can help? One of the best ways you can help Django REST Framework is to ask interviewers if their company is signed up for \nREST Framework sponsorship\n yet.", + "text": "Jobs\n\n\nLooking for a new Django REST Framework related role? On this site we provide a list of job resources that may be helpful. It's also worth checking out if any of \nour sponsors are hiring\n.\n\n\nPlaces to look for Django REST Framework Jobs\n\n\n\n\nhttps://www.djangoproject.com/community/jobs/\n\n\nhttps://www.python.org/jobs/\n\n\nhttps://djangogigs.com\n\n\nhttps://djangojobs.net/jobs/\n\n\nhttp://djangojobbers.com\n\n\nhttps://www.indeed.com/q-Django-jobs.html\n\n\nhttps://stackoverflow.com/jobs/developer-jobs-using-django\n\n\nhttps://www.upwork.com/o/jobs/browse/skill/django-framework/\n\n\nhttps://www.technojobs.co.uk/django-jobs\n\n\nhttps://remoteok.io/remote-django-jobs\n\n\nhttps://www.remotepython.com/jobs/\n\n\nhttps://weworkcontract.com/python-contract-jobs\n\n\n\n\nKnow of any other great resources for Django REST Framework jobs that are missing in our list? Please \nsubmit a pull request\n or \nemail us\n.\n\n\nWonder how else you can help? One of the best ways you can help Django REST Framework is to ask interviewers if their company is signed up for \nREST Framework sponsorship\n yet.", "title": "Jobs" }, { @@ -4902,7 +4937,7 @@ }, { "location": "/topics/jobs/#places-to-look-for-django-rest-framework-jobs", - "text": "https://www.djangoproject.com/community/jobs/ https://www.python.org/jobs/ https://djangogigs.com https://djangojobs.net/jobs/ http://djangojobbers.com https://www.indeed.com/q-Django-jobs.html https://stackoverflow.com/jobs/developer-jobs-using-django https://www.upwork.com/o/jobs/browse/skill/django-framework/ https://www.technojobs.co.uk/django-jobs https://remoteok.io/remote-django-jobs https://www.remotepython.com/jobs/ Know of any other great resources for Django REST Framework jobs that are missing in our list? Please submit a pull request or email us . Wonder how else you can help? One of the best ways you can help Django REST Framework is to ask interviewers if their company is signed up for REST Framework sponsorship yet.", + "text": "https://www.djangoproject.com/community/jobs/ https://www.python.org/jobs/ https://djangogigs.com https://djangojobs.net/jobs/ http://djangojobbers.com https://www.indeed.com/q-Django-jobs.html https://stackoverflow.com/jobs/developer-jobs-using-django https://www.upwork.com/o/jobs/browse/skill/django-framework/ https://www.technojobs.co.uk/django-jobs https://remoteok.io/remote-django-jobs https://www.remotepython.com/jobs/ https://weworkcontract.com/python-contract-jobs Know of any other great resources for Django REST Framework jobs that are missing in our list? Please submit a pull request or email us . Wonder how else you can help? One of the best ways you can help Django REST Framework is to ask interviewers if their company is signed up for REST Framework sponsorship yet.", "title": "Places to look for Django REST Framework Jobs" }, { @@ -5687,7 +5722,7 @@ }, { "location": "/topics/release-notes/", - "text": "Release Notes\n\n\n\n\nRelease Early, Release Often\n\n\n\u2014 Eric S. Raymond, \nThe Cathedral and the Bazaar\n.\n\n\n\n\nVersioning\n\n\nMinor version numbers (0.0.x) are used for changes that are API compatible. You should be able to upgrade between minor point releases without any other code changes.\n\n\nMedium version numbers (0.x.0) may include API changes, in line with the \ndeprecation policy\n. You should read the release notes carefully before upgrading between medium point releases.\n\n\nMajor version numbers (x.0.0) are reserved for substantial project milestones.\n\n\nDeprecation policy\n\n\nREST framework releases follow a formal deprecation policy, which is in line with \nDjango's deprecation policy\n.\n\n\nThe timeline for deprecation of a feature present in version 1.0 would work as follows:\n\n\n\n\n\n\nVersion 1.1 would remain \nfully backwards compatible\n with 1.0, but would raise \nPendingDeprecationWarning\n warnings if you use the feature that are due to be deprecated. These warnings are \nsilent by default\n, but can be explicitly enabled when you're ready to start migrating any required changes. For example if you start running your tests using \npython -Wd manage.py test\n, you'll be warned of any API changes you need to make.\n\n\n\n\n\n\nVersion 1.2 would escalate these warnings to \nDeprecationWarning\n, which is loud by default.\n\n\n\n\n\n\nVersion 1.3 would remove the deprecated bits of API entirely.\n\n\n\n\n\n\nNote that in line with Django's policy, any parts of the framework not mentioned in the documentation should generally be considered private API, and may be subject to change.\n\n\nUpgrading\n\n\nTo upgrade Django REST framework to the latest version, use pip:\n\n\npip install -U djangorestframework\n\n\n\nYou can determine your currently installed version using \npip freeze\n:\n\n\npip freeze | grep djangorestframework\n\n\n\n\n\n3.7.x series\n\n\n3.7.7\n\n\nDate\n: \n21st December 2017\n\n\n\n\nFix typo to include *.mo locale files to packaging. \n#5697\n, \n#5695\n\n\n\n\n3.7.6\n\n\nDate\n: \n21st December 2017\n\n\n\n\nAdd missing *.ico icon files to packaging.\n\n\n\n\n3.7.5\n\n\nDate\n: \n21st December 2017\n\n\n\n\nAdd missing *.woff2 font files to packaging. \n#5692\n\n\nAdd missing *.mo locale files to packaging. \n#5695\n, \n#5696\n\n\n\n\n3.7.4\n\n\nDate\n: \n20th December 2017\n\n\n\n\n\n\nSchema: Extract method for \nmanual_fields\n processing \n#5633\n\n\nAllows for easier customisation of \nmanual_fields\n processing, for example\nto provide per-method manual fields. \nAutoSchema\n adds \nget_manual_fields\n,\nas the intended override point, and a utility method \nupdate_fields\n, to\nhandle by-name field replacement from a list, which, in general, you are not\nexpected to override.\n\n\nNote: \nAutoSchema.__init__\n now ensures \nmanual_fields\n is a list.\nPreviously may have been stored internally as \nNone\n.\n\n\n\n\n\n\nRemove ulrparse compatability shim; use six instead \n#5579\n\n\n\n\nDrop compat wrapper for \nTimeDelta.total_seconds()\n \n#5577\n\n\nClean up all whitespace throughout project \n#5578\n\n\nCompat cleanup \n#5581\n\n\nAdd pygments CSS block in browsable API views \n#5584\n \n#5587\n\n\nRemove \nset_rollback()\n from compat \n#5591\n\n\nFix request body/POST access \n#5590\n\n\nRename test to reference correct issue \n#5610\n\n\nDocumentation Fixes \n#5611\n \n#5612\n\n\nRemove references to unsupported Django versions in docs and code \n#5602\n\n\nTest Serializer exclude for declared fields \n#5599\n\n\nFixed schema generation for filter backends \n#5613\n\n\nMinor cleanup for ModelSerializer tests \n#5598\n\n\nReimplement request attribute access w/ \n__getattr__\n \n#5617\n\n\nFixed SchemaJSRenderer renders invalid Javascript \n#5607\n\n\nMake Django 2.0 support official/explicit \n#5619\n\n\nPerform type check on passed request argument \n#5618\n\n\nFix AttributeError hiding on request authenticators \n#5600\n\n\nUpdate test requirements \n#5626\n\n\nDocs: \nSerializer._declared_fields\n enable modifying fields on a serializer \n#5629\n\n\nFix packaging \n#5624\n\n\nFix readme rendering for PyPI, add readme build to CI \n#5625\n\n\nUpdate tutorial \n#5622\n\n\nNon-required fields with \nallow_null=True\n should not imply a default value \n#5639\n\n\nDocs: Add \nallow_null\n serialization output note \n#5641\n\n\nUpdate to use the Django 2.0 release in tox.ini \n#5645\n\n\nFix \nSerializer.data\n for Browsable API rendering when provided invalid \ndata\n \n#5646\n\n\nDocs: Note AutoSchema limitations on bare APIView \n#5649\n\n\nAdd \n.basename\n and \n.reverse_action()\n to ViewSet \n#5648\n\n\nDocs: Fix typos in serializers documentation \n#5652\n\n\nFix \noverride_settings\n compat \n#5668\n\n\nAdd DEFAULT_SCHEMA_CLASS setting \n#5658\n\n\nAdd docs note re generated BooleanField being \nrequired=False\n \n#5665\n\n\nAdd 'dist' build \n#5656\n\n\nFix typo in docstring \n#5678\n\n\nDocs: Add \nUNAUTHENTICATED_USER = None\n note \n#5679\n\n\nUpdate OPTIONS example from \u201cDocumenting Your API\u201d \n#5680\n\n\nDocs: Add note on object permissions for FBVs \n#5681\n\n\nDocs: Add example to \nto_representation\n docs \n#5682\n\n\nAdd link to Classy DRF in docs \n#5683\n\n\nDocument ViewSet.action \n#5685\n\n\nFix schema docs typo \n#5687\n\n\nFix URL pattern parsing in schema generation \n#5689\n\n\nAdd example using \nsource=\u2018*\u2019\n to custom field docs. \n#5688\n\n\nFix format_suffix_patterns behavior with Django 2 path() routes \n#5691\n\n\n\n\n3.7.3\n\n\nDate\n: \n6th November 2017\n\n\n\n\nFix \nAppRegistryNotReady\n error from contrib.auth view imports \n#5567\n\n\n\n\n3.7.2\n\n\nDate\n: \n6th November 2017\n\n\n\n\nFixed Django 2.1 compatibility due to removal of django.contrib.auth.login()/logout() views. \n#5510\n\n\nAdd missing import for TextLexer. \n#5512\n\n\nAdding examples and documentation for caching \n#5514\n\n\nInclude date and date-time format for schema generation \n#5511\n\n\nUse triple backticks for markdown code blocks \n#5513\n\n\nInteractive docs - make bottom sidebar items sticky \n#5516\n\n\nClarify pagination system check \n#5524\n\n\nStop JSONBoundField mangling invalid JSON \n#5527\n\n\nHave JSONField render as textarea in Browsable API \n#5530\n\n\nSchema: Exclude OPTIONS/HEAD for ViewSet actions \n#5532\n\n\nFix ordering for dotted sources \n#5533\n\n\nFix: Fields with \nallow_null=True\n should imply a default serialization value \n#5518\n\n\nEnsure Location header is strictly a 'str', not subclass. \n#5544\n\n\nAdd import to example in api-guide/parsers \n#5547\n\n\nCatch OverflowError for \"out of range\" datetimes \n#5546\n\n\nAdd djangorestframework-rapidjson to third party packages \n#5549\n\n\nIncrease test coverage for \ndrf_create_token\n command \n#5550\n\n\nAdd trove classifier for Python 3.6 support. \n#5555\n\n\nAdd pip cache support to the Travis CI configuration \n#5556\n\n\nRename [\nwheel\n] section to [\nbdist_wheel\n] as the former is legacy \n#5557\n\n\nFix invalid escape sequence deprecation warnings \n#5560\n\n\nAdd interactive docs error template \n#5548\n\n\nAdd rounding parameter to DecimalField \n#5562\n\n\nFix all BytesWarning caught during tests \n#5561\n\n\nUse dict and set literals instead of calls to dict() and set() \n#5559\n\n\nChange ImageField validation pattern, use validators from DjangoImageField \n#5539\n\n\nFix processing unicode symbols in query_string by Python 2 \n#5552\n\n\n\n\n3.7.1\n\n\nDate\n: \n16th October 2017\n\n\n\n\nFix Interactive documentation always uses false for boolean fields in requests \n#5492\n\n\nImprove compatibility with Django 2.0 alpha. \n#5500\n \n#5503\n\n\nImproved handling of schema naming collisions \n#5486\n\n\nAdded additional docs and tests around providing a default value for dotted \nsource\n fields \n#5489\n\n\n\n\n3.7.0\n\n\nDate\n: \n6th October 2017\n\n\n\n\nFix \nDjangoModelPermissions\n to ensure user authentication before calling the view's \nget_queryset()\n method. As a side effect, this changes the order of the HTTP method permissions and authentication checks, and 405 responses will only be returned when authenticated. If you want to replicate the old behavior, see the PR for details. \n#5376\n\n\nDeprecated \nexclude_from_schema\n on \nAPIView\n and \napi_view\n decorator. Set \nschema = None\n or \n@schema(None)\n as appropriate. \n#5422\n\n\n\n\nTimezone-aware \nDateTimeField\ns now respect active or default \ntimezone\n during serialization, instead of always using UTC. \n#5435\n\n\nResolves inconsistency whereby instances were serialised with supplied datetime for \ncreate\n but UTC for \nretrieve\n. \n#3732\n\n\nPossible backwards compatibility break\n if you were relying on datetime strings being UTC. Have client interpret datetimes or \nset default or active timezone (docs)\n to UTC if needed.\n\n\n\n\n\n\nRemoved DjangoFilterBackend inline with deprecation policy. Use \ndjango_filters.rest_framework.FilterSet\n and/or \ndjango_filters.rest_framework.DjangoFilterBackend\n instead. \n#5273\n\n\n\n\nDon't strip microseconds from \ntime\n when encoding. Makes consistent with \ndatetime\n.\n \nBC Change\n: Previously only milliseconds were encoded. \n#5440\n\n\nAdded \nSTRICT_JSON\n setting (default \nTrue\n) to raise exception for the extended float values (\nnan\n, \ninf\n, \n-inf\n) accepted by Python's \njson\n module.\n \nBC Change\n: Previously these values would converted to corresponding strings. Set \nSTRICT_JSON\n to \nFalse\n to restore the previous behaviour. \n#5265\n\n\nAdd support for \npage_size\n parameter in CursorPaginator class \n#5250\n\n\nMake \nDEFAULT_PAGINATION_CLASS\n \nNone\n by default.\n \nBC Change\n: If your were \njust\n setting \nPAGE_SIZE\n to enable pagination you will need to add \nDEFAULT_PAGINATION_CLASS\n.\n The previous default was \nrest_framework.pagination.PageNumberPagination\n. There is a system check warning to catch this case. You may silence that if you are setting pagination class on a per-view basis. \n#5170\n\n\nCatch \nAPIException\n from \nget_serializer_fields\n in schema generation. \n#5443\n\n\nAllow custom authentication and permission classes when using \ninclude_docs_urls\n \n#5448\n\n\nDefer translated string evaluation on validators. \n#5452\n\n\nAdded default value for 'detail' param into 'ValidationError' exception \n#5342\n\n\nAdjust schema get_filter_fields rules to match framework \n#5454\n\n\nUpdated test matrix to add Django 2.0 and drop Django 1.8 & 1.9\n \nBC Change\n: This removes Django 1.8 and Django 1.9 from Django REST Framework supported versions. \n#5457\n\n\nFixed a deprecation warning in serializers.ModelField \n#5058\n\n\nAdded a more explicit error message when \nget_queryset\n returned \nNone\n \n#5348\n\n\nFix docs for Response \ndata\n description \n#5361\n\n\nFix \npycache\n/.pyc excludes when packaging \n#5373\n\n\nFix default value handling for dotted sources \n#5375\n\n\nEnsure content_type is set when passing empty body to RequestFactory \n#5351\n\n\nFix ErrorDetail Documentation \n#5380\n\n\nAllow optional content in the generic content form \n#5372\n\n\nUpdated supported values for the NullBooleanField \n#5387\n\n\nFix ModelSerializer custom named fields with source on model \n#5388\n\n\nFixed the MultipleFieldLookupMixin documentation example to properly check for object level permission \n#5398\n\n\nUpdate get_object() example in permissions.md \n#5401\n\n\nFix authtoken management command \n#5415\n\n\nFix schema generation markdown \n#5421\n\n\nAllow \nChoiceField.choices\n to be set dynamically \n#5426\n\n\nAdd the project layout to the quickstart \n#5434\n\n\nReuse 'apply_markdown' function in 'render_markdown' templatetag \n#5469\n\n\nAdded links to \ndrf-openapi\n package in docs \n#5470\n\n\nAdded docstrings code highlighting with pygments \n#5462\n\n\nFixed documentation rendering for views named \ndata\n \n#5472\n\n\nDocs: Clarified 'to_internal_value()' validation behavior \n#5466\n\n\nFix missing six.text_type() call on APIException.\nstr\n \n#5476\n\n\nDocument documentation.py \n#5478\n\n\nFix naming collisions in Schema Generation \n#5464\n\n\nCall Django's authenticate function with the request object \n#5295\n\n\nUpdate coreapi JS to 0.1.1 \n#5479\n\n\nHave \nis_list_view\n recognise RetrieveModel\u2026 views \n#5480\n\n\nRemove Django 1.8 & 1.9 compatibility code \n#5481\n\n\nRemove deprecated schema code from DefaultRouter \n#5482\n\n\nRefactor schema generation to allow per-view customisation.\n \nBC Change\n: \nSchemaGenerator.get_serializer_fields\n has been refactored as \nAutoSchema.get_serializer_fields\n and drops the \nview\n argument [#5354][gh5354]\n\n\n\n\n3.6.x series\n\n\n3.6.4\n\n\nDate\n: \n21st August 2017\n\n\n\n\nIgnore any invalidly formed query parameters for OrderingFilter. \n#5131\n\n\nImprove memory footprint when reading large JSON requests. \n#5147\n\n\nFix schema generation for pagination. \n#5161\n\n\nFix exception when \nHTML_CUTOFF\n is set to \nNone\n. \n#5174\n\n\nFix browsable API not supporting \nmultipart/form-data\n correctly. \n#5176\n\n\nFixed \ntest_hyperlinked_related_lookup_url_encoded_exists\n. \n#5179\n\n\nMake sure max_length is in FileField kwargs. \n#5186\n\n\nFix \nlist_route\n & \ndetail_route\n with kwargs contains curly bracket in \nurl_path\n \n#5187\n\n\nAdd Django manage command to create a DRF user Token. \n#5188\n\n\nEnsure API documentation templates do not check for user authentication \n#5162\n\n\nFix special case where OneToOneField is also primary key. \n#5192\n\n\nAdded aria-label and a new region for accessibility purposes in base.html \n#5196\n\n\nQuote nested API parameters in api.js. \n#5214\n\n\nSet ViewSet args/kwargs/request before dispatch. \n#5229\n\n\nAdded unicode support to SlugField. \n#5231\n\n\nFix HiddenField appears in Raw Data form initial content. \n#5259\n\n\nRaise validation error on invalid timezone parsing. \n#5261\n\n\nFix SearchFilter to-many behavior/performance. \n#5264\n\n\nSimplified chained comparisons and minor code fixes. \n#5276\n\n\nRemoteUserAuthentication, docs, and tests. \n#5306\n\n\nRevert \"Cached the field's root and context property\" \n#5313\n\n\nFix introspection of list field in schema. \n#5326\n\n\nFix interactive docs for multiple nested and extra methods. \n#5334\n\n\nFix/remove undefined template var \"schema\" \n#5346\n\n\n\n\n3.6.3\n\n\nDate\n: \n12th May 2017\n\n\n\n\nRaise 404 if a URL lookup results in ValidationError. (\n#5126\n)\n\n\nHonor http_method_names on class based view, when generating API schemas. (\n#5085\n)\n\n\nAllow overridden \nget_limit\n in LimitOffsetPagination to return all records. (\n#4437\n)\n\n\nFix partial update for the ListSerializer. (\n#4222\n)\n\n\nRender JSONField control correctly in browsable API. (\n#4999\n, \n#5042\n)\n\n\nRaise validation errors for invalid datetime in given timezone. (\n#4987\n)\n\n\nSupport restricting doc & schema shortcuts to a subset of urls. (\n#4979\n)\n\n\nResolve SchemaGenerator error with paginators that have no \npage_size\n attribute. (\n#5086\n, \n#3692\n)\n\n\nResolve HyperlinkedRelatedField exception on string with %20 instead of space. (\n#4748\n, \n#5078\n)\n\n\nCustomizable schema generator classes. (\n#5082\n)\n\n\nUpdate existing vary headers in response instead of overwriting them. (\n#5047\n)\n\n\nSupport passing \n.as_view()\n to view instance. (\n#5053\n)\n\n\nUse correct exception handler when settings overridden on a view. (\n#5055\n, \n#5054\n)\n\n\nUpdate Boolean field to support 'yes' and 'no' values. (\n#5038\n)\n\n\nFix unique validator for ChoiceField. (\n#5004\n, \n#5026\n, \n#5028\n)\n\n\nJavaScript cleanups in API Docs. (\n#5001\n)\n\n\nInclude URL path regexs in API schemas where valid. (\n#5014\n)\n\n\nCorrectly set scheme in coreapi TokenAuthentication. (\n#5000\n, \n#4994\n)\n\n\nHEAD requests on ViewSets should not return 405. (\n#4705\n, \n#4973\n, \n#4864\n)\n\n\nSupport usage of 'source' in \nextra_kwargs\n. (\n#4688\n)\n\n\nFix invalid content type for schema.js (\n#4968\n)\n\n\nFix DjangoFilterBackend inheritance issues. (\n#5089\n, \n#5117\n)\n\n\n\n\n3.6.2\n\n\nDate\n: \n10th March 2017\n\n\n\n\nSupport for Safari & IE in API docs. (\n#4959\n, \n#4961\n)\n\n\nAdd missing \nmark_safe\n in API docs template tags. (\n#4952\n, \n#4953\n)\n\n\nAdd missing glyphicon fonts. (\n#4950\n, \n#4951\n)\n\n\nFix One-to-one fields in API docs. (\n#4955\n, \n#4956\n)\n\n\nTest clean ups. (\n#4949\n)\n\n\n\n\n3.6.1\n\n\nDate\n: \n9th March 2017\n\n\n\n\nEnsure \nmarkdown\n dependency is optional. (\n#4947\n)\n\n\n\n\n3.6.0\n\n\nDate\n: \n9th March 2017\n\n\nSee the \nrelease announcement\n.\n\n\n\n\n3.5.x series\n\n\n3.5.4\n\n\nDate\n: \n10th February 2017\n\n\n\n\nAdd max_length and min_length arguments for ListField. (\n#4877\n)\n\n\nAdd per-view custom exception handler support. (\n#4753\n)\n\n\nSupport disabling of declared fields on serializer subclasses. (\n#4764\n)\n\n\nSupport custom view names on \n@list_route\n and \n@detail_route\n endpoints. (\n#4821\n)\n\n\nCorrect labels for fields in login template when custom user model is used. (\n#4841\n)\n\n\nWhitespace fixes for descriptions generated from docstrings. (\n#4759\n, \n#4869\n, \n#4870\n)\n\n\nBetter error reporting when schemas are returned by views without a schema renderer. (\n#4790\n)\n\n\nFix for returned response of \nPUT\n requests when \nprefetch_related\n is used. (\n#4661\n, \n#4668\n)\n\n\nFix for breadcrumb view names. (\n#4750\n)\n\n\nFix for RequestsClient ensuring fully qualified URLs. (\n#4678\n)\n\n\nFix for incorrect behavior of writable-nested fields check in some cases. (\n#4634\n, \n#4669\n)\n\n\nResolve Django deprecation warnings. (\n#4712\n)\n\n\nVarious cleanup of test cases.\n\n\n\n\n3.5.3\n\n\nDate\n: \n7th November 2016\n\n\n\n\nDon't raise incorrect FilterSet deprecation warnings. (\n#4660\n, \n#4643\n, \n#4644\n)\n\n\nSchema generation should not raise 404 when a view permission class does. (\n#4645\n, \n#4646\n)\n\n\nAdd \nautofocus\n support for input controls. (\n#4650\n)\n\n\n\n\n3.5.2\n\n\nDate\n: \n1st November 2016\n\n\n\n\nRestore exception tracebacks in Python 2.7. (\n#4631\n, \n#4638\n)\n\n\nProperly display dicts in the admin console. (\n#4532\n, \n#4636\n)\n\n\nFix is_simple_callable with variable args, kwargs. (\n#4622\n, \n#4602\n)\n\n\nSupport 'on'/'off' literals with BooleanField. (\n#4640\n, \n#4624\n)\n\n\nEnable cursor pagination of value querysets. (\n#4569\n)\n\n\nFix support of get_full_details() for Throttled exceptions. (\n#4627\n)\n\n\nFix FilterSet proxy. (\n#4620\n)\n\n\nMake serializer fields import explicit. (\n#4628\n)\n\n\nDrop redundant requests adapter. (\n#4639\n)\n\n\n\n\n3.5.1\n\n\nDate\n: \n21st October 2016\n\n\n\n\nMake \nrest_framework/compat.py\n imports. (\n#4612\n, \n#4608\n, \n#4601\n)\n\n\nFix bug in schema base path generation. (\n#4611\n, \n#4605\n)\n\n\nFix broken case of ListSerializer with single item. (\n#4609\n, \n#4606\n)\n\n\nRemove bare \nraise\n for Python 3.5 compat. (\n#4600\n)\n\n\n\n\n3.5.0\n\n\nDate\n: \n20th October 2016\n\n\n\n\n3.4.x series\n\n\n3.4.7\n\n\nDate\n: \n21st September 2016\n\n\n\n\nFallback behavior for request parsing when request.POST already accessed. (\n#3951\n, \n#4500\n)\n\n\nFix regression of \nRegexField\n. (\n#4489\n, \n#4490\n, \n#2617\n)\n\n\nMissing comma in \nadmin.html\n causing CSRF error. (\n#4472\n, \n#4473\n)\n\n\nFix response rendering with empty context. (\n#4495\n)\n\n\nFix indentation regression in API listing. (\n#4493\n)\n\n\nFixed an issue where the incorrect value is set to \nResolverMatch.func_name\n of api_view decorated view. (\n#4465\n, \n#4462\n)\n\n\nFix \nAPIClient.get()\n when path contains unicode arguments (\n#4458\n)\n\n\n\n\n3.4.6\n\n\nDate\n: \n23rd August 2016\n\n\n\n\nFix malformed Javascript in browsable API. (\n#4435\n)\n\n\nSkip HiddenField from Schema fields. (\n#4425\n, \n#4429\n)\n\n\nImprove Create to show the original exception traceback. (\n#3508\n)\n\n\nFix \nAdminRenderer\n display of PK only related fields. (\n#4419\n, \n#4423\n)\n\n\n\n\n3.4.5\n\n\nDate\n: \n19th August 2016\n\n\n\n\nImprove debug error handling. (\n#4416\n, \n#4409\n)\n\n\nAllow custom CSRF_HEADER_NAME setting. (\n#4415\n, \n#4410\n)\n\n\nInclude .action attribute on viewsets when generating schemas. (\n#4408\n, \n#4398\n)\n\n\nDo not include request.FILES items in request.POST. (\n#4407\n)\n\n\nFix rendering of checkbox multiple. (\n#4403\n)\n\n\nFix docstring of Field.get_default. (\n#4404\n)\n\n\nReplace utf8 character with its ascii counterpart in README. (\n#4412\n)\n\n\n\n\n3.4.4\n\n\nDate\n: \n12th August 2016\n\n\n\n\nEnsure views are fully initialized when generating schemas. (\n#4373\n, \n#4382\n, \n#4383\n, \n#4279\n, \n#4278\n)\n\n\nAdd form field descriptions to schemas. (\n#4387\n)\n\n\nFix category generation for schema endpoints. (\n#4391\n, \n#4394\n, \n#4390\n, \n#4386\n, \n#4376\n, \n#4329\n)\n\n\nDon't strip empty query params when paginating. (\n#4392\n, \n#4393\n, \n#4260\n)\n\n\nDo not re-run query for empty results with LimitOffsetPagination. (\n#4201\n, \n#4388\n)\n\n\nStricter type validation for CharField. (\n#4380\n, \n#3394\n)\n\n\nRelatedField.choices should preserve non-string values. (\n#4111\n, \n#4379\n, \n#3365\n)\n\n\nTest case for rendering checkboxes in vertical form style. (\n#4378\n, \n#3868\n, \n#3868\n)\n\n\nShow error traceback HTML in browsable API (\n#4042\n, \n#4172\n)\n\n\nFix handling of ALLOWED_VERSIONS and no DEFAULT_VERSION. \n#4370\n\n\nAllow \nmax_digits=None\n on DecimalField. (\n#4377\n, \n#4372\n)\n\n\nLimit queryset when rendering relational choices. (\n#4375\n, \n#4122\n, \n#3329\n, \n#3330\n, \n#3877\n)\n\n\nResolve form display with ChoiceField, MultipleChoiceField and non-string choices. (\n#4374\n, \n#4119\n, \n#4121\n, \n#4137\n, \n#4120\n)\n\n\nFix call to TemplateHTMLRenderer.resolve_context() fallback method. (\n#4371\n)\n\n\n\n\n3.4.3\n\n\nDate\n: \n5th August 2016\n\n\n\n\nInclude fallback for users of older TemplateHTMLRenderer internal API. (\n#4361\n)\n\n\n\n\n3.4.2\n\n\nDate\n: \n5th August 2016\n\n\n\n\nInclude kwargs passed to 'as_view' when generating schemas. (\n#4359\n, \n#4330\n, \n#4331\n)\n\n\nAccess \nrequest.user.is_authenticated\n as property not method, under Django 1.10+ (\n#4358\n, \n#4354\n)\n\n\nFilter HEAD out from schemas. (\n#4357\n)\n\n\nextra_kwargs takes precedence over uniqueness kwargs. (\n#4198\n, \n#4199\n, \n#4349\n)\n\n\nCorrect descriptions when tabs are used in code indentation. (\n#4345\n, \n#4347\n)*\n\n\nChange template context generation in TemplateHTMLRenderer. (\n#4236\n)\n\n\nSerializer defaults should not be included in partial updates. (\n#4346\n, \n#3565\n)\n\n\nConsistent behavior & descriptive error from FileUploadParser when filename not included. (\n#4340\n, \n#3610\n, \n#4292\n, \n#4296\n)\n\n\nDecimalField quantizes incoming digitals. (\n#4339\n, \n#4318\n)\n\n\nHandle non-string input for IP fields. (\n#4335\n, \n#4336\n, \n#4338\n)\n\n\nFix leading slash handling when Schema generation includes a root URL. (\n#4332\n)\n\n\nTest cases for DictField with allow_null options. (\n#4348\n)\n\n\nUpdate tests from Django 1.10 beta to Django 1.10. (\n#4344\n)\n\n\n\n\n3.4.1\n\n\nDate\n: \n28th July 2016\n\n\n\n\nAdded \nroot_renderers\n argument to \nDefaultRouter\n. (\n#4323\n, \n#4268\n)\n\n\nAdded \nurl\n and \nschema_url\n arguments. (\n#4321\n, \n#4308\n, \n#4305\n)\n\n\nUnique together checks should apply to read-only fields which have a default. (\n#4316\n, \n#4294\n)\n\n\nSet view.format_kwarg in schema generator. (\n#4293\n, \n#4315\n)\n\n\nFix schema generator for views with \npagination_class = None\n. (\n#4314\n, \n#4289\n)\n\n\nFix schema generator for views with no \nget_serializer_class\n. (\n#4265\n, \n#4285\n)\n\n\nFixes for media type parameters in \nAccept\n and \nContent-Type\n headers. (\n#4287\n, \n#4313\n, \n#4281\n)\n\n\nUse verbose_name instead of object_name in error messages. (\n#4299\n)\n\n\nMinor version update to Twitter Bootstrap. (\n#4307\n)\n\n\nSearchFilter raises error when using with related field. (\n#4302\n, \n#4303\n, \n#4298\n)\n\n\nAdding support for RFC 4918 status codes. (\n#4291\n)\n\n\nAdd LICENSE.md to the built wheel. (\n#4270\n)\n\n\nSerializing \"complex\" field returns None instead of the value since 3.4 (\n#4272\n, \n#4273\n, \n#4288\n)\n\n\n\n\n3.4.0\n\n\nDate\n: \n14th July 2016\n\n\n\n\nDon't strip microseconds in JSON output. (\n#4256\n)\n\n\nTwo slightly different iso 8601 datetime serialization. (\n#4255\n)\n\n\nResolve incorrect inclusion of media type parameters. (\n#4254\n)\n\n\nResponse Content-Type potentially malformed. (\n#4253\n)\n\n\nFix setup.py error on some platforms. (\n#4246\n)\n\n\nMove alternate formats in coreapi into separate packages. (\n#4244\n)\n\n\nAdd localize keyword argument to \nDecimalField\n. (\n#4233\n)\n\n\nFix issues with routers for custom list-route and detail-routes. (\n#4229\n)\n\n\nNamespace versioning with nested namespaces. (\n#4219\n)\n\n\nRobust uniqueness checks. (\n#4217\n)\n\n\nMinor refactoring of \nmust_call_distinct\n. (\n#4215\n)\n\n\nOverridable offset cutoff in CursorPagination. (\n#4212\n)\n\n\nPass through strings as-in with date/time fields. (\n#4196\n)\n\n\nAdd test confirming that required=False is valid on a relational field. (\n#4195\n)\n\n\nIn LimitOffsetPagination \nlimit=0\n should revert to default limit. (\n#4194\n)\n\n\nExclude read_only=True fields from unique_together validation & add docs. (\n#4192\n)\n\n\nHandle bytestrings in JSON. (\n#4191\n)\n\n\nJSONField(binary=True) represents using binary strings, which JSONRenderer does not support. (\n#4187\n)\n\n\nJSONField(binary=True) represents using binary strings, which JSONRenderer does not support. (\n#4185\n)\n\n\nMore robust form rendering in the browsable API. (\n#4181\n)\n\n\nEmpty cases of \n.validated_data\n and \n.errors\n as lists not dicts for ListSerializer. (\n#4180\n)\n\n\nSchemas & client libraries. (\n#4179\n)\n\n\nRemoved \nAUTH_USER_MODEL\n compat property. (\n#4176\n)\n\n\nClean up existing deprecation warnings. (\n#4166\n)\n\n\nDjango 1.10 support. (\n#4158\n)\n\n\nUpdated jQuery version to 1.12.4. (\n#4157\n)\n\n\nMore robust default behavior on OrderingFilter. (\n#4156\n)\n\n\ndescription.py codes and tests removal. (\n#4153\n)\n\n\nWrap guardian.VERSION in tuple. (\n#4149\n)\n\n\nRefine validator for fields with \n kwargs. (\n#4146\n)\n\n\nFix None values representation in childs of ListField, DictField. (\n#4118\n)\n\n\nResolve TimeField representation for midnight value. (\n#4107\n)\n\n\nSet proper status code in AdminRenderer for the redirection after POST/DELETE requests. (\n#4106\n)\n\n\nTimeField render returns None instead of 00:00:00. (\n#4105\n)\n\n\nFix incorrectly named zh-hans and zh-hant locale path. (\n#4103\n)\n\n\nPrevent raising exception when limit is 0. (\n#4098\n)\n\n\nTokenAuthentication: Allow custom keyword in the header. (\n#4097\n)\n\n\nHandle incorrectly padded HTTP basic auth header. (\n#4090\n)\n\n\nLimitOffset pagination crashes Browseable API when limit=0. (\n#4079\n)\n\n\nFixed DecimalField arbitrary precision support. (\n#4075\n)\n\n\nAdded support for custom CSRF cookie names. (\n#4049\n)\n\n\nFix regression introduced by #4035. (\n#4041\n)\n\n\nNo auth view failing permission should raise 403. (\n#4040\n)\n\n\nFix string_types / text_types confusion. (\n#4025\n)\n\n\nDo not list related field choices in OPTIONS requests. (\n#4021\n)\n\n\nFix typo. (\n#4008\n)\n\n\nReorder initializing the view. (\n#4006\n)\n\n\nType error in DjangoObjectPermissionsFilter on Python 3.4. (\n#4005\n)\n\n\nFixed use of deprecated Query.aggregates. (\n#4003\n)\n\n\nFix blank lines around docstrings. (\n#4002\n)\n\n\nFixed admin pagination when limit is 0. (\n#3990\n)\n\n\nOrderingFilter adjustments. (\n#3983\n)\n\n\nNon-required serializer related fields. (\n#3976\n)\n\n\nUsing safer calling way of \"@api_view\" in tutorial. (\n#3971\n)\n\n\nListSerializer doesn't handle unique_together constraints. (\n#3970\n)\n\n\nAdd missing migration file. (\n#3968\n)\n\n\nOrderingFilter\n should call \nget_serializer_class()\n to determine default fields. (\n#3964\n)\n\n\nRemove old Django checks from tests and compat. (\n#3953\n)\n\n\nSupport callable as the value of \ninitial\n for any \nserializer.Field\n. (\n#3943\n)\n\n\nPrevented unnecessary distinct() call in SearchFilter. (\n#3938\n)\n\n\nFix None UUID ForeignKey serialization. (\n#3936\n)\n\n\nDrop EOL Django 1.7. (\n#3933\n)\n\n\nAdd missing space in serializer error message. (\n#3926\n)\n\n\nFixed _force_text_recursive typo. (\n#3908\n)\n\n\nAttempt to address Django 2.0 deprecate warnings related to \nfield.rel\n. (\n#3906\n)\n\n\nFix parsing multipart data using a nested serializer with list. (\n#3820\n)\n\n\nResolving APIs URL to different namespaces. (\n#3816\n)\n\n\nDo not HTML-escape \nhelp_text\n in Browsable API forms. (\n#3812\n)\n\n\nOPTIONS fetches and shows all possible foreign keys in choices field. (\n#3751\n)\n\n\nDjango 1.9 deprecation warnings (\n#3729\n)\n\n\nTest case for #3598 (\n#3710\n)\n\n\nAdding support for multiple values for search filter. (\n#3541\n)\n\n\nUse get_serializer_class in ordering filter. (\n#3487\n)\n\n\nSerializers with many=True should return empty list rather than empty dict. (\n#3476\n)\n\n\nLimitOffsetPagination limit=0 fix. (\n#3444\n)\n\n\nEnable Validators to defer string evaluation and handle new string format. (\n#3438\n)\n\n\nUnique validator is executed and breaks if field is invalid. (\n#3381\n)\n\n\nDo not ignore overridden View.get_view_name() in breadcrumbs. (\n#3273\n)\n\n\nRetry form rendering when rendering with serializer fails. (\n#3164\n)\n\n\nUnique constraint prevents nested serializers from updating. (\n#2996\n)\n\n\nUniqueness validators should not be run for excluded (read_only) fields. (\n#2848\n)\n\n\nUniqueValidator raises exception for nested objects. (\n#2403\n)\n\n\nlookup_type\n is deprecated in favor of \nlookup_expr\n. (\n#4259\n)\n\n\n\n\n\n\n3.3.x series\n\n\n3.3.3\n\n\nDate\n: \n14th March 2016\n.\n\n\n\n\nRemove version string from templates. Thanks to @blag for the report and fixes. (\n#3878\n, \n#3913\n, \n#3912\n)\n\n\nFixes vertical html layout for \nBooleanField\n. Thanks to Mikalai Radchuk for the fix. (\n#3910\n)\n\n\nSilenced deprecation warnings on Django 1.8. Thanks to Simon Charette for the fix. (\n#3903\n)\n\n\nInternationalization for authtoken. Thanks to Michael Nacharov for the fix. (\n#3887\n, \n#3968\n)\n\n\nFix \nToken\n model as \nabstract\n when the authtoken application isn't declared. Thanks to Adam Thomas for the report. (\n#3860\n, \n#3858\n)\n\n\nImprove Markdown version compatibility. Thanks to Michael J. Schultz for the fix. (\n#3604\n, \n#3842\n)\n\n\nQueryParameterVersioning\n does not use \nDEFAULT_VERSION\n setting. Thanks to Brad Montgomery for the fix. (\n#3833\n)\n\n\nAdd an explicit \non_delete\n on the models. Thanks to Mads Jensen for the fix. (\n#3832\n)\n\n\nFix \nDateField.to_representation\n to work with Python 2 unicode. Thanks to Mikalai Radchuk for the fix. (\n#3819\n)\n\n\nFixed \nTimeField\n not handling string times. Thanks to Areski Belaid for the fix. (\n#3809\n)\n\n\nAvoid updates of \nMeta.extra_kwargs\n. Thanks to Kevin Massey for the report and fix. (\n#3805\n, \n#3804\n)\n\n\nFix nested validation error being rendered incorrectly. Thanks to Craig de Stigter for the fix. (\n#3801\n)\n\n\nDocument how to avoid CSRF and missing button issues with \ndjango-crispy-forms\n. Thanks to Emmanuelle Delescolle, Jos\u00e9 Padilla and Luis San Pablo for the report, analysis and fix. (\n#3787\n, \n#3636\n, \n#3637\n)\n\n\nImprove Rest Framework Settings file setup time. Thanks to Miles Hutson for the report and Mads Jensen for the fix. (\n#3786\n, \n#3815\n)\n\n\nImprove authtoken compatibility with Django 1.9. Thanks to S. Andrew Sheppard for the fix. (\n#3785\n)\n\n\nFix \nMin/MaxValueValidator\n transfer from a model's \nDecimalField\n. Thanks to Kevin Brown for the fix. (\n#3774\n)\n\n\nImprove HTML title in the Browsable API. Thanks to Mike Lissner for the report and fix. (\n#3769\n)\n\n\nFix \nAutoFilterSet\n to inherit from \ndefault_filter_set\n. Thanks to Tom Linford for the fix. (\n#3753\n)\n\n\nFix transifex config to handle the new Chinese language codes. Thanks to @nypisces for the report and fix. (\n#3739\n)\n\n\nDateTimeField\n does not handle empty values correctly. Thanks to Mick Parker for the report and fix. (\n#3731\n, \n#3726\n)\n\n\nRaise error when setting a removed rest_framework setting. Thanks to Luis San Pablo for the fix. (\n#3715\n)\n\n\nAdd missing csrf_token in AdminRenderer post form. Thanks to Piotr \u015aniegowski for the fix. (\n#3703\n)\n\n\nRefactored \n_get_reverse_relationships()\n to use correct \nto_field\n. Thanks to Benjamin Phillips for the fix. (\n#3696\n)\n\n\nDocument the use of \nget_queryset\n for \nRelatedField\n. Thanks to Ryan Hiebert for the fix. (\n#3605\n)\n\n\nFix empty pk detection in HyperlinkRelatedField.get_url. Thanks to @jslang for the fix (\n#3962\n)\n\n\n\n\n3.3.2\n\n\nDate\n: \n14th December 2015\n.\n\n\n\n\nListField\n enforces input is a list. (\n#3513\n)\n\n\nFix regression hiding raw data form. (\n#3600\n, \n#3578\n)\n\n\nFix Python 3.5 compatibility. (\n#3534\n, \n#3626\n)\n\n\nAllow setting a custom Django Paginator in \npagination.PageNumberPagination\n. (\n#3631\n, \n#3684\n)\n\n\nFix relational fields without \nto_fields\n attribute. (\n#3635\n, \n#3634\n)\n\n\nFix \ntemplate.render\n deprecation warnings for Django 1.9. (\n#3654\n)\n\n\nSort response headers in browsable API renderer. (\n#3655\n)\n\n\nUse related_objects api for Django 1.9+. (\n#3656\n, \n#3252\n)\n\n\nAdd confirm modal when deleting. (\n#3228\n, \n#3662\n)\n\n\nReveal previously hidden AttributeErrors and TypeErrors while calling has_[object_]permissions. (\n#3668\n)\n\n\nMake DRF compatible with multi template engine in Django 1.8. (\n#3672\n)\n\n\nUpdate \nNestedBoundField\n to also handle empty string when rendering its form. (\n#3677\n)\n\n\nFix UUID validation to properly catch invalid input types. (\n#3687\n, \n#3679\n)\n\n\nFix caching issues. (\n#3628\n, \n#3701\n)\n\n\nFix Admin and API browser for views without a filter_class. (\n#3705\n, \n#3596\n, \n#3597\n)\n\n\nAdd app_name to rest_framework.urls. (\n#3714\n)\n\n\nImprove authtoken's views to support url versioning. (\n#3718\n, \n#3723\n)\n\n\n\n\n3.3.1\n\n\nDate\n: \n4th November 2015\n.\n\n\n\n\nResolve parsing bug when accessing \nrequest.POST\n (\n#3592\n)\n\n\nCorrectly deal with \nto_field\n referring to primary key. (\n#3593\n)\n\n\nAllow filter HTML to render when no \nfilter_class\n is defined. (\n#3560\n)\n\n\nFix admin rendering issues. (\n#3564\n, \n#3556\n)\n\n\nFix issue with DecimalValidator. (\n#3568\n)\n\n\n\n\n3.3.0\n\n\nDate\n: \n28th October 2015\n.\n\n\n\n\nHTML controls for filters. (\n#3315\n)\n\n\nForms API. (\n#3475\n)\n\n\nAJAX browsable API. (\n#3410\n)\n\n\nAdded JSONField. (\n#3454\n)\n\n\nCorrectly map \nto_field\n when creating \nModelSerializer\n relational fields. (\n#3526\n)\n\n\nInclude keyword arguments when mapping \nFilePathField\n to a serializer field. (\n#3536\n)\n\n\nMap appropriate model \nerror_messages\n on \nModelSerializer\n uniqueness constraints. (\n#3435\n)\n\n\nInclude \nmax_length\n constraint for \nModelSerializer\n fields mapped from TextField. (\n#3509\n)\n\n\nAdded support for Django 1.9. (\n#3450\n, \n#3525\n)\n\n\nRemoved support for Django 1.5 & 1.6. (\n#3421\n, \n#3429\n)\n\n\nRemoved 'south' migrations. (\n#3495\n)\n\n\n\n\n\n\n3.2.x series\n\n\n3.2.5\n\n\nDate\n: \n27th October 2015\n.\n\n\n\n\nEscape \nusername\n in optional logout tag. (\n#3550\n)\n\n\n\n\n3.2.4\n\n\nDate\n: \n21th September 2015\n.\n\n\n\n\nDon't error on missing \nViewSet.search_fields\n attribute. (\n#3324\n, \n#3323\n)\n\n\nFix \nallow_empty\n not working on serializers with \nmany=True\n. (\n#3361\n, \n#3364\n)\n\n\nLet \nDurationField\n accepts integers. (\n#3359\n)\n\n\nMulti-level dictionaries not supported in multipart requests. (\n#3314\n)\n\n\nFix \nListField\n truncation on HTTP PATCH (\n#3415\n, \n#2761\n)\n\n\n\n\n3.2.3\n\n\nDate\n: \n24th August 2015\n.\n\n\n\n\nAdded \nhtml_cutoff\n and \nhtml_cutoff_text\n for limiting select dropdowns. (\n#3313\n)\n\n\nAdded regex style to \nSearchFilter\n. (\n#3316\n)\n\n\nResolve issues with setting blank HTML fields. (\n#3318\n) (\n#3321\n)\n\n\nCorrectly display existing 'select multiple' values in browsable API forms. (\n#3290\n)\n\n\nResolve duplicated validation message for \nIPAddressField\n. ([#3249[gh3249]) (\n#3250\n)\n\n\nFix to ensure admin renderer continues to work when pagination is disabled. (\n#3275\n)\n\n\nResolve error with \nLimitOffsetPagination\n when count=0, offset=0. (\n#3303\n)\n\n\n\n\n3.2.2\n\n\nDate\n: \n13th August 2015\n.\n\n\n\n\nAdd \ndisplay_value()\n method for use when displaying relational field select inputs. (\n#3254\n)\n\n\nFix issue with \nBooleanField\n checkboxes incorrectly displaying as checked. (\n#3258\n)\n\n\nEnsure empty checkboxes properly set \nBooleanField\n to \nFalse\n in all cases. (\n#2776\n)\n\n\nAllow \nWSGIRequest.FILES\n property without raising incorrect deprecated error. (\n#3261\n)\n\n\nResolve issue with rendering nested serializers in forms. (\n#3260\n)\n\n\nRaise an error if user accidentally pass a serializer instance to a response, rather than data. (\n#3241\n)\n\n\n\n\n3.2.1\n\n\nDate\n: \n7th August 2015\n.\n\n\n\n\nFix for relational select widgets rendering without any choices. (\n#3237\n)\n\n\nFix for \n1\n, \n0\n rendering as \ntrue\n, \nfalse\n in the admin interface. \n#3227\n)\n\n\nFix for ListFields with single value in HTML form input. (\n#3238\n)\n\n\nAllow \nrequest.FILES\n for compat with Django's \nHTTPRequest\n class. (\n#3239\n)\n\n\n\n\n3.2.0\n\n\nDate\n: \n6th August 2015\n.\n\n\n\n\nAdd \nAdminRenderer\n. (\n#2926\n)\n\n\nAdd \nFilePathField\n. (\n#1854\n)\n\n\nAdd \nallow_empty\n to \nListField\n. (\n#2250\n)\n\n\nSupport django-guardian 1.3. (\n#3165\n)\n\n\nSupport grouped choices. (\n#3225\n)\n\n\nSupport error forms in browsable API. (\n#3024\n)\n\n\nAllow permission classes to customize the error message. (\n#2539\n)\n\n\nSupport \nsource=\n on hyperlinked fields. (\n#2690\n)\n\n\nListField(allow_null=True)\n now allows null as the list value, not null items in the list. (\n#2766\n)\n\n\nManyToMany()\n maps to \nallow_empty=False\n, \nManyToMany(blank=True)\n maps to \nallow_empty=True\n. (\n#2804\n)\n\n\nSupport custom serialization styles for primary key fields. (\n#2789\n)\n\n\nOPTIONS\n requests support nested representations. (\n#2915\n)\n\n\nSet \nview.action == \"metadata\"\n for viewsets with \nOPTIONS\n requests. (\n#3115\n)\n\n\nSupport \nallow_blank\n on \nUUIDField\n. ([#3130][gh#3130])\n\n\nDo not display view docstrings with 401 or 403 response codes. (\n#3216\n)\n\n\nResolve Django 1.8 deprecation warnings. (\n#2886\n)\n\n\nFix for \nDecimalField\n validation. (\n#3139\n)\n\n\nFix behavior of \nallow_blank=False\n when used with \ntrim_whitespace=True\n. (\n#2712\n)\n\n\nFix issue with some field combinations incorrectly mapping to an invalid \nallow_blank\n argument. (\n#3011\n)\n\n\nFix for output representations with prefetches and modified querysets. (\n#2704\n, \n#2727\n)\n\n\nFix assertion error when CursorPagination is provided with certain invalid query parameters. (#2920)\ngh2920\n.\n\n\nFix \nUnicodeDecodeError\n when invalid characters included in header with \nTokenAuthentication\n. (\n#2928\n)\n\n\nFix transaction rollbacks with \n@non_atomic_requests\n decorator. (\n#3016\n)\n\n\nFix duplicate results issue with Oracle databases using \nSearchFilter\n. (\n#2935\n)\n\n\nFix checkbox alignment and rendering in browsable API forms. (\n#2783\n)\n\n\nFix for unsaved file objects which should use \n\"url\": null\n in the representation. (\n#2759\n)\n\n\nFix field value rendering in browsable API. (\n#2416\n)\n\n\nFix \nHStoreField\n to include \nallow_blank=True\n in \nDictField\n mapping. (\n#2659\n)\n\n\nNumerous other cleanups, improvements to error messaging, private API & minor fixes.\n\n\n\n\n\n\n3.1.x series\n\n\n3.1.3\n\n\nDate\n: \n4th June 2015\n.\n\n\n\n\nAdd \nDurationField\n. (\n#2481\n, \n#2989\n)\n\n\nAdd \nformat\n argument to \nUUIDField\n. (\n#2788\n, \n#3000\n)\n\n\nMultipleChoiceField\n empties incorrectly on a partial update using multipart/form-data (\n#2993\n, \n#2894\n)\n\n\nFix a bug in options related to read-only \nRelatedField\n. (\n#2981\n, \n#2811\n)\n\n\nFix nested serializers with \nunique_together\n relations. (\n#2975\n)\n\n\nAllow unexpected values for \nChoiceField\n/\nMultipleChoiceField\n representations. (\n#2839\n, \n#2940\n)\n\n\nRollback the transaction on error if \nATOMIC_REQUESTS\n is set. (\n#2887\n, \n#2034\n)\n\n\nSet the action on a view when override_method regardless of its None-ness. (\n#2933\n)\n\n\nDecimalField\n accepts \n2E+2\n as 200 and validates decimal place correctly. (\n#2948\n, \n#2947\n)\n\n\nSupport basic authentication with custom \nUserModel\n that change \nusername\n. (\n#2952\n)\n\n\nIPAddressField\n improvements. (\n#2747\n, \n#2618\n, \n#3008\n)\n\n\nImprove \nDecimalField\n for easier subclassing. (\n#2695\n)\n\n\n\n\n3.1.2\n\n\nDate\n: \n13rd May 2015\n.\n\n\n\n\nDateField.to_representation\n can handle str and empty values. (\n#2656\n, \n#2687\n, \n#2869\n)\n\n\nUse default reason phrases from HTTP standard. (\n#2764\n, \n#2763\n)\n\n\nRaise error when \nModelSerializer\n used with abstract model. (\n#2757\n, \n#2630\n)\n\n\nHandle reversal of non-API view_name in \nHyperLinkedRelatedField\n (\n#2724\n, \n#2711\n)\n\n\nDon't require pk strictly for related fields. (\n#2745\n, \n#2754\n)\n\n\nMetadata detects null boolean field type. (\n#2762\n)\n\n\nProper handling of depth in nested serializers. (\n#2798\n)\n\n\nDisplay viewset without paginator. (\n#2807\n)\n\n\nDon't check for deprecated \n.model\n attribute in permissions (\n#2818\n)\n\n\nRestrict integer field to integers and strings. (\n#2835\n, \n#2836\n)\n\n\nImprove \nIntegerField\n to use compiled decimal regex. (\n#2853\n)\n\n\nPrevent empty \nqueryset\n to raise AssertionError. (\n#2862\n)\n\n\nDjangoModelPermissions\n rely on \nget_queryset\n. (\n#2863\n)\n\n\nCheck \nAcceptHeaderVersioning\n with content negotiation in place. (\n#2868\n)\n\n\nAllow \nDjangoObjectPermissions\n to use views that define \nget_queryset\n. (\n#2905\n)\n\n\n\n\n3.1.1\n\n\nDate\n: \n23rd March 2015\n.\n\n\n\n\nSecurity fix\n: Escape tab switching cookie name in browsable API.\n\n\nDisplay input forms in browsable API if \nserializer_class\n is used, even when \nget_serializer\n method does not exist on the view. (\n#2743\n)\n\n\nUse a password input for the AuthTokenSerializer. (\n#2741\n)\n\n\nFix missing anchor closing tag after next button. (\n#2691\n)\n\n\nFix \nlookup_url_kwarg\n handling in viewsets. (\n#2685\n, \n#2591\n)\n\n\nFix problem with importing \nrest_framework.views\n in \napps.py\n (\n#2678\n)\n\n\nLimitOffsetPagination raises \nTypeError\n if PAGE_SIZE not set (\n#2667\n, \n#2700\n)\n\n\nGerman translation for \nmin_value\n field error message references \nmax_value\n. (\n#2645\n)\n\n\nRemove \nMergeDict\n. (\n#2640\n)\n\n\nSupport serializing unsaved models with related fields. (\n#2637\n, \n#2641\n)\n\n\nAllow blank/null on radio.html choices. (\n#2631\n)\n\n\n\n\n3.1.0\n\n\nDate\n: \n5th March 2015\n.\n\n\nFor full details see the \n3.1 release announcement\n.\n\n\n\n\n3.0.x series\n\n\n3.0.5\n\n\nDate\n: \n10th February 2015\n.\n\n\n\n\nFix a bug where \n_closable_objects\n breaks pickling. (\n#1850\n, \n#2492\n)\n\n\nAllow non-standard \nUser\n models with \nThrottling\n. (\n#2524\n)\n\n\nSupport custom \nUser.db_table\n in TokenAuthentication migration. (\n#2479\n)\n\n\nFix misleading \nAttributeError\n tracebacks on \nRequest\n objects. (\n#2530\n, \n#2108\n)\n\n\nManyRelatedField.get_value\n clearing field on partial update. (\n#2475\n)\n\n\nRemoved '.model' shortcut from code. (\n#2486\n)\n\n\nFix \ndetail_route\n and \nlist_route\n mutable argument. (\n#2518\n)\n\n\nPrefetching the user object when getting the token in \nTokenAuthentication\n. (\n#2519\n)\n\n\n\n\n3.0.4\n\n\nDate\n: \n28th January 2015\n.\n\n\n\n\nDjango 1.8a1 support. (\n#2425\n, \n#2446\n, \n#2441\n)\n\n\nAdd \nDictField\n and support Django 1.8 \nHStoreField\n. (\n#2451\n, \n#2106\n)\n\n\nAdd \nUUIDField\n and support Django 1.8 \nUUIDField\n. (\n#2448\n, \n#2433\n, \n#2432\n)\n\n\nBaseRenderer.render\n now raises \nNotImplementedError\n. (\n#2434\n)\n\n\nFix timedelta JSON serialization on Python 2.6. (\n#2430\n)\n\n\nResultDict\n and \nResultList\n now appear as standard dict/list. (\n#2421\n)\n\n\nFix visible \nHiddenField\n in the HTML form of the web browsable API page. (\n#2410\n)\n\n\nUse \nOrderedDict\n for \nRelatedField.choices\n. (\n#2408\n)\n\n\nFix ident format when using \nHTTP_X_FORWARDED_FOR\n. (\n#2401\n)\n\n\nFix invalid key with memcached while using throttling. (\n#2400\n)\n\n\nFix \nFileUploadParser\n with version 3.x. (\n#2399\n)\n\n\nFix the serializer inheritance. (\n#2388\n)\n\n\nFix caching issues with \nReturnDict\n. (\n#2360\n)\n\n\n\n\n3.0.3\n\n\nDate\n: \n8th January 2015\n.\n\n\n\n\nFix \nMinValueValidator\n on \nmodels.DateField\n. (\n#2369\n)\n\n\nFix serializer missing context when pagination is used. (\n#2355\n)\n\n\nNamespaced router URLs are now supported by the \nDefaultRouter\n. (\n#2351\n)\n\n\nrequired=False\n allows omission of value for output. (\n#2342\n)\n\n\nUse textarea input for \nmodels.TextField\n. (\n#2340\n)\n\n\nUse custom \nListSerializer\n for pagination if required. (\n#2331\n, \n#2327\n)\n\n\nBetter behavior with null and '' for blank HTML fields. (\n#2330\n)\n\n\nEnsure fields in \nexclude\n are model fields. (\n#2319\n)\n\n\nFix \nIntegerField\n and \nmax_length\n argument incompatibility. (\n#2317\n)\n\n\nFix the YAML encoder for 3.0 serializers. (\n#2315\n, \n#2283\n)\n\n\nFix the behavior of empty HTML fields. (\n#2311\n, \n#1101\n)\n\n\nFix Metaclass attribute depth ignoring fields attribute. (\n#2287\n)\n\n\nFix \nformat_suffix_patterns\n to work with Django's \ni18n_patterns\n. (\n#2278\n)\n\n\nAbility to customize router URLs for custom actions, using \nurl_path\n. (\n#2010\n)\n\n\nDon't install Django REST Framework as egg. (\n#2386\n)\n\n\n\n\n3.0.2\n\n\nDate\n: \n17th December 2014\n.\n\n\n\n\nEnsure \nrequest.user\n is made available to response middleware. (\n#2155\n)\n\n\nClient.logout()\n also cancels any existing \nforce_authenticate\n. (\n#2218\n, \n#2259\n)\n\n\nExtra assertions and better checks to preventing incorrect serializer API use. (\n#2228\n, \n#2234\n, \n#2262\n, \n#2263\n, \n#2266\n, \n#2267\n, \n#2289\n, \n#2291\n)\n\n\nFixed \nmin_length\n message for \nCharField\n. (\n#2255\n)\n\n\nFix \nUnicodeDecodeError\n, which can occur on serializer \nrepr\n. (\n#2270\n, \n#2279\n)\n\n\nFix empty HTML values when a default is provided. (\n#2280\n, \n#2294\n)\n\n\nFix \nSlugRelatedField\n raising \nUnicodeEncodeError\n when used as a multiple choice input. (\n#2290\n)\n\n\n\n\n3.0.1\n\n\nDate\n: \n11th December 2014\n.\n\n\n\n\nMore helpful error message when the default Serializer \ncreate()\n fails. (\n#2013\n)\n\n\nRaise error when attempting to save serializer if data is not valid. (\n#2098\n)\n\n\nFix \nFileUploadParser\n breaks with empty file names and multiple upload handlers. (\n#2109\n)\n\n\nImprove \nBindingDict\n to support standard dict-functions. (\n#2135\n, \n#2163\n)\n\n\nAdd \nvalidate()\n to \nListSerializer\n. (\n#2168\n, \n#2225\n, \n#2232\n)\n\n\nFix JSONP renderer failing to escape some characters. (\n#2169\n, \n#2195\n)\n\n\nAdd missing default style for \nFileField\n. (\n#2172\n)\n\n\nActions are required when calling \nViewSet.as_view()\n. (\n#2175\n)\n\n\nAdd \nallow_blank\n to \nChoiceField\n. (\n#2184\n, \n#2239\n)\n\n\nCosmetic fixes in the HTML renderer. (\n#2187\n)\n\n\nRaise error if \nfields\n on serializer is not a list of strings. (\n#2193\n, \n#2213\n)\n\n\nImprove checks for nested creates and updates. (\n#2194\n, \n#2196\n)\n\n\nvalidated_attrs\n argument renamed to \nvalidated_data\n in \nSerializer\n \ncreate()\n/\nupdate()\n. (\n#2197\n)\n\n\nRemove deprecated code to reflect the dropped Django versions. (\n#2200\n)\n\n\nBetter serializer errors for nested writes. (\n#2202\n, \n#2215\n)\n\n\nFix pagination and custom permissions incompatibility. (\n#2205\n)\n\n\nRaise error if \nfields\n on serializer is not a list of strings. (\n#2213\n)\n\n\nAdd missing translation markers for relational fields. (\n#2231\n)\n\n\nImprove field lookup behavior for dicts/mappings. (\n#2244\n, \n#2243\n)\n\n\nOptimized hyperlinked PK. (\n#2242\n)\n\n\n\n\n3.0.0\n\n\nDate\n: 1st December 2014\n\n\nFor full details see the \n3.0 release announcement\n.\n\n\n\n\nFor older release notes, \nplease see the version 2.x documentation\n.", + "text": "Release Notes\n\n\n\n\nRelease Early, Release Often\n\n\n\u2014 Eric S. Raymond, \nThe Cathedral and the Bazaar\n.\n\n\n\n\nVersioning\n\n\nMinor version numbers (0.0.x) are used for changes that are API compatible. You should be able to upgrade between minor point releases without any other code changes.\n\n\nMedium version numbers (0.x.0) may include API changes, in line with the \ndeprecation policy\n. You should read the release notes carefully before upgrading between medium point releases.\n\n\nMajor version numbers (x.0.0) are reserved for substantial project milestones.\n\n\nDeprecation policy\n\n\nREST framework releases follow a formal deprecation policy, which is in line with \nDjango's deprecation policy\n.\n\n\nThe timeline for deprecation of a feature present in version 1.0 would work as follows:\n\n\n\n\n\n\nVersion 1.1 would remain \nfully backwards compatible\n with 1.0, but would raise \nPendingDeprecationWarning\n warnings if you use the feature that are due to be deprecated. These warnings are \nsilent by default\n, but can be explicitly enabled when you're ready to start migrating any required changes. For example if you start running your tests using \npython -Wd manage.py test\n, you'll be warned of any API changes you need to make.\n\n\n\n\n\n\nVersion 1.2 would escalate these warnings to \nDeprecationWarning\n, which is loud by default.\n\n\n\n\n\n\nVersion 1.3 would remove the deprecated bits of API entirely.\n\n\n\n\n\n\nNote that in line with Django's policy, any parts of the framework not mentioned in the documentation should generally be considered private API, and may be subject to change.\n\n\nUpgrading\n\n\nTo upgrade Django REST framework to the latest version, use pip:\n\n\npip install -U djangorestframework\n\n\n\nYou can determine your currently installed version using \npip show\n:\n\n\npip show djangorestframework\n\n\n\n\n\n3.8.x series\n\n\n3.8.0\n\n\nDate\n: \n3rd April 2018\n\n\n\n\n\n\nBreaking Change\n: Alter \nread_only\n plus \ndefault\n behaviour. \n#5886\n\n\nread_only\n fields will now \nalways\n be excluded from writable fields.\n\n\nPreviously \nread_only\n fields with a \ndefault\n value would use the \ndefault\n for create and update operations.\n\n\nIn order to maintain the old behaviour you may need to pass the value of \nread_only\n fields when calling \nsave()\n in\nthe view:\n\n\ndef perform_create(self, serializer):\n serializer.save(owner=self.request.user)\n\n\n\nAlternatively you may override \nsave()\n or \ncreate()\n or \nupdate()\n on the serialiser as appropriate.\n* Correct allow_null behaviour when required=False \n#5888\n\n\nWithout an explicit \ndefault\n, \nallow_null\n implies a default of \nnull\n for outgoing serialisation. Previously such\nfields were being skipped when read-only or otherwise not required.\n\n\nPossible backwards compatibility break\n if you were relying on such fields being excluded from the outgoing\nrepresentation. In order to restore the old behaviour you can override \ndata\n to exclude the field when \nNone\n.\n\n\nFor example:\n\n\n@property\ndef data(self):\n \"\"\"\n Drop `maybe_none` field if None.\n \"\"\"\n data = super().data()\n if 'maybe_none' in data and data['maybe_none'] is None:\n del data['maybe_none']\n return data\n\n\n\n\n\n\n\nRefactor dynamic route generation and improve viewset action introspectibility. \n#5705\n\n\nViewSet\ns have been provided with new attributes and methods that allow\nit to introspect its set of actions and the details of the current action.\n\n\n\n\nMerged \nlist_route\n and \ndetail_route\n into a single \naction\n decorator.\n\n\nGet all extra actions on a \nViewSet\n with \n.get_extra_actions()\n.\n\n\nExtra actions now set the \nurl_name\n and \nurl_path\n on the decorated method.\n\n\nEnable action url reversing through \n.reverse_action()\n method (added in 3.7.4)\n\n\nExample reverse call: \nself.reverse_action(self.custom_action.url_name)\n\n\nAdd \ndetail\n initkwarg to indicate if the current action is operating on a\n collection or a single instance.\n\n\n\n\nAdditional changes:\n\n\n\n\nDeprecated \nlist_route\n & \ndetail_route\n in favor of \naction\n decorator with \ndetail\n boolean.\n\n\nDeprecated dynamic list/detail route variants in favor of \nDynamicRoute\n with \ndetail\n boolean.\n\n\nRefactored the router's dynamic route generation.\n\n\nFix formatting of the 3.7.4 release note \n#5704\n\n\nDocs: Update DRF Writable Nested Serializers references \n#5711\n\n\nDocs: Fixed typo in auth URLs example. \n#5713\n\n\nImprove composite field child errors \n#5655\n\n\nDisable HTML inputs for dict/list fields \n#5702\n\n\nFix typo in HostNameVersioning doc \n#5709\n\n\nUse rsplit to get module and classname for imports \n#5712\n\n\nFormalize URLPatternsTestCase \n#5703\n\n\nAdd exception translation test \n#5700\n\n\nTest staticfiles \n#5701\n\n\nAdd drf-yasg to documentation and schema 3rd party packages \n#5720\n\n\nRemove unused \ncompat._resolve_model()\n \n#5733\n\n\nDrop compat workaround for unsupported Python 3.2 \n#5734\n\n\nPrefer \niter(dict)\n over \niter(dict.keys())\n \n#5736\n\n\nPass \npython_requires\n argument to setuptools \n#5739\n\n\nRemove unused links from docs \n#5735\n\n\nPrefer https protocol for links in docs when available \n#5729\n\n\nAdd HStoreField, postgres fields tests \n#5654\n\n\nAlways fully qualify ValidationError in docs \n#5751\n\n\nRemove unreachable code from ManualSchema \n#5766\n\n\nAllowed customising API documentation code samples \n#5752\n\n\nUpdated docs to use \npip show\n \n#5757\n\n\nLoad 'static' instead of 'staticfiles' in templates \n#5773\n\n\nFixed a typo in \nfields\n docs \n#5783\n\n\nRefer to \"NamespaceVersioning\" instead of \"NamespacedVersioning\" in the documentation \n#5754\n\n\nErrorDetail: add \n__eq__\n/\n__ne__\n and \n__repr__\n \n#5787\n\n\nReplace \nbackground-attachment: fixed\n in docs \n#5777\n\n\nMake 404 & 403 responses consistent with \nexceptions.APIException\n output \n#5763\n\n\nSmall fix to API documentation: schemas \n#5796\n\n\nFix schema generation for PrimaryKeyRelatedField \n#5764\n\n\nRepresent serializer DictField as an Object in schema \n#5765\n\n\nAdded docs example reimplementing ObtainAuthToken \n#5802\n\n\nAdd schema to the ObtainAuthToken view \n#5676\n\n\nFix request formdata handling \n#5800\n\n\nFix authtoken views imports \n#5818\n\n\nUpdate pytest, isort \n#5815\n \n#5817\n \n#5894\n\n\nFixed active timezone handling for non ISO8601 datetimes. \n#5833\n\n\nMade TemplateHTMLRenderer render IntegerField inputs when value is \n0\n. \n#5834\n\n\nCorrected endpoint in tutorial instructions \n#5835\n\n\nAdd Django Rest Framework Role Filters to Third party packages \n#5809\n\n\nUse single copy of static assets. Update jQuery \n#5823\n\n\nChanges ternary conditionals to be PEP308 compliant \n#5827\n\n\nAdded links to 'A Todo List API with React' and 'Blog API' tutorials \n#5837\n\n\nFix comment typo in ModelSerializer \n#5844\n\n\nAdd admin to installed apps to avoid test failures. \n#5870\n\n\nFixed schema for UUIDField in SimpleMetadata. \n#5872\n\n\nCorrected docs on router include with namespaces. \n#5843\n\n\nTest using model objects for dotted source default \n#5880\n\n\nAllow traversing nullable related fields \n#5849\n\n\nAdded: Tutorial: Django REST with React (Django 2.0) \n#5891\n\n\nAdd \nLimitOffsetPagination.get_count\n to allow method override \n#5846\n\n\nDon't show hidden fields in metadata \n#5854\n\n\nEnable OrderingFilter to handle an empty tuple (or list) for the 'ordering' field. \n#5899\n\n\nAdded generic 500 and 400 JSON error handlers. \n#5904\n\n\n\n\n\n\n\n\n3.7.x series\n\n\n3.7.7\n\n\nDate\n: \n21st December 2017\n\n\n\n\nFix typo to include *.mo locale files to packaging. \n#5697\n, \n#5695\n\n\n\n\n3.7.6\n\n\nDate\n: \n21st December 2017\n\n\n\n\nAdd missing *.ico icon files to packaging.\n\n\n\n\n3.7.5\n\n\nDate\n: \n21st December 2017\n\n\n\n\nAdd missing *.woff2 font files to packaging. \n#5692\n\n\nAdd missing *.mo locale files to packaging. \n#5695\n, \n#5696\n\n\n\n\n3.7.4\n\n\nDate\n: \n20th December 2017\n\n\n\n\n\n\nSchema: Extract method for \nmanual_fields\n processing \n#5633\n\n\nAllows for easier customisation of \nmanual_fields\n processing, for example\nto provide per-method manual fields. \nAutoSchema\n adds \nget_manual_fields\n,\nas the intended override point, and a utility method \nupdate_fields\n, to\nhandle by-name field replacement from a list, which, in general, you are not\nexpected to override.\n\n\nNote: \nAutoSchema.__init__\n now ensures \nmanual_fields\n is a list.\nPreviously may have been stored internally as \nNone\n.\n\n\n\n\n\n\nRemove ulrparse compatability shim; use six instead \n#5579\n\n\n\n\nDrop compat wrapper for \nTimeDelta.total_seconds()\n \n#5577\n\n\nClean up all whitespace throughout project \n#5578\n\n\nCompat cleanup \n#5581\n\n\nAdd pygments CSS block in browsable API views \n#5584\n \n#5587\n\n\nRemove \nset_rollback()\n from compat \n#5591\n\n\nFix request body/POST access \n#5590\n\n\nRename test to reference correct issue \n#5610\n\n\nDocumentation Fixes \n#5611\n \n#5612\n\n\nRemove references to unsupported Django versions in docs and code \n#5602\n\n\nTest Serializer exclude for declared fields \n#5599\n\n\nFixed schema generation for filter backends \n#5613\n\n\nMinor cleanup for ModelSerializer tests \n#5598\n\n\nReimplement request attribute access w/ \n__getattr__\n \n#5617\n\n\nFixed SchemaJSRenderer renders invalid Javascript \n#5607\n\n\nMake Django 2.0 support official/explicit \n#5619\n\n\nPerform type check on passed request argument \n#5618\n\n\nFix AttributeError hiding on request authenticators \n#5600\n\n\nUpdate test requirements \n#5626\n\n\nDocs: \nSerializer._declared_fields\n enable modifying fields on a serializer \n#5629\n\n\nFix packaging \n#5624\n\n\nFix readme rendering for PyPI, add readme build to CI \n#5625\n\n\nUpdate tutorial \n#5622\n\n\nNon-required fields with \nallow_null=True\n should not imply a default value \n#5639\n\n\nDocs: Add \nallow_null\n serialization output note \n#5641\n\n\nUpdate to use the Django 2.0 release in tox.ini \n#5645\n\n\nFix \nSerializer.data\n for Browsable API rendering when provided invalid \ndata\n \n#5646\n\n\nDocs: Note AutoSchema limitations on bare APIView \n#5649\n\n\nAdd \n.basename\n and \n.reverse_action()\n to ViewSet \n#5648\n\n\nDocs: Fix typos in serializers documentation \n#5652\n\n\nFix \noverride_settings\n compat \n#5668\n\n\nAdd DEFAULT_SCHEMA_CLASS setting \n#5658\n\n\nAdd docs note re generated BooleanField being \nrequired=False\n \n#5665\n\n\nAdd 'dist' build \n#5656\n\n\nFix typo in docstring \n#5678\n\n\nDocs: Add \nUNAUTHENTICATED_USER = None\n note \n#5679\n\n\nUpdate OPTIONS example from \u201cDocumenting Your API\u201d \n#5680\n\n\nDocs: Add note on object permissions for FBVs \n#5681\n\n\nDocs: Add example to \nto_representation\n docs \n#5682\n\n\nAdd link to Classy DRF in docs \n#5683\n\n\nDocument ViewSet.action \n#5685\n\n\nFix schema docs typo \n#5687\n\n\nFix URL pattern parsing in schema generation \n#5689\n\n\nAdd example using \nsource=\u2018*\u2019\n to custom field docs. \n#5688\n\n\nFix format_suffix_patterns behavior with Django 2 path() routes \n#5691\n\n\n\n\n3.7.3\n\n\nDate\n: \n6th November 2017\n\n\n\n\nFix \nAppRegistryNotReady\n error from contrib.auth view imports \n#5567\n\n\n\n\n3.7.2\n\n\nDate\n: \n6th November 2017\n\n\n\n\nFixed Django 2.1 compatibility due to removal of django.contrib.auth.login()/logout() views. \n#5510\n\n\nAdd missing import for TextLexer. \n#5512\n\n\nAdding examples and documentation for caching \n#5514\n\n\nInclude date and date-time format for schema generation \n#5511\n\n\nUse triple backticks for markdown code blocks \n#5513\n\n\nInteractive docs - make bottom sidebar items sticky \n#5516\n\n\nClarify pagination system check \n#5524\n\n\nStop JSONBoundField mangling invalid JSON \n#5527\n\n\nHave JSONField render as textarea in Browsable API \n#5530\n\n\nSchema: Exclude OPTIONS/HEAD for ViewSet actions \n#5532\n\n\nFix ordering for dotted sources \n#5533\n\n\nFix: Fields with \nallow_null=True\n should imply a default serialization value \n#5518\n\n\nEnsure Location header is strictly a 'str', not subclass. \n#5544\n\n\nAdd import to example in api-guide/parsers \n#5547\n\n\nCatch OverflowError for \"out of range\" datetimes \n#5546\n\n\nAdd djangorestframework-rapidjson to third party packages \n#5549\n\n\nIncrease test coverage for \ndrf_create_token\n command \n#5550\n\n\nAdd trove classifier for Python 3.6 support. \n#5555\n\n\nAdd pip cache support to the Travis CI configuration \n#5556\n\n\nRename [\nwheel\n] section to [\nbdist_wheel\n] as the former is legacy \n#5557\n\n\nFix invalid escape sequence deprecation warnings \n#5560\n\n\nAdd interactive docs error template \n#5548\n\n\nAdd rounding parameter to DecimalField \n#5562\n\n\nFix all BytesWarning caught during tests \n#5561\n\n\nUse dict and set literals instead of calls to dict() and set() \n#5559\n\n\nChange ImageField validation pattern, use validators from DjangoImageField \n#5539\n\n\nFix processing unicode symbols in query_string by Python 2 \n#5552\n\n\n\n\n3.7.1\n\n\nDate\n: \n16th October 2017\n\n\n\n\nFix Interactive documentation always uses false for boolean fields in requests \n#5492\n\n\nImprove compatibility with Django 2.0 alpha. \n#5500\n \n#5503\n\n\nImproved handling of schema naming collisions \n#5486\n\n\nAdded additional docs and tests around providing a default value for dotted \nsource\n fields \n#5489\n\n\n\n\n3.7.0\n\n\nDate\n: \n6th October 2017\n\n\n\n\nFix \nDjangoModelPermissions\n to ensure user authentication before calling the view's \nget_queryset()\n method. As a side effect, this changes the order of the HTTP method permissions and authentication checks, and 405 responses will only be returned when authenticated. If you want to replicate the old behavior, see the PR for details. \n#5376\n\n\nDeprecated \nexclude_from_schema\n on \nAPIView\n and \napi_view\n decorator. Set \nschema = None\n or \n@schema(None)\n as appropriate. \n#5422\n\n\n\n\nTimezone-aware \nDateTimeField\ns now respect active or default \ntimezone\n during serialization, instead of always using UTC. \n#5435\n\n\nResolves inconsistency whereby instances were serialised with supplied datetime for \ncreate\n but UTC for \nretrieve\n. \n#3732\n\n\nPossible backwards compatibility break\n if you were relying on datetime strings being UTC. Have client interpret datetimes or \nset default or active timezone (docs)\n to UTC if needed.\n\n\n\n\n\n\nRemoved DjangoFilterBackend inline with deprecation policy. Use \ndjango_filters.rest_framework.FilterSet\n and/or \ndjango_filters.rest_framework.DjangoFilterBackend\n instead. \n#5273\n\n\n\n\nDon't strip microseconds from \ntime\n when encoding. Makes consistent with \ndatetime\n.\n \nBC Change\n: Previously only milliseconds were encoded. \n#5440\n\n\nAdded \nSTRICT_JSON\n setting (default \nTrue\n) to raise exception for the extended float values (\nnan\n, \ninf\n, \n-inf\n) accepted by Python's \njson\n module.\n \nBC Change\n: Previously these values would converted to corresponding strings. Set \nSTRICT_JSON\n to \nFalse\n to restore the previous behaviour. \n#5265\n\n\nAdd support for \npage_size\n parameter in CursorPaginator class \n#5250\n\n\nMake \nDEFAULT_PAGINATION_CLASS\n \nNone\n by default.\n \nBC Change\n: If your were \njust\n setting \nPAGE_SIZE\n to enable pagination you will need to add \nDEFAULT_PAGINATION_CLASS\n.\n The previous default was \nrest_framework.pagination.PageNumberPagination\n. There is a system check warning to catch this case. You may silence that if you are setting pagination class on a per-view basis. \n#5170\n\n\nCatch \nAPIException\n from \nget_serializer_fields\n in schema generation. \n#5443\n\n\nAllow custom authentication and permission classes when using \ninclude_docs_urls\n \n#5448\n\n\nDefer translated string evaluation on validators. \n#5452\n\n\nAdded default value for 'detail' param into 'ValidationError' exception \n#5342\n\n\nAdjust schema get_filter_fields rules to match framework \n#5454\n\n\nUpdated test matrix to add Django 2.0 and drop Django 1.8 & 1.9\n \nBC Change\n: This removes Django 1.8 and Django 1.9 from Django REST Framework supported versions. \n#5457\n\n\nFixed a deprecation warning in serializers.ModelField \n#5058\n\n\nAdded a more explicit error message when \nget_queryset\n returned \nNone\n \n#5348\n\n\nFix docs for Response \ndata\n description \n#5361\n\n\nFix \npycache\n/.pyc excludes when packaging \n#5373\n\n\nFix default value handling for dotted sources \n#5375\n\n\nEnsure content_type is set when passing empty body to RequestFactory \n#5351\n\n\nFix ErrorDetail Documentation \n#5380\n\n\nAllow optional content in the generic content form \n#5372\n\n\nUpdated supported values for the NullBooleanField \n#5387\n\n\nFix ModelSerializer custom named fields with source on model \n#5388\n\n\nFixed the MultipleFieldLookupMixin documentation example to properly check for object level permission \n#5398\n\n\nUpdate get_object() example in permissions.md \n#5401\n\n\nFix authtoken management command \n#5415\n\n\nFix schema generation markdown \n#5421\n\n\nAllow \nChoiceField.choices\n to be set dynamically \n#5426\n\n\nAdd the project layout to the quickstart \n#5434\n\n\nReuse 'apply_markdown' function in 'render_markdown' templatetag \n#5469\n\n\nAdded links to \ndrf-openapi\n package in docs \n#5470\n\n\nAdded docstrings code highlighting with pygments \n#5462\n\n\nFixed documentation rendering for views named \ndata\n \n#5472\n\n\nDocs: Clarified 'to_internal_value()' validation behavior \n#5466\n\n\nFix missing six.text_type() call on APIException.\nstr\n \n#5476\n\n\nDocument documentation.py \n#5478\n\n\nFix naming collisions in Schema Generation \n#5464\n\n\nCall Django's authenticate function with the request object \n#5295\n\n\nUpdate coreapi JS to 0.1.1 \n#5479\n\n\nHave \nis_list_view\n recognise RetrieveModel\u2026 views \n#5480\n\n\nRemove Django 1.8 & 1.9 compatibility code \n#5481\n\n\nRemove deprecated schema code from DefaultRouter \n#5482\n\n\nRefactor schema generation to allow per-view customisation.\n \nBC Change\n: \nSchemaGenerator.get_serializer_fields\n has been refactored as \nAutoSchema.get_serializer_fields\n and drops the \nview\n argument [#5354][gh5354]\n\n\n\n\n3.6.x series\n\n\n3.6.4\n\n\nDate\n: \n21st August 2017\n\n\n\n\nIgnore any invalidly formed query parameters for OrderingFilter. \n#5131\n\n\nImprove memory footprint when reading large JSON requests. \n#5147\n\n\nFix schema generation for pagination. \n#5161\n\n\nFix exception when \nHTML_CUTOFF\n is set to \nNone\n. \n#5174\n\n\nFix browsable API not supporting \nmultipart/form-data\n correctly. \n#5176\n\n\nFixed \ntest_hyperlinked_related_lookup_url_encoded_exists\n. \n#5179\n\n\nMake sure max_length is in FileField kwargs. \n#5186\n\n\nFix \nlist_route\n & \ndetail_route\n with kwargs contains curly bracket in \nurl_path\n \n#5187\n\n\nAdd Django manage command to create a DRF user Token. \n#5188\n\n\nEnsure API documentation templates do not check for user authentication \n#5162\n\n\nFix special case where OneToOneField is also primary key. \n#5192\n\n\nAdded aria-label and a new region for accessibility purposes in base.html \n#5196\n\n\nQuote nested API parameters in api.js. \n#5214\n\n\nSet ViewSet args/kwargs/request before dispatch. \n#5229\n\n\nAdded unicode support to SlugField. \n#5231\n\n\nFix HiddenField appears in Raw Data form initial content. \n#5259\n\n\nRaise validation error on invalid timezone parsing. \n#5261\n\n\nFix SearchFilter to-many behavior/performance. \n#5264\n\n\nSimplified chained comparisons and minor code fixes. \n#5276\n\n\nRemoteUserAuthentication, docs, and tests. \n#5306\n\n\nRevert \"Cached the field's root and context property\" \n#5313\n\n\nFix introspection of list field in schema. \n#5326\n\n\nFix interactive docs for multiple nested and extra methods. \n#5334\n\n\nFix/remove undefined template var \"schema\" \n#5346\n\n\n\n\n3.6.3\n\n\nDate\n: \n12th May 2017\n\n\n\n\nRaise 404 if a URL lookup results in ValidationError. (\n#5126\n)\n\n\nHonor http_method_names on class based view, when generating API schemas. (\n#5085\n)\n\n\nAllow overridden \nget_limit\n in LimitOffsetPagination to return all records. (\n#4437\n)\n\n\nFix partial update for the ListSerializer. (\n#4222\n)\n\n\nRender JSONField control correctly in browsable API. (\n#4999\n, \n#5042\n)\n\n\nRaise validation errors for invalid datetime in given timezone. (\n#4987\n)\n\n\nSupport restricting doc & schema shortcuts to a subset of urls. (\n#4979\n)\n\n\nResolve SchemaGenerator error with paginators that have no \npage_size\n attribute. (\n#5086\n, \n#3692\n)\n\n\nResolve HyperlinkedRelatedField exception on string with %20 instead of space. (\n#4748\n, \n#5078\n)\n\n\nCustomizable schema generator classes. (\n#5082\n)\n\n\nUpdate existing vary headers in response instead of overwriting them. (\n#5047\n)\n\n\nSupport passing \n.as_view()\n to view instance. (\n#5053\n)\n\n\nUse correct exception handler when settings overridden on a view. (\n#5055\n, \n#5054\n)\n\n\nUpdate Boolean field to support 'yes' and 'no' values. (\n#5038\n)\n\n\nFix unique validator for ChoiceField. (\n#5004\n, \n#5026\n, \n#5028\n)\n\n\nJavaScript cleanups in API Docs. (\n#5001\n)\n\n\nInclude URL path regexs in API schemas where valid. (\n#5014\n)\n\n\nCorrectly set scheme in coreapi TokenAuthentication. (\n#5000\n, \n#4994\n)\n\n\nHEAD requests on ViewSets should not return 405. (\n#4705\n, \n#4973\n, \n#4864\n)\n\n\nSupport usage of 'source' in \nextra_kwargs\n. (\n#4688\n)\n\n\nFix invalid content type for schema.js (\n#4968\n)\n\n\nFix DjangoFilterBackend inheritance issues. (\n#5089\n, \n#5117\n)\n\n\n\n\n3.6.2\n\n\nDate\n: \n10th March 2017\n\n\n\n\nSupport for Safari & IE in API docs. (\n#4959\n, \n#4961\n)\n\n\nAdd missing \nmark_safe\n in API docs template tags. (\n#4952\n, \n#4953\n)\n\n\nAdd missing glyphicon fonts. (\n#4950\n, \n#4951\n)\n\n\nFix One-to-one fields in API docs. (\n#4955\n, \n#4956\n)\n\n\nTest clean ups. (\n#4949\n)\n\n\n\n\n3.6.1\n\n\nDate\n: \n9th March 2017\n\n\n\n\nEnsure \nmarkdown\n dependency is optional. (\n#4947\n)\n\n\n\n\n3.6.0\n\n\nDate\n: \n9th March 2017\n\n\nSee the \nrelease announcement\n.\n\n\n\n\n3.5.x series\n\n\n3.5.4\n\n\nDate\n: \n10th February 2017\n\n\n\n\nAdd max_length and min_length arguments for ListField. (\n#4877\n)\n\n\nAdd per-view custom exception handler support. (\n#4753\n)\n\n\nSupport disabling of declared fields on serializer subclasses. (\n#4764\n)\n\n\nSupport custom view names on \n@list_route\n and \n@detail_route\n endpoints. (\n#4821\n)\n\n\nCorrect labels for fields in login template when custom user model is used. (\n#4841\n)\n\n\nWhitespace fixes for descriptions generated from docstrings. (\n#4759\n, \n#4869\n, \n#4870\n)\n\n\nBetter error reporting when schemas are returned by views without a schema renderer. (\n#4790\n)\n\n\nFix for returned response of \nPUT\n requests when \nprefetch_related\n is used. (\n#4661\n, \n#4668\n)\n\n\nFix for breadcrumb view names. (\n#4750\n)\n\n\nFix for RequestsClient ensuring fully qualified URLs. (\n#4678\n)\n\n\nFix for incorrect behavior of writable-nested fields check in some cases. (\n#4634\n, \n#4669\n)\n\n\nResolve Django deprecation warnings. (\n#4712\n)\n\n\nVarious cleanup of test cases.\n\n\n\n\n3.5.3\n\n\nDate\n: \n7th November 2016\n\n\n\n\nDon't raise incorrect FilterSet deprecation warnings. (\n#4660\n, \n#4643\n, \n#4644\n)\n\n\nSchema generation should not raise 404 when a view permission class does. (\n#4645\n, \n#4646\n)\n\n\nAdd \nautofocus\n support for input controls. (\n#4650\n)\n\n\n\n\n3.5.2\n\n\nDate\n: \n1st November 2016\n\n\n\n\nRestore exception tracebacks in Python 2.7. (\n#4631\n, \n#4638\n)\n\n\nProperly display dicts in the admin console. (\n#4532\n, \n#4636\n)\n\n\nFix is_simple_callable with variable args, kwargs. (\n#4622\n, \n#4602\n)\n\n\nSupport 'on'/'off' literals with BooleanField. (\n#4640\n, \n#4624\n)\n\n\nEnable cursor pagination of value querysets. (\n#4569\n)\n\n\nFix support of get_full_details() for Throttled exceptions. (\n#4627\n)\n\n\nFix FilterSet proxy. (\n#4620\n)\n\n\nMake serializer fields import explicit. (\n#4628\n)\n\n\nDrop redundant requests adapter. (\n#4639\n)\n\n\n\n\n3.5.1\n\n\nDate\n: \n21st October 2016\n\n\n\n\nMake \nrest_framework/compat.py\n imports. (\n#4612\n, \n#4608\n, \n#4601\n)\n\n\nFix bug in schema base path generation. (\n#4611\n, \n#4605\n)\n\n\nFix broken case of ListSerializer with single item. (\n#4609\n, \n#4606\n)\n\n\nRemove bare \nraise\n for Python 3.5 compat. (\n#4600\n)\n\n\n\n\n3.5.0\n\n\nDate\n: \n20th October 2016\n\n\n\n\n3.4.x series\n\n\n3.4.7\n\n\nDate\n: \n21st September 2016\n\n\n\n\nFallback behavior for request parsing when request.POST already accessed. (\n#3951\n, \n#4500\n)\n\n\nFix regression of \nRegexField\n. (\n#4489\n, \n#4490\n, \n#2617\n)\n\n\nMissing comma in \nadmin.html\n causing CSRF error. (\n#4472\n, \n#4473\n)\n\n\nFix response rendering with empty context. (\n#4495\n)\n\n\nFix indentation regression in API listing. (\n#4493\n)\n\n\nFixed an issue where the incorrect value is set to \nResolverMatch.func_name\n of api_view decorated view. (\n#4465\n, \n#4462\n)\n\n\nFix \nAPIClient.get()\n when path contains unicode arguments (\n#4458\n)\n\n\n\n\n3.4.6\n\n\nDate\n: \n23rd August 2016\n\n\n\n\nFix malformed Javascript in browsable API. (\n#4435\n)\n\n\nSkip HiddenField from Schema fields. (\n#4425\n, \n#4429\n)\n\n\nImprove Create to show the original exception traceback. (\n#3508\n)\n\n\nFix \nAdminRenderer\n display of PK only related fields. (\n#4419\n, \n#4423\n)\n\n\n\n\n3.4.5\n\n\nDate\n: \n19th August 2016\n\n\n\n\nImprove debug error handling. (\n#4416\n, \n#4409\n)\n\n\nAllow custom CSRF_HEADER_NAME setting. (\n#4415\n, \n#4410\n)\n\n\nInclude .action attribute on viewsets when generating schemas. (\n#4408\n, \n#4398\n)\n\n\nDo not include request.FILES items in request.POST. (\n#4407\n)\n\n\nFix rendering of checkbox multiple. (\n#4403\n)\n\n\nFix docstring of Field.get_default. (\n#4404\n)\n\n\nReplace utf8 character with its ascii counterpart in README. (\n#4412\n)\n\n\n\n\n3.4.4\n\n\nDate\n: \n12th August 2016\n\n\n\n\nEnsure views are fully initialized when generating schemas. (\n#4373\n, \n#4382\n, \n#4383\n, \n#4279\n, \n#4278\n)\n\n\nAdd form field descriptions to schemas. (\n#4387\n)\n\n\nFix category generation for schema endpoints. (\n#4391\n, \n#4394\n, \n#4390\n, \n#4386\n, \n#4376\n, \n#4329\n)\n\n\nDon't strip empty query params when paginating. (\n#4392\n, \n#4393\n, \n#4260\n)\n\n\nDo not re-run query for empty results with LimitOffsetPagination. (\n#4201\n, \n#4388\n)\n\n\nStricter type validation for CharField. (\n#4380\n, \n#3394\n)\n\n\nRelatedField.choices should preserve non-string values. (\n#4111\n, \n#4379\n, \n#3365\n)\n\n\nTest case for rendering checkboxes in vertical form style. (\n#4378\n, \n#3868\n, \n#3868\n)\n\n\nShow error traceback HTML in browsable API (\n#4042\n, \n#4172\n)\n\n\nFix handling of ALLOWED_VERSIONS and no DEFAULT_VERSION. \n#4370\n\n\nAllow \nmax_digits=None\n on DecimalField. (\n#4377\n, \n#4372\n)\n\n\nLimit queryset when rendering relational choices. (\n#4375\n, \n#4122\n, \n#3329\n, \n#3330\n, \n#3877\n)\n\n\nResolve form display with ChoiceField, MultipleChoiceField and non-string choices. (\n#4374\n, \n#4119\n, \n#4121\n, \n#4137\n, \n#4120\n)\n\n\nFix call to TemplateHTMLRenderer.resolve_context() fallback method. (\n#4371\n)\n\n\n\n\n3.4.3\n\n\nDate\n: \n5th August 2016\n\n\n\n\nInclude fallback for users of older TemplateHTMLRenderer internal API. (\n#4361\n)\n\n\n\n\n3.4.2\n\n\nDate\n: \n5th August 2016\n\n\n\n\nInclude kwargs passed to 'as_view' when generating schemas. (\n#4359\n, \n#4330\n, \n#4331\n)\n\n\nAccess \nrequest.user.is_authenticated\n as property not method, under Django 1.10+ (\n#4358\n, \n#4354\n)\n\n\nFilter HEAD out from schemas. (\n#4357\n)\n\n\nextra_kwargs takes precedence over uniqueness kwargs. (\n#4198\n, \n#4199\n, \n#4349\n)\n\n\nCorrect descriptions when tabs are used in code indentation. (\n#4345\n, \n#4347\n)*\n\n\nChange template context generation in TemplateHTMLRenderer. (\n#4236\n)\n\n\nSerializer defaults should not be included in partial updates. (\n#4346\n, \n#3565\n)\n\n\nConsistent behavior & descriptive error from FileUploadParser when filename not included. (\n#4340\n, \n#3610\n, \n#4292\n, \n#4296\n)\n\n\nDecimalField quantizes incoming digitals. (\n#4339\n, \n#4318\n)\n\n\nHandle non-string input for IP fields. (\n#4335\n, \n#4336\n, \n#4338\n)\n\n\nFix leading slash handling when Schema generation includes a root URL. (\n#4332\n)\n\n\nTest cases for DictField with allow_null options. (\n#4348\n)\n\n\nUpdate tests from Django 1.10 beta to Django 1.10. (\n#4344\n)\n\n\n\n\n3.4.1\n\n\nDate\n: \n28th July 2016\n\n\n\n\nAdded \nroot_renderers\n argument to \nDefaultRouter\n. (\n#4323\n, \n#4268\n)\n\n\nAdded \nurl\n and \nschema_url\n arguments. (\n#4321\n, \n#4308\n, \n#4305\n)\n\n\nUnique together checks should apply to read-only fields which have a default. (\n#4316\n, \n#4294\n)\n\n\nSet view.format_kwarg in schema generator. (\n#4293\n, \n#4315\n)\n\n\nFix schema generator for views with \npagination_class = None\n. (\n#4314\n, \n#4289\n)\n\n\nFix schema generator for views with no \nget_serializer_class\n. (\n#4265\n, \n#4285\n)\n\n\nFixes for media type parameters in \nAccept\n and \nContent-Type\n headers. (\n#4287\n, \n#4313\n, \n#4281\n)\n\n\nUse verbose_name instead of object_name in error messages. (\n#4299\n)\n\n\nMinor version update to Twitter Bootstrap. (\n#4307\n)\n\n\nSearchFilter raises error when using with related field. (\n#4302\n, \n#4303\n, \n#4298\n)\n\n\nAdding support for RFC 4918 status codes. (\n#4291\n)\n\n\nAdd LICENSE.md to the built wheel. (\n#4270\n)\n\n\nSerializing \"complex\" field returns None instead of the value since 3.4 (\n#4272\n, \n#4273\n, \n#4288\n)\n\n\n\n\n3.4.0\n\n\nDate\n: \n14th July 2016\n\n\n\n\nDon't strip microseconds in JSON output. (\n#4256\n)\n\n\nTwo slightly different iso 8601 datetime serialization. (\n#4255\n)\n\n\nResolve incorrect inclusion of media type parameters. (\n#4254\n)\n\n\nResponse Content-Type potentially malformed. (\n#4253\n)\n\n\nFix setup.py error on some platforms. (\n#4246\n)\n\n\nMove alternate formats in coreapi into separate packages. (\n#4244\n)\n\n\nAdd localize keyword argument to \nDecimalField\n. (\n#4233\n)\n\n\nFix issues with routers for custom list-route and detail-routes. (\n#4229\n)\n\n\nNamespace versioning with nested namespaces. (\n#4219\n)\n\n\nRobust uniqueness checks. (\n#4217\n)\n\n\nMinor refactoring of \nmust_call_distinct\n. (\n#4215\n)\n\n\nOverridable offset cutoff in CursorPagination. (\n#4212\n)\n\n\nPass through strings as-in with date/time fields. (\n#4196\n)\n\n\nAdd test confirming that required=False is valid on a relational field. (\n#4195\n)\n\n\nIn LimitOffsetPagination \nlimit=0\n should revert to default limit. (\n#4194\n)\n\n\nExclude read_only=True fields from unique_together validation & add docs. (\n#4192\n)\n\n\nHandle bytestrings in JSON. (\n#4191\n)\n\n\nJSONField(binary=True) represents using binary strings, which JSONRenderer does not support. (\n#4187\n)\n\n\nJSONField(binary=True) represents using binary strings, which JSONRenderer does not support. (\n#4185\n)\n\n\nMore robust form rendering in the browsable API. (\n#4181\n)\n\n\nEmpty cases of \n.validated_data\n and \n.errors\n as lists not dicts for ListSerializer. (\n#4180\n)\n\n\nSchemas & client libraries. (\n#4179\n)\n\n\nRemoved \nAUTH_USER_MODEL\n compat property. (\n#4176\n)\n\n\nClean up existing deprecation warnings. (\n#4166\n)\n\n\nDjango 1.10 support. (\n#4158\n)\n\n\nUpdated jQuery version to 1.12.4. (\n#4157\n)\n\n\nMore robust default behavior on OrderingFilter. (\n#4156\n)\n\n\ndescription.py codes and tests removal. (\n#4153\n)\n\n\nWrap guardian.VERSION in tuple. (\n#4149\n)\n\n\nRefine validator for fields with \n kwargs. (\n#4146\n)\n\n\nFix None values representation in childs of ListField, DictField. (\n#4118\n)\n\n\nResolve TimeField representation for midnight value. (\n#4107\n)\n\n\nSet proper status code in AdminRenderer for the redirection after POST/DELETE requests. (\n#4106\n)\n\n\nTimeField render returns None instead of 00:00:00. (\n#4105\n)\n\n\nFix incorrectly named zh-hans and zh-hant locale path. (\n#4103\n)\n\n\nPrevent raising exception when limit is 0. (\n#4098\n)\n\n\nTokenAuthentication: Allow custom keyword in the header. (\n#4097\n)\n\n\nHandle incorrectly padded HTTP basic auth header. (\n#4090\n)\n\n\nLimitOffset pagination crashes Browseable API when limit=0. (\n#4079\n)\n\n\nFixed DecimalField arbitrary precision support. (\n#4075\n)\n\n\nAdded support for custom CSRF cookie names. (\n#4049\n)\n\n\nFix regression introduced by #4035. (\n#4041\n)\n\n\nNo auth view failing permission should raise 403. (\n#4040\n)\n\n\nFix string_types / text_types confusion. (\n#4025\n)\n\n\nDo not list related field choices in OPTIONS requests. (\n#4021\n)\n\n\nFix typo. (\n#4008\n)\n\n\nReorder initializing the view. (\n#4006\n)\n\n\nType error in DjangoObjectPermissionsFilter on Python 3.4. (\n#4005\n)\n\n\nFixed use of deprecated Query.aggregates. (\n#4003\n)\n\n\nFix blank lines around docstrings. (\n#4002\n)\n\n\nFixed admin pagination when limit is 0. (\n#3990\n)\n\n\nOrderingFilter adjustments. (\n#3983\n)\n\n\nNon-required serializer related fields. (\n#3976\n)\n\n\nUsing safer calling way of \"@api_view\" in tutorial. (\n#3971\n)\n\n\nListSerializer doesn't handle unique_together constraints. (\n#3970\n)\n\n\nAdd missing migration file. (\n#3968\n)\n\n\nOrderingFilter\n should call \nget_serializer_class()\n to determine default fields. (\n#3964\n)\n\n\nRemove old Django checks from tests and compat. (\n#3953\n)\n\n\nSupport callable as the value of \ninitial\n for any \nserializer.Field\n. (\n#3943\n)\n\n\nPrevented unnecessary distinct() call in SearchFilter. (\n#3938\n)\n\n\nFix None UUID ForeignKey serialization. (\n#3936\n)\n\n\nDrop EOL Django 1.7. (\n#3933\n)\n\n\nAdd missing space in serializer error message. (\n#3926\n)\n\n\nFixed _force_text_recursive typo. (\n#3908\n)\n\n\nAttempt to address Django 2.0 deprecate warnings related to \nfield.rel\n. (\n#3906\n)\n\n\nFix parsing multipart data using a nested serializer with list. (\n#3820\n)\n\n\nResolving APIs URL to different namespaces. (\n#3816\n)\n\n\nDo not HTML-escape \nhelp_text\n in Browsable API forms. (\n#3812\n)\n\n\nOPTIONS fetches and shows all possible foreign keys in choices field. (\n#3751\n)\n\n\nDjango 1.9 deprecation warnings (\n#3729\n)\n\n\nTest case for #3598 (\n#3710\n)\n\n\nAdding support for multiple values for search filter. (\n#3541\n)\n\n\nUse get_serializer_class in ordering filter. (\n#3487\n)\n\n\nSerializers with many=True should return empty list rather than empty dict. (\n#3476\n)\n\n\nLimitOffsetPagination limit=0 fix. (\n#3444\n)\n\n\nEnable Validators to defer string evaluation and handle new string format. (\n#3438\n)\n\n\nUnique validator is executed and breaks if field is invalid. (\n#3381\n)\n\n\nDo not ignore overridden View.get_view_name() in breadcrumbs. (\n#3273\n)\n\n\nRetry form rendering when rendering with serializer fails. (\n#3164\n)\n\n\nUnique constraint prevents nested serializers from updating. (\n#2996\n)\n\n\nUniqueness validators should not be run for excluded (read_only) fields. (\n#2848\n)\n\n\nUniqueValidator raises exception for nested objects. (\n#2403\n)\n\n\nlookup_type\n is deprecated in favor of \nlookup_expr\n. (\n#4259\n)\n\n\n\n\n\n\n3.3.x series\n\n\n3.3.3\n\n\nDate\n: \n14th March 2016\n.\n\n\n\n\nRemove version string from templates. Thanks to @blag for the report and fixes. (\n#3878\n, \n#3913\n, \n#3912\n)\n\n\nFixes vertical html layout for \nBooleanField\n. Thanks to Mikalai Radchuk for the fix. (\n#3910\n)\n\n\nSilenced deprecation warnings on Django 1.8. Thanks to Simon Charette for the fix. (\n#3903\n)\n\n\nInternationalization for authtoken. Thanks to Michael Nacharov for the fix. (\n#3887\n, \n#3968\n)\n\n\nFix \nToken\n model as \nabstract\n when the authtoken application isn't declared. Thanks to Adam Thomas for the report. (\n#3860\n, \n#3858\n)\n\n\nImprove Markdown version compatibility. Thanks to Michael J. Schultz for the fix. (\n#3604\n, \n#3842\n)\n\n\nQueryParameterVersioning\n does not use \nDEFAULT_VERSION\n setting. Thanks to Brad Montgomery for the fix. (\n#3833\n)\n\n\nAdd an explicit \non_delete\n on the models. Thanks to Mads Jensen for the fix. (\n#3832\n)\n\n\nFix \nDateField.to_representation\n to work with Python 2 unicode. Thanks to Mikalai Radchuk for the fix. (\n#3819\n)\n\n\nFixed \nTimeField\n not handling string times. Thanks to Areski Belaid for the fix. (\n#3809\n)\n\n\nAvoid updates of \nMeta.extra_kwargs\n. Thanks to Kevin Massey for the report and fix. (\n#3805\n, \n#3804\n)\n\n\nFix nested validation error being rendered incorrectly. Thanks to Craig de Stigter for the fix. (\n#3801\n)\n\n\nDocument how to avoid CSRF and missing button issues with \ndjango-crispy-forms\n. Thanks to Emmanuelle Delescolle, Jos\u00e9 Padilla and Luis San Pablo for the report, analysis and fix. (\n#3787\n, \n#3636\n, \n#3637\n)\n\n\nImprove Rest Framework Settings file setup time. Thanks to Miles Hutson for the report and Mads Jensen for the fix. (\n#3786\n, \n#3815\n)\n\n\nImprove authtoken compatibility with Django 1.9. Thanks to S. Andrew Sheppard for the fix. (\n#3785\n)\n\n\nFix \nMin/MaxValueValidator\n transfer from a model's \nDecimalField\n. Thanks to Kevin Brown for the fix. (\n#3774\n)\n\n\nImprove HTML title in the Browsable API. Thanks to Mike Lissner for the report and fix. (\n#3769\n)\n\n\nFix \nAutoFilterSet\n to inherit from \ndefault_filter_set\n. Thanks to Tom Linford for the fix. (\n#3753\n)\n\n\nFix transifex config to handle the new Chinese language codes. Thanks to @nypisces for the report and fix. (\n#3739\n)\n\n\nDateTimeField\n does not handle empty values correctly. Thanks to Mick Parker for the report and fix. (\n#3731\n, \n#3726\n)\n\n\nRaise error when setting a removed rest_framework setting. Thanks to Luis San Pablo for the fix. (\n#3715\n)\n\n\nAdd missing csrf_token in AdminRenderer post form. Thanks to Piotr \u015aniegowski for the fix. (\n#3703\n)\n\n\nRefactored \n_get_reverse_relationships()\n to use correct \nto_field\n. Thanks to Benjamin Phillips for the fix. (\n#3696\n)\n\n\nDocument the use of \nget_queryset\n for \nRelatedField\n. Thanks to Ryan Hiebert for the fix. (\n#3605\n)\n\n\nFix empty pk detection in HyperlinkRelatedField.get_url. Thanks to @jslang for the fix (\n#3962\n)\n\n\n\n\n3.3.2\n\n\nDate\n: \n14th December 2015\n.\n\n\n\n\nListField\n enforces input is a list. (\n#3513\n)\n\n\nFix regression hiding raw data form. (\n#3600\n, \n#3578\n)\n\n\nFix Python 3.5 compatibility. (\n#3534\n, \n#3626\n)\n\n\nAllow setting a custom Django Paginator in \npagination.PageNumberPagination\n. (\n#3631\n, \n#3684\n)\n\n\nFix relational fields without \nto_fields\n attribute. (\n#3635\n, \n#3634\n)\n\n\nFix \ntemplate.render\n deprecation warnings for Django 1.9. (\n#3654\n)\n\n\nSort response headers in browsable API renderer. (\n#3655\n)\n\n\nUse related_objects api for Django 1.9+. (\n#3656\n, \n#3252\n)\n\n\nAdd confirm modal when deleting. (\n#3228\n, \n#3662\n)\n\n\nReveal previously hidden AttributeErrors and TypeErrors while calling has_[object_]permissions. (\n#3668\n)\n\n\nMake DRF compatible with multi template engine in Django 1.8. (\n#3672\n)\n\n\nUpdate \nNestedBoundField\n to also handle empty string when rendering its form. (\n#3677\n)\n\n\nFix UUID validation to properly catch invalid input types. (\n#3687\n, \n#3679\n)\n\n\nFix caching issues. (\n#3628\n, \n#3701\n)\n\n\nFix Admin and API browser for views without a filter_class. (\n#3705\n, \n#3596\n, \n#3597\n)\n\n\nAdd app_name to rest_framework.urls. (\n#3714\n)\n\n\nImprove authtoken's views to support url versioning. (\n#3718\n, \n#3723\n)\n\n\n\n\n3.3.1\n\n\nDate\n: \n4th November 2015\n.\n\n\n\n\nResolve parsing bug when accessing \nrequest.POST\n (\n#3592\n)\n\n\nCorrectly deal with \nto_field\n referring to primary key. (\n#3593\n)\n\n\nAllow filter HTML to render when no \nfilter_class\n is defined. (\n#3560\n)\n\n\nFix admin rendering issues. (\n#3564\n, \n#3556\n)\n\n\nFix issue with DecimalValidator. (\n#3568\n)\n\n\n\n\n3.3.0\n\n\nDate\n: \n28th October 2015\n.\n\n\n\n\nHTML controls for filters. (\n#3315\n)\n\n\nForms API. (\n#3475\n)\n\n\nAJAX browsable API. (\n#3410\n)\n\n\nAdded JSONField. (\n#3454\n)\n\n\nCorrectly map \nto_field\n when creating \nModelSerializer\n relational fields. (\n#3526\n)\n\n\nInclude keyword arguments when mapping \nFilePathField\n to a serializer field. (\n#3536\n)\n\n\nMap appropriate model \nerror_messages\n on \nModelSerializer\n uniqueness constraints. (\n#3435\n)\n\n\nInclude \nmax_length\n constraint for \nModelSerializer\n fields mapped from TextField. (\n#3509\n)\n\n\nAdded support for Django 1.9. (\n#3450\n, \n#3525\n)\n\n\nRemoved support for Django 1.5 & 1.6. (\n#3421\n, \n#3429\n)\n\n\nRemoved 'south' migrations. (\n#3495\n)\n\n\n\n\n\n\n3.2.x series\n\n\n3.2.5\n\n\nDate\n: \n27th October 2015\n.\n\n\n\n\nEscape \nusername\n in optional logout tag. (\n#3550\n)\n\n\n\n\n3.2.4\n\n\nDate\n: \n21th September 2015\n.\n\n\n\n\nDon't error on missing \nViewSet.search_fields\n attribute. (\n#3324\n, \n#3323\n)\n\n\nFix \nallow_empty\n not working on serializers with \nmany=True\n. (\n#3361\n, \n#3364\n)\n\n\nLet \nDurationField\n accepts integers. (\n#3359\n)\n\n\nMulti-level dictionaries not supported in multipart requests. (\n#3314\n)\n\n\nFix \nListField\n truncation on HTTP PATCH (\n#3415\n, \n#2761\n)\n\n\n\n\n3.2.3\n\n\nDate\n: \n24th August 2015\n.\n\n\n\n\nAdded \nhtml_cutoff\n and \nhtml_cutoff_text\n for limiting select dropdowns. (\n#3313\n)\n\n\nAdded regex style to \nSearchFilter\n. (\n#3316\n)\n\n\nResolve issues with setting blank HTML fields. (\n#3318\n) (\n#3321\n)\n\n\nCorrectly display existing 'select multiple' values in browsable API forms. (\n#3290\n)\n\n\nResolve duplicated validation message for \nIPAddressField\n. ([#3249[gh3249]) (\n#3250\n)\n\n\nFix to ensure admin renderer continues to work when pagination is disabled. (\n#3275\n)\n\n\nResolve error with \nLimitOffsetPagination\n when count=0, offset=0. (\n#3303\n)\n\n\n\n\n3.2.2\n\n\nDate\n: \n13th August 2015\n.\n\n\n\n\nAdd \ndisplay_value()\n method for use when displaying relational field select inputs. (\n#3254\n)\n\n\nFix issue with \nBooleanField\n checkboxes incorrectly displaying as checked. (\n#3258\n)\n\n\nEnsure empty checkboxes properly set \nBooleanField\n to \nFalse\n in all cases. (\n#2776\n)\n\n\nAllow \nWSGIRequest.FILES\n property without raising incorrect deprecated error. (\n#3261\n)\n\n\nResolve issue with rendering nested serializers in forms. (\n#3260\n)\n\n\nRaise an error if user accidentally pass a serializer instance to a response, rather than data. (\n#3241\n)\n\n\n\n\n3.2.1\n\n\nDate\n: \n7th August 2015\n.\n\n\n\n\nFix for relational select widgets rendering without any choices. (\n#3237\n)\n\n\nFix for \n1\n, \n0\n rendering as \ntrue\n, \nfalse\n in the admin interface. \n#3227\n)\n\n\nFix for ListFields with single value in HTML form input. (\n#3238\n)\n\n\nAllow \nrequest.FILES\n for compat with Django's \nHTTPRequest\n class. (\n#3239\n)\n\n\n\n\n3.2.0\n\n\nDate\n: \n6th August 2015\n.\n\n\n\n\nAdd \nAdminRenderer\n. (\n#2926\n)\n\n\nAdd \nFilePathField\n. (\n#1854\n)\n\n\nAdd \nallow_empty\n to \nListField\n. (\n#2250\n)\n\n\nSupport django-guardian 1.3. (\n#3165\n)\n\n\nSupport grouped choices. (\n#3225\n)\n\n\nSupport error forms in browsable API. (\n#3024\n)\n\n\nAllow permission classes to customize the error message. (\n#2539\n)\n\n\nSupport \nsource=\n on hyperlinked fields. (\n#2690\n)\n\n\nListField(allow_null=True)\n now allows null as the list value, not null items in the list. (\n#2766\n)\n\n\nManyToMany()\n maps to \nallow_empty=False\n, \nManyToMany(blank=True)\n maps to \nallow_empty=True\n. (\n#2804\n)\n\n\nSupport custom serialization styles for primary key fields. (\n#2789\n)\n\n\nOPTIONS\n requests support nested representations. (\n#2915\n)\n\n\nSet \nview.action == \"metadata\"\n for viewsets with \nOPTIONS\n requests. (\n#3115\n)\n\n\nSupport \nallow_blank\n on \nUUIDField\n. ([#3130][gh#3130])\n\n\nDo not display view docstrings with 401 or 403 response codes. (\n#3216\n)\n\n\nResolve Django 1.8 deprecation warnings. (\n#2886\n)\n\n\nFix for \nDecimalField\n validation. (\n#3139\n)\n\n\nFix behavior of \nallow_blank=False\n when used with \ntrim_whitespace=True\n. (\n#2712\n)\n\n\nFix issue with some field combinations incorrectly mapping to an invalid \nallow_blank\n argument. (\n#3011\n)\n\n\nFix for output representations with prefetches and modified querysets. (\n#2704\n, \n#2727\n)\n\n\nFix assertion error when CursorPagination is provided with certain invalid query parameters. (#2920)\ngh2920\n.\n\n\nFix \nUnicodeDecodeError\n when invalid characters included in header with \nTokenAuthentication\n. (\n#2928\n)\n\n\nFix transaction rollbacks with \n@non_atomic_requests\n decorator. (\n#3016\n)\n\n\nFix duplicate results issue with Oracle databases using \nSearchFilter\n. (\n#2935\n)\n\n\nFix checkbox alignment and rendering in browsable API forms. (\n#2783\n)\n\n\nFix for unsaved file objects which should use \n\"url\": null\n in the representation. (\n#2759\n)\n\n\nFix field value rendering in browsable API. (\n#2416\n)\n\n\nFix \nHStoreField\n to include \nallow_blank=True\n in \nDictField\n mapping. (\n#2659\n)\n\n\nNumerous other cleanups, improvements to error messaging, private API & minor fixes.\n\n\n\n\n\n\n3.1.x series\n\n\n3.1.3\n\n\nDate\n: \n4th June 2015\n.\n\n\n\n\nAdd \nDurationField\n. (\n#2481\n, \n#2989\n)\n\n\nAdd \nformat\n argument to \nUUIDField\n. (\n#2788\n, \n#3000\n)\n\n\nMultipleChoiceField\n empties incorrectly on a partial update using multipart/form-data (\n#2993\n, \n#2894\n)\n\n\nFix a bug in options related to read-only \nRelatedField\n. (\n#2981\n, \n#2811\n)\n\n\nFix nested serializers with \nunique_together\n relations. (\n#2975\n)\n\n\nAllow unexpected values for \nChoiceField\n/\nMultipleChoiceField\n representations. (\n#2839\n, \n#2940\n)\n\n\nRollback the transaction on error if \nATOMIC_REQUESTS\n is set. (\n#2887\n, \n#2034\n)\n\n\nSet the action on a view when override_method regardless of its None-ness. (\n#2933\n)\n\n\nDecimalField\n accepts \n2E+2\n as 200 and validates decimal place correctly. (\n#2948\n, \n#2947\n)\n\n\nSupport basic authentication with custom \nUserModel\n that change \nusername\n. (\n#2952\n)\n\n\nIPAddressField\n improvements. (\n#2747\n, \n#2618\n, \n#3008\n)\n\n\nImprove \nDecimalField\n for easier subclassing. (\n#2695\n)\n\n\n\n\n3.1.2\n\n\nDate\n: \n13rd May 2015\n.\n\n\n\n\nDateField.to_representation\n can handle str and empty values. (\n#2656\n, \n#2687\n, \n#2869\n)\n\n\nUse default reason phrases from HTTP standard. (\n#2764\n, \n#2763\n)\n\n\nRaise error when \nModelSerializer\n used with abstract model. (\n#2757\n, \n#2630\n)\n\n\nHandle reversal of non-API view_name in \nHyperLinkedRelatedField\n (\n#2724\n, \n#2711\n)\n\n\nDon't require pk strictly for related fields. (\n#2745\n, \n#2754\n)\n\n\nMetadata detects null boolean field type. (\n#2762\n)\n\n\nProper handling of depth in nested serializers. (\n#2798\n)\n\n\nDisplay viewset without paginator. (\n#2807\n)\n\n\nDon't check for deprecated \n.model\n attribute in permissions (\n#2818\n)\n\n\nRestrict integer field to integers and strings. (\n#2835\n, \n#2836\n)\n\n\nImprove \nIntegerField\n to use compiled decimal regex. (\n#2853\n)\n\n\nPrevent empty \nqueryset\n to raise AssertionError. (\n#2862\n)\n\n\nDjangoModelPermissions\n rely on \nget_queryset\n. (\n#2863\n)\n\n\nCheck \nAcceptHeaderVersioning\n with content negotiation in place. (\n#2868\n)\n\n\nAllow \nDjangoObjectPermissions\n to use views that define \nget_queryset\n. (\n#2905\n)\n\n\n\n\n3.1.1\n\n\nDate\n: \n23rd March 2015\n.\n\n\n\n\nSecurity fix\n: Escape tab switching cookie name in browsable API.\n\n\nDisplay input forms in browsable API if \nserializer_class\n is used, even when \nget_serializer\n method does not exist on the view. (\n#2743\n)\n\n\nUse a password input for the AuthTokenSerializer. (\n#2741\n)\n\n\nFix missing anchor closing tag after next button. (\n#2691\n)\n\n\nFix \nlookup_url_kwarg\n handling in viewsets. (\n#2685\n, \n#2591\n)\n\n\nFix problem with importing \nrest_framework.views\n in \napps.py\n (\n#2678\n)\n\n\nLimitOffsetPagination raises \nTypeError\n if PAGE_SIZE not set (\n#2667\n, \n#2700\n)\n\n\nGerman translation for \nmin_value\n field error message references \nmax_value\n. (\n#2645\n)\n\n\nRemove \nMergeDict\n. (\n#2640\n)\n\n\nSupport serializing unsaved models with related fields. (\n#2637\n, \n#2641\n)\n\n\nAllow blank/null on radio.html choices. (\n#2631\n)\n\n\n\n\n3.1.0\n\n\nDate\n: \n5th March 2015\n.\n\n\nFor full details see the \n3.1 release announcement\n.\n\n\n\n\n3.0.x series\n\n\n3.0.5\n\n\nDate\n: \n10th February 2015\n.\n\n\n\n\nFix a bug where \n_closable_objects\n breaks pickling. (\n#1850\n, \n#2492\n)\n\n\nAllow non-standard \nUser\n models with \nThrottling\n. (\n#2524\n)\n\n\nSupport custom \nUser.db_table\n in TokenAuthentication migration. (\n#2479\n)\n\n\nFix misleading \nAttributeError\n tracebacks on \nRequest\n objects. (\n#2530\n, \n#2108\n)\n\n\nManyRelatedField.get_value\n clearing field on partial update. (\n#2475\n)\n\n\nRemoved '.model' shortcut from code. (\n#2486\n)\n\n\nFix \ndetail_route\n and \nlist_route\n mutable argument. (\n#2518\n)\n\n\nPrefetching the user object when getting the token in \nTokenAuthentication\n. (\n#2519\n)\n\n\n\n\n3.0.4\n\n\nDate\n: \n28th January 2015\n.\n\n\n\n\nDjango 1.8a1 support. (\n#2425\n, \n#2446\n, \n#2441\n)\n\n\nAdd \nDictField\n and support Django 1.8 \nHStoreField\n. (\n#2451\n, \n#2106\n)\n\n\nAdd \nUUIDField\n and support Django 1.8 \nUUIDField\n. (\n#2448\n, \n#2433\n, \n#2432\n)\n\n\nBaseRenderer.render\n now raises \nNotImplementedError\n. (\n#2434\n)\n\n\nFix timedelta JSON serialization on Python 2.6. (\n#2430\n)\n\n\nResultDict\n and \nResultList\n now appear as standard dict/list. (\n#2421\n)\n\n\nFix visible \nHiddenField\n in the HTML form of the web browsable API page. (\n#2410\n)\n\n\nUse \nOrderedDict\n for \nRelatedField.choices\n. (\n#2408\n)\n\n\nFix ident format when using \nHTTP_X_FORWARDED_FOR\n. (\n#2401\n)\n\n\nFix invalid key with memcached while using throttling. (\n#2400\n)\n\n\nFix \nFileUploadParser\n with version 3.x. (\n#2399\n)\n\n\nFix the serializer inheritance. (\n#2388\n)\n\n\nFix caching issues with \nReturnDict\n. (\n#2360\n)\n\n\n\n\n3.0.3\n\n\nDate\n: \n8th January 2015\n.\n\n\n\n\nFix \nMinValueValidator\n on \nmodels.DateField\n. (\n#2369\n)\n\n\nFix serializer missing context when pagination is used. (\n#2355\n)\n\n\nNamespaced router URLs are now supported by the \nDefaultRouter\n. (\n#2351\n)\n\n\nrequired=False\n allows omission of value for output. (\n#2342\n)\n\n\nUse textarea input for \nmodels.TextField\n. (\n#2340\n)\n\n\nUse custom \nListSerializer\n for pagination if required. (\n#2331\n, \n#2327\n)\n\n\nBetter behavior with null and '' for blank HTML fields. (\n#2330\n)\n\n\nEnsure fields in \nexclude\n are model fields. (\n#2319\n)\n\n\nFix \nIntegerField\n and \nmax_length\n argument incompatibility. (\n#2317\n)\n\n\nFix the YAML encoder for 3.0 serializers. (\n#2315\n, \n#2283\n)\n\n\nFix the behavior of empty HTML fields. (\n#2311\n, \n#1101\n)\n\n\nFix Metaclass attribute depth ignoring fields attribute. (\n#2287\n)\n\n\nFix \nformat_suffix_patterns\n to work with Django's \ni18n_patterns\n. (\n#2278\n)\n\n\nAbility to customize router URLs for custom actions, using \nurl_path\n. (\n#2010\n)\n\n\nDon't install Django REST Framework as egg. (\n#2386\n)\n\n\n\n\n3.0.2\n\n\nDate\n: \n17th December 2014\n.\n\n\n\n\nEnsure \nrequest.user\n is made available to response middleware. (\n#2155\n)\n\n\nClient.logout()\n also cancels any existing \nforce_authenticate\n. (\n#2218\n, \n#2259\n)\n\n\nExtra assertions and better checks to preventing incorrect serializer API use. (\n#2228\n, \n#2234\n, \n#2262\n, \n#2263\n, \n#2266\n, \n#2267\n, \n#2289\n, \n#2291\n)\n\n\nFixed \nmin_length\n message for \nCharField\n. (\n#2255\n)\n\n\nFix \nUnicodeDecodeError\n, which can occur on serializer \nrepr\n. (\n#2270\n, \n#2279\n)\n\n\nFix empty HTML values when a default is provided. (\n#2280\n, \n#2294\n)\n\n\nFix \nSlugRelatedField\n raising \nUnicodeEncodeError\n when used as a multiple choice input. (\n#2290\n)\n\n\n\n\n3.0.1\n\n\nDate\n: \n11th December 2014\n.\n\n\n\n\nMore helpful error message when the default Serializer \ncreate()\n fails. (\n#2013\n)\n\n\nRaise error when attempting to save serializer if data is not valid. (\n#2098\n)\n\n\nFix \nFileUploadParser\n breaks with empty file names and multiple upload handlers. (\n#2109\n)\n\n\nImprove \nBindingDict\n to support standard dict-functions. (\n#2135\n, \n#2163\n)\n\n\nAdd \nvalidate()\n to \nListSerializer\n. (\n#2168\n, \n#2225\n, \n#2232\n)\n\n\nFix JSONP renderer failing to escape some characters. (\n#2169\n, \n#2195\n)\n\n\nAdd missing default style for \nFileField\n. (\n#2172\n)\n\n\nActions are required when calling \nViewSet.as_view()\n. (\n#2175\n)\n\n\nAdd \nallow_blank\n to \nChoiceField\n. (\n#2184\n, \n#2239\n)\n\n\nCosmetic fixes in the HTML renderer. (\n#2187\n)\n\n\nRaise error if \nfields\n on serializer is not a list of strings. (\n#2193\n, \n#2213\n)\n\n\nImprove checks for nested creates and updates. (\n#2194\n, \n#2196\n)\n\n\nvalidated_attrs\n argument renamed to \nvalidated_data\n in \nSerializer\n \ncreate()\n/\nupdate()\n. (\n#2197\n)\n\n\nRemove deprecated code to reflect the dropped Django versions. (\n#2200\n)\n\n\nBetter serializer errors for nested writes. (\n#2202\n, \n#2215\n)\n\n\nFix pagination and custom permissions incompatibility. (\n#2205\n)\n\n\nRaise error if \nfields\n on serializer is not a list of strings. (\n#2213\n)\n\n\nAdd missing translation markers for relational fields. (\n#2231\n)\n\n\nImprove field lookup behavior for dicts/mappings. (\n#2244\n, \n#2243\n)\n\n\nOptimized hyperlinked PK. (\n#2242\n)\n\n\n\n\n3.0.0\n\n\nDate\n: 1st December 2014\n\n\nFor full details see the \n3.0 release announcement\n.\n\n\n\n\nFor older release notes, \nplease see the version 2.x documentation\n.", "title": "Release Notes" }, { @@ -5707,9 +5742,19 @@ }, { "location": "/topics/release-notes/#upgrading", - "text": "To upgrade Django REST framework to the latest version, use pip: pip install -U djangorestframework You can determine your currently installed version using pip freeze : pip freeze | grep djangorestframework", + "text": "To upgrade Django REST framework to the latest version, use pip: pip install -U djangorestframework You can determine your currently installed version using pip show : pip show djangorestframework", "title": "Upgrading" }, + { + "location": "/topics/release-notes/#38x-series", + "text": "", + "title": "3.8.x series" + }, + { + "location": "/topics/release-notes/#380", + "text": "Date : 3rd April 2018 Breaking Change : Alter read_only plus default behaviour. #5886 read_only fields will now always be excluded from writable fields. Previously read_only fields with a default value would use the default for create and update operations. In order to maintain the old behaviour you may need to pass the value of read_only fields when calling save() in\nthe view: def perform_create(self, serializer):\n serializer.save(owner=self.request.user) Alternatively you may override save() or create() or update() on the serialiser as appropriate.\n* Correct allow_null behaviour when required=False #5888 Without an explicit default , allow_null implies a default of null for outgoing serialisation. Previously such\nfields were being skipped when read-only or otherwise not required. Possible backwards compatibility break if you were relying on such fields being excluded from the outgoing\nrepresentation. In order to restore the old behaviour you can override data to exclude the field when None . For example: @property\ndef data(self):\n \"\"\"\n Drop `maybe_none` field if None.\n \"\"\"\n data = super().data()\n if 'maybe_none' in data and data['maybe_none'] is None:\n del data['maybe_none']\n return data Refactor dynamic route generation and improve viewset action introspectibility. #5705 ViewSet s have been provided with new attributes and methods that allow\nit to introspect its set of actions and the details of the current action. Merged list_route and detail_route into a single action decorator. Get all extra actions on a ViewSet with .get_extra_actions() . Extra actions now set the url_name and url_path on the decorated method. Enable action url reversing through .reverse_action() method (added in 3.7.4) Example reverse call: self.reverse_action(self.custom_action.url_name) Add detail initkwarg to indicate if the current action is operating on a\n collection or a single instance. Additional changes: Deprecated list_route & detail_route in favor of action decorator with detail boolean. Deprecated dynamic list/detail route variants in favor of DynamicRoute with detail boolean. Refactored the router's dynamic route generation. Fix formatting of the 3.7.4 release note #5704 Docs: Update DRF Writable Nested Serializers references #5711 Docs: Fixed typo in auth URLs example. #5713 Improve composite field child errors #5655 Disable HTML inputs for dict/list fields #5702 Fix typo in HostNameVersioning doc #5709 Use rsplit to get module and classname for imports #5712 Formalize URLPatternsTestCase #5703 Add exception translation test #5700 Test staticfiles #5701 Add drf-yasg to documentation and schema 3rd party packages #5720 Remove unused compat._resolve_model() #5733 Drop compat workaround for unsupported Python 3.2 #5734 Prefer iter(dict) over iter(dict.keys()) #5736 Pass python_requires argument to setuptools #5739 Remove unused links from docs #5735 Prefer https protocol for links in docs when available #5729 Add HStoreField, postgres fields tests #5654 Always fully qualify ValidationError in docs #5751 Remove unreachable code from ManualSchema #5766 Allowed customising API documentation code samples #5752 Updated docs to use pip show #5757 Load 'static' instead of 'staticfiles' in templates #5773 Fixed a typo in fields docs #5783 Refer to \"NamespaceVersioning\" instead of \"NamespacedVersioning\" in the documentation #5754 ErrorDetail: add __eq__ / __ne__ and __repr__ #5787 Replace background-attachment: fixed in docs #5777 Make 404 & 403 responses consistent with exceptions.APIException output #5763 Small fix to API documentation: schemas #5796 Fix schema generation for PrimaryKeyRelatedField #5764 Represent serializer DictField as an Object in schema #5765 Added docs example reimplementing ObtainAuthToken #5802 Add schema to the ObtainAuthToken view #5676 Fix request formdata handling #5800 Fix authtoken views imports #5818 Update pytest, isort #5815 #5817 #5894 Fixed active timezone handling for non ISO8601 datetimes. #5833 Made TemplateHTMLRenderer render IntegerField inputs when value is 0 . #5834 Corrected endpoint in tutorial instructions #5835 Add Django Rest Framework Role Filters to Third party packages #5809 Use single copy of static assets. Update jQuery #5823 Changes ternary conditionals to be PEP308 compliant #5827 Added links to 'A Todo List API with React' and 'Blog API' tutorials #5837 Fix comment typo in ModelSerializer #5844 Add admin to installed apps to avoid test failures. #5870 Fixed schema for UUIDField in SimpleMetadata. #5872 Corrected docs on router include with namespaces. #5843 Test using model objects for dotted source default #5880 Allow traversing nullable related fields #5849 Added: Tutorial: Django REST with React (Django 2.0) #5891 Add LimitOffsetPagination.get_count to allow method override #5846 Don't show hidden fields in metadata #5854 Enable OrderingFilter to handle an empty tuple (or list) for the 'ordering' field. #5899 Added generic 500 and 400 JSON error handlers. #5904", + "title": "3.8.0" + }, { "location": "/topics/release-notes/#37x-series", "text": "", diff --git a/sitemap.xml b/sitemap.xml index d6d62d437..b5b9cc299 100644 --- a/sitemap.xml +++ b/sitemap.xml @@ -4,7 +4,7 @@ http://www.django-rest-framework.org// - 2018-01-15 + 2018-04-03 daily @@ -13,49 +13,49 @@ http://www.django-rest-framework.org//tutorial/quickstart/ - 2018-01-15 + 2018-04-03 daily http://www.django-rest-framework.org//tutorial/1-serialization/ - 2018-01-15 + 2018-04-03 daily http://www.django-rest-framework.org//tutorial/2-requests-and-responses/ - 2018-01-15 + 2018-04-03 daily http://www.django-rest-framework.org//tutorial/3-class-based-views/ - 2018-01-15 + 2018-04-03 daily http://www.django-rest-framework.org//tutorial/4-authentication-and-permissions/ - 2018-01-15 + 2018-04-03 daily http://www.django-rest-framework.org//tutorial/5-relationships-and-hyperlinked-apis/ - 2018-01-15 + 2018-04-03 daily http://www.django-rest-framework.org//tutorial/6-viewsets-and-routers/ - 2018-01-15 + 2018-04-03 daily http://www.django-rest-framework.org//tutorial/7-schemas-and-client-libraries/ - 2018-01-15 + 2018-04-03 daily @@ -65,163 +65,163 @@ http://www.django-rest-framework.org//api-guide/requests/ - 2018-01-15 + 2018-04-03 daily http://www.django-rest-framework.org//api-guide/responses/ - 2018-01-15 + 2018-04-03 daily http://www.django-rest-framework.org//api-guide/views/ - 2018-01-15 + 2018-04-03 daily http://www.django-rest-framework.org//api-guide/generic-views/ - 2018-01-15 + 2018-04-03 daily http://www.django-rest-framework.org//api-guide/viewsets/ - 2018-01-15 + 2018-04-03 daily http://www.django-rest-framework.org//api-guide/routers/ - 2018-01-15 + 2018-04-03 daily http://www.django-rest-framework.org//api-guide/parsers/ - 2018-01-15 + 2018-04-03 daily http://www.django-rest-framework.org//api-guide/renderers/ - 2018-01-15 + 2018-04-03 daily http://www.django-rest-framework.org//api-guide/serializers/ - 2018-01-15 + 2018-04-03 daily http://www.django-rest-framework.org//api-guide/fields/ - 2018-01-15 + 2018-04-03 daily http://www.django-rest-framework.org//api-guide/relations/ - 2018-01-15 + 2018-04-03 daily http://www.django-rest-framework.org//api-guide/validators/ - 2018-01-15 + 2018-04-03 daily http://www.django-rest-framework.org//api-guide/authentication/ - 2018-01-15 + 2018-04-03 daily http://www.django-rest-framework.org//api-guide/permissions/ - 2018-01-15 + 2018-04-03 daily http://www.django-rest-framework.org//api-guide/throttling/ - 2018-01-15 + 2018-04-03 daily http://www.django-rest-framework.org//api-guide/filtering/ - 2018-01-15 + 2018-04-03 daily http://www.django-rest-framework.org//api-guide/pagination/ - 2018-01-15 + 2018-04-03 daily http://www.django-rest-framework.org//api-guide/versioning/ - 2018-01-15 + 2018-04-03 daily http://www.django-rest-framework.org//api-guide/content-negotiation/ - 2018-01-15 + 2018-04-03 daily http://www.django-rest-framework.org//api-guide/metadata/ - 2018-01-15 + 2018-04-03 daily http://www.django-rest-framework.org//api-guide/schemas/ - 2018-01-15 + 2018-04-03 daily http://www.django-rest-framework.org//api-guide/format-suffixes/ - 2018-01-15 + 2018-04-03 daily http://www.django-rest-framework.org//api-guide/reverse/ - 2018-01-15 + 2018-04-03 daily http://www.django-rest-framework.org//api-guide/exceptions/ - 2018-01-15 + 2018-04-03 daily http://www.django-rest-framework.org//api-guide/status-codes/ - 2018-01-15 + 2018-04-03 daily http://www.django-rest-framework.org//api-guide/testing/ - 2018-01-15 + 2018-04-03 daily http://www.django-rest-framework.org//api-guide/settings/ - 2018-01-15 + 2018-04-03 daily @@ -231,151 +231,151 @@ http://www.django-rest-framework.org//topics/documenting-your-api/ - 2018-01-15 + 2018-04-03 daily http://www.django-rest-framework.org//topics/api-clients/ - 2018-01-15 + 2018-04-03 daily http://www.django-rest-framework.org//topics/internationalization/ - 2018-01-15 + 2018-04-03 daily http://www.django-rest-framework.org//topics/ajax-csrf-cors/ - 2018-01-15 + 2018-04-03 daily http://www.django-rest-framework.org//topics/html-and-forms/ - 2018-01-15 + 2018-04-03 daily http://www.django-rest-framework.org//topics/browser-enhancements/ - 2018-01-15 + 2018-04-03 daily http://www.django-rest-framework.org//topics/browsable-api/ - 2018-01-15 + 2018-04-03 daily http://www.django-rest-framework.org//topics/rest-hypermedia-hateoas/ - 2018-01-15 + 2018-04-03 daily http://www.django-rest-framework.org//topics/third-party-packages/ - 2018-01-15 + 2018-04-03 daily http://www.django-rest-framework.org//topics/tutorials-and-resources/ - 2018-01-15 + 2018-04-03 daily http://www.django-rest-framework.org//topics/contributing/ - 2018-01-15 + 2018-04-03 daily http://www.django-rest-framework.org//topics/project-management/ - 2018-01-15 + 2018-04-03 daily http://www.django-rest-framework.org//topics/jobs/ - 2018-01-15 + 2018-04-03 daily http://www.django-rest-framework.org//topics/3.0-announcement/ - 2018-01-15 + 2018-04-03 daily http://www.django-rest-framework.org//topics/3.1-announcement/ - 2018-01-15 + 2018-04-03 daily http://www.django-rest-framework.org//topics/3.2-announcement/ - 2018-01-15 + 2018-04-03 daily http://www.django-rest-framework.org//topics/3.3-announcement/ - 2018-01-15 + 2018-04-03 daily http://www.django-rest-framework.org//topics/3.4-announcement/ - 2018-01-15 + 2018-04-03 daily http://www.django-rest-framework.org//topics/3.5-announcement/ - 2018-01-15 + 2018-04-03 daily http://www.django-rest-framework.org//topics/3.6-announcement/ - 2018-01-15 + 2018-04-03 daily http://www.django-rest-framework.org//topics/3.7-announcement/ - 2018-01-15 + 2018-04-03 daily http://www.django-rest-framework.org//topics/kickstarter-announcement/ - 2018-01-15 + 2018-04-03 daily http://www.django-rest-framework.org//topics/mozilla-grant/ - 2018-01-15 + 2018-04-03 daily http://www.django-rest-framework.org//topics/funding/ - 2018-01-15 + 2018-04-03 daily http://www.django-rest-framework.org//topics/release-notes/ - 2018-01-15 + 2018-04-03 daily diff --git a/topics/api-clients/index.html b/topics/api-clients/index.html index b69c33032..66eff7b2f 100644 --- a/topics/api-clients/index.html +++ b/topics/api-clients/index.html @@ -784,7 +784,7 @@ urlpatterns = [ /static/rest_framework/js/coreapi-0.1.1.js /docs/schema.js --> -{% load staticfiles %} +{% load static %} <script src="{% static 'rest_framework/js/coreapi-0.1.1.js' %}"></script> <script src="{% url 'api-docs:schema-js' %}"></script>
    diff --git a/topics/contributing/index.html b/topics/contributing/index.html index e8ec49a01..280120068 100644 --- a/topics/contributing/index.html +++ b/topics/contributing/index.html @@ -490,9 +490,13 @@
  • If a ticket hasn't had much activity and it addresses something you need, then comment on the ticket and try to find out what's needed to get it moving again.
  • Development

    -

    To start developing on Django REST framework, clone the repo:

    -
    git clone git@github.com:encode/django-rest-framework.git
    +

    To start developing on Django REST framework, first create a Fork from the +Django REST Framework repo on GitHub.

    +

    Then clone your fork. The clone command will look like this, with your GitHub +username instead of YOUR-USERNAME:

    +
    git clone https://github.com/YOUR-USERNAME/Spoon-Knife
     
    +

    See GitHub's Fork a Repo Guide for more help.

    Changes should broadly follow the PEP 8 style conventions, and we recommend you set up your editor to automatically indicate non-conforming styles.

    Testing

    To run the tests, clone the repository, and then:

    diff --git a/topics/documenting-your-api/index.html b/topics/documenting-your-api/index.html index 9afa403cf..346365ef3 100644 --- a/topics/documenting-your-api/index.html +++ b/topics/documenting-your-api/index.html @@ -505,6 +505,7 @@ For example:

  • generator_class: Default rest_framework.schemas.SchemaGenerator. May be used to specify a SchemaGenerator subclass to be passed to the SchemaView.
  • authentication_classes: Default api_settings.DEFAULT_AUTHENTICATION_CLASSES. May be used to pass custom authentication classes to the SchemaView.
  • permission_classes: Default api_settings.DEFAULT_PERMISSION_CLASSES May be used to pass custom permission classes to the SchemaView.
  • +
  • renderer_classes: Default None. May be used to pass custom renderer classes to the SchemaView.
  • get_docs_view

      @@ -515,7 +516,8 @@ For example:

    • patterns: Default None. A list of URLs to inspect when generating the schema. If None project's URL conf will be used.
    • generator_class: Default rest_framework.schemas.SchemaGenerator. May be used to specify a SchemaGenerator subclass to be passed to the SchemaView.
    • authentication_classes: Default api_settings.DEFAULT_AUTHENTICATION_CLASSES. May be used to pass custom authentication classes to the SchemaView.
    • -
    • permission_classes: Default api_settings.DEFAULT_PERMISSION_CLASSES May be used to pass custom permission classes to the SchemaView.
    • +
    • permission_classes: Default api_settings.DEFAULT_PERMISSION_CLASSES. May be used to pass custom permission classes to the SchemaView.
    • +
    • renderer_classes: Default None. May be used to pass custom renderer classes to the SchemaView. If None the SchemaView will be configured with DocumentationRenderer and CoreJSONRenderer renderers, corresponding to the (default) html and corejson formats.

    get_schemajs_view

      @@ -528,14 +530,28 @@ For example:

    • authentication_classes: Default api_settings.DEFAULT_AUTHENTICATION_CLASSES. May be used to pass custom authentication classes to the SchemaView.
    • permission_classes: Default api_settings.DEFAULT_PERMISSION_CLASSES May be used to pass custom permission classes to the SchemaView.
    +

    Customising code samples

    +

    The built-in API documentation includes automatically generated code samples for +each of the available API client libraries.

    +

    You may customise these samples by subclassing DocumentationRenderer, setting +languages to the list of languages you wish to support:

    +
    from rest_framework.renderers import DocumentationRenderer
    +
    +
    +class CustomRenderer(DocumentationRenderer):
    +    languages = ['ruby', 'go']
    +
    +

    For each language you need to provide an intro template, detailing installation instructions and such, +plus a generic template for making API requests, that can be filled with individual request details. +See the templates for the bundled languages for examples.


    Third party packages

    There are a number of mature third-party packages for providing API documentation.

    drf-yasg - Yet Another Swagger Generator

    -

    drf-yasg is a Swagger generation tool implemented without using the schema generation provided +

    drf-yasg is a Swagger generation tool implemented without using the schema generation provided by Django Rest Framework.

    -

    It aims to implement as much of the OpenAPI specification as possible - nested schemas, named models, -response bodies, enum/pattern/min/max validators, form parameters, etc. - and to generate documents usable with code +

    It aims to implement as much of the OpenAPI specification as possible - nested schemas, named models, +response bodies, enum/pattern/min/max validators, form parameters, etc. - and to generate documents usable with code generation tools like swagger-codegen.

    This also translates into a very useful interactive documentation viewer in the form of swagger-ui:

    Screenshot - drf-yasg

    diff --git a/topics/funding/index.html b/topics/funding/index.html index d08d51a96..c1b7e1b06 100644 --- a/topics/funding/index.html +++ b/topics/funding/index.html @@ -750,7 +750,7 @@ DRF is one of the core reasons why Django is top choice among web frameworks tod

    For further enquires please contact funding@django-rest-framework.org.


    Accountability

    -

    In an effort to keep the project as transparent as possible, we are releasing monthly progress reports and regularly include financial reports and cost breakdowns.

    +

    In an effort to keep the project as transparent as possible, we are releasing monthly progress reports and regularly include financial reports and cost breakdowns.

    diff --git a/topics/jobs/index.html b/topics/jobs/index.html index 5e9850d29..58049f05d 100644 --- a/topics/jobs/index.html +++ b/topics/jobs/index.html @@ -420,6 +420,7 @@

  • https://www.technojobs.co.uk/django-jobs
  • https://remoteok.io/remote-django-jobs
  • https://www.remotepython.com/jobs/
  • +
  • https://weworkcontract.com/python-contract-jobs
  • Know of any other great resources for Django REST Framework jobs that are missing in our list? Please submit a pull request or email us.

    Wonder how else you can help? One of the best ways you can help Django REST Framework is to ask interviewers if their company is signed up for REST Framework sponsorship yet.

    diff --git a/topics/release-notes/index.html b/topics/release-notes/index.html index 207cdd7b6..05ed639b1 100644 --- a/topics/release-notes/index.html +++ b/topics/release-notes/index.html @@ -398,6 +398,10 @@ Upgrading +
  • + 3.8.x series +
  • +
  • 3.7.x series
  • @@ -473,10 +477,116 @@

    To upgrade Django REST framework to the latest version, use pip:

    pip install -U djangorestframework
     
    -

    You can determine your currently installed version using pip freeze:

    -
    pip freeze | grep djangorestframework
    +

    You can determine your currently installed version using pip show:

    +
    pip show djangorestframework
     

    +

    3.8.x series

    +

    3.8.0

    +

    Date: 3rd April 2018

    +
      +
    • +

      Breaking Change: Alter read_only plus default behaviour. #5886

      +

      read_only fields will now always be excluded from writable fields.

      +

      Previously read_only fields with a default value would use the default for create and update operations.

      +

      In order to maintain the old behaviour you may need to pass the value of read_only fields when calling save() in +the view:

      +
      def perform_create(self, serializer):
      +    serializer.save(owner=self.request.user)
      +
      +

      Alternatively you may override save() or create() or update() on the serialiser as appropriate. +* Correct allow_null behaviour when required=False #5888

      +

      Without an explicit default, allow_null implies a default of null for outgoing serialisation. Previously such +fields were being skipped when read-only or otherwise not required.

      +

      Possible backwards compatibility break if you were relying on such fields being excluded from the outgoing +representation. In order to restore the old behaviour you can override data to exclude the field when None.

      +

      For example:

      +
      @property
      +def data(self):
      +    """
      +    Drop `maybe_none` field if None.
      +    """
      +    data = super().data()
      +    if 'maybe_none' in data and data['maybe_none'] is None:
      +        del data['maybe_none']
      +    return data
      +
      +
    • +
    • +

      Refactor dynamic route generation and improve viewset action introspectibility. #5705

      +

      ViewSets have been provided with new attributes and methods that allow +it to introspect its set of actions and the details of the current action.

      +
        +
      • Merged list_route and detail_route into a single action decorator.
      • +
      • Get all extra actions on a ViewSet with .get_extra_actions().
      • +
      • Extra actions now set the url_name and url_path on the decorated method.
      • +
      • Enable action url reversing through .reverse_action() method (added in 3.7.4)
      • +
      • Example reverse call: self.reverse_action(self.custom_action.url_name)
      • +
      • Add detail initkwarg to indicate if the current action is operating on a + collection or a single instance.
      • +
      +

      Additional changes:

      +
        +
      • Deprecated list_route & detail_route in favor of action decorator with detail boolean.
      • +
      • Deprecated dynamic list/detail route variants in favor of DynamicRoute with detail boolean.
      • +
      • Refactored the router's dynamic route generation.
      • +
      • Fix formatting of the 3.7.4 release note #5704
      • +
      • Docs: Update DRF Writable Nested Serializers references #5711
      • +
      • Docs: Fixed typo in auth URLs example. #5713
      • +
      • Improve composite field child errors #5655
      • +
      • Disable HTML inputs for dict/list fields #5702
      • +
      • Fix typo in HostNameVersioning doc #5709
      • +
      • Use rsplit to get module and classname for imports #5712
      • +
      • Formalize URLPatternsTestCase #5703
      • +
      • Add exception translation test #5700
      • +
      • Test staticfiles #5701
      • +
      • Add drf-yasg to documentation and schema 3rd party packages #5720
      • +
      • Remove unused compat._resolve_model() #5733
      • +
      • Drop compat workaround for unsupported Python 3.2 #5734
      • +
      • Prefer iter(dict) over iter(dict.keys()) #5736
      • +
      • Pass python_requires argument to setuptools #5739
      • +
      • Remove unused links from docs #5735
      • +
      • Prefer https protocol for links in docs when available #5729
      • +
      • Add HStoreField, postgres fields tests #5654
      • +
      • Always fully qualify ValidationError in docs #5751
      • +
      • Remove unreachable code from ManualSchema #5766
      • +
      • Allowed customising API documentation code samples #5752
      • +
      • Updated docs to use pip show #5757
      • +
      • Load 'static' instead of 'staticfiles' in templates #5773
      • +
      • Fixed a typo in fields docs #5783
      • +
      • Refer to "NamespaceVersioning" instead of "NamespacedVersioning" in the documentation #5754
      • +
      • ErrorDetail: add __eq__/__ne__ and __repr__ #5787
      • +
      • Replace background-attachment: fixed in docs #5777
      • +
      • Make 404 & 403 responses consistent with exceptions.APIException output #5763
      • +
      • Small fix to API documentation: schemas #5796
      • +
      • Fix schema generation for PrimaryKeyRelatedField #5764
      • +
      • Represent serializer DictField as an Object in schema #5765
      • +
      • Added docs example reimplementing ObtainAuthToken #5802
      • +
      • Add schema to the ObtainAuthToken view #5676
      • +
      • Fix request formdata handling #5800
      • +
      • Fix authtoken views imports #5818
      • +
      • Update pytest, isort #5815 #5817 #5894
      • +
      • Fixed active timezone handling for non ISO8601 datetimes. #5833
      • +
      • Made TemplateHTMLRenderer render IntegerField inputs when value is 0. #5834
      • +
      • Corrected endpoint in tutorial instructions #5835
      • +
      • Add Django Rest Framework Role Filters to Third party packages #5809
      • +
      • Use single copy of static assets. Update jQuery #5823
      • +
      • Changes ternary conditionals to be PEP308 compliant #5827
      • +
      • Added links to 'A Todo List API with React' and 'Blog API' tutorials #5837
      • +
      • Fix comment typo in ModelSerializer #5844
      • +
      • Add admin to installed apps to avoid test failures. #5870
      • +
      • Fixed schema for UUIDField in SimpleMetadata. #5872
      • +
      • Corrected docs on router include with namespaces. #5843
      • +
      • Test using model objects for dotted source default #5880
      • +
      • Allow traversing nullable related fields #5849
      • +
      • Added: Tutorial: Django REST with React (Django 2.0) #5891
      • +
      • Add LimitOffsetPagination.get_count to allow method override #5846
      • +
      • Don't show hidden fields in metadata #5854
      • +
      • Enable OrderingFilter to handle an empty tuple (or list) for the 'ordering' field. #5899
      • +
      • Added generic 500 and 400 JSON error handlers. #5904
      • +
      +
    • +

    3.7.x series

    3.7.7

    Date: 21st December 2017

    @@ -1327,6 +1437,8 @@ Previously may have been stored internally as None.

    + + diff --git a/topics/tutorials-and-resources/index.html b/topics/tutorials-and-resources/index.html index fb55a758b..fa68024a2 100644 --- a/topics/tutorials-and-resources/index.html +++ b/topics/tutorials-and-resources/index.html @@ -445,6 +445,9 @@
  • Check Credentials Using Django REST Framework
  • Creating a Production Ready API with Python and Django REST Framework – Part 1
  • Creating a Production Ready API with Python and Django REST Framework – Part 2
  • +
  • Django REST Framework Tutorial - Build a Blog API
  • +
  • Django REST Framework & React Tutorial - Build a Todo List API
  • +
  • Tutorial: Django REST with React (Django 2.0)
  • Videos

    Talks

    diff --git a/tutorial/4-authentication-and-permissions/index.html b/tutorial/4-authentication-and-permissions/index.html index dcef4ebe4..c5ec7e255 100644 --- a/tutorial/4-authentication-and-permissions/index.html +++ b/tutorial/4-authentication-and-permissions/index.html @@ -465,8 +465,8 @@ from pygments import highlight representation of the code snippet. """ lexer = get_lexer_by_name(self.language) - linenos = self.linenos and 'table' or False - options = self.title and {'title': self.title} or {} + linenos = 'table' if self.linenos else False + options = {'title': self.title} if self.title else {} formatter = HtmlFormatter(style=self.style, linenos=linenos, full=True, **options) self.highlighted = highlight(self.code, lexer, formatter) diff --git a/tutorial/6-viewsets-and-routers/index.html b/tutorial/6-viewsets-and-routers/index.html index b7065521a..3c1e069e4 100644 --- a/tutorial/6-viewsets-and-routers/index.html +++ b/tutorial/6-viewsets-and-routers/index.html @@ -435,7 +435,7 @@ class UserViewSet(viewsets.ReadOnlyModelViewSet):

    Here we've used the ReadOnlyModelViewSet class to automatically provide the default 'read-only' operations. We're still setting the queryset and serializer_class attributes exactly as we did when we were using regular views, but we no longer need to provide the same information to two separate classes.

    Next we're going to replace the SnippetList, SnippetDetail and SnippetHighlight view classes. We can remove the three views, and again replace them with a single class.

    -
    from rest_framework.decorators import detail_route
    +
    from rest_framework.decorators import action
     from rest_framework.response import Response
     
     class SnippetViewSet(viewsets.ModelViewSet):
    @@ -450,7 +450,7 @@ class SnippetViewSet(viewsets.ModelViewSet):
         permission_classes = (permissions.IsAuthenticatedOrReadOnly,
                               IsOwnerOrReadOnly,)
     
    -    @detail_route(renderer_classes=[renderers.StaticHTMLRenderer])
    +    @action(detail=True, renderer_classes=[renderers.StaticHTMLRenderer])
         def highlight(self, request, *args, **kwargs):
             snippet = self.get_object()
             return Response(snippet.highlighted)
    @@ -459,9 +459,9 @@ class SnippetViewSet(viewsets.ModelViewSet):
             serializer.save(owner=self.request.user)
     

    This time we've used the ModelViewSet class in order to get the complete set of default read and write operations.

    -

    Notice that we've also used the @detail_route decorator to create a custom action, named highlight. This decorator can be used to add any custom endpoints that don't fit into the standard create/update/delete style.

    -

    Custom actions which use the @detail_route decorator will respond to GET requests by default. We can use the methods argument if we wanted an action that responded to POST requests.

    -

    The URLs for custom actions by default depend on the method name itself. If you want to change the way url should be constructed, you can include url_path as a decorator keyword argument.

    +

    Notice that we've also used the @action decorator to create a custom action, named highlight. This decorator can be used to add any custom endpoints that don't fit into the standard create/update/delete style.

    +

    Custom actions which use the @action decorator will respond to GET requests by default. We can use the methods argument if we wanted an action that responded to POST requests.

    +

    The URLs for custom actions by default depend on the method name itself. If you want to change the way url should be constructed, you can include url_path as a decorator keyword argument.

    Binding ViewSets to URLs explicitly

    The handler methods only get bound to the actions when we define the URLConf. To see what's going on under the hood let's first explicitly create a set of views from our ViewSets.

    diff --git a/tutorial/7-schemas-and-client-libraries/index.html b/tutorial/7-schemas-and-client-libraries/index.html index de1a0f101..684e9c7d5 100644 --- a/tutorial/7-schemas-and-client-libraries/index.html +++ b/tutorial/7-schemas-and-client-libraries/index.html @@ -461,7 +461,7 @@ urlpatterns = [ ]
    -

    If you visit the API root endpoint in a browser you should now see corejson +

    If you visit the /schema/ endpoint in a browser you should now see corejson representation become available as an option.

    Schema format

    We can also request the schema from the command line, by specifying the desired