diff --git a/404.html b/404.html index 4d7e19e9b..6330872e6 100644 --- a/404.html +++ b/404.html @@ -302,6 +302,10 @@ 3.4 Announcement +
  • + 3.5 Announcement +
  • +
  • Kickstarter Announcement
  • diff --git a/api-guide/authentication/index.html b/api-guide/authentication/index.html index 4588e5214..dfc424059 100644 --- a/api-guide/authentication/index.html +++ b/api-guide/authentication/index.html @@ -302,6 +302,10 @@ 3.4 Announcement +
  • + 3.5 Announcement +
  • +
  • Kickstarter Announcement
  • diff --git a/api-guide/content-negotiation/index.html b/api-guide/content-negotiation/index.html index 6ed6bb7ab..bc296cde7 100644 --- a/api-guide/content-negotiation/index.html +++ b/api-guide/content-negotiation/index.html @@ -302,6 +302,10 @@ 3.4 Announcement +
  • + 3.5 Announcement +
  • +
  • Kickstarter Announcement
  • diff --git a/api-guide/exceptions/index.html b/api-guide/exceptions/index.html index 4d8988cf3..12933aafa 100644 --- a/api-guide/exceptions/index.html +++ b/api-guide/exceptions/index.html @@ -302,6 +302,10 @@ 3.4 Announcement +
  • + 3.5 Announcement +
  • +
  • Kickstarter Announcement
  • diff --git a/api-guide/fields/index.html b/api-guide/fields/index.html index fb97d7da1..d0b5087fd 100644 --- a/api-guide/fields/index.html +++ b/api-guide/fields/index.html @@ -302,6 +302,10 @@ 3.4 Announcement +
  • + 3.5 Announcement +
  • +
  • Kickstarter Announcement
  • @@ -786,7 +790,7 @@ color_channel = serializers.ChoiceField(

    Format strings may either be Python strftime formats which explicitly specify the format, or the special string 'iso-8601', which indicates that ISO 8601 style datetimes should be used. (eg '2013-01-29T12:34:56.000000Z')

    When a value of None is used for the format datetime objects will be returned by to_representation and the final output representation will determined by the renderer class.

    In the case of JSON this means the default datetime representation uses the ECMA 262 date time string specification. This is a subset of ISO 8601 which uses millisecond precision, and includes the 'Z' suffix for the UTC timezone, for example: 2013-01-29T12:34:56.123Z.

    -

    auto_now and auto_now_add model fields.

    +

    auto_now_add model fields.auto_now and

    When using ModelSerializer or HyperlinkedModelSerializer, note that any model fields with auto_now=True or auto_now_add=True will use serializer fields that are read_only=True by default.

    If you want to override this behavior, you'll need to declare the DateTimeField explicitly on the serializer. For example:

    class CommentSerializer(serializers.ModelSerializer):
    diff --git a/api-guide/filtering/index.html b/api-guide/filtering/index.html
    index a4e74f15e..d7af9ceaf 100644
    --- a/api-guide/filtering/index.html
    +++ b/api-guide/filtering/index.html
    @@ -302,6 +302,10 @@
                         3.4 Announcement
                       
                       
    +                  
  • + 3.5 Announcement +
  • +
  • Kickstarter Announcement
  • @@ -546,22 +550,22 @@ class PurchaseList(generics.ListAPIView):

    Generic filters can also present themselves as HTML controls in the browsable API and admin API.

    Filter Example

    Setting filter backends

    -

    The default filter backends may be set globally, using the DEFAULT_FILTER_BACKENDS setting. For example.

    +

    The default filter backends may be set globally, using the DEFAULT_FILTER_BACKENDS setting. For example.

    REST_FRAMEWORK = {
    -    'DEFAULT_FILTER_BACKENDS': ('rest_framework.filters.DjangoFilterBackend',)
    +    'DEFAULT_FILTER_BACKENDS': ('django_filters.rest_framework.DjangoFilterBackend',)
     }
     

    You can also set the filter backends on a per-view, or per-viewset basis, using the GenericAPIView class-based views.

    -
    from django.contrib.auth.models import User
    +
    import django_filters
    +from django.contrib.auth.models import User
     from myapp.serializers import UserSerializer
    -from rest_framework import filters
     from rest_framework import generics
     
     class UserListView(generics.ListAPIView):
         queryset = User.objects.all()
         serializer_class = UserSerializer
    -    filter_backends = (filters.DjangoFilterBackend,)
    +    filter_backends = (django_filters.rest_framework.DjangoFilterBackend,)
     

    Filtering and object lookups

    Note that if a filter backend is configured for a view, then as well as being used to filter list views, it will also be used to filter the querysets used for returning a single object.

    @@ -586,10 +590,23 @@ class UserListView(generics.ListAPIView):

    API Guide

    DjangoFilterBackend

    -

    The DjangoFilterBackend class supports highly customizable field filtering, using the django-filter package.

    -

    To use REST framework's DjangoFilterBackend, first install django-filter.

    +

    The django-filter library includes a DjangoFilterBackend class which +supports highly customizable field filtering for REST framework.

    +

    To use DjangoFilterBackend, first install django-filter.

    pip install django-filter
     
    +

    You should now either add the filter backend to your settings:

    +
    REST_FRAMEWORK = {
    +    'DEFAULT_FILTER_BACKENDS': ('django_filters.rest_framework.DjangoFilterBackend',)
    +}
    +
    +

    Or add the filter backend to an individual View or ViewSet.

    +
    from django_filters.rest_framework import DjangoFilterBackend
    +
    +class UserListView(generics.ListAPIView):
    +    ...
    +    filter_backends = (DjangoFilterBackend,)
    +

    If you are using the browsable API or admin API you may also want to install django-crispy-forms, which will enhance the presentation of the filter forms in HTML views, by allowing them to render Bootstrap 3 HTML.

    pip install django-crispy-forms
     
    @@ -611,10 +628,9 @@ class UserListView(generics.ListAPIView):
    import django_filters
     from myapp.models import Product
     from myapp.serializers import ProductSerializer
    -from rest_framework import filters
     from rest_framework import generics
     
    -class ProductFilter(filters.FilterSet):
    +class ProductFilter(django_filters.rest_framework.FilterSet):
         min_price = django_filters.NumberFilter(name="price", lookup_expr='gte')
         max_price = django_filters.NumberFilter(name="price", lookup_expr='lte')
         class Meta:
    @@ -624,7 +640,7 @@ class ProductFilter(filters.FilterSet):
     class ProductList(generics.ListAPIView):
         queryset = Product.objects.all()
         serializer_class = ProductSerializer
    -    filter_backends = (filters.DjangoFilterBackend,)
    +    filter_backends = (django_filters.rest_framework.DjangoFilterBackend,)
         filter_class = ProductFilter
     

    Which will allow you to make requests such as:

    @@ -633,12 +649,12 @@ class ProductList(generics.ListAPIView):

    You can also span relationships using django-filter, let's assume that each product has foreign key to Manufacturer model, so we create filter that filters using Manufacturer name. For example:

    -
    from myapp.models import Product
    +
    import django_filters
    +from myapp.models import Product
     from myapp.serializers import ProductSerializer
    -from rest_framework import filters
     from rest_framework import generics
     
    -class ProductFilter(filters.FilterSet):
    +class ProductFilter(django_filters.rest_framework.FilterSet):
         class Meta:
             model = Product
             fields = ['category', 'in_stock', 'manufacturer__name']
    @@ -650,10 +666,9 @@ class ProductFilter(filters.FilterSet):
     
    import django_filters
     from myapp.models import Product
     from myapp.serializers import ProductSerializer
    -from rest_framework import filters
     from rest_framework import generics
     
    -class ProductFilter(filters.FilterSet):
    +class ProductFilter(django_filters.rest_framework.FilterSet):
         manufacturer = django_filters.CharFilter(name="manufacturer__name")
     
         class Meta:
    diff --git a/api-guide/format-suffixes/index.html b/api-guide/format-suffixes/index.html
    index 929394771..fde9b2218 100644
    --- a/api-guide/format-suffixes/index.html
    +++ b/api-guide/format-suffixes/index.html
    @@ -302,6 +302,10 @@
                         3.4 Announcement
                       
                       
    +                  
  • + 3.5 Announcement +
  • +
  • Kickstarter Announcement
  • diff --git a/api-guide/generic-views/index.html b/api-guide/generic-views/index.html index 46f307a7f..605ea2bff 100644 --- a/api-guide/generic-views/index.html +++ b/api-guide/generic-views/index.html @@ -302,6 +302,10 @@ 3.4 Announcement +
  • + 3.5 Announcement +
  • +
  • Kickstarter Announcement
  • diff --git a/api-guide/metadata/index.html b/api-guide/metadata/index.html index 87a0aa6c3..a05422a35 100644 --- a/api-guide/metadata/index.html +++ b/api-guide/metadata/index.html @@ -302,6 +302,10 @@ 3.4 Announcement +
  • + 3.5 Announcement +
  • +
  • Kickstarter Announcement
  • diff --git a/api-guide/pagination/index.html b/api-guide/pagination/index.html index 3fd8e2c67..7357e1103 100644 --- a/api-guide/pagination/index.html +++ b/api-guide/pagination/index.html @@ -302,6 +302,10 @@ 3.4 Announcement +
  • + 3.5 Announcement +
  • +
  • Kickstarter Announcement
  • diff --git a/api-guide/parsers/index.html b/api-guide/parsers/index.html index 6e080bd49..cc80c447f 100644 --- a/api-guide/parsers/index.html +++ b/api-guide/parsers/index.html @@ -302,6 +302,10 @@ 3.4 Announcement +
  • + 3.5 Announcement +
  • +
  • Kickstarter Announcement
  • diff --git a/api-guide/permissions/index.html b/api-guide/permissions/index.html index 1da41ec9e..9042ddbdb 100644 --- a/api-guide/permissions/index.html +++ b/api-guide/permissions/index.html @@ -302,6 +302,10 @@ 3.4 Announcement +
  • + 3.5 Announcement +
  • +
  • Kickstarter Announcement
  • diff --git a/api-guide/relations/index.html b/api-guide/relations/index.html index ec2b0a686..c6d6afa64 100644 --- a/api-guide/relations/index.html +++ b/api-guide/relations/index.html @@ -302,6 +302,10 @@ 3.4 Announcement +
  • + 3.5 Announcement +
  • +
  • Kickstarter Announcement
  • diff --git a/api-guide/renderers/index.html b/api-guide/renderers/index.html index f034e4f9a..67c0fb2f8 100644 --- a/api-guide/renderers/index.html +++ b/api-guide/renderers/index.html @@ -302,6 +302,10 @@ 3.4 Announcement +
  • + 3.5 Announcement +
  • +
  • Kickstarter Announcement
  • diff --git a/api-guide/requests/index.html b/api-guide/requests/index.html index 0f7cf9547..1edaaad7b 100644 --- a/api-guide/requests/index.html +++ b/api-guide/requests/index.html @@ -302,6 +302,10 @@ 3.4 Announcement +
  • + 3.5 Announcement +
  • +
  • Kickstarter Announcement
  • diff --git a/api-guide/responses/index.html b/api-guide/responses/index.html index 1760df8fb..49b28c5c7 100644 --- a/api-guide/responses/index.html +++ b/api-guide/responses/index.html @@ -302,6 +302,10 @@ 3.4 Announcement +
  • + 3.5 Announcement +
  • +
  • Kickstarter Announcement
  • diff --git a/api-guide/reverse/index.html b/api-guide/reverse/index.html index d62960aad..89122baf2 100644 --- a/api-guide/reverse/index.html +++ b/api-guide/reverse/index.html @@ -302,6 +302,10 @@ 3.4 Announcement +
  • + 3.5 Announcement +
  • +
  • Kickstarter Announcement
  • diff --git a/api-guide/routers/index.html b/api-guide/routers/index.html index 237775b50..fc35e74d8 100644 --- a/api-guide/routers/index.html +++ b/api-guide/routers/index.html @@ -302,6 +302,10 @@ 3.4 Announcement +
  • + 3.5 Announcement +
  • +
  • Kickstarter Announcement
  • diff --git a/api-guide/schemas/index.html b/api-guide/schemas/index.html index 92552db0e..a8496564e 100644 --- a/api-guide/schemas/index.html +++ b/api-guide/schemas/index.html @@ -302,6 +302,10 @@ 3.4 Announcement +
  • + 3.5 Announcement +
  • +
  • Kickstarter Announcement
  • @@ -738,12 +742,12 @@ generate a schema.

    Arguments:

      -
    • title - The name of the API. required
    • +
    • title required - The name of the API.
    • url - The root URL of the API schema. This option is not required unless the schema is included under path prefix.
    • patterns - A list of URLs to inspect when generating the schema. Defaults to the project's URL conf.
    • urlconf - A URL conf module name to use when generating the schema. Defaults to settings.ROOT_URLCONF.
    -

    get_schema()

    +

    get_schema(self, request)

    Returns a coreapi.Document instance that represents the API schema.

    @api_view
     @renderer_classes([renderers.CoreJSONRenderer])
    @@ -751,10 +755,30 @@ def schema_view(request):
         generator = schemas.SchemaGenerator(title='Bookings API')
         return Response(generator.get_schema())
     
    -

    Arguments:

    -
      -
    • request - The incoming request. Optionally used if you want to apply per-user permissions to the schema-generation.
    • -
    +

    The request argument is optional, and may be used if you want to apply per-user +permissions to the resulting schema generation.

    +

    get_links(self, request)

    +

    Return a nested dictionary containing all the links that should be included in the API schema.

    +

    This is a good point to override if you want to modify the resulting structure of the generated schema, +as you can build a new dictionary with a different layout.

    +

    get_link(self, path, method, view)

    +

    Returns a coreapi.Link instance corresponding to the given view.

    +

    You can override this if you need to provide custom behaviors for particular views.

    +

    get_description(self, path, method, view)

    +

    Returns a string to use as the link description. By default this is based on the +view docstring as described in the "Schemas as Documentation" section above.

    +

    get_encoding(self, path, method, view)

    +

    Returns a string to indicate the encoding for any request body, when interacting +with the given view. Eg. 'application/json'. May return a blank string for views +that do not expect a request body.

    +

    get_path_fields(self, path, method, view):

    +

    Return a list of coreapi.Link() instances. One for each path parameter in the URL.

    +

    get_serializer_fields(self, path, method, view)

    +

    Return a list of coreapi.Link() instances. One for each field in the serializer class used by the view.

    +

    get_pagination_fields(self, path, method, view

    +

    Return a list of coreapi.Link() instances, as returned by the get_schema_fields() method on any pagination class used by the view.

    +

    get_filter_fields(self, path, method, view)

    +

    Return a list of coreapi.Link() instances, as returned by the get_schema_fields() method of any filter classes used by the view.


    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 479ec4dc3..d7b3f6437 100644 --- a/api-guide/serializers/index.html +++ b/api-guide/serializers/index.html @@ -302,6 +302,10 @@ 3.4 Announcement +

  • + 3.5 Announcement +
  • +
  • Kickstarter Announcement
  • diff --git a/api-guide/settings/index.html b/api-guide/settings/index.html index 110a0b61a..6488c63b7 100644 --- a/api-guide/settings/index.html +++ b/api-guide/settings/index.html @@ -302,6 +302,10 @@ 3.4 Announcement +
  • + 3.5 Announcement +
  • +
  • Kickstarter Announcement
  • diff --git a/api-guide/status-codes/index.html b/api-guide/status-codes/index.html index 30a621fc0..294b4c915 100644 --- a/api-guide/status-codes/index.html +++ b/api-guide/status-codes/index.html @@ -302,6 +302,10 @@ 3.4 Announcement +
  • + 3.5 Announcement +
  • +
  • Kickstarter Announcement
  • diff --git a/api-guide/testing/index.html b/api-guide/testing/index.html index 44bbd1461..36ed0db7c 100644 --- a/api-guide/testing/index.html +++ b/api-guide/testing/index.html @@ -302,6 +302,10 @@ 3.4 Announcement +
  • + 3.5 Announcement +
  • +
  • Kickstarter Announcement
  • @@ -628,6 +632,7 @@ using the popular Python library, requests.

    directly.

    client = RequestsClient()
     response = client.get('http://testserver/users/')
    +assert response.status_code == 200
     

    Note that the requests client requires you to pass fully qualified URLs.

    Headers & Authentication

    @@ -672,9 +677,8 @@ do not directly affect customer data.

    The CoreAPIClient allows you to interact with your API using the Python coreapi client library.

    # Fetch the API schema
    -url = reverse('schema')
     client = CoreAPIClient()
    -schema = client.get(url)
    +schema = client.get('http://testserver/schema/')
     
     # Create a new organisation
     params = {'name': 'MegaCorp', 'status': 'active'}
    diff --git a/api-guide/throttling/index.html b/api-guide/throttling/index.html
    index 3c4e4d0e6..170a3e74e 100644
    --- a/api-guide/throttling/index.html
    +++ b/api-guide/throttling/index.html
    @@ -302,6 +302,10 @@
                         3.4 Announcement
                       
                       
    +                  
  • + 3.5 Announcement +
  • +
  • Kickstarter Announcement
  • diff --git a/api-guide/validators/index.html b/api-guide/validators/index.html index 395b66287..af9dda557 100644 --- a/api-guide/validators/index.html +++ b/api-guide/validators/index.html @@ -302,6 +302,10 @@ 3.4 Announcement +
  • + 3.5 Announcement +
  • +
  • Kickstarter Announcement
  • diff --git a/api-guide/versioning/index.html b/api-guide/versioning/index.html index 7a2d8f280..b635fbced 100644 --- a/api-guide/versioning/index.html +++ b/api-guide/versioning/index.html @@ -302,6 +302,10 @@ 3.4 Announcement +
  • + 3.5 Announcement +
  • +
  • Kickstarter Announcement
  • diff --git a/api-guide/views/index.html b/api-guide/views/index.html index 4db79efca..e6f506149 100644 --- a/api-guide/views/index.html +++ b/api-guide/views/index.html @@ -302,6 +302,10 @@ 3.4 Announcement +
  • + 3.5 Announcement +
  • +
  • Kickstarter Announcement
  • diff --git a/api-guide/viewsets/index.html b/api-guide/viewsets/index.html index 7436a4eb4..67779867f 100644 --- a/api-guide/viewsets/index.html +++ b/api-guide/viewsets/index.html @@ -302,6 +302,10 @@ 3.4 Announcement +
  • + 3.5 Announcement +
  • +
  • Kickstarter Announcement
  • diff --git a/img/raml.png b/img/raml.png new file mode 100644 index 000000000..87790dc48 Binary files /dev/null and b/img/raml.png differ diff --git a/index.html b/index.html index 230b9709e..fe72bb8ef 100644 --- a/index.html +++ b/index.html @@ -302,6 +302,10 @@ 3.4 Announcement +
  • + 3.5 Announcement +
  • +
  • Kickstarter Announcement
  • @@ -668,6 +672,7 @@ urlpatterns = [
  • 3.2 Announcement
  • 3.3 Announcement
  • 3.4 Announcement
  • +
  • 3.5 Announcement
  • Kickstarter Announcement
  • Mozilla Grant
  • Funding
  • diff --git a/mkdocs/search_index.json b/mkdocs/search_index.json index 643eb2f97..71faf07bb 100644 --- a/mkdocs/search_index.json +++ b/mkdocs/search_index.json @@ -2,7 +2,7 @@ "docs": [ { "location": "/", - "text": ".promo li a {\n float: left;\n width: 130px;\n height: 20px;\n text-align: center;\n margin: 10px 30px;\n padding: 150px 0 0 0;\n background-position: 0 50%;\n background-size: 130px auto;\n background-repeat: no-repeat;\n font-size: 120%;\n color: black;\n}\n.promo li {\n list-style: none;\n}\n\n\n\n\n\n \n\n\n \n\n \n\n \n\n\n \n\n \n\n \n\n\n\n\n\n\n\nNote\n: This is the documentation for the \nversion 3\n of REST framework. Documentation for \nversion 2\n is also available.\n\n\n\n\n\n\nDjango REST Framework\n\n\n\n\n\n\n\n\nDjango REST framework is a powerful and flexible toolkit for building Web APIs.\n\n\nSome reasons you might want to use REST framework:\n\n\n\n\nThe \nWeb browsable API\n is a huge usability win for your developers.\n\n\nAuthentication policies\n including packages for \nOAuth1a\n and \nOAuth2\n.\n\n\nSerialization\n that supports both \nORM\n and \nnon-ORM\n data sources.\n\n\nCustomizable all the way down - just use \nregular function-based views\n if you don't need the \nmore\n \npowerful\n \nfeatures\n.\n\n\nExtensive documentation\n, and \ngreat community support\n.\n\n\nUsed and trusted by internationally recognised companies including \nMozilla\n, \nRed Hat\n, \nHeroku\n, and \nEventbrite\n.\n\n\n\n\n\n\nFunding\n\n\nREST framework is a \ncollaboratively funded project\n. If you use\nREST framework commercially we strongly encourage you to invest in its\ncontinued development by \nsigning up for a paid plan\n.\n\n\nThe initial aim is to provide a single full-time position on REST framework.\n\nEvery single sign-up makes a significant impact towards making that possible.\n\n\n\n \nRover.com\n\n \nSentry\n\n \nStream\n\n \nMachinalis\n\n\n\n\n\n\n\n\nMany thanks to all our \nwonderful sponsors\n, and in particular to our premium backers, \nRover\n, \nSentry\n, \nStream\n, and \nMachinalis\n.\n\n\n\n\nRequirements\n\n\nREST framework requires the following:\n\n\n\n\nPython (2.7, 3.2, 3.3, 3.4, 3.5)\n\n\nDjango (1.8, 1.9, 1.10)\n\n\n\n\nThe following packages are optional:\n\n\n\n\ncoreapi\n (1.32.0+) - Schema generation support.\n\n\nMarkdown\n (2.1.0+) - Markdown support for the browsable API.\n\n\ndjango-filter\n (0.9.2+) - Filtering support.\n\n\ndjango-crispy-forms\n - Improved HTML display for filtering.\n\n\ndjango-guardian\n (1.1.1+) - Object level permissions support.\n\n\n\n\nInstallation\n\n\nInstall using \npip\n, including any optional packages you want...\n\n\npip install djangorestframework\npip install markdown # Markdown support for the browsable API.\npip install django-filter # Filtering support\n\n\n\n...or clone the project from github.\n\n\ngit clone git@github.com:tomchristie/django-rest-framework.git\n\n\n\nAdd \n'rest_framework'\n to your \nINSTALLED_APPS\n setting.\n\n\nINSTALLED_APPS = (\n ...\n 'rest_framework',\n)\n\n\n\nIf you're intending to use the browsable API you'll probably also want to add REST framework's login and logout views. Add the following to your root \nurls.py\n file.\n\n\nurlpatterns = [\n ...\n url(r'^api-auth/', include('rest_framework.urls', namespace='rest_framework'))\n]\n\n\n\nNote that the URL path can be whatever you want, but you must include \n'rest_framework.urls'\n with the \n'rest_framework'\n namespace. You may leave out the namespace in Django 1.9+, and REST framework will set it for you.\n\n\nExample\n\n\nLet's take a look at a quick example of using REST framework to build a simple model-backed API.\n\n\nWe'll create a read-write API for accessing information on the users of our project.\n\n\nAny global settings for a REST framework API are kept in a single configuration dictionary named \nREST_FRAMEWORK\n. Start off by adding the following to your \nsettings.py\n module:\n\n\nREST_FRAMEWORK = {\n # Use Django's standard `django.contrib.auth` permissions,\n # or allow read-only access for unauthenticated users.\n 'DEFAULT_PERMISSION_CLASSES': [\n 'rest_framework.permissions.DjangoModelPermissionsOrAnonReadOnly'\n ]\n}\n\n\n\nDon't forget to make sure you've also added \nrest_framework\n to your \nINSTALLED_APPS\n.\n\n\nWe're ready to create our API now.\nHere's our project's root \nurls.py\n module:\n\n\nfrom django.conf.urls import url, include\nfrom django.contrib.auth.models import User\nfrom rest_framework import routers, serializers, viewsets\n\n# Serializers define the API representation.\nclass UserSerializer(serializers.HyperlinkedModelSerializer):\n class Meta:\n model = User\n fields = ('url', 'username', 'email', 'is_staff')\n\n# ViewSets define the view behavior.\nclass UserViewSet(viewsets.ModelViewSet):\n queryset = User.objects.all()\n serializer_class = UserSerializer\n\n# Routers provide an easy way of automatically determining the URL conf.\nrouter = routers.DefaultRouter()\nrouter.register(r'users', UserViewSet)\n\n# Wire up our API using automatic URL routing.\n# Additionally, we include login URLs for the browsable API.\nurlpatterns = [\n url(r'^', include(router.urls)),\n url(r'^api-auth/', include('rest_framework.urls', namespace='rest_framework'))\n]\n\n\n\nYou can now open the API in your browser at \nhttp://127.0.0.1:8000/\n, and view your new 'users' API. If you use the login control in the top right corner you'll also be able to add, create and delete users from the system.\n\n\nQuickstart\n\n\nCan't wait to get started? The \nquickstart guide\n is the fastest way to get up and running, and building APIs with REST framework.\n\n\nTutorial\n\n\nThe tutorial will walk you through the building blocks that make up REST framework. It'll take a little while to get through, but it'll give you a comprehensive understanding of how everything fits together, and is highly recommended reading.\n\n\n\n\n1 - Serialization\n\n\n2 - Requests \n Responses\n\n\n3 - Class-based views\n\n\n4 - Authentication \n permissions\n\n\n5 - Relationships \n hyperlinked APIs\n\n\n6 - Viewsets \n routers\n\n\n7 - Schemas \n client libraries\n\n\n\n\nThere is a live example API of the finished tutorial API for testing purposes, \navailable here\n.\n\n\nAPI Guide\n\n\nThe API guide is your complete reference manual to all the functionality provided by REST framework.\n\n\n\n\nRequests\n\n\nResponses\n\n\nViews\n\n\nGeneric views\n\n\nViewsets\n\n\nRouters\n\n\nParsers\n\n\nRenderers\n\n\nSerializers\n\n\nSerializer fields\n\n\nSerializer relations\n\n\nValidators\n\n\nAuthentication\n\n\nPermissions\n\n\nThrottling\n\n\nFiltering\n\n\nPagination\n\n\nVersioning\n\n\nContent negotiation\n\n\nMetadata\n\n\nSchemas\n\n\nFormat suffixes\n\n\nReturning URLs\n\n\nExceptions\n\n\nStatus codes\n\n\nTesting\n\n\nSettings\n\n\n\n\nTopics\n\n\nGeneral guides to using REST framework.\n\n\n\n\nDocumenting your API\n\n\nAPI Clients\n\n\nInternationalization\n\n\nAJAX, CSRF \n CORS\n\n\nHTML \n Forms\n\n\nBrowser enhancements\n\n\nThe Browsable API\n\n\nREST, Hypermedia \n HATEOAS\n\n\nThird Party Resources\n\n\nContributing to REST framework\n\n\nProject management\n\n\n3.0 Announcement\n\n\n3.1 Announcement\n\n\n3.2 Announcement\n\n\n3.3 Announcement\n\n\n3.4 Announcement\n\n\nKickstarter Announcement\n\n\nMozilla Grant\n\n\nFunding\n\n\nRelease Notes\n\n\n\n\nDevelopment\n\n\nSee the \nContribution guidelines\n for information on how to clone\nthe repository, run the test suite and contribute changes back to REST\nFramework.\n\n\nSupport\n\n\nFor support please see the \nREST framework discussion group\n, try the \n#restframework\n channel on \nirc.freenode.net\n, search \nthe IRC archives\n, or raise a question on \nStack Overflow\n, making sure to include the \n'django-rest-framework'\n tag.\n\n\nPaid support is available\n from \nDabApps\n, and can include work on REST framework core, or support with building your REST framework API. Please \ncontact DabApps\n if you'd like to discuss commercial support options.\n\n\nFor updates on REST framework development, you may also want to follow \nthe author\n on Twitter.\n\n\nFollow @_tomchristie\n\n\n!function(d,s,id){var js,fjs=d.getElementsByTagName(s)[0];if(!d.getElementById(id)){js=d.createElement(s);js.id=id;js.src=\"//platform.twitter.com/widgets.js\";fjs.parentNode.insertBefore(js,fjs);}}(document,\"script\",\"twitter-wjs\");\n\n\nSecurity\n\n\nIf you believe you\u2019ve found something in Django REST framework which has security implications, please \ndo not raise the issue in a public forum\n.\n\n\nSend a description of the issue via email to \nrest-framework-security@googlegroups.com\n. The project maintainers will then work with you to resolve any issues where required, prior to any public disclosure.\n\n\nLicense\n\n\nCopyright (c) 2011-2016, Tom Christie\nAll rights reserved.\n\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n\n\nRedistributions of source code must retain the above copyright notice, this\nlist of conditions and the following disclaimer.\nRedistributions in binary form must reproduce the above copyright notice, this\nlist of conditions and the following disclaimer in the documentation and/or\nother materials provided with the distribution.\n\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND\nANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\nWARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE\nFOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\nDAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\nSERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\nCAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\nOR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.", + "text": ".promo li a {\n float: left;\n width: 130px;\n height: 20px;\n text-align: center;\n margin: 10px 30px;\n padding: 150px 0 0 0;\n background-position: 0 50%;\n background-size: 130px auto;\n background-repeat: no-repeat;\n font-size: 120%;\n color: black;\n}\n.promo li {\n list-style: none;\n}\n\n\n\n\n\n \n\n\n \n\n \n\n \n\n\n \n\n \n\n \n\n\n\n\n\n\n\nNote\n: This is the documentation for the \nversion 3\n of REST framework. Documentation for \nversion 2\n is also available.\n\n\n\n\n\n\nDjango REST Framework\n\n\n\n\n\n\n\n\nDjango REST framework is a powerful and flexible toolkit for building Web APIs.\n\n\nSome reasons you might want to use REST framework:\n\n\n\n\nThe \nWeb browsable API\n is a huge usability win for your developers.\n\n\nAuthentication policies\n including packages for \nOAuth1a\n and \nOAuth2\n.\n\n\nSerialization\n that supports both \nORM\n and \nnon-ORM\n data sources.\n\n\nCustomizable all the way down - just use \nregular function-based views\n if you don't need the \nmore\n \npowerful\n \nfeatures\n.\n\n\nExtensive documentation\n, and \ngreat community support\n.\n\n\nUsed and trusted by internationally recognised companies including \nMozilla\n, \nRed Hat\n, \nHeroku\n, and \nEventbrite\n.\n\n\n\n\n\n\nFunding\n\n\nREST framework is a \ncollaboratively funded project\n. If you use\nREST framework commercially we strongly encourage you to invest in its\ncontinued development by \nsigning up for a paid plan\n.\n\n\nThe initial aim is to provide a single full-time position on REST framework.\n\nEvery single sign-up makes a significant impact towards making that possible.\n\n\n\n \nRover.com\n\n \nSentry\n\n \nStream\n\n \nMachinalis\n\n\n\n\n\n\n\n\nMany thanks to all our \nwonderful sponsors\n, and in particular to our premium backers, \nRover\n, \nSentry\n, \nStream\n, and \nMachinalis\n.\n\n\n\n\nRequirements\n\n\nREST framework requires the following:\n\n\n\n\nPython (2.7, 3.2, 3.3, 3.4, 3.5)\n\n\nDjango (1.8, 1.9, 1.10)\n\n\n\n\nThe following packages are optional:\n\n\n\n\ncoreapi\n (1.32.0+) - Schema generation support.\n\n\nMarkdown\n (2.1.0+) - Markdown support for the browsable API.\n\n\ndjango-filter\n (0.9.2+) - Filtering support.\n\n\ndjango-crispy-forms\n - Improved HTML display for filtering.\n\n\ndjango-guardian\n (1.1.1+) - Object level permissions support.\n\n\n\n\nInstallation\n\n\nInstall using \npip\n, including any optional packages you want...\n\n\npip install djangorestframework\npip install markdown # Markdown support for the browsable API.\npip install django-filter # Filtering support\n\n\n\n...or clone the project from github.\n\n\ngit clone git@github.com:tomchristie/django-rest-framework.git\n\n\n\nAdd \n'rest_framework'\n to your \nINSTALLED_APPS\n setting.\n\n\nINSTALLED_APPS = (\n ...\n 'rest_framework',\n)\n\n\n\nIf you're intending to use the browsable API you'll probably also want to add REST framework's login and logout views. Add the following to your root \nurls.py\n file.\n\n\nurlpatterns = [\n ...\n url(r'^api-auth/', include('rest_framework.urls', namespace='rest_framework'))\n]\n\n\n\nNote that the URL path can be whatever you want, but you must include \n'rest_framework.urls'\n with the \n'rest_framework'\n namespace. You may leave out the namespace in Django 1.9+, and REST framework will set it for you.\n\n\nExample\n\n\nLet's take a look at a quick example of using REST framework to build a simple model-backed API.\n\n\nWe'll create a read-write API for accessing information on the users of our project.\n\n\nAny global settings for a REST framework API are kept in a single configuration dictionary named \nREST_FRAMEWORK\n. Start off by adding the following to your \nsettings.py\n module:\n\n\nREST_FRAMEWORK = {\n # Use Django's standard `django.contrib.auth` permissions,\n # or allow read-only access for unauthenticated users.\n 'DEFAULT_PERMISSION_CLASSES': [\n 'rest_framework.permissions.DjangoModelPermissionsOrAnonReadOnly'\n ]\n}\n\n\n\nDon't forget to make sure you've also added \nrest_framework\n to your \nINSTALLED_APPS\n.\n\n\nWe're ready to create our API now.\nHere's our project's root \nurls.py\n module:\n\n\nfrom django.conf.urls import url, include\nfrom django.contrib.auth.models import User\nfrom rest_framework import routers, serializers, viewsets\n\n# Serializers define the API representation.\nclass UserSerializer(serializers.HyperlinkedModelSerializer):\n class Meta:\n model = User\n fields = ('url', 'username', 'email', 'is_staff')\n\n# ViewSets define the view behavior.\nclass UserViewSet(viewsets.ModelViewSet):\n queryset = User.objects.all()\n serializer_class = UserSerializer\n\n# Routers provide an easy way of automatically determining the URL conf.\nrouter = routers.DefaultRouter()\nrouter.register(r'users', UserViewSet)\n\n# Wire up our API using automatic URL routing.\n# Additionally, we include login URLs for the browsable API.\nurlpatterns = [\n url(r'^', include(router.urls)),\n url(r'^api-auth/', include('rest_framework.urls', namespace='rest_framework'))\n]\n\n\n\nYou can now open the API in your browser at \nhttp://127.0.0.1:8000/\n, and view your new 'users' API. If you use the login control in the top right corner you'll also be able to add, create and delete users from the system.\n\n\nQuickstart\n\n\nCan't wait to get started? The \nquickstart guide\n is the fastest way to get up and running, and building APIs with REST framework.\n\n\nTutorial\n\n\nThe tutorial will walk you through the building blocks that make up REST framework. It'll take a little while to get through, but it'll give you a comprehensive understanding of how everything fits together, and is highly recommended reading.\n\n\n\n\n1 - Serialization\n\n\n2 - Requests \n Responses\n\n\n3 - Class-based views\n\n\n4 - Authentication \n permissions\n\n\n5 - Relationships \n hyperlinked APIs\n\n\n6 - Viewsets \n routers\n\n\n7 - Schemas \n client libraries\n\n\n\n\nThere is a live example API of the finished tutorial API for testing purposes, \navailable here\n.\n\n\nAPI Guide\n\n\nThe API guide is your complete reference manual to all the functionality provided by REST framework.\n\n\n\n\nRequests\n\n\nResponses\n\n\nViews\n\n\nGeneric views\n\n\nViewsets\n\n\nRouters\n\n\nParsers\n\n\nRenderers\n\n\nSerializers\n\n\nSerializer fields\n\n\nSerializer relations\n\n\nValidators\n\n\nAuthentication\n\n\nPermissions\n\n\nThrottling\n\n\nFiltering\n\n\nPagination\n\n\nVersioning\n\n\nContent negotiation\n\n\nMetadata\n\n\nSchemas\n\n\nFormat suffixes\n\n\nReturning URLs\n\n\nExceptions\n\n\nStatus codes\n\n\nTesting\n\n\nSettings\n\n\n\n\nTopics\n\n\nGeneral guides to using REST framework.\n\n\n\n\nDocumenting your API\n\n\nAPI Clients\n\n\nInternationalization\n\n\nAJAX, CSRF \n CORS\n\n\nHTML \n Forms\n\n\nBrowser enhancements\n\n\nThe Browsable API\n\n\nREST, Hypermedia \n HATEOAS\n\n\nThird Party Resources\n\n\nContributing to REST framework\n\n\nProject management\n\n\n3.0 Announcement\n\n\n3.1 Announcement\n\n\n3.2 Announcement\n\n\n3.3 Announcement\n\n\n3.4 Announcement\n\n\n3.5 Announcement\n\n\nKickstarter Announcement\n\n\nMozilla Grant\n\n\nFunding\n\n\nRelease Notes\n\n\n\n\nDevelopment\n\n\nSee the \nContribution guidelines\n for information on how to clone\nthe repository, run the test suite and contribute changes back to REST\nFramework.\n\n\nSupport\n\n\nFor support please see the \nREST framework discussion group\n, try the \n#restframework\n channel on \nirc.freenode.net\n, search \nthe IRC archives\n, or raise a question on \nStack Overflow\n, making sure to include the \n'django-rest-framework'\n tag.\n\n\nPaid support is available\n from \nDabApps\n, and can include work on REST framework core, or support with building your REST framework API. Please \ncontact DabApps\n if you'd like to discuss commercial support options.\n\n\nFor updates on REST framework development, you may also want to follow \nthe author\n on Twitter.\n\n\nFollow @_tomchristie\n\n\n!function(d,s,id){var js,fjs=d.getElementsByTagName(s)[0];if(!d.getElementById(id)){js=d.createElement(s);js.id=id;js.src=\"//platform.twitter.com/widgets.js\";fjs.parentNode.insertBefore(js,fjs);}}(document,\"script\",\"twitter-wjs\");\n\n\nSecurity\n\n\nIf you believe you\u2019ve found something in Django REST framework which has security implications, please \ndo not raise the issue in a public forum\n.\n\n\nSend a description of the issue via email to \nrest-framework-security@googlegroups.com\n. The project maintainers will then work with you to resolve any issues where required, prior to any public disclosure.\n\n\nLicense\n\n\nCopyright (c) 2011-2016, Tom Christie\nAll rights reserved.\n\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n\n\nRedistributions of source code must retain the above copyright notice, this\nlist of conditions and the following disclaimer.\nRedistributions in binary form must reproduce the above copyright notice, this\nlist of conditions and the following disclaimer in the documentation and/or\nother materials provided with the distribution.\n\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND\nANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\nWARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE\nFOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\nDAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\nSERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\nCAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\nOR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.", "title": "Home" }, { @@ -42,7 +42,7 @@ }, { "location": "/#topics", - "text": "General guides to using REST framework. Documenting your API API Clients Internationalization AJAX, CSRF CORS HTML Forms Browser enhancements The Browsable API REST, Hypermedia HATEOAS Third Party Resources Contributing to REST framework Project management 3.0 Announcement 3.1 Announcement 3.2 Announcement 3.3 Announcement 3.4 Announcement Kickstarter Announcement Mozilla Grant Funding Release Notes", + "text": "General guides to using REST framework. Documenting your API API Clients Internationalization AJAX, CSRF CORS HTML Forms Browser enhancements The Browsable API REST, Hypermedia HATEOAS Third Party Resources Contributing to REST framework Project management 3.0 Announcement 3.1 Announcement 3.2 Announcement 3.3 Announcement 3.4 Announcement 3.5 Announcement Kickstarter Announcement Mozilla Grant Funding Release Notes", "title": "Topics" }, { @@ -107,7 +107,7 @@ }, { "location": "/tutorial/1-serialization/", - "text": "Tutorial 1: Serialization\n\n\nIntroduction\n\n\nThis tutorial will cover creating a simple pastebin code highlighting Web API. Along the way it will introduce the various components that make up REST framework, and give you a comprehensive understanding of how everything fits together.\n\n\nThe tutorial is fairly in-depth, so you should probably get a cookie and a cup of your favorite brew before getting started. If you just want a quick overview, you should head over to the \nquickstart\n documentation instead.\n\n\n\n\nNote\n: The code for this tutorial is available in the \ntomchristie/rest-framework-tutorial\n repository on GitHub. The completed implementation is also online as a sandbox version for testing, \navailable here\n.\n\n\n\n\nSetting up a new environment\n\n\nBefore we do anything else we'll create a new virtual environment, using \nvirtualenv\n. This will make sure our package configuration is kept nicely isolated from any other projects we're working on.\n\n\nvirtualenv env\nsource env/bin/activate\n\n\n\nNow that we're inside a virtualenv environment, we can install our package requirements.\n\n\npip install django\npip install djangorestframework\npip install pygments # We'll be using this for the code highlighting\n\n\n\nNote:\n To exit the virtualenv environment at any time, just type \ndeactivate\n. For more information see the \nvirtualenv documentation\n.\n\n\nGetting started\n\n\nOkay, we're ready to get coding.\nTo get started, let's create a new project to work with.\n\n\ncd ~\ndjango-admin.py startproject tutorial\ncd tutorial\n\n\n\nOnce that's done we can create an app that we'll use to create a simple Web API.\n\n\npython manage.py startapp snippets\n\n\n\nWe'll need to add our new \nsnippets\n app and the \nrest_framework\n app to \nINSTALLED_APPS\n. Let's edit the \ntutorial/settings.py\n file:\n\n\nINSTALLED_APPS = (\n ...\n 'rest_framework',\n 'snippets.apps.SnippetsConfig',\n)\n\n\n\nOkay, we're ready to roll.\n\n\nCreating a model to work with\n\n\nFor the purposes of this tutorial we're going to start by creating a simple \nSnippet\n model that is used to store code snippets. Go ahead and edit the \nsnippets/models.py\n file. Note: Good programming practices include comments. Although you will find them in our repository version of this tutorial code, we have omitted them here to focus on the code itself.\n\n\nfrom django.db import models\nfrom pygments.lexers import get_all_lexers\nfrom pygments.styles import get_all_styles\n\nLEXERS = [item for item in get_all_lexers() if item[1]]\nLANGUAGE_CHOICES = sorted([(item[1][0], item[0]) for item in LEXERS])\nSTYLE_CHOICES = sorted((item, item) for item in get_all_styles())\n\n\nclass Snippet(models.Model):\n created = models.DateTimeField(auto_now_add=True)\n title = models.CharField(max_length=100, blank=True, default='')\n code = models.TextField()\n linenos = models.BooleanField(default=False)\n language = models.CharField(choices=LANGUAGE_CHOICES, default='python', max_length=100)\n style = models.CharField(choices=STYLE_CHOICES, default='friendly', max_length=100)\n\n class Meta:\n ordering = ('created',)\n\n\n\nWe'll also need to create an initial migration for our snippet model, and sync the database for the first time.\n\n\npython manage.py makemigrations snippets\npython manage.py migrate\n\n\n\nCreating a Serializer class\n\n\nThe first thing we need to get started on our Web API is to provide a way of serializing and deserializing the snippet instances into representations such as \njson\n. We can do this by declaring serializers that work very similar to Django's forms. Create a file in the \nsnippets\n directory named \nserializers.py\n and add the following.\n\n\nfrom rest_framework import serializers\nfrom snippets.models import Snippet, LANGUAGE_CHOICES, STYLE_CHOICES\n\n\nclass SnippetSerializer(serializers.Serializer):\n id = serializers.IntegerField(read_only=True)\n title = serializers.CharField(required=False, allow_blank=True, max_length=100)\n code = serializers.CharField(style={'base_template': 'textarea.html'})\n linenos = serializers.BooleanField(required=False)\n language = serializers.ChoiceField(choices=LANGUAGE_CHOICES, default='python')\n style = serializers.ChoiceField(choices=STYLE_CHOICES, default='friendly')\n\n def create(self, validated_data):\n \"\"\"\n Create and return a new `Snippet` instance, given the validated data.\n \"\"\"\n return Snippet.objects.create(**validated_data)\n\n def update(self, instance, validated_data):\n \"\"\"\n Update and return an existing `Snippet` instance, given the validated data.\n \"\"\"\n instance.title = validated_data.get('title', instance.title)\n instance.code = validated_data.get('code', instance.code)\n instance.linenos = validated_data.get('linenos', instance.linenos)\n instance.language = validated_data.get('language', instance.language)\n instance.style = validated_data.get('style', instance.style)\n instance.save()\n return instance\n\n\n\nThe first part of the serializer class defines the fields that get serialized/deserialized. The \ncreate()\n and \nupdate()\n methods define how fully fledged instances are created or modified when calling \nserializer.save()\n\n\nA serializer class is very similar to a Django \nForm\n class, and includes similar validation flags on the various fields, such as \nrequired\n, \nmax_length\n and \ndefault\n.\n\n\nThe field flags can also control how the serializer should be displayed in certain circumstances, such as when rendering to HTML. The \n{'base_template': 'textarea.html'}\n flag above is equivalent to using \nwidget=widgets.Textarea\n on a Django \nForm\n class. This is particularly useful for controlling how the browsable API should be displayed, as we'll see later in the tutorial.\n\n\nWe can actually also save ourselves some time by using the \nModelSerializer\n class, as we'll see later, but for now we'll keep our serializer definition explicit.\n\n\nWorking with Serializers\n\n\nBefore we go any further we'll familiarize ourselves with using our new Serializer class. Let's drop into the Django shell.\n\n\npython manage.py shell\n\n\n\nOkay, once we've got a few imports out of the way, let's create a couple of code snippets to work with.\n\n\nfrom snippets.models import Snippet\nfrom snippets.serializers import SnippetSerializer\nfrom rest_framework.renderers import JSONRenderer\nfrom rest_framework.parsers import JSONParser\n\nsnippet = Snippet(code='foo = \"bar\"\\n')\nsnippet.save()\n\nsnippet = Snippet(code='print \"hello, world\"\\n')\nsnippet.save()\n\n\n\nWe've now got a few snippet instances to play with. Let's take a look at serializing one of those instances.\n\n\nserializer = SnippetSerializer(snippet)\nserializer.data\n# {'id': 2, 'title': u'', 'code': u'print \"hello, world\"\\n', 'linenos': False, 'language': u'python', 'style': u'friendly'}\n\n\n\nAt this point we've translated the model instance into Python native datatypes. To finalize the serialization process we render the data into \njson\n.\n\n\ncontent = JSONRenderer().render(serializer.data)\ncontent\n# '{\"id\": 2, \"title\": \"\", \"code\": \"print \\\\\"hello, world\\\\\"\\\\n\", \"linenos\": false, \"language\": \"python\", \"style\": \"friendly\"}'\n\n\n\nDeserialization is similar. First we parse a stream into Python native datatypes...\n\n\nfrom django.utils.six import BytesIO\n\nstream = BytesIO(content)\ndata = JSONParser().parse(stream)\n\n\n\n...then we restore those native datatypes into a fully populated object instance.\n\n\nserializer = SnippetSerializer(data=data)\nserializer.is_valid()\n# True\nserializer.validated_data\n# OrderedDict([('title', ''), ('code', 'print \"hello, world\"\\n'), ('linenos', False), ('language', 'python'), ('style', 'friendly')])\nserializer.save()\n# \nSnippet: Snippet object\n\n\n\n\nNotice how similar the API is to working with forms. The similarity should become even more apparent when we start writing views that use our serializer.\n\n\nWe can also serialize querysets instead of model instances. To do so we simply add a \nmany=True\n flag to the serializer arguments.\n\n\nserializer = SnippetSerializer(Snippet.objects.all(), many=True)\nserializer.data\n# [OrderedDict([('id', 1), ('title', u''), ('code', u'foo = \"bar\"\\n'), ('linenos', False), ('language', 'python'), ('style', 'friendly')]), OrderedDict([('id', 2), ('title', u''), ('code', u'print \"hello, world\"\\n'), ('linenos', False), ('language', 'python'), ('style', 'friendly')]), OrderedDict([('id', 3), ('title', u''), ('code', u'print \"hello, world\"'), ('linenos', False), ('language', 'python'), ('style', 'friendly')])]\n\n\n\nUsing ModelSerializers\n\n\nOur \nSnippetSerializer\n class is replicating a lot of information that's also contained in the \nSnippet\n model. It would be nice if we could keep our code a bit more concise.\n\n\nIn the same way that Django provides both \nForm\n classes and \nModelForm\n classes, REST framework includes both \nSerializer\n classes, and \nModelSerializer\n classes.\n\n\nLet's look at refactoring our serializer using the \nModelSerializer\n class.\nOpen the file \nsnippets/serializers.py\n again, and replace the \nSnippetSerializer\n class with the following.\n\n\nclass SnippetSerializer(serializers.ModelSerializer):\n class Meta:\n model = Snippet\n fields = ('id', 'title', 'code', 'linenos', 'language', 'style')\n\n\n\nOne nice property that serializers have is that you can inspect all the fields in a serializer instance, by printing its representation. Open the Django shell with \npython manage.py shell\n, then try the following:\n\n\nfrom snippets.serializers import SnippetSerializer\nserializer = SnippetSerializer()\nprint(repr(serializer))\n# SnippetSerializer():\n# id = IntegerField(label='ID', read_only=True)\n# title = CharField(allow_blank=True, max_length=100, required=False)\n# code = CharField(style={'base_template': 'textarea.html'})\n# linenos = BooleanField(required=False)\n# language = ChoiceField(choices=[('Clipper', 'FoxPro'), ('Cucumber', 'Gherkin'), ('RobotFramework', 'RobotFramework'), ('abap', 'ABAP'), ('ada', 'Ada')...\n# style = ChoiceField(choices=[('autumn', 'autumn'), ('borland', 'borland'), ('bw', 'bw'), ('colorful', 'colorful')...\n\n\n\nIt's important to remember that \nModelSerializer\n classes don't do anything particularly magical, they are simply a shortcut for creating serializer classes:\n\n\n\n\nAn automatically determined set of fields.\n\n\nSimple default implementations for the \ncreate()\n and \nupdate()\n methods.\n\n\n\n\nWriting regular Django views using our Serializer\n\n\nLet's see how we can write some API views using our new Serializer class.\nFor the moment we won't use any of REST framework's other features, we'll just write the views as regular Django views.\n\n\nWe'll start off by creating a subclass of HttpResponse that we can use to render any data we return into \njson\n.\n\n\nEdit the \nsnippets/views.py\n file, and add the following.\n\n\nfrom django.http import HttpResponse\nfrom django.views.decorators.csrf import csrf_exempt\nfrom rest_framework.renderers import JSONRenderer\nfrom rest_framework.parsers import JSONParser\nfrom snippets.models import Snippet\nfrom snippets.serializers import SnippetSerializer\n\nclass JSONResponse(HttpResponse):\n \"\"\"\n An HttpResponse that renders its content into JSON.\n \"\"\"\n def __init__(self, data, **kwargs):\n content = JSONRenderer().render(data)\n kwargs['content_type'] = 'application/json'\n super(JSONResponse, self).__init__(content, **kwargs)\n\n\n\nThe root of our API is going to be a view that supports listing all the existing snippets, or creating a new snippet.\n\n\n@csrf_exempt\ndef snippet_list(request):\n \"\"\"\n List all code snippets, or create a new snippet.\n \"\"\"\n if request.method == 'GET':\n snippets = Snippet.objects.all()\n serializer = SnippetSerializer(snippets, many=True)\n return JSONResponse(serializer.data)\n\n elif request.method == 'POST':\n data = JSONParser().parse(request)\n serializer = SnippetSerializer(data=data)\n if serializer.is_valid():\n serializer.save()\n return JSONResponse(serializer.data, status=201)\n return JSONResponse(serializer.errors, status=400)\n\n\n\nNote that because we want to be able to POST to this view from clients that won't have a CSRF token we need to mark the view as \ncsrf_exempt\n. This isn't something that you'd normally want to do, and REST framework views actually use more sensible behavior than this, but it'll do for our purposes right now.\n\n\nWe'll also need a view which corresponds to an individual snippet, and can be used to retrieve, update or delete the snippet.\n\n\n@csrf_exempt\ndef snippet_detail(request, id):\n \"\"\"\n Retrieve, update or delete a code snippet.\n \"\"\"\n try:\n snippet = Snippet.objects.get(id=id)\n except Snippet.DoesNotExist:\n return HttpResponse(status=404)\n\n if request.method == 'GET':\n serializer = SnippetSerializer(snippet)\n return JSONResponse(serializer.data)\n\n elif request.method == 'PUT':\n data = JSONParser().parse(request)\n serializer = SnippetSerializer(snippet, data=data)\n if serializer.is_valid():\n serializer.save()\n return JSONResponse(serializer.data)\n return JSONResponse(serializer.errors, status=400)\n\n elif request.method == 'DELETE':\n snippet.delete()\n return HttpResponse(status=204)\n\n\n\nFinally we need to wire these views up. Create the \nsnippets/urls.py\n file:\n\n\nfrom django.conf.urls import url\nfrom snippets import views\n\nurlpatterns = [\n url(r'^snippets/$', views.snippet_list),\n url(r'^snippets/(?P\nid\n[0-9]+)/$', views.snippet_detail),\n]\n\n\n\nWe also need to wire up the root urlconf, in the \ntutorial/urls.py\n file, to include our snippet app's URLs.\n\n\nfrom django.conf.urls import url, include\n\nurlpatterns = [\n url(r'^', include('snippets.urls')),\n]\n\n\n\nIt's worth noting that there are a couple of edge cases we're not dealing with properly at the moment. If we send malformed \njson\n, or if a request is made with a method that the view doesn't handle, then we'll end up with a 500 \"server error\" response. Still, this'll do for now.\n\n\nTesting our first attempt at a Web API\n\n\nNow we can start up a sample server that serves our snippets.\n\n\nQuit out of the shell...\n\n\nquit()\n\n\n\n...and start up Django's development server.\n\n\npython manage.py runserver\n\nValidating models...\n\n0 errors found\nDjango version 1.8.3, using settings 'tutorial.settings'\nDevelopment server is running at http://127.0.0.1:8000/\nQuit the server with CONTROL-C.\n\n\n\nIn another terminal window, we can test the server.\n\n\nWe can test our API using \ncurl\n or \nhttpie\n. Httpie is a user friendly http client that's written in Python. Let's install that.\n\n\nYou can install httpie using pip:\n\n\npip install httpie\n\n\n\nFinally, we can get a list of all of the snippets:\n\n\nhttp http://127.0.0.1:8000/snippets/\n\nHTTP/1.1 200 OK\n...\n[\n {\n \"id\": 1,\n \"title\": \"\",\n \"code\": \"foo = \\\"bar\\\"\\n\",\n \"linenos\": false,\n \"language\": \"python\",\n \"style\": \"friendly\"\n },\n {\n \"id\": 2,\n \"title\": \"\",\n \"code\": \"print \\\"hello, world\\\"\\n\",\n \"linenos\": false,\n \"language\": \"python\",\n \"style\": \"friendly\"\n }\n]\n\n\n\nOr we can get a particular snippet by referencing its id:\n\n\nhttp http://127.0.0.1:8000/snippets/2/\n\nHTTP/1.1 200 OK\n...\n{\n \"id\": 2,\n \"title\": \"\",\n \"code\": \"print \\\"hello, world\\\"\\n\",\n \"linenos\": false,\n \"language\": \"python\",\n \"style\": \"friendly\"\n}\n\n\n\nSimilarly, you can have the same json displayed by visiting these URLs in a web browser.\n\n\nWhere are we now\n\n\nWe're doing okay so far, we've got a serialization API that feels pretty similar to Django's Forms API, and some regular Django views.\n\n\nOur API views don't do anything particularly special at the moment, beyond serving \njson\n responses, and there are some error handling edge cases we'd still like to clean up, but it's a functioning Web API.\n\n\nWe'll see how we can start to improve things in \npart 2 of the tutorial\n.", + "text": "Tutorial 1: Serialization\n\n\nIntroduction\n\n\nThis tutorial will cover creating a simple pastebin code highlighting Web API. Along the way it will introduce the various components that make up REST framework, and give you a comprehensive understanding of how everything fits together.\n\n\nThe tutorial is fairly in-depth, so you should probably get a cookie and a cup of your favorite brew before getting started. If you just want a quick overview, you should head over to the \nquickstart\n documentation instead.\n\n\n\n\nNote\n: The code for this tutorial is available in the \ntomchristie/rest-framework-tutorial\n repository on GitHub. The completed implementation is also online as a sandbox version for testing, \navailable here\n.\n\n\n\n\nSetting up a new environment\n\n\nBefore we do anything else we'll create a new virtual environment, using \nvirtualenv\n. This will make sure our package configuration is kept nicely isolated from any other projects we're working on.\n\n\nvirtualenv env\nsource env/bin/activate\n\n\n\nNow that we're inside a virtualenv environment, we can install our package requirements.\n\n\npip install django\npip install djangorestframework\npip install pygments # We'll be using this for the code highlighting\n\n\n\nNote:\n To exit the virtualenv environment at any time, just type \ndeactivate\n. For more information see the \nvirtualenv documentation\n.\n\n\nGetting started\n\n\nOkay, we're ready to get coding.\nTo get started, let's create a new project to work with.\n\n\ncd ~\ndjango-admin.py startproject tutorial\ncd tutorial\n\n\n\nOnce that's done we can create an app that we'll use to create a simple Web API.\n\n\npython manage.py startapp snippets\n\n\n\nWe'll need to add our new \nsnippets\n app and the \nrest_framework\n app to \nINSTALLED_APPS\n. Let's edit the \ntutorial/settings.py\n file:\n\n\nINSTALLED_APPS = (\n ...\n 'rest_framework',\n 'snippets.apps.SnippetsConfig',\n)\n\n\n\nOkay, we're ready to roll.\n\n\nCreating a model to work with\n\n\nFor the purposes of this tutorial we're going to start by creating a simple \nSnippet\n model that is used to store code snippets. Go ahead and edit the \nsnippets/models.py\n file. Note: Good programming practices include comments. Although you will find them in our repository version of this tutorial code, we have omitted them here to focus on the code itself.\n\n\nfrom django.db import models\nfrom pygments.lexers import get_all_lexers\nfrom pygments.styles import get_all_styles\n\nLEXERS = [item for item in get_all_lexers() if item[1]]\nLANGUAGE_CHOICES = sorted([(item[1][0], item[0]) for item in LEXERS])\nSTYLE_CHOICES = sorted((item, item) for item in get_all_styles())\n\n\nclass Snippet(models.Model):\n created = models.DateTimeField(auto_now_add=True)\n title = models.CharField(max_length=100, blank=True, default='')\n code = models.TextField()\n linenos = models.BooleanField(default=False)\n language = models.CharField(choices=LANGUAGE_CHOICES, default='python', max_length=100)\n style = models.CharField(choices=STYLE_CHOICES, default='friendly', max_length=100)\n\n class Meta:\n ordering = ('created',)\n\n\n\nWe'll also need to create an initial migration for our snippet model, and sync the database for the first time.\n\n\npython manage.py makemigrations snippets\npython manage.py migrate\n\n\n\nCreating a Serializer class\n\n\nThe first thing we need to get started on our Web API is to provide a way of serializing and deserializing the snippet instances into representations such as \njson\n. We can do this by declaring serializers that work very similar to Django's forms. Create a file in the \nsnippets\n directory named \nserializers.py\n and add the following.\n\n\nfrom rest_framework import serializers\nfrom snippets.models import Snippet, LANGUAGE_CHOICES, STYLE_CHOICES\n\n\nclass SnippetSerializer(serializers.Serializer):\n id = serializers.IntegerField(read_only=True)\n title = serializers.CharField(required=False, allow_blank=True, max_length=100)\n code = serializers.CharField(style={'base_template': 'textarea.html'})\n linenos = serializers.BooleanField(required=False)\n language = serializers.ChoiceField(choices=LANGUAGE_CHOICES, default='python')\n style = serializers.ChoiceField(choices=STYLE_CHOICES, default='friendly')\n\n def create(self, validated_data):\n \"\"\"\n Create and return a new `Snippet` instance, given the validated data.\n \"\"\"\n return Snippet.objects.create(**validated_data)\n\n def update(self, instance, validated_data):\n \"\"\"\n Update and return an existing `Snippet` instance, given the validated data.\n \"\"\"\n instance.title = validated_data.get('title', instance.title)\n instance.code = validated_data.get('code', instance.code)\n instance.linenos = validated_data.get('linenos', instance.linenos)\n instance.language = validated_data.get('language', instance.language)\n instance.style = validated_data.get('style', instance.style)\n instance.save()\n return instance\n\n\n\nThe first part of the serializer class defines the fields that get serialized/deserialized. The \ncreate()\n and \nupdate()\n methods define how fully fledged instances are created or modified when calling \nserializer.save()\n\n\nA serializer class is very similar to a Django \nForm\n class, and includes similar validation flags on the various fields, such as \nrequired\n, \nmax_length\n and \ndefault\n.\n\n\nThe field flags can also control how the serializer should be displayed in certain circumstances, such as when rendering to HTML. The \n{'base_template': 'textarea.html'}\n flag above is equivalent to using \nwidget=widgets.Textarea\n on a Django \nForm\n class. This is particularly useful for controlling how the browsable API should be displayed, as we'll see later in the tutorial.\n\n\nWe can actually also save ourselves some time by using the \nModelSerializer\n class, as we'll see later, but for now we'll keep our serializer definition explicit.\n\n\nWorking with Serializers\n\n\nBefore we go any further we'll familiarize ourselves with using our new Serializer class. Let's drop into the Django shell.\n\n\npython manage.py shell\n\n\n\nOkay, once we've got a few imports out of the way, let's create a couple of code snippets to work with.\n\n\nfrom snippets.models import Snippet\nfrom snippets.serializers import SnippetSerializer\nfrom rest_framework.renderers import JSONRenderer\nfrom rest_framework.parsers import JSONParser\n\nsnippet = Snippet(code='foo = \"bar\"\\n')\nsnippet.save()\n\nsnippet = Snippet(code='print \"hello, world\"\\n')\nsnippet.save()\n\n\n\nWe've now got a few snippet instances to play with. Let's take a look at serializing one of those instances.\n\n\nserializer = SnippetSerializer(snippet)\nserializer.data\n# {'id': 2, 'title': u'', 'code': u'print \"hello, world\"\\n', 'linenos': False, 'language': u'python', 'style': u'friendly'}\n\n\n\nAt this point we've translated the model instance into Python native datatypes. To finalize the serialization process we render the data into \njson\n.\n\n\ncontent = JSONRenderer().render(serializer.data)\ncontent\n# '{\"id\": 2, \"title\": \"\", \"code\": \"print \\\\\"hello, world\\\\\"\\\\n\", \"linenos\": false, \"language\": \"python\", \"style\": \"friendly\"}'\n\n\n\nDeserialization is similar. First we parse a stream into Python native datatypes...\n\n\nfrom django.utils.six import BytesIO\n\nstream = BytesIO(content)\ndata = JSONParser().parse(stream)\n\n\n\n...then we restore those native datatypes into a fully populated object instance.\n\n\nserializer = SnippetSerializer(data=data)\nserializer.is_valid()\n# True\nserializer.validated_data\n# OrderedDict([('title', ''), ('code', 'print \"hello, world\"\\n'), ('linenos', False), ('language', 'python'), ('style', 'friendly')])\nserializer.save()\n# \nSnippet: Snippet object\n\n\n\n\nNotice how similar the API is to working with forms. The similarity should become even more apparent when we start writing views that use our serializer.\n\n\nWe can also serialize querysets instead of model instances. To do so we simply add a \nmany=True\n flag to the serializer arguments.\n\n\nserializer = SnippetSerializer(Snippet.objects.all(), many=True)\nserializer.data\n# [OrderedDict([('id', 1), ('title', u''), ('code', u'foo = \"bar\"\\n'), ('linenos', False), ('language', 'python'), ('style', 'friendly')]), OrderedDict([('id', 2), ('title', u''), ('code', u'print \"hello, world\"\\n'), ('linenos', False), ('language', 'python'), ('style', 'friendly')]), OrderedDict([('id', 3), ('title', u''), ('code', u'print \"hello, world\"'), ('linenos', False), ('language', 'python'), ('style', 'friendly')])]\n\n\n\nUsing ModelSerializers\n\n\nOur \nSnippetSerializer\n class is replicating a lot of information that's also contained in the \nSnippet\n model. It would be nice if we could keep our code a bit more concise.\n\n\nIn the same way that Django provides both \nForm\n classes and \nModelForm\n classes, REST framework includes both \nSerializer\n classes, and \nModelSerializer\n classes.\n\n\nLet's look at refactoring our serializer using the \nModelSerializer\n class.\nOpen the file \nsnippets/serializers.py\n again, and replace the \nSnippetSerializer\n class with the following.\n\n\nclass SnippetSerializer(serializers.ModelSerializer):\n class Meta:\n model = Snippet\n fields = ('id', 'title', 'code', 'linenos', 'language', 'style')\n\n\n\nOne nice property that serializers have is that you can inspect all the fields in a serializer instance, by printing its representation. Open the Django shell with \npython manage.py shell\n, then try the following:\n\n\nfrom snippets.serializers import SnippetSerializer\nserializer = SnippetSerializer()\nprint(repr(serializer))\n# SnippetSerializer():\n# id = IntegerField(label='ID', read_only=True)\n# title = CharField(allow_blank=True, max_length=100, required=False)\n# code = CharField(style={'base_template': 'textarea.html'})\n# linenos = BooleanField(required=False)\n# language = ChoiceField(choices=[('Clipper', 'FoxPro'), ('Cucumber', 'Gherkin'), ('RobotFramework', 'RobotFramework'), ('abap', 'ABAP'), ('ada', 'Ada')...\n# style = ChoiceField(choices=[('autumn', 'autumn'), ('borland', 'borland'), ('bw', 'bw'), ('colorful', 'colorful')...\n\n\n\nIt's important to remember that \nModelSerializer\n classes don't do anything particularly magical, they are simply a shortcut for creating serializer classes:\n\n\n\n\nAn automatically determined set of fields.\n\n\nSimple default implementations for the \ncreate()\n and \nupdate()\n methods.\n\n\n\n\nWriting regular Django views using our Serializer\n\n\nLet's see how we can write some API views using our new Serializer class.\nFor the moment we won't use any of REST framework's other features, we'll just write the views as regular Django views.\n\n\nWe'll start off by creating a subclass of HttpResponse that we can use to render any data we return into \njson\n.\n\n\nEdit the \nsnippets/views.py\n file, and add the following.\n\n\nfrom django.http import HttpResponse\nfrom django.views.decorators.csrf import csrf_exempt\nfrom rest_framework.renderers import JSONRenderer\nfrom rest_framework.parsers import JSONParser\nfrom snippets.models import Snippet\nfrom snippets.serializers import SnippetSerializer\n\nclass JSONResponse(HttpResponse):\n \"\"\"\n An HttpResponse that renders its content into JSON.\n \"\"\"\n def __init__(self, data, **kwargs):\n content = JSONRenderer().render(data)\n kwargs['content_type'] = 'application/json'\n super(JSONResponse, self).__init__(content, **kwargs)\n\n\n\nThe root of our API is going to be a view that supports listing all the existing snippets, or creating a new snippet.\n\n\n@csrf_exempt\ndef snippet_list(request):\n \"\"\"\n List all code snippets, or create a new snippet.\n \"\"\"\n if request.method == 'GET':\n snippets = Snippet.objects.all()\n serializer = SnippetSerializer(snippets, many=True)\n return JSONResponse(serializer.data)\n\n elif request.method == 'POST':\n data = JSONParser().parse(request)\n serializer = SnippetSerializer(data=data)\n if serializer.is_valid():\n serializer.save()\n return JSONResponse(serializer.data, status=201)\n return JSONResponse(serializer.errors, status=400)\n\n\n\nNote that because we want to be able to POST to this view from clients that won't have a CSRF token we need to mark the view as \ncsrf_exempt\n. This isn't something that you'd normally want to do, and REST framework views actually use more sensible behavior than this, but it'll do for our purposes right now.\n\n\nWe'll also need a view which corresponds to an individual snippet, and can be used to retrieve, update or delete the snippet.\n\n\n@csrf_exempt\ndef snippet_detail(request, pk):\n \"\"\"\n Retrieve, update or delete a code snippet.\n \"\"\"\n try:\n snippet = Snippet.objects.get(pk=pk)\n except Snippet.DoesNotExist:\n return HttpResponse(status=404)\n\n if request.method == 'GET':\n serializer = SnippetSerializer(snippet)\n return JSONResponse(serializer.data)\n\n elif request.method == 'PUT':\n data = JSONParser().parse(request)\n serializer = SnippetSerializer(snippet, data=data)\n if serializer.is_valid():\n serializer.save()\n return JSONResponse(serializer.data)\n return JSONResponse(serializer.errors, status=400)\n\n elif request.method == 'DELETE':\n snippet.delete()\n return HttpResponse(status=204)\n\n\n\nFinally we need to wire these views up. Create the \nsnippets/urls.py\n file:\n\n\nfrom django.conf.urls import url\nfrom snippets import views\n\nurlpatterns = [\n url(r'^snippets/$', views.snippet_list),\n url(r'^snippets/(?P\npk\n[0-9]+)/$', views.snippet_detail),\n]\n\n\n\nWe also need to wire up the root urlconf, in the \ntutorial/urls.py\n file, to include our snippet app's URLs.\n\n\nfrom django.conf.urls import url, include\n\nurlpatterns = [\n url(r'^', include('snippets.urls')),\n]\n\n\n\nIt's worth noting that there are a couple of edge cases we're not dealing with properly at the moment. If we send malformed \njson\n, or if a request is made with a method that the view doesn't handle, then we'll end up with a 500 \"server error\" response. Still, this'll do for now.\n\n\nTesting our first attempt at a Web API\n\n\nNow we can start up a sample server that serves our snippets.\n\n\nQuit out of the shell...\n\n\nquit()\n\n\n\n...and start up Django's development server.\n\n\npython manage.py runserver\n\nValidating models...\n\n0 errors found\nDjango version 1.8.3, using settings 'tutorial.settings'\nDevelopment server is running at http://127.0.0.1:8000/\nQuit the server with CONTROL-C.\n\n\n\nIn another terminal window, we can test the server.\n\n\nWe can test our API using \ncurl\n or \nhttpie\n. Httpie is a user friendly http client that's written in Python. Let's install that.\n\n\nYou can install httpie using pip:\n\n\npip install httpie\n\n\n\nFinally, we can get a list of all of the snippets:\n\n\nhttp http://127.0.0.1:8000/snippets/\n\nHTTP/1.1 200 OK\n...\n[\n {\n \"id\": 1,\n \"title\": \"\",\n \"code\": \"foo = \\\"bar\\\"\\n\",\n \"linenos\": false,\n \"language\": \"python\",\n \"style\": \"friendly\"\n },\n {\n \"id\": 2,\n \"title\": \"\",\n \"code\": \"print \\\"hello, world\\\"\\n\",\n \"linenos\": false,\n \"language\": \"python\",\n \"style\": \"friendly\"\n }\n]\n\n\n\nOr we can get a particular snippet by referencing its id:\n\n\nhttp http://127.0.0.1:8000/snippets/2/\n\nHTTP/1.1 200 OK\n...\n{\n \"id\": 2,\n \"title\": \"\",\n \"code\": \"print \\\"hello, world\\\"\\n\",\n \"linenos\": false,\n \"language\": \"python\",\n \"style\": \"friendly\"\n}\n\n\n\nSimilarly, you can have the same json displayed by visiting these URLs in a web browser.\n\n\nWhere are we now\n\n\nWe're doing okay so far, we've got a serialization API that feels pretty similar to Django's Forms API, and some regular Django views.\n\n\nOur API views don't do anything particularly special at the moment, beyond serving \njson\n responses, and there are some error handling edge cases we'd still like to clean up, but it's a functioning Web API.\n\n\nWe'll see how we can start to improve things in \npart 2 of the tutorial\n.", "title": "1 - Serialization" }, { @@ -152,7 +152,7 @@ }, { "location": "/tutorial/1-serialization/#writing-regular-django-views-using-our-serializer", - "text": "Let's see how we can write some API views using our new Serializer class.\nFor the moment we won't use any of REST framework's other features, we'll just write the views as regular Django views. We'll start off by creating a subclass of HttpResponse that we can use to render any data we return into json . Edit the snippets/views.py file, and add the following. from django.http import HttpResponse\nfrom django.views.decorators.csrf import csrf_exempt\nfrom rest_framework.renderers import JSONRenderer\nfrom rest_framework.parsers import JSONParser\nfrom snippets.models import Snippet\nfrom snippets.serializers import SnippetSerializer\n\nclass JSONResponse(HttpResponse):\n \"\"\"\n An HttpResponse that renders its content into JSON.\n \"\"\"\n def __init__(self, data, **kwargs):\n content = JSONRenderer().render(data)\n kwargs['content_type'] = 'application/json'\n super(JSONResponse, self).__init__(content, **kwargs) The root of our API is going to be a view that supports listing all the existing snippets, or creating a new snippet. @csrf_exempt\ndef snippet_list(request):\n \"\"\"\n List all code snippets, or create a new snippet.\n \"\"\"\n if request.method == 'GET':\n snippets = Snippet.objects.all()\n serializer = SnippetSerializer(snippets, many=True)\n return JSONResponse(serializer.data)\n\n elif request.method == 'POST':\n data = JSONParser().parse(request)\n serializer = SnippetSerializer(data=data)\n if serializer.is_valid():\n serializer.save()\n return JSONResponse(serializer.data, status=201)\n return JSONResponse(serializer.errors, status=400) Note that because we want to be able to POST to this view from clients that won't have a CSRF token we need to mark the view as csrf_exempt . This isn't something that you'd normally want to do, and REST framework views actually use more sensible behavior than this, but it'll do for our purposes right now. We'll also need a view which corresponds to an individual snippet, and can be used to retrieve, update or delete the snippet. @csrf_exempt\ndef snippet_detail(request, id):\n \"\"\"\n Retrieve, update or delete a code snippet.\n \"\"\"\n try:\n snippet = Snippet.objects.get(id=id)\n except Snippet.DoesNotExist:\n return HttpResponse(status=404)\n\n if request.method == 'GET':\n serializer = SnippetSerializer(snippet)\n return JSONResponse(serializer.data)\n\n elif request.method == 'PUT':\n data = JSONParser().parse(request)\n serializer = SnippetSerializer(snippet, data=data)\n if serializer.is_valid():\n serializer.save()\n return JSONResponse(serializer.data)\n return JSONResponse(serializer.errors, status=400)\n\n elif request.method == 'DELETE':\n snippet.delete()\n return HttpResponse(status=204) Finally we need to wire these views up. Create the snippets/urls.py file: from django.conf.urls import url\nfrom snippets import views\n\nurlpatterns = [\n url(r'^snippets/$', views.snippet_list),\n url(r'^snippets/(?P id [0-9]+)/$', views.snippet_detail),\n] We also need to wire up the root urlconf, in the tutorial/urls.py file, to include our snippet app's URLs. from django.conf.urls import url, include\n\nurlpatterns = [\n url(r'^', include('snippets.urls')),\n] It's worth noting that there are a couple of edge cases we're not dealing with properly at the moment. If we send malformed json , or if a request is made with a method that the view doesn't handle, then we'll end up with a 500 \"server error\" response. Still, this'll do for now.", + "text": "Let's see how we can write some API views using our new Serializer class.\nFor the moment we won't use any of REST framework's other features, we'll just write the views as regular Django views. We'll start off by creating a subclass of HttpResponse that we can use to render any data we return into json . Edit the snippets/views.py file, and add the following. from django.http import HttpResponse\nfrom django.views.decorators.csrf import csrf_exempt\nfrom rest_framework.renderers import JSONRenderer\nfrom rest_framework.parsers import JSONParser\nfrom snippets.models import Snippet\nfrom snippets.serializers import SnippetSerializer\n\nclass JSONResponse(HttpResponse):\n \"\"\"\n An HttpResponse that renders its content into JSON.\n \"\"\"\n def __init__(self, data, **kwargs):\n content = JSONRenderer().render(data)\n kwargs['content_type'] = 'application/json'\n super(JSONResponse, self).__init__(content, **kwargs) The root of our API is going to be a view that supports listing all the existing snippets, or creating a new snippet. @csrf_exempt\ndef snippet_list(request):\n \"\"\"\n List all code snippets, or create a new snippet.\n \"\"\"\n if request.method == 'GET':\n snippets = Snippet.objects.all()\n serializer = SnippetSerializer(snippets, many=True)\n return JSONResponse(serializer.data)\n\n elif request.method == 'POST':\n data = JSONParser().parse(request)\n serializer = SnippetSerializer(data=data)\n if serializer.is_valid():\n serializer.save()\n return JSONResponse(serializer.data, status=201)\n return JSONResponse(serializer.errors, status=400) Note that because we want to be able to POST to this view from clients that won't have a CSRF token we need to mark the view as csrf_exempt . This isn't something that you'd normally want to do, and REST framework views actually use more sensible behavior than this, but it'll do for our purposes right now. We'll also need a view which corresponds to an individual snippet, and can be used to retrieve, update or delete the snippet. @csrf_exempt\ndef snippet_detail(request, pk):\n \"\"\"\n Retrieve, update or delete a code snippet.\n \"\"\"\n try:\n snippet = Snippet.objects.get(pk=pk)\n except Snippet.DoesNotExist:\n return HttpResponse(status=404)\n\n if request.method == 'GET':\n serializer = SnippetSerializer(snippet)\n return JSONResponse(serializer.data)\n\n elif request.method == 'PUT':\n data = JSONParser().parse(request)\n serializer = SnippetSerializer(snippet, data=data)\n if serializer.is_valid():\n serializer.save()\n return JSONResponse(serializer.data)\n return JSONResponse(serializer.errors, status=400)\n\n elif request.method == 'DELETE':\n snippet.delete()\n return HttpResponse(status=204) Finally we need to wire these views up. Create the snippets/urls.py file: from django.conf.urls import url\nfrom snippets import views\n\nurlpatterns = [\n url(r'^snippets/$', views.snippet_list),\n url(r'^snippets/(?P pk [0-9]+)/$', views.snippet_detail),\n] We also need to wire up the root urlconf, in the tutorial/urls.py file, to include our snippet app's URLs. from django.conf.urls import url, include\n\nurlpatterns = [\n url(r'^', include('snippets.urls')),\n] It's worth noting that there are a couple of edge cases we're not dealing with properly at the moment. If we send malformed json , or if a request is made with a method that the view doesn't handle, then we'll end up with a 500 \"server error\" response. Still, this'll do for now.", "title": "Writing regular Django views using our Serializer" }, { @@ -167,7 +167,7 @@ }, { "location": "/tutorial/2-requests-and-responses/", - "text": "Tutorial 2: Requests and Responses\n\n\nFrom this point we're going to really start covering the core of REST framework.\nLet's introduce a couple of essential building blocks.\n\n\nRequest objects\n\n\nREST framework introduces a \nRequest\n object that extends the regular \nHttpRequest\n, and provides more flexible request parsing. The core functionality of the \nRequest\n object is the \nrequest.data\n attribute, which is similar to \nrequest.POST\n, but more useful for working with Web APIs.\n\n\nrequest.POST # Only handles form data. Only works for 'POST' method.\nrequest.data # Handles arbitrary data. Works for 'POST', 'PUT' and 'PATCH' methods.\n\n\n\nResponse objects\n\n\nREST framework also introduces a \nResponse\n object, which is a type of \nTemplateResponse\n that takes unrendered content and uses content negotiation to determine the correct content type to return to the client.\n\n\nreturn Response(data) # Renders to content type as requested by the client.\n\n\n\nStatus codes\n\n\nUsing numeric HTTP status codes in your views doesn't always make for obvious reading, and it's easy to not notice if you get an error code wrong. REST framework provides more explicit identifiers for each status code, such as \nHTTP_400_BAD_REQUEST\n in the \nstatus\n module. It's a good idea to use these throughout rather than using numeric identifiers.\n\n\nWrapping API views\n\n\nREST framework provides two wrappers you can use to write API views.\n\n\n\n\nThe \n@api_view\n decorator for working with function based views.\n\n\nThe \nAPIView\n class for working with class-based views.\n\n\n\n\nThese wrappers provide a few bits of functionality such as making sure you receive \nRequest\n instances in your view, and adding context to \nResponse\n objects so that content negotiation can be performed.\n\n\nThe wrappers also provide behaviour such as returning \n405 Method Not Allowed\n responses when appropriate, and handling any \nParseError\n exception that occurs when accessing \nrequest.data\n with malformed input.\n\n\nPulling it all together\n\n\nOkay, let's go ahead and start using these new components to write a few views.\n\n\nWe don't need our \nJSONResponse\n class in \nviews.py\n anymore, so go ahead and delete that. Once that's done we can start refactoring our views slightly.\n\n\nfrom rest_framework import status\nfrom rest_framework.decorators import api_view\nfrom rest_framework.response import Response\nfrom snippets.models import Snippet\nfrom snippets.serializers import SnippetSerializer\n\n\n@api_view(['GET', 'POST'])\ndef snippet_list(request):\n \"\"\"\n List all snippets, or create a new snippet.\n \"\"\"\n if request.method == 'GET':\n snippets = Snippet.objects.all()\n serializer = SnippetSerializer(snippets, many=True)\n return Response(serializer.data)\n\n elif request.method == 'POST':\n serializer = SnippetSerializer(data=request.data)\n if serializer.is_valid():\n serializer.save()\n return Response(serializer.data, status=status.HTTP_201_CREATED)\n return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)\n\n\n\nOur instance view is an improvement over the previous example. It's a little more concise, and the code now feels very similar to if we were working with the Forms API. We're also using named status codes, which makes the response meanings more obvious.\n\n\nHere is the view for an individual snippet, in the \nviews.py\n module.\n\n\n@api_view(['GET', 'PUT', 'DELETE'])\ndef snippet_detail(request, id):\n \"\"\"\n Retrieve, update or delete a snippet instance.\n \"\"\"\n try:\n snippet = Snippet.objects.get(id=id)\n except Snippet.DoesNotExist:\n return Response(status=status.HTTP_404_NOT_FOUND)\n\n if request.method == 'GET':\n serializer = SnippetSerializer(snippet)\n return Response(serializer.data)\n\n elif request.method == 'PUT':\n serializer = SnippetSerializer(snippet, data=request.data)\n if serializer.is_valid():\n serializer.save()\n return Response(serializer.data)\n return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)\n\n elif request.method == 'DELETE':\n snippet.delete()\n return Response(status=status.HTTP_204_NO_CONTENT)\n\n\n\nThis should all feel very familiar - it is not a lot different from working with regular Django views.\n\n\nNotice that we're no longer explicitly tying our requests or responses to a given content type. \nrequest.data\n can handle incoming \njson\n requests, but it can also handle other formats. Similarly we're returning response objects with data, but allowing REST framework to render the response into the correct content type for us.\n\n\nAdding optional format suffixes to our URLs\n\n\nTo take advantage of the fact that our responses are no longer hardwired to a single content type let's add support for format suffixes to our API endpoints. Using format suffixes gives us URLs that explicitly refer to a given format, and means our API will be able to handle URLs such as \nhttp://example.com/api/items/4.json\n.\n\n\nStart by adding a \nformat\n keyword argument to both of the views, like so.\n\n\ndef snippet_list(request, format=None):\n\n\n\nand\n\n\ndef snippet_detail(request, id, format=None):\n\n\n\nNow update the \nurls.py\n file slightly, to append a set of \nformat_suffix_patterns\n in addition to the existing URLs.\n\n\nfrom django.conf.urls import url\nfrom rest_framework.urlpatterns import format_suffix_patterns\nfrom snippets import views\n\nurlpatterns = [\n url(r'^snippets/$', views.snippet_list),\n url(r'^snippets/(?P\nid\n[0-9]+)$', views.snippet_detail),\n]\n\nurlpatterns = format_suffix_patterns(urlpatterns)\n\n\n\nWe don't necessarily need to add these extra url patterns in, but it gives us a simple, clean way of referring to a specific format.\n\n\nHow's it looking?\n\n\nGo ahead and test the API from the command line, as we did in \ntutorial part 1\n. Everything is working pretty similarly, although we've got some nicer error handling if we send invalid requests.\n\n\nWe can get a list of all of the snippets, as before.\n\n\nhttp http://127.0.0.1:8000/snippets/\n\nHTTP/1.1 200 OK\n...\n[\n {\n \"id\": 1,\n \"title\": \"\",\n \"code\": \"foo = \\\"bar\\\"\\n\",\n \"linenos\": false,\n \"language\": \"python\",\n \"style\": \"friendly\"\n },\n {\n \"id\": 2,\n \"title\": \"\",\n \"code\": \"print \\\"hello, world\\\"\\n\",\n \"linenos\": false,\n \"language\": \"python\",\n \"style\": \"friendly\"\n }\n]\n\n\n\nWe can control the format of the response that we get back, either by using the \nAccept\n header:\n\n\nhttp http://127.0.0.1:8000/snippets/ Accept:application/json # Request JSON\nhttp http://127.0.0.1:8000/snippets/ Accept:text/html # Request HTML\n\n\n\nOr by appending a format suffix:\n\n\nhttp http://127.0.0.1:8000/snippets.json # JSON suffix\nhttp http://127.0.0.1:8000/snippets.api # Browsable API suffix\n\n\n\nSimilarly, we can control the format of the request that we send, using the \nContent-Type\n header.\n\n\n# POST using form data\nhttp --form POST http://127.0.0.1:8000/snippets/ code=\"print 123\"\n\n{\n \"id\": 3,\n \"title\": \"\",\n \"code\": \"print 123\",\n \"linenos\": false,\n \"language\": \"python\",\n \"style\": \"friendly\"\n}\n\n# POST using JSON\nhttp --json POST http://127.0.0.1:8000/snippets/ code=\"print 456\"\n\n{\n \"id\": 4,\n \"title\": \"\",\n \"code\": \"print 456\",\n \"linenos\": false,\n \"language\": \"python\",\n \"style\": \"friendly\"\n}\n\n\n\nIf you add a \n--debug\n switch to the \nhttp\n requests above, you will be able to see the request type in request headers.\n\n\nNow go and open the API in a web browser, by visiting \nhttp://127.0.0.1:8000/snippets/\n.\n\n\nBrowsability\n\n\nBecause the API chooses the content type of the response based on the client request, it will, by default, return an HTML-formatted representation of the resource when that resource is requested by a web browser. This allows for the API to return a fully web-browsable HTML representation.\n\n\nHaving a web-browsable API is a huge usability win, and makes developing and using your API much easier. It also dramatically lowers the barrier-to-entry for other developers wanting to inspect and work with your API.\n\n\nSee the \nbrowsable api\n topic for more information about the browsable API feature and how to customize it.\n\n\nWhat's next?\n\n\nIn \ntutorial part 3\n, we'll start using class-based views, and see how generic views reduce the amount of code we need to write.", + "text": "Tutorial 2: Requests and Responses\n\n\nFrom this point we're going to really start covering the core of REST framework.\nLet's introduce a couple of essential building blocks.\n\n\nRequest objects\n\n\nREST framework introduces a \nRequest\n object that extends the regular \nHttpRequest\n, and provides more flexible request parsing. The core functionality of the \nRequest\n object is the \nrequest.data\n attribute, which is similar to \nrequest.POST\n, but more useful for working with Web APIs.\n\n\nrequest.POST # Only handles form data. Only works for 'POST' method.\nrequest.data # Handles arbitrary data. Works for 'POST', 'PUT' and 'PATCH' methods.\n\n\n\nResponse objects\n\n\nREST framework also introduces a \nResponse\n object, which is a type of \nTemplateResponse\n that takes unrendered content and uses content negotiation to determine the correct content type to return to the client.\n\n\nreturn Response(data) # Renders to content type as requested by the client.\n\n\n\nStatus codes\n\n\nUsing numeric HTTP status codes in your views doesn't always make for obvious reading, and it's easy to not notice if you get an error code wrong. REST framework provides more explicit identifiers for each status code, such as \nHTTP_400_BAD_REQUEST\n in the \nstatus\n module. It's a good idea to use these throughout rather than using numeric identifiers.\n\n\nWrapping API views\n\n\nREST framework provides two wrappers you can use to write API views.\n\n\n\n\nThe \n@api_view\n decorator for working with function based views.\n\n\nThe \nAPIView\n class for working with class-based views.\n\n\n\n\nThese wrappers provide a few bits of functionality such as making sure you receive \nRequest\n instances in your view, and adding context to \nResponse\n objects so that content negotiation can be performed.\n\n\nThe wrappers also provide behaviour such as returning \n405 Method Not Allowed\n responses when appropriate, and handling any \nParseError\n exception that occurs when accessing \nrequest.data\n with malformed input.\n\n\nPulling it all together\n\n\nOkay, let's go ahead and start using these new components to write a few views.\n\n\nWe don't need our \nJSONResponse\n class in \nviews.py\n anymore, so go ahead and delete that. Once that's done we can start refactoring our views slightly.\n\n\nfrom rest_framework import status\nfrom rest_framework.decorators import api_view\nfrom rest_framework.response import Response\nfrom snippets.models import Snippet\nfrom snippets.serializers import SnippetSerializer\n\n\n@api_view(['GET', 'POST'])\ndef snippet_list(request):\n \"\"\"\n List all snippets, or create a new snippet.\n \"\"\"\n if request.method == 'GET':\n snippets = Snippet.objects.all()\n serializer = SnippetSerializer(snippets, many=True)\n return Response(serializer.data)\n\n elif request.method == 'POST':\n serializer = SnippetSerializer(data=request.data)\n if serializer.is_valid():\n serializer.save()\n return Response(serializer.data, status=status.HTTP_201_CREATED)\n return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)\n\n\n\nOur instance view is an improvement over the previous example. It's a little more concise, and the code now feels very similar to if we were working with the Forms API. We're also using named status codes, which makes the response meanings more obvious.\n\n\nHere is the view for an individual snippet, in the \nviews.py\n module.\n\n\n@api_view(['GET', 'PUT', 'DELETE'])\ndef snippet_detail(request, pk):\n \"\"\"\n Retrieve, update or delete a snippet instance.\n \"\"\"\n try:\n snippet = Snippet.objects.get(pk=pk)\n except Snippet.DoesNotExist:\n return Response(status=status.HTTP_404_NOT_FOUND)\n\n if request.method == 'GET':\n serializer = SnippetSerializer(snippet)\n return Response(serializer.data)\n\n elif request.method == 'PUT':\n serializer = SnippetSerializer(snippet, data=request.data)\n if serializer.is_valid():\n serializer.save()\n return Response(serializer.data)\n return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)\n\n elif request.method == 'DELETE':\n snippet.delete()\n return Response(status=status.HTTP_204_NO_CONTENT)\n\n\n\nThis should all feel very familiar - it is not a lot different from working with regular Django views.\n\n\nNotice that we're no longer explicitly tying our requests or responses to a given content type. \nrequest.data\n can handle incoming \njson\n requests, but it can also handle other formats. Similarly we're returning response objects with data, but allowing REST framework to render the response into the correct content type for us.\n\n\nAdding optional format suffixes to our URLs\n\n\nTo take advantage of the fact that our responses are no longer hardwired to a single content type let's add support for format suffixes to our API endpoints. Using format suffixes gives us URLs that explicitly refer to a given format, and means our API will be able to handle URLs such as \nhttp://example.com/api/items/4.json\n.\n\n\nStart by adding a \nformat\n keyword argument to both of the views, like so.\n\n\ndef snippet_list(request, format=None):\n\n\n\nand\n\n\ndef snippet_detail(request, pk, format=None):\n\n\n\nNow update the \nurls.py\n file slightly, to append a set of \nformat_suffix_patterns\n in addition to the existing URLs.\n\n\nfrom django.conf.urls import url\nfrom rest_framework.urlpatterns import format_suffix_patterns\nfrom snippets import views\n\nurlpatterns = [\n url(r'^snippets/$', views.snippet_list),\n url(r'^snippets/(?P\npk\n[0-9]+)$', views.snippet_detail),\n]\n\nurlpatterns = format_suffix_patterns(urlpatterns)\n\n\n\nWe don't necessarily need to add these extra url patterns in, but it gives us a simple, clean way of referring to a specific format.\n\n\nHow's it looking?\n\n\nGo ahead and test the API from the command line, as we did in \ntutorial part 1\n. Everything is working pretty similarly, although we've got some nicer error handling if we send invalid requests.\n\n\nWe can get a list of all of the snippets, as before.\n\n\nhttp http://127.0.0.1:8000/snippets/\n\nHTTP/1.1 200 OK\n...\n[\n {\n \"id\": 1,\n \"title\": \"\",\n \"code\": \"foo = \\\"bar\\\"\\n\",\n \"linenos\": false,\n \"language\": \"python\",\n \"style\": \"friendly\"\n },\n {\n \"id\": 2,\n \"title\": \"\",\n \"code\": \"print \\\"hello, world\\\"\\n\",\n \"linenos\": false,\n \"language\": \"python\",\n \"style\": \"friendly\"\n }\n]\n\n\n\nWe can control the format of the response that we get back, either by using the \nAccept\n header:\n\n\nhttp http://127.0.0.1:8000/snippets/ Accept:application/json # Request JSON\nhttp http://127.0.0.1:8000/snippets/ Accept:text/html # Request HTML\n\n\n\nOr by appending a format suffix:\n\n\nhttp http://127.0.0.1:8000/snippets.json # JSON suffix\nhttp http://127.0.0.1:8000/snippets.api # Browsable API suffix\n\n\n\nSimilarly, we can control the format of the request that we send, using the \nContent-Type\n header.\n\n\n# POST using form data\nhttp --form POST http://127.0.0.1:8000/snippets/ code=\"print 123\"\n\n{\n \"id\": 3,\n \"title\": \"\",\n \"code\": \"print 123\",\n \"linenos\": false,\n \"language\": \"python\",\n \"style\": \"friendly\"\n}\n\n# POST using JSON\nhttp --json POST http://127.0.0.1:8000/snippets/ code=\"print 456\"\n\n{\n \"id\": 4,\n \"title\": \"\",\n \"code\": \"print 456\",\n \"linenos\": false,\n \"language\": \"python\",\n \"style\": \"friendly\"\n}\n\n\n\nIf you add a \n--debug\n switch to the \nhttp\n requests above, you will be able to see the request type in request headers.\n\n\nNow go and open the API in a web browser, by visiting \nhttp://127.0.0.1:8000/snippets/\n.\n\n\nBrowsability\n\n\nBecause the API chooses the content type of the response based on the client request, it will, by default, return an HTML-formatted representation of the resource when that resource is requested by a web browser. This allows for the API to return a fully web-browsable HTML representation.\n\n\nHaving a web-browsable API is a huge usability win, and makes developing and using your API much easier. It also dramatically lowers the barrier-to-entry for other developers wanting to inspect and work with your API.\n\n\nSee the \nbrowsable api\n topic for more information about the browsable API feature and how to customize it.\n\n\nWhat's next?\n\n\nIn \ntutorial part 3\n, we'll start using class-based views, and see how generic views reduce the amount of code we need to write.", "title": "2 - Requests and responses" }, { @@ -197,12 +197,12 @@ }, { "location": "/tutorial/2-requests-and-responses/#pulling-it-all-together", - "text": "Okay, let's go ahead and start using these new components to write a few views. We don't need our JSONResponse class in views.py anymore, so go ahead and delete that. Once that's done we can start refactoring our views slightly. from rest_framework import status\nfrom rest_framework.decorators import api_view\nfrom rest_framework.response import Response\nfrom snippets.models import Snippet\nfrom snippets.serializers import SnippetSerializer\n\n\n@api_view(['GET', 'POST'])\ndef snippet_list(request):\n \"\"\"\n List all snippets, or create a new snippet.\n \"\"\"\n if request.method == 'GET':\n snippets = Snippet.objects.all()\n serializer = SnippetSerializer(snippets, many=True)\n return Response(serializer.data)\n\n elif request.method == 'POST':\n serializer = SnippetSerializer(data=request.data)\n if serializer.is_valid():\n serializer.save()\n return Response(serializer.data, status=status.HTTP_201_CREATED)\n return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) Our instance view is an improvement over the previous example. It's a little more concise, and the code now feels very similar to if we were working with the Forms API. We're also using named status codes, which makes the response meanings more obvious. Here is the view for an individual snippet, in the views.py module. @api_view(['GET', 'PUT', 'DELETE'])\ndef snippet_detail(request, id):\n \"\"\"\n Retrieve, update or delete a snippet instance.\n \"\"\"\n try:\n snippet = Snippet.objects.get(id=id)\n except Snippet.DoesNotExist:\n return Response(status=status.HTTP_404_NOT_FOUND)\n\n if request.method == 'GET':\n serializer = SnippetSerializer(snippet)\n return Response(serializer.data)\n\n elif request.method == 'PUT':\n serializer = SnippetSerializer(snippet, data=request.data)\n if serializer.is_valid():\n serializer.save()\n return Response(serializer.data)\n return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)\n\n elif request.method == 'DELETE':\n snippet.delete()\n return Response(status=status.HTTP_204_NO_CONTENT) This should all feel very familiar - it is not a lot different from working with regular Django views. Notice that we're no longer explicitly tying our requests or responses to a given content type. request.data can handle incoming json requests, but it can also handle other formats. Similarly we're returning response objects with data, but allowing REST framework to render the response into the correct content type for us.", + "text": "Okay, let's go ahead and start using these new components to write a few views. We don't need our JSONResponse class in views.py anymore, so go ahead and delete that. Once that's done we can start refactoring our views slightly. from rest_framework import status\nfrom rest_framework.decorators import api_view\nfrom rest_framework.response import Response\nfrom snippets.models import Snippet\nfrom snippets.serializers import SnippetSerializer\n\n\n@api_view(['GET', 'POST'])\ndef snippet_list(request):\n \"\"\"\n List all snippets, or create a new snippet.\n \"\"\"\n if request.method == 'GET':\n snippets = Snippet.objects.all()\n serializer = SnippetSerializer(snippets, many=True)\n return Response(serializer.data)\n\n elif request.method == 'POST':\n serializer = SnippetSerializer(data=request.data)\n if serializer.is_valid():\n serializer.save()\n return Response(serializer.data, status=status.HTTP_201_CREATED)\n return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) Our instance view is an improvement over the previous example. It's a little more concise, and the code now feels very similar to if we were working with the Forms API. We're also using named status codes, which makes the response meanings more obvious. Here is the view for an individual snippet, in the views.py module. @api_view(['GET', 'PUT', 'DELETE'])\ndef snippet_detail(request, pk):\n \"\"\"\n Retrieve, update or delete a snippet instance.\n \"\"\"\n try:\n snippet = Snippet.objects.get(pk=pk)\n except Snippet.DoesNotExist:\n return Response(status=status.HTTP_404_NOT_FOUND)\n\n if request.method == 'GET':\n serializer = SnippetSerializer(snippet)\n return Response(serializer.data)\n\n elif request.method == 'PUT':\n serializer = SnippetSerializer(snippet, data=request.data)\n if serializer.is_valid():\n serializer.save()\n return Response(serializer.data)\n return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)\n\n elif request.method == 'DELETE':\n snippet.delete()\n return Response(status=status.HTTP_204_NO_CONTENT) This should all feel very familiar - it is not a lot different from working with regular Django views. Notice that we're no longer explicitly tying our requests or responses to a given content type. request.data can handle incoming json requests, but it can also handle other formats. Similarly we're returning response objects with data, but allowing REST framework to render the response into the correct content type for us.", "title": "Pulling it all together" }, { "location": "/tutorial/2-requests-and-responses/#adding-optional-format-suffixes-to-our-urls", - "text": "To take advantage of the fact that our responses are no longer hardwired to a single content type let's add support for format suffixes to our API endpoints. Using format suffixes gives us URLs that explicitly refer to a given format, and means our API will be able to handle URLs such as http://example.com/api/items/4.json . Start by adding a format keyword argument to both of the views, like so. def snippet_list(request, format=None): and def snippet_detail(request, id, format=None): Now update the urls.py file slightly, to append a set of format_suffix_patterns in addition to the existing URLs. from django.conf.urls import url\nfrom rest_framework.urlpatterns import format_suffix_patterns\nfrom snippets import views\n\nurlpatterns = [\n url(r'^snippets/$', views.snippet_list),\n url(r'^snippets/(?P id [0-9]+)$', views.snippet_detail),\n]\n\nurlpatterns = format_suffix_patterns(urlpatterns) We don't necessarily need to add these extra url patterns in, but it gives us a simple, clean way of referring to a specific format.", + "text": "To take advantage of the fact that our responses are no longer hardwired to a single content type let's add support for format suffixes to our API endpoints. Using format suffixes gives us URLs that explicitly refer to a given format, and means our API will be able to handle URLs such as http://example.com/api/items/4.json . Start by adding a format keyword argument to both of the views, like so. def snippet_list(request, format=None): and def snippet_detail(request, pk, format=None): Now update the urls.py file slightly, to append a set of format_suffix_patterns in addition to the existing URLs. from django.conf.urls import url\nfrom rest_framework.urlpatterns import format_suffix_patterns\nfrom snippets import views\n\nurlpatterns = [\n url(r'^snippets/$', views.snippet_list),\n url(r'^snippets/(?P pk [0-9]+)$', views.snippet_detail),\n]\n\nurlpatterns = format_suffix_patterns(urlpatterns) We don't necessarily need to add these extra url patterns in, but it gives us a simple, clean way of referring to a specific format.", "title": "Adding optional format suffixes to our URLs" }, { @@ -222,7 +222,7 @@ }, { "location": "/tutorial/3-class-based-views/", - "text": "Tutorial 3: Class-based Views\n\n\nWe can also write our API views using class-based views, rather than function based views. As we'll see this is a powerful pattern that allows us to reuse common functionality, and helps us keep our code \nDRY\n.\n\n\nRewriting our API using class-based views\n\n\nWe'll start by rewriting the root view as a class-based view. All this involves is a little bit of refactoring of \nviews.py\n.\n\n\nfrom snippets.models import Snippet\nfrom snippets.serializers import SnippetSerializer\nfrom django.http import Http404\nfrom rest_framework.views import APIView\nfrom rest_framework.response import Response\nfrom rest_framework import status\n\n\nclass SnippetList(APIView):\n \"\"\"\n List all snippets, or create a new snippet.\n \"\"\"\n def get(self, request, format=None):\n snippets = Snippet.objects.all()\n serializer = SnippetSerializer(snippets, many=True)\n return Response(serializer.data)\n\n def post(self, request, format=None):\n serializer = SnippetSerializer(data=request.data)\n if serializer.is_valid():\n serializer.save()\n return Response(serializer.data, status=status.HTTP_201_CREATED)\n return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)\n\n\n\nSo far, so good. It looks pretty similar to the previous case, but we've got better separation between the different HTTP methods. We'll also need to update the instance view in \nviews.py\n.\n\n\nclass SnippetDetail(APIView):\n \"\"\"\n Retrieve, update or delete a snippet instance.\n \"\"\"\n def get_object(self, id):\n try:\n return Snippet.objects.get(id=id)\n except Snippet.DoesNotExist:\n raise Http404\n\n def get(self, request, id, format=None):\n snippet = self.get_object(id)\n serializer = SnippetSerializer(snippet)\n return Response(serializer.data)\n\n def put(self, request, id, format=None):\n snippet = self.get_object(id)\n serializer = SnippetSerializer(snippet, data=request.data)\n if serializer.is_valid():\n serializer.save()\n return Response(serializer.data)\n return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)\n\n def delete(self, request, id, format=None):\n snippet = self.get_object(id)\n snippet.delete()\n return Response(status=status.HTTP_204_NO_CONTENT)\n\n\n\nThat's looking good. Again, it's still pretty similar to the function based view right now.\n\n\nWe'll also need to refactor our \nurls.py\n slightly now we're using class-based views.\n\n\nfrom django.conf.urls import url\nfrom rest_framework.urlpatterns import format_suffix_patterns\nfrom snippets import views\n\nurlpatterns = [\n url(r'^snippets/$', views.SnippetList.as_view()),\n url(r'^snippets/(?P\nid\n[0-9]+)/$', views.SnippetDetail.as_view()),\n]\n\nurlpatterns = format_suffix_patterns(urlpatterns)\n\n\n\nOkay, we're done. If you run the development server everything should be working just as before.\n\n\nUsing mixins\n\n\nOne of the big wins of using class-based views is that it allows us to easily compose reusable bits of behaviour.\n\n\nThe create/retrieve/update/delete operations that we've been using so far are going to be pretty similar for any model-backed API views we create. Those bits of common behaviour are implemented in REST framework's mixin classes.\n\n\nLet's take a look at how we can compose the views by using the mixin classes. Here's our \nviews.py\n module again.\n\n\nfrom snippets.models import Snippet\nfrom snippets.serializers import SnippetSerializer\nfrom rest_framework import mixins\nfrom rest_framework import generics\n\nclass SnippetList(mixins.ListModelMixin,\n mixins.CreateModelMixin,\n generics.GenericAPIView):\n queryset = Snippet.objects.all()\n serializer_class = SnippetSerializer\n\n def get(self, request, *args, **kwargs):\n return self.list(request, *args, **kwargs)\n\n def post(self, request, *args, **kwargs):\n return self.create(request, *args, **kwargs)\n\n\n\nWe'll take a moment to examine exactly what's happening here. We're building our view using \nGenericAPIView\n, and adding in \nListModelMixin\n and \nCreateModelMixin\n.\n\n\nThe base class provides the core functionality, and the mixin classes provide the \n.list()\n and \n.create()\n actions. We're then explicitly binding the \nget\n and \npost\n methods to the appropriate actions. Simple enough stuff so far.\n\n\nclass SnippetDetail(mixins.RetrieveModelMixin,\n mixins.UpdateModelMixin,\n mixins.DestroyModelMixin,\n generics.GenericAPIView):\n queryset = Snippet.objects.all()\n serializer_class = SnippetSerializer\n\n def get(self, request, *args, **kwargs):\n return self.retrieve(request, *args, **kwargs)\n\n def put(self, request, *args, **kwargs):\n return self.update(request, *args, **kwargs)\n\n def delete(self, request, *args, **kwargs):\n return self.destroy(request, *args, **kwargs)\n\n\n\nPretty similar. Again we're using the \nGenericAPIView\n class to provide the core functionality, and adding in mixins to provide the \n.retrieve()\n, \n.update()\n and \n.destroy()\n actions.\n\n\nUsing generic class-based views\n\n\nUsing the mixin classes we've rewritten the views to use slightly less code than before, but we can go one step further. REST framework provides a set of already mixed-in generic views that we can use to trim down our \nviews.py\n module even more.\n\n\nfrom snippets.models import Snippet\nfrom snippets.serializers import SnippetSerializer\nfrom rest_framework import generics\n\n\nclass SnippetList(generics.ListCreateAPIView):\n queryset = Snippet.objects.all()\n serializer_class = SnippetSerializer\n\n\nclass SnippetDetail(generics.RetrieveUpdateDestroyAPIView):\n queryset = Snippet.objects.all()\n serializer_class = SnippetSerializer\n\n\n\nWow, that's pretty concise. We've gotten a huge amount for free, and our code looks like good, clean, idiomatic Django.\n\n\nNext we'll move onto \npart 4 of the tutorial\n, where we'll take a look at how we can deal with authentication and permissions for our API.", + "text": "Tutorial 3: Class-based Views\n\n\nWe can also write our API views using class-based views, rather than function based views. As we'll see this is a powerful pattern that allows us to reuse common functionality, and helps us keep our code \nDRY\n.\n\n\nRewriting our API using class-based views\n\n\nWe'll start by rewriting the root view as a class-based view. All this involves is a little bit of refactoring of \nviews.py\n.\n\n\nfrom snippets.models import Snippet\nfrom snippets.serializers import SnippetSerializer\nfrom django.http import Http404\nfrom rest_framework.views import APIView\nfrom rest_framework.response import Response\nfrom rest_framework import status\n\n\nclass SnippetList(APIView):\n \"\"\"\n List all snippets, or create a new snippet.\n \"\"\"\n def get(self, request, format=None):\n snippets = Snippet.objects.all()\n serializer = SnippetSerializer(snippets, many=True)\n return Response(serializer.data)\n\n def post(self, request, format=None):\n serializer = SnippetSerializer(data=request.data)\n if serializer.is_valid():\n serializer.save()\n return Response(serializer.data, status=status.HTTP_201_CREATED)\n return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)\n\n\n\nSo far, so good. It looks pretty similar to the previous case, but we've got better separation between the different HTTP methods. We'll also need to update the instance view in \nviews.py\n.\n\n\nclass SnippetDetail(APIView):\n \"\"\"\n Retrieve, update or delete a snippet instance.\n \"\"\"\n def get_object(self, pk):\n try:\n return Snippet.objects.get(pk=pk)\n except Snippet.DoesNotExist:\n raise Http404\n\n def get(self, request, pk, format=None):\n snippet = self.get_object(pk)\n serializer = SnippetSerializer(snippet)\n return Response(serializer.data)\n\n def put(self, request, pk, format=None):\n snippet = self.get_object(pk)\n serializer = SnippetSerializer(snippet, data=request.data)\n if serializer.is_valid():\n serializer.save()\n return Response(serializer.data)\n return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)\n\n def delete(self, request, pk, format=None):\n snippet = self.get_object(pk)\n snippet.delete()\n return Response(status=status.HTTP_204_NO_CONTENT)\n\n\n\nThat's looking good. Again, it's still pretty similar to the function based view right now.\n\n\nWe'll also need to refactor our \nurls.py\n slightly now we're using class-based views.\n\n\nfrom django.conf.urls import url\nfrom rest_framework.urlpatterns import format_suffix_patterns\nfrom snippets import views\n\nurlpatterns = [\n url(r'^snippets/$', views.SnippetList.as_view()),\n url(r'^snippets/(?P\npk\n[0-9]+)/$', views.SnippetDetail.as_view()),\n]\n\nurlpatterns = format_suffix_patterns(urlpatterns)\n\n\n\nOkay, we're done. If you run the development server everything should be working just as before.\n\n\nUsing mixins\n\n\nOne of the big wins of using class-based views is that it allows us to easily compose reusable bits of behaviour.\n\n\nThe create/retrieve/update/delete operations that we've been using so far are going to be pretty similar for any model-backed API views we create. Those bits of common behaviour are implemented in REST framework's mixin classes.\n\n\nLet's take a look at how we can compose the views by using the mixin classes. Here's our \nviews.py\n module again.\n\n\nfrom snippets.models import Snippet\nfrom snippets.serializers import SnippetSerializer\nfrom rest_framework import mixins\nfrom rest_framework import generics\n\nclass SnippetList(mixins.ListModelMixin,\n mixins.CreateModelMixin,\n generics.GenericAPIView):\n queryset = Snippet.objects.all()\n serializer_class = SnippetSerializer\n\n def get(self, request, *args, **kwargs):\n return self.list(request, *args, **kwargs)\n\n def post(self, request, *args, **kwargs):\n return self.create(request, *args, **kwargs)\n\n\n\nWe'll take a moment to examine exactly what's happening here. We're building our view using \nGenericAPIView\n, and adding in \nListModelMixin\n and \nCreateModelMixin\n.\n\n\nThe base class provides the core functionality, and the mixin classes provide the \n.list()\n and \n.create()\n actions. We're then explicitly binding the \nget\n and \npost\n methods to the appropriate actions. Simple enough stuff so far.\n\n\nclass SnippetDetail(mixins.RetrieveModelMixin,\n mixins.UpdateModelMixin,\n mixins.DestroyModelMixin,\n generics.GenericAPIView):\n queryset = Snippet.objects.all()\n serializer_class = SnippetSerializer\n\n def get(self, request, *args, **kwargs):\n return self.retrieve(request, *args, **kwargs)\n\n def put(self, request, *args, **kwargs):\n return self.update(request, *args, **kwargs)\n\n def delete(self, request, *args, **kwargs):\n return self.destroy(request, *args, **kwargs)\n\n\n\nPretty similar. Again we're using the \nGenericAPIView\n class to provide the core functionality, and adding in mixins to provide the \n.retrieve()\n, \n.update()\n and \n.destroy()\n actions.\n\n\nUsing generic class-based views\n\n\nUsing the mixin classes we've rewritten the views to use slightly less code than before, but we can go one step further. REST framework provides a set of already mixed-in generic views that we can use to trim down our \nviews.py\n module even more.\n\n\nfrom snippets.models import Snippet\nfrom snippets.serializers import SnippetSerializer\nfrom rest_framework import generics\n\n\nclass SnippetList(generics.ListCreateAPIView):\n queryset = Snippet.objects.all()\n serializer_class = SnippetSerializer\n\n\nclass SnippetDetail(generics.RetrieveUpdateDestroyAPIView):\n queryset = Snippet.objects.all()\n serializer_class = SnippetSerializer\n\n\n\nWow, that's pretty concise. We've gotten a huge amount for free, and our code looks like good, clean, idiomatic Django.\n\n\nNext we'll move onto \npart 4 of the tutorial\n, where we'll take a look at how we can deal with authentication and permissions for our API.", "title": "3 - Class based views" }, { @@ -232,7 +232,7 @@ }, { "location": "/tutorial/3-class-based-views/#rewriting-our-api-using-class-based-views", - "text": "We'll start by rewriting the root view as a class-based view. All this involves is a little bit of refactoring of views.py . from snippets.models import Snippet\nfrom snippets.serializers import SnippetSerializer\nfrom django.http import Http404\nfrom rest_framework.views import APIView\nfrom rest_framework.response import Response\nfrom rest_framework import status\n\n\nclass SnippetList(APIView):\n \"\"\"\n List all snippets, or create a new snippet.\n \"\"\"\n def get(self, request, format=None):\n snippets = Snippet.objects.all()\n serializer = SnippetSerializer(snippets, many=True)\n return Response(serializer.data)\n\n def post(self, request, format=None):\n serializer = SnippetSerializer(data=request.data)\n if serializer.is_valid():\n serializer.save()\n return Response(serializer.data, status=status.HTTP_201_CREATED)\n return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) So far, so good. It looks pretty similar to the previous case, but we've got better separation between the different HTTP methods. We'll also need to update the instance view in views.py . class SnippetDetail(APIView):\n \"\"\"\n Retrieve, update or delete a snippet instance.\n \"\"\"\n def get_object(self, id):\n try:\n return Snippet.objects.get(id=id)\n except Snippet.DoesNotExist:\n raise Http404\n\n def get(self, request, id, format=None):\n snippet = self.get_object(id)\n serializer = SnippetSerializer(snippet)\n return Response(serializer.data)\n\n def put(self, request, id, format=None):\n snippet = self.get_object(id)\n serializer = SnippetSerializer(snippet, data=request.data)\n if serializer.is_valid():\n serializer.save()\n return Response(serializer.data)\n return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)\n\n def delete(self, request, id, format=None):\n snippet = self.get_object(id)\n snippet.delete()\n return Response(status=status.HTTP_204_NO_CONTENT) That's looking good. Again, it's still pretty similar to the function based view right now. We'll also need to refactor our urls.py slightly now we're using class-based views. from django.conf.urls import url\nfrom rest_framework.urlpatterns import format_suffix_patterns\nfrom snippets import views\n\nurlpatterns = [\n url(r'^snippets/$', views.SnippetList.as_view()),\n url(r'^snippets/(?P id [0-9]+)/$', views.SnippetDetail.as_view()),\n]\n\nurlpatterns = format_suffix_patterns(urlpatterns) Okay, we're done. If you run the development server everything should be working just as before.", + "text": "We'll start by rewriting the root view as a class-based view. All this involves is a little bit of refactoring of views.py . from snippets.models import Snippet\nfrom snippets.serializers import SnippetSerializer\nfrom django.http import Http404\nfrom rest_framework.views import APIView\nfrom rest_framework.response import Response\nfrom rest_framework import status\n\n\nclass SnippetList(APIView):\n \"\"\"\n List all snippets, or create a new snippet.\n \"\"\"\n def get(self, request, format=None):\n snippets = Snippet.objects.all()\n serializer = SnippetSerializer(snippets, many=True)\n return Response(serializer.data)\n\n def post(self, request, format=None):\n serializer = SnippetSerializer(data=request.data)\n if serializer.is_valid():\n serializer.save()\n return Response(serializer.data, status=status.HTTP_201_CREATED)\n return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) So far, so good. It looks pretty similar to the previous case, but we've got better separation between the different HTTP methods. We'll also need to update the instance view in views.py . class SnippetDetail(APIView):\n \"\"\"\n Retrieve, update or delete a snippet instance.\n \"\"\"\n def get_object(self, pk):\n try:\n return Snippet.objects.get(pk=pk)\n except Snippet.DoesNotExist:\n raise Http404\n\n def get(self, request, pk, format=None):\n snippet = self.get_object(pk)\n serializer = SnippetSerializer(snippet)\n return Response(serializer.data)\n\n def put(self, request, pk, format=None):\n snippet = self.get_object(pk)\n serializer = SnippetSerializer(snippet, data=request.data)\n if serializer.is_valid():\n serializer.save()\n return Response(serializer.data)\n return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)\n\n def delete(self, request, pk, format=None):\n snippet = self.get_object(pk)\n snippet.delete()\n return Response(status=status.HTTP_204_NO_CONTENT) That's looking good. Again, it's still pretty similar to the function based view right now. We'll also need to refactor our urls.py slightly now we're using class-based views. from django.conf.urls import url\nfrom rest_framework.urlpatterns import format_suffix_patterns\nfrom snippets import views\n\nurlpatterns = [\n url(r'^snippets/$', views.SnippetList.as_view()),\n url(r'^snippets/(?P pk [0-9]+)/$', views.SnippetDetail.as_view()),\n]\n\nurlpatterns = format_suffix_patterns(urlpatterns) Okay, we're done. If you run the development server everything should be working just as before.", "title": "Rewriting our API using class-based views" }, { @@ -247,7 +247,7 @@ }, { "location": "/tutorial/4-authentication-and-permissions/", - "text": "Tutorial 4: Authentication \n 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')\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 tmp.db 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\nid\n[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 namespace='rest_framework')),\n]\n\n\n\nThe \nr'^api-auth/'\n part of pattern can actually be whatever URL you want to use. The only restriction is that the included urls must use the \n'rest_framework'\n namespace. In Django 1.9+, REST framework will set the namespace, so you may leave it out.\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 tom:password123 POST http://127.0.0.1:8000/snippets/ code=\"print 789\"\n\n{\n \"id\": 5,\n \"owner\": \"tom\",\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 \n 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')\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 tmp.db 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\npk\n[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 namespace='rest_framework')),\n]\n\n\n\nThe \nr'^api-auth/'\n part of pattern can actually be whatever URL you want to use. The only restriction is that the included urls must use the \n'rest_framework'\n namespace. In Django 1.9+, REST framework will set the namespace, so you may leave it out.\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 tom:password123 POST http://127.0.0.1:8000/snippets/ code=\"print 789\"\n\n{\n \"id\": 5,\n \"owner\": \"tom\",\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" }, { @@ -262,7 +262,7 @@ }, { "location": "/tutorial/4-authentication-and-permissions/#adding-endpoints-for-our-user-models", - "text": "Now 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 serializers.py add: from 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') Because 'snippets' is a reverse relationship on the User model, it will not be included by default when using the ModelSerializer class, so we needed to add an explicit field for it. We'll also add a couple of views to views.py . We'd like to just use read-only views for the user representations, so we'll use the ListAPIView and RetrieveAPIView generic class-based views. from 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 Make sure to also import the UserSerializer class from snippets.serializers import UserSerializer Finally we need to add those views into the API, by referencing them from the URL conf. Add the following to the patterns in urls.py . url(r'^users/$', views.UserList.as_view()),\nurl(r'^users/(?P id [0-9]+)/$', views.UserDetail.as_view()),", + "text": "Now 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 serializers.py add: from 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') Because 'snippets' is a reverse relationship on the User model, it will not be included by default when using the ModelSerializer class, so we needed to add an explicit field for it. We'll also add a couple of views to views.py . We'd like to just use read-only views for the user representations, so we'll use the ListAPIView and RetrieveAPIView generic class-based views. from 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 Make sure to also import the UserSerializer class from snippets.serializers import UserSerializer Finally we need to add those views into the API, by referencing them from the URL conf. Add the following to the patterns in urls.py . url(r'^users/$', views.UserList.as_view()),\nurl(r'^users/(?P pk [0-9]+)/$', views.UserDetail.as_view()),", "title": "Adding endpoints for our User models" }, { @@ -302,7 +302,7 @@ }, { "location": "/tutorial/5-relationships-and-hyperlinked-apis/", - "text": "Tutorial 5: Relationships \n Hyperlinked APIs\n\n\nAt the moment relationships within our API are represented by using primary keys. In this part of the tutorial we'll improve the cohesion and discoverability of our API, by instead using hyperlinking for relationships.\n\n\nCreating an endpoint for the root of our API\n\n\nRight now we have endpoints for 'snippets' and 'users', but we don't have a single entry point to our API. To create one, we'll use a regular function-based view and the \n@api_view\n decorator we introduced earlier. In your \nsnippets/views.py\n add:\n\n\nfrom rest_framework.decorators import api_view\nfrom rest_framework.response import Response\nfrom rest_framework.reverse import reverse\n\n\n@api_view(['GET'])\ndef api_root(request, format=None):\n return Response({\n 'users': reverse('user-list', request=request, format=format),\n 'snippets': reverse('snippet-list', request=request, format=format)\n })\n\n\n\nTwo things should be noticed here. First, we're using REST framework's \nreverse\n function in order to return fully-qualified URLs; second, URL patterns are identified by convenience names that we will declare later on in our \nsnippets/urls.py\n.\n\n\nCreating an endpoint for the highlighted snippets\n\n\nThe other obvious thing that's still missing from our pastebin API is the code highlighting endpoints.\n\n\nUnlike all our other API endpoints, we don't want to use JSON, but instead just present an HTML representation. There are two styles of HTML renderer provided by REST framework, one for dealing with HTML rendered using templates, the other for dealing with pre-rendered HTML. The second renderer is the one we'd like to use for this endpoint.\n\n\nThe other thing we need to consider when creating the code highlight view is that there's no existing concrete generic view that we can use. We're not returning an object instance, but instead a property of an object instance.\n\n\nInstead of using a concrete generic view, we'll use the base class for representing instances, and create our own \n.get()\n method. In your \nsnippets/views.py\n add:\n\n\nfrom rest_framework import renderers\nfrom rest_framework.response import Response\n\nclass SnippetHighlight(generics.GenericAPIView):\n queryset = Snippet.objects.all()\n renderer_classes = (renderers.StaticHTMLRenderer,)\n\n def get(self, request, *args, **kwargs):\n snippet = self.get_object()\n return Response(snippet.highlighted)\n\n\n\nAs usual we need to add the new views that we've created in to our URLconf.\nWe'll add a url pattern for our new API root in \nsnippets/urls.py\n:\n\n\nurl(r'^$', views.api_root),\n\n\n\nAnd then add a url pattern for the snippet highlights:\n\n\nurl(r'^snippets/(?P\nid\n[0-9]+)/highlight/$', views.SnippetHighlight.as_view()),\n\n\n\nHyperlinking our API\n\n\nDealing with relationships between entities is one of the more challenging aspects of Web API design. There are a number of different ways that we might choose to represent a relationship:\n\n\n\n\nUsing primary keys.\n\n\nUsing hyperlinking between entities.\n\n\nUsing a unique identifying slug field on the related entity.\n\n\nUsing the default string representation of the related entity.\n\n\nNesting the related entity inside the parent representation.\n\n\nSome other custom representation.\n\n\n\n\nREST framework supports all of these styles, and can apply them across forward or reverse relationships, or apply them across custom managers such as generic foreign keys.\n\n\nIn this case we'd like to use a hyperlinked style between entities. In order to do so, we'll modify our serializers to extend \nHyperlinkedModelSerializer\n instead of the existing \nModelSerializer\n.\n\n\nThe \nHyperlinkedModelSerializer\n has the following differences from \nModelSerializer\n:\n\n\n\n\nIt does not include the \nid\n field by default.\n\n\nIt includes a \nurl\n field, using \nHyperlinkedIdentityField\n.\n\n\nRelationships use \nHyperlinkedRelatedField\n,\n instead of \nPrimaryKeyRelatedField\n.\n\n\n\n\nWe can easily re-write our existing serializers to use hyperlinking. In your \nsnippets/serializers.py\n add:\n\n\nclass SnippetSerializer(serializers.HyperlinkedModelSerializer):\n owner = serializers.ReadOnlyField(source='owner.username')\n highlight = serializers.HyperlinkedIdentityField(view_name='snippet-highlight', format='html')\n\n class Meta:\n model = Snippet\n fields = ('url', 'id', 'highlight', 'owner',\n 'title', 'code', 'linenos', 'language', 'style')\n\n\nclass UserSerializer(serializers.HyperlinkedModelSerializer):\n snippets = serializers.HyperlinkedRelatedField(many=True, view_name='snippet-detail', read_only=True)\n\n class Meta:\n model = User\n fields = ('url', 'id', 'username', 'snippets')\n\n\n\nNotice that we've also added a new \n'highlight'\n field. This field is of the same type as the \nurl\n field, except that it points to the \n'snippet-highlight'\n url pattern, instead of the \n'snippet-detail'\n url pattern.\n\n\nBecause we've included format suffixed URLs such as \n'.json'\n, we also need to indicate on the \nhighlight\n field that any format suffixed hyperlinks it returns should use the \n'.html'\n suffix.\n\n\nMaking sure our URL patterns are named\n\n\nIf we're going to have a hyperlinked API, we need to make sure we name our URL patterns. Let's take a look at which URL patterns we need to name.\n\n\n\n\nThe root of our API refers to \n'user-list'\n and \n'snippet-list'\n.\n\n\nOur snippet serializer includes a field that refers to \n'snippet-highlight'\n.\n\n\nOur user serializer includes a field that refers to \n'snippet-detail'\n.\n\n\nOur snippet and user serializers include \n'url'\n fields that by default will refer to \n'{model_name}-detail'\n, which in this case will be \n'snippet-detail'\n and \n'user-detail'\n.\n\n\n\n\nAfter adding all those names into our URLconf, our final \nsnippets/urls.py\n file should look like this:\n\n\nfrom django.conf.urls import url, include\nfrom rest_framework.urlpatterns import format_suffix_patterns\nfrom snippets import views\n\n# API endpoints\nurlpatterns = format_suffix_patterns([\n url(r'^$', views.api_root),\n url(r'^snippets/$',\n views.SnippetList.as_view(),\n name='snippet-list'),\n url(r'^snippets/(?P\nid\n[0-9]+)/$',\n views.SnippetDetail.as_view(),\n name='snippet-detail'),\n url(r'^snippets/(?P\nid\n[0-9]+)/highlight/$',\n views.SnippetHighlight.as_view(),\n name='snippet-highlight'),\n url(r'^users/$',\n views.UserList.as_view(),\n name='user-list'),\n url(r'^users/(?P\nid\n[0-9]+)/$',\n views.UserDetail.as_view(),\n name='user-detail')\n])\n\n# Login and logout views for the browsable API\nurlpatterns += [\n url(r'^api-auth/', include('rest_framework.urls',\n namespace='rest_framework')),\n]\n\n\n\nAdding pagination\n\n\nThe list views for users and code snippets could end up returning quite a lot of instances, so really we'd like to make sure we paginate the results, and allow the API client to step through each of the individual pages.\n\n\nWe can change the default list style to use pagination, by modifying our \ntutorial/settings.py\n file slightly. Add the following setting:\n\n\nREST_FRAMEWORK = {\n 'PAGE_SIZE': 10\n}\n\n\n\nNote that settings in REST framework are all namespaced into a single dictionary setting, named 'REST_FRAMEWORK', which helps keep them well separated from your other project settings.\n\n\nWe could also customize the pagination style if we needed too, but in this case we'll just stick with the default.\n\n\nBrowsing the API\n\n\nIf we open a browser and navigate to the browsable API, you'll find that you can now work your way around the API simply by following links.\n\n\nYou'll also be able to see the 'highlight' links on the snippet instances, that will take you to the highlighted code HTML representations.\n\n\nIn \npart 6\n of the tutorial we'll look at how we can use ViewSets and Routers to reduce the amount of code we need to build our API.", + "text": "Tutorial 5: Relationships \n Hyperlinked APIs\n\n\nAt the moment relationships within our API are represented by using primary keys. In this part of the tutorial we'll improve the cohesion and discoverability of our API, by instead using hyperlinking for relationships.\n\n\nCreating an endpoint for the root of our API\n\n\nRight now we have endpoints for 'snippets' and 'users', but we don't have a single entry point to our API. To create one, we'll use a regular function-based view and the \n@api_view\n decorator we introduced earlier. In your \nsnippets/views.py\n add:\n\n\nfrom rest_framework.decorators import api_view\nfrom rest_framework.response import Response\nfrom rest_framework.reverse import reverse\n\n\n@api_view(['GET'])\ndef api_root(request, format=None):\n return Response({\n 'users': reverse('user-list', request=request, format=format),\n 'snippets': reverse('snippet-list', request=request, format=format)\n })\n\n\n\nTwo things should be noticed here. First, we're using REST framework's \nreverse\n function in order to return fully-qualified URLs; second, URL patterns are identified by convenience names that we will declare later on in our \nsnippets/urls.py\n.\n\n\nCreating an endpoint for the highlighted snippets\n\n\nThe other obvious thing that's still missing from our pastebin API is the code highlighting endpoints.\n\n\nUnlike all our other API endpoints, we don't want to use JSON, but instead just present an HTML representation. There are two styles of HTML renderer provided by REST framework, one for dealing with HTML rendered using templates, the other for dealing with pre-rendered HTML. The second renderer is the one we'd like to use for this endpoint.\n\n\nThe other thing we need to consider when creating the code highlight view is that there's no existing concrete generic view that we can use. We're not returning an object instance, but instead a property of an object instance.\n\n\nInstead of using a concrete generic view, we'll use the base class for representing instances, and create our own \n.get()\n method. In your \nsnippets/views.py\n add:\n\n\nfrom rest_framework import renderers\nfrom rest_framework.response import Response\n\nclass SnippetHighlight(generics.GenericAPIView):\n queryset = Snippet.objects.all()\n renderer_classes = (renderers.StaticHTMLRenderer,)\n\n def get(self, request, *args, **kwargs):\n snippet = self.get_object()\n return Response(snippet.highlighted)\n\n\n\nAs usual we need to add the new views that we've created in to our URLconf.\nWe'll add a url pattern for our new API root in \nsnippets/urls.py\n:\n\n\nurl(r'^$', views.api_root),\n\n\n\nAnd then add a url pattern for the snippet highlights:\n\n\nurl(r'^snippets/(?P\npk\n[0-9]+)/highlight/$', views.SnippetHighlight.as_view()),\n\n\n\nHyperlinking our API\n\n\nDealing with relationships between entities is one of the more challenging aspects of Web API design. There are a number of different ways that we might choose to represent a relationship:\n\n\n\n\nUsing primary keys.\n\n\nUsing hyperlinking between entities.\n\n\nUsing a unique identifying slug field on the related entity.\n\n\nUsing the default string representation of the related entity.\n\n\nNesting the related entity inside the parent representation.\n\n\nSome other custom representation.\n\n\n\n\nREST framework supports all of these styles, and can apply them across forward or reverse relationships, or apply them across custom managers such as generic foreign keys.\n\n\nIn this case we'd like to use a hyperlinked style between entities. In order to do so, we'll modify our serializers to extend \nHyperlinkedModelSerializer\n instead of the existing \nModelSerializer\n.\n\n\nThe \nHyperlinkedModelSerializer\n has the following differences from \nModelSerializer\n:\n\n\n\n\nIt does not include the \nid\n field by default.\n\n\nIt includes a \nurl\n field, using \nHyperlinkedIdentityField\n.\n\n\nRelationships use \nHyperlinkedRelatedField\n,\n instead of \nPrimaryKeyRelatedField\n.\n\n\n\n\nWe can easily re-write our existing serializers to use hyperlinking. In your \nsnippets/serializers.py\n add:\n\n\nclass SnippetSerializer(serializers.HyperlinkedModelSerializer):\n owner = serializers.ReadOnlyField(source='owner.username')\n highlight = serializers.HyperlinkedIdentityField(view_name='snippet-highlight', format='html')\n\n class Meta:\n model = Snippet\n fields = ('url', 'id', 'highlight', 'owner',\n 'title', 'code', 'linenos', 'language', 'style')\n\n\nclass UserSerializer(serializers.HyperlinkedModelSerializer):\n snippets = serializers.HyperlinkedRelatedField(many=True, view_name='snippet-detail', read_only=True)\n\n class Meta:\n model = User\n fields = ('url', 'id', 'username', 'snippets')\n\n\n\nNotice that we've also added a new \n'highlight'\n field. This field is of the same type as the \nurl\n field, except that it points to the \n'snippet-highlight'\n url pattern, instead of the \n'snippet-detail'\n url pattern.\n\n\nBecause we've included format suffixed URLs such as \n'.json'\n, we also need to indicate on the \nhighlight\n field that any format suffixed hyperlinks it returns should use the \n'.html'\n suffix.\n\n\nMaking sure our URL patterns are named\n\n\nIf we're going to have a hyperlinked API, we need to make sure we name our URL patterns. Let's take a look at which URL patterns we need to name.\n\n\n\n\nThe root of our API refers to \n'user-list'\n and \n'snippet-list'\n.\n\n\nOur snippet serializer includes a field that refers to \n'snippet-highlight'\n.\n\n\nOur user serializer includes a field that refers to \n'snippet-detail'\n.\n\n\nOur snippet and user serializers include \n'url'\n fields that by default will refer to \n'{model_name}-detail'\n, which in this case will be \n'snippet-detail'\n and \n'user-detail'\n.\n\n\n\n\nAfter adding all those names into our URLconf, our final \nsnippets/urls.py\n file should look like this:\n\n\nfrom django.conf.urls import url, include\nfrom rest_framework.urlpatterns import format_suffix_patterns\nfrom snippets import views\n\n# API endpoints\nurlpatterns = format_suffix_patterns([\n url(r'^$', views.api_root),\n url(r'^snippets/$',\n views.SnippetList.as_view(),\n name='snippet-list'),\n url(r'^snippets/(?P\npk\n[0-9]+)/$',\n views.SnippetDetail.as_view(),\n name='snippet-detail'),\n url(r'^snippets/(?P\npk\n[0-9]+)/highlight/$',\n views.SnippetHighlight.as_view(),\n name='snippet-highlight'),\n url(r'^users/$',\n views.UserList.as_view(),\n name='user-list'),\n url(r'^users/(?P\npk\n[0-9]+)/$',\n views.UserDetail.as_view(),\n name='user-detail')\n])\n\n# Login and logout views for the browsable API\nurlpatterns += [\n url(r'^api-auth/', include('rest_framework.urls',\n namespace='rest_framework')),\n]\n\n\n\nAdding pagination\n\n\nThe list views for users and code snippets could end up returning quite a lot of instances, so really we'd like to make sure we paginate the results, and allow the API client to step through each of the individual pages.\n\n\nWe can change the default list style to use pagination, by modifying our \ntutorial/settings.py\n file slightly. Add the following setting:\n\n\nREST_FRAMEWORK = {\n 'PAGE_SIZE': 10\n}\n\n\n\nNote that settings in REST framework are all namespaced into a single dictionary setting, named 'REST_FRAMEWORK', which helps keep them well separated from your other project settings.\n\n\nWe could also customize the pagination style if we needed too, but in this case we'll just stick with the default.\n\n\nBrowsing the API\n\n\nIf we open a browser and navigate to the browsable API, you'll find that you can now work your way around the API simply by following links.\n\n\nYou'll also be able to see the 'highlight' links on the snippet instances, that will take you to the highlighted code HTML representations.\n\n\nIn \npart 6\n of the tutorial we'll look at how we can use ViewSets and Routers to reduce the amount of code we need to build our API.", "title": "5 - Relationships and hyperlinked APIs" }, { @@ -317,7 +317,7 @@ }, { "location": "/tutorial/5-relationships-and-hyperlinked-apis/#creating-an-endpoint-for-the-highlighted-snippets", - "text": "The other obvious thing that's still missing from our pastebin API is the code highlighting endpoints. Unlike all our other API endpoints, we don't want to use JSON, but instead just present an HTML representation. There are two styles of HTML renderer provided by REST framework, one for dealing with HTML rendered using templates, the other for dealing with pre-rendered HTML. The second renderer is the one we'd like to use for this endpoint. The other thing we need to consider when creating the code highlight view is that there's no existing concrete generic view that we can use. We're not returning an object instance, but instead a property of an object instance. Instead of using a concrete generic view, we'll use the base class for representing instances, and create our own .get() method. In your snippets/views.py add: from rest_framework import renderers\nfrom rest_framework.response import Response\n\nclass SnippetHighlight(generics.GenericAPIView):\n queryset = Snippet.objects.all()\n renderer_classes = (renderers.StaticHTMLRenderer,)\n\n def get(self, request, *args, **kwargs):\n snippet = self.get_object()\n return Response(snippet.highlighted) As usual we need to add the new views that we've created in to our URLconf.\nWe'll add a url pattern for our new API root in snippets/urls.py : url(r'^$', views.api_root), And then add a url pattern for the snippet highlights: url(r'^snippets/(?P id [0-9]+)/highlight/$', views.SnippetHighlight.as_view()),", + "text": "The other obvious thing that's still missing from our pastebin API is the code highlighting endpoints. Unlike all our other API endpoints, we don't want to use JSON, but instead just present an HTML representation. There are two styles of HTML renderer provided by REST framework, one for dealing with HTML rendered using templates, the other for dealing with pre-rendered HTML. The second renderer is the one we'd like to use for this endpoint. The other thing we need to consider when creating the code highlight view is that there's no existing concrete generic view that we can use. We're not returning an object instance, but instead a property of an object instance. Instead of using a concrete generic view, we'll use the base class for representing instances, and create our own .get() method. In your snippets/views.py add: from rest_framework import renderers\nfrom rest_framework.response import Response\n\nclass SnippetHighlight(generics.GenericAPIView):\n queryset = Snippet.objects.all()\n renderer_classes = (renderers.StaticHTMLRenderer,)\n\n def get(self, request, *args, **kwargs):\n snippet = self.get_object()\n return Response(snippet.highlighted) As usual we need to add the new views that we've created in to our URLconf.\nWe'll add a url pattern for our new API root in snippets/urls.py : url(r'^$', views.api_root), And then add a url pattern for the snippet highlights: url(r'^snippets/(?P pk [0-9]+)/highlight/$', views.SnippetHighlight.as_view()),", "title": "Creating an endpoint for the highlighted snippets" }, { @@ -327,7 +327,7 @@ }, { "location": "/tutorial/5-relationships-and-hyperlinked-apis/#making-sure-our-url-patterns-are-named", - "text": "If we're going to have a hyperlinked API, we need to make sure we name our URL patterns. Let's take a look at which URL patterns we need to name. The root of our API refers to 'user-list' and 'snippet-list' . Our snippet serializer includes a field that refers to 'snippet-highlight' . Our user serializer includes a field that refers to 'snippet-detail' . Our snippet and user serializers include 'url' fields that by default will refer to '{model_name}-detail' , which in this case will be 'snippet-detail' and 'user-detail' . After adding all those names into our URLconf, our final snippets/urls.py file should look like this: from django.conf.urls import url, include\nfrom rest_framework.urlpatterns import format_suffix_patterns\nfrom snippets import views\n\n# API endpoints\nurlpatterns = format_suffix_patterns([\n url(r'^$', views.api_root),\n url(r'^snippets/$',\n views.SnippetList.as_view(),\n name='snippet-list'),\n url(r'^snippets/(?P id [0-9]+)/$',\n views.SnippetDetail.as_view(),\n name='snippet-detail'),\n url(r'^snippets/(?P id [0-9]+)/highlight/$',\n views.SnippetHighlight.as_view(),\n name='snippet-highlight'),\n url(r'^users/$',\n views.UserList.as_view(),\n name='user-list'),\n url(r'^users/(?P id [0-9]+)/$',\n views.UserDetail.as_view(),\n name='user-detail')\n])\n\n# Login and logout views for the browsable API\nurlpatterns += [\n url(r'^api-auth/', include('rest_framework.urls',\n namespace='rest_framework')),\n]", + "text": "If we're going to have a hyperlinked API, we need to make sure we name our URL patterns. Let's take a look at which URL patterns we need to name. The root of our API refers to 'user-list' and 'snippet-list' . Our snippet serializer includes a field that refers to 'snippet-highlight' . Our user serializer includes a field that refers to 'snippet-detail' . Our snippet and user serializers include 'url' fields that by default will refer to '{model_name}-detail' , which in this case will be 'snippet-detail' and 'user-detail' . After adding all those names into our URLconf, our final snippets/urls.py file should look like this: from django.conf.urls import url, include\nfrom rest_framework.urlpatterns import format_suffix_patterns\nfrom snippets import views\n\n# API endpoints\nurlpatterns = format_suffix_patterns([\n url(r'^$', views.api_root),\n url(r'^snippets/$',\n views.SnippetList.as_view(),\n name='snippet-list'),\n url(r'^snippets/(?P pk [0-9]+)/$',\n views.SnippetDetail.as_view(),\n name='snippet-detail'),\n url(r'^snippets/(?P pk [0-9]+)/highlight/$',\n views.SnippetHighlight.as_view(),\n name='snippet-highlight'),\n url(r'^users/$',\n views.UserList.as_view(),\n name='user-list'),\n url(r'^users/(?P pk [0-9]+)/$',\n views.UserDetail.as_view(),\n name='user-detail')\n])\n\n# Login and logout views for the browsable API\nurlpatterns += [\n url(r'^api-auth/', include('rest_framework.urls',\n namespace='rest_framework')),\n]", "title": "Making sure our URL patterns are named" }, { @@ -342,7 +342,7 @@ }, { "location": "/tutorial/6-viewsets-and-routers/", - "text": "Tutorial 6: ViewSets \n 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\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. 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 \nurls.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\nid\n[0-9]+)/$', snippet_detail, name='snippet-detail'),\n url(r'^snippets/(?P\nid\n[0-9]+)/highlight/$', snippet_highlight, name='snippet-highlight'),\n url(r'^users/$', user_list, name='user-list'),\n url(r'^users/(?P\nid\n[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 \nurls.py\n file.\n\n\nfrom django.conf.urls import url, include\nfrom snippets import views\nfrom rest_framework.routers import DefaultRouter\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.\n# Additionally, we include the login URLs for the browsable API.\nurlpatterns = [\n url(r'^', include(router.urls)),\n url(r'^api-auth/', include('rest_framework.urls', namespace='rest_framework'))\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 \n 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\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 \nurls.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\npk\n[0-9]+)/$', snippet_detail, name='snippet-detail'),\n url(r'^snippets/(?P\npk\n[0-9]+)/highlight/$', snippet_highlight, name='snippet-highlight'),\n url(r'^users/$', user_list, name='user-list'),\n url(r'^users/(?P\npk\n[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 \nurls.py\n file.\n\n\nfrom django.conf.urls import url, include\nfrom snippets import views\nfrom rest_framework.routers import DefaultRouter\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.\n# Additionally, we include the login URLs for the browsable API.\nurlpatterns = [\n url(r'^', include(router.urls)),\n url(r'^api-auth/', include('rest_framework.urls', namespace='rest_framework'))\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,12 +352,12 @@ }, { "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\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. 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 detail_route\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.", "title": "Refactoring to use ViewSets" }, { "location": "/tutorial/6-viewsets-and-routers/#binding-viewsets-to-urls-explicitly", - "text": "The 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. In the urls.py file we bind our ViewSet classes into a set of concrete views. from 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}) Notice how we're creating multiple views from each ViewSet class, by binding the http methods to the required action for each view. Now that we've bound our resources into concrete views, we can register the views with the URL conf as usual. urlpatterns = format_suffix_patterns([\n url(r'^$', api_root),\n url(r'^snippets/$', snippet_list, name='snippet-list'),\n url(r'^snippets/(?P id [0-9]+)/$', snippet_detail, name='snippet-detail'),\n url(r'^snippets/(?P id [0-9]+)/highlight/$', snippet_highlight, name='snippet-highlight'),\n url(r'^users/$', user_list, name='user-list'),\n url(r'^users/(?P id [0-9]+)/$', user_detail, name='user-detail')\n])", + "text": "The 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. In the urls.py file we bind our ViewSet classes into a set of concrete views. from 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}) Notice how we're creating multiple views from each ViewSet class, by binding the http methods to the required action for each view. Now that we've bound our resources into concrete views, we can register the views with the URL conf as usual. urlpatterns = format_suffix_patterns([\n url(r'^$', api_root),\n url(r'^snippets/$', snippet_list, name='snippet-list'),\n url(r'^snippets/(?P pk [0-9]+)/$', snippet_detail, name='snippet-detail'),\n url(r'^snippets/(?P pk [0-9]+)/highlight/$', snippet_highlight, name='snippet-highlight'),\n url(r'^users/$', user_list, name='user-list'),\n url(r'^users/(?P pk [0-9]+)/$', user_detail, name='user-detail')\n])", "title": "Binding ViewSets to URLs explicitly" }, { @@ -1707,7 +1707,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 \n normalizing it to a consistent format.\n\n\n \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.\nFieldName\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\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\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.\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 \ninput type=\"password\"\n 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 \n 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\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://\nhost\n/\npath\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. Note that this number must be greater than or equal to decimal_places.\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\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\nIn the case of JSON this means the default datetime representation uses the \nECMA 262 date time string specification\n. This is a subset of ISO 8601 which uses millisecond precision, and includes the 'Z' suffix for the UTC timezone, for example: \n2013-01-29T12:34:56.123Z\n.\n\n\nauto_now\n and \nauto_now_add\n model fields.\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\nNote:\n This field is only available with Django versions \n= 1.8.\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)\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\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=\nDjango ModelField instance\n)\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_\nfield_name\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\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 \n= 0 and green \n= 0 and blue \n= 0)\n assert(red \n 256 and green \n 256 and blue \n 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 \n 255 or col \n 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 msg = 'Incorrect type. Expected a string, but got %s'\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 \n 255 or col \n 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 you error messages more cleanly separated from your code, and should be preferred.\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 \n normalizing it to a consistent format.\n\n\n \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.\nFieldName\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\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\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.\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 \ninput type=\"password\"\n 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 \n 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\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://\nhost\n/\npath\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. Note that this number must be greater than or equal to decimal_places.\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\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\nIn the case of JSON this means the default datetime representation uses the \nECMA 262 date time string specification\n. This is a subset of ISO 8601 which uses millisecond precision, and includes the 'Z' suffix for the UTC timezone, for example: \n2013-01-29T12:34:56.123Z\n.\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\nNote:\n This field is only available with Django versions \n= 1.8.\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)\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\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=\nDjango ModelField instance\n)\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_\nfield_name\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\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 \n= 0 and green \n= 0 and blue \n= 0)\n assert(red \n 256 and green \n 256 and blue \n 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 \n 255 or col \n 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 msg = 'Incorrect type. Expected a string, but got %s'\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 \n 255 or col \n 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 you error messages more cleanly separated from your code, and should be preferred.\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.", "title": "Serializer fields" }, { @@ -2602,7 +2602,7 @@ }, { "location": "/api-guide/filtering/", - "text": "Filtering\n\n\n\n\nThe root QuerySet provided by the Manager describes all objects in the database table. Usually, though, you'll need to select only a subset of the complete set of objects.\n\n\n \nDjango documentation\n\n\n\n\nThe default behavior of REST framework's generic list views is to return the entire queryset for a model manager. Often you will want your API to restrict the items that are returned by the queryset.\n\n\nThe simplest way to filter the queryset of any view that subclasses \nGenericAPIView\n is to override the \n.get_queryset()\n method.\n\n\nOverriding this method allows you to customize the queryset returned by the view in a number of different ways.\n\n\nFiltering against the current user\n\n\nYou might want to filter the queryset to ensure that only results relevant to the currently authenticated user making the request are returned.\n\n\nYou can do so by filtering based on the value of \nrequest.user\n.\n\n\nFor example:\n\n\nfrom myapp.models import Purchase\nfrom myapp.serializers import PurchaseSerializer\nfrom rest_framework import generics\n\nclass PurchaseList(generics.ListAPIView):\n serializer_class = PurchaseSerializer\n\n def get_queryset(self):\n \"\"\"\n This view should return a list of all the purchases\n for the currently authenticated user.\n \"\"\"\n user = self.request.user\n return Purchase.objects.filter(purchaser=user)\n\n\n\nFiltering against the URL\n\n\nAnother style of filtering might involve restricting the queryset based on some part of the URL.\n\n\nFor example if your URL config contained an entry like this:\n\n\nurl('^purchases/(?P\nusername\n.+)/$', PurchaseList.as_view()),\n\n\n\nYou could then write a view that returned a purchase queryset filtered by the username portion of the URL:\n\n\nclass PurchaseList(generics.ListAPIView):\n serializer_class = PurchaseSerializer\n\n def get_queryset(self):\n \"\"\"\n This view should return a list of all the purchases for\n the user as determined by the username portion of the URL.\n \"\"\"\n username = self.kwargs['username']\n return Purchase.objects.filter(purchaser__username=username)\n\n\n\nFiltering against query parameters\n\n\nA final example of filtering the initial queryset would be to determine the initial queryset based on query parameters in the url.\n\n\nWe can override \n.get_queryset()\n to deal with URLs such as \nhttp://example.com/api/purchases?username=denvercoder9\n, and filter the queryset only if the \nusername\n parameter is included in the URL:\n\n\nclass PurchaseList(generics.ListAPIView):\n serializer_class = PurchaseSerializer\n\n def get_queryset(self):\n \"\"\"\n Optionally restricts the returned purchases to a given user,\n by filtering against a `username` query parameter in the URL.\n \"\"\"\n queryset = Purchase.objects.all()\n username = self.request.query_params.get('username', None)\n if username is not None:\n queryset = queryset.filter(purchaser__username=username)\n return queryset\n\n\n\n\n\nGeneric Filtering\n\n\nAs well as being able to override the default queryset, REST framework also includes support for generic filtering backends that allow you to easily construct complex searches and filters.\n\n\nGeneric filters can also present themselves as HTML controls in the browsable API and admin API.\n\n\n\n\nSetting filter backends\n\n\nThe default filter backends may be set globally, using the \nDEFAULT_FILTER_BACKENDS\n setting. For example.\n\n\nREST_FRAMEWORK = {\n 'DEFAULT_FILTER_BACKENDS': ('rest_framework.filters.DjangoFilterBackend',)\n}\n\n\n\nYou can also set the filter backends on a per-view, or per-viewset basis,\nusing the \nGenericAPIView\n class-based views.\n\n\nfrom django.contrib.auth.models import User\nfrom myapp.serializers import UserSerializer\nfrom rest_framework import filters\nfrom rest_framework import generics\n\nclass UserListView(generics.ListAPIView):\n queryset = User.objects.all()\n serializer_class = UserSerializer\n filter_backends = (filters.DjangoFilterBackend,)\n\n\n\nFiltering and object lookups\n\n\nNote that if a filter backend is configured for a view, then as well as being used to filter list views, it will also be used to filter the querysets used for returning a single object.\n\n\nFor instance, given the previous example, and a product with an id of \n4675\n, the following URL would either return the corresponding object, or return a 404 response, depending on if the filtering conditions were met by the given product instance:\n\n\nhttp://example.com/api/products/4675/?category=clothing\nmax_price=10.00\n\n\n\nOverriding the initial queryset\n\n\nNote that you can use both an overridden \n.get_queryset()\n and generic filtering together, and everything will work as expected. For example, if \nProduct\n had a many-to-many relationship with \nUser\n, named \npurchase\n, you might want to write a view like this:\n\n\nclass PurchasedProductsList(generics.ListAPIView):\n \"\"\"\n Return a list of all the products that the authenticated\n user has ever purchased, with optional filtering.\n \"\"\"\n model = Product\n serializer_class = ProductSerializer\n filter_class = ProductFilter\n\n def get_queryset(self):\n user = self.request.user\n return user.purchase_set.all()\n\n\n\n\n\nAPI Guide\n\n\nDjangoFilterBackend\n\n\nThe \nDjangoFilterBackend\n class supports highly customizable field filtering, using the \ndjango-filter package\n.\n\n\nTo use REST framework's \nDjangoFilterBackend\n, first install \ndjango-filter\n.\n\n\npip install django-filter\n\n\n\nIf you are using the browsable API or admin API you may also want to install \ndjango-crispy-forms\n, which will enhance the presentation of the filter forms in HTML views, by allowing them to render Bootstrap 3 HTML.\n\n\npip install django-crispy-forms\n\n\n\nWith crispy forms installed and added to Django's \nINSTALLED_APPS\n, the browsable API will present a filtering control for \nDjangoFilterBackend\n, like so:\n\n\n\n\nSpecifying filter fields\n\n\nIf all you need is simple equality-based filtering, you can set a \nfilter_fields\n attribute on the view, or viewset, listing the set of fields you wish to filter against.\n\n\nclass ProductList(generics.ListAPIView):\n queryset = Product.objects.all()\n serializer_class = ProductSerializer\n filter_backends = (filters.DjangoFilterBackend,)\n filter_fields = ('category', 'in_stock')\n\n\n\nThis will automatically create a \nFilterSet\n class for the given fields, and will allow you to make requests such as:\n\n\nhttp://example.com/api/products?category=clothing\nin_stock=True\n\n\n\nSpecifying a FilterSet\n\n\nFor more advanced filtering requirements you can specify a \nFilterSet\n class that should be used by the view. For example:\n\n\nimport django_filters\nfrom myapp.models import Product\nfrom myapp.serializers import ProductSerializer\nfrom rest_framework import filters\nfrom rest_framework import generics\n\nclass ProductFilter(filters.FilterSet):\n min_price = django_filters.NumberFilter(name=\"price\", lookup_expr='gte')\n max_price = django_filters.NumberFilter(name=\"price\", lookup_expr='lte')\n class Meta:\n model = Product\n fields = ['category', 'in_stock', 'min_price', 'max_price']\n\nclass ProductList(generics.ListAPIView):\n queryset = Product.objects.all()\n serializer_class = ProductSerializer\n filter_backends = (filters.DjangoFilterBackend,)\n filter_class = ProductFilter\n\n\n\nWhich will allow you to make requests such as:\n\n\nhttp://example.com/api/products?category=clothing\nmax_price=10.00\n\n\n\nYou can also span relationships using \ndjango-filter\n, let's assume that each\nproduct has foreign key to \nManufacturer\n model, so we create filter that\nfilters using \nManufacturer\n name. For example:\n\n\nfrom myapp.models import Product\nfrom myapp.serializers import ProductSerializer\nfrom rest_framework import filters\nfrom rest_framework import generics\n\nclass ProductFilter(filters.FilterSet):\n class Meta:\n model = Product\n fields = ['category', 'in_stock', 'manufacturer__name']\n\n\n\nThis enables us to make queries like:\n\n\nhttp://example.com/api/products?manufacturer__name=foo\n\n\n\nThis is nice, but it exposes the Django's double underscore convention as part of the API. If you instead want to explicitly name the filter argument you can instead explicitly include it on the \nFilterSet\n class:\n\n\nimport django_filters\nfrom myapp.models import Product\nfrom myapp.serializers import ProductSerializer\nfrom rest_framework import filters\nfrom rest_framework import generics\n\nclass ProductFilter(filters.FilterSet):\n manufacturer = django_filters.CharFilter(name=\"manufacturer__name\")\n\n class Meta:\n model = Product\n fields = ['category', 'in_stock', 'manufacturer']\n\n\n\nAnd now you can execute:\n\n\nhttp://example.com/api/products?manufacturer=foo\n\n\n\nFor more details on using filter sets see the \ndjango-filter documentation\n.\n\n\n\n\nHints \n Tips\n\n\n\n\nBy default filtering is not enabled. If you want to use \nDjangoFilterBackend\n remember to make sure it is installed by using the \n'DEFAULT_FILTER_BACKENDS'\n setting.\n\n\nWhen using boolean fields, you should use the values \nTrue\n and \nFalse\n in the URL query parameters, rather than \n0\n, \n1\n, \ntrue\n or \nfalse\n. (The allowed boolean values are currently hardwired in Django's \nNullBooleanSelect implementation\n.)\n\n\ndjango-filter\n supports filtering across relationships, using Django's double-underscore syntax.\n\n\n\n\n\n\nSearchFilter\n\n\nThe \nSearchFilter\n class supports simple single query parameter based searching, and is based on the \nDjango admin's search functionality\n.\n\n\nWhen in use, the browsable API will include a \nSearchFilter\n control:\n\n\n\n\nThe \nSearchFilter\n class will only be applied if the view has a \nsearch_fields\n attribute set. The \nsearch_fields\n attribute should be a list of names of text type fields on the model, such as \nCharField\n or \nTextField\n.\n\n\nclass UserListView(generics.ListAPIView):\n queryset = User.objects.all()\n serializer_class = UserSerializer\n filter_backends = (filters.SearchFilter,)\n search_fields = ('username', 'email')\n\n\n\nThis will allow the client to filter the items in the list by making queries such as:\n\n\nhttp://example.com/api/users?search=russell\n\n\n\nYou can also perform a related lookup on a ForeignKey or ManyToManyField with the lookup API double-underscore notation:\n\n\nsearch_fields = ('username', 'email', 'profile__profession')\n\n\n\nBy default, searches will use case-insensitive partial matches. The search parameter may contain multiple search terms, which should be whitespace and/or comma separated. If multiple search terms are used then objects will be returned in the list only if all the provided terms are matched.\n\n\nThe search behavior may be restricted by prepending various characters to the \nsearch_fields\n.\n\n\n\n\n'^' Starts-with search.\n\n\n'=' Exact matches.\n\n\n'@' Full-text search. (Currently only supported Django's MySQL backend.)\n\n\n'$' Regex search.\n\n\n\n\nFor example:\n\n\nsearch_fields = ('=username', '=email')\n\n\n\nBy default, the search parameter is named \n'search\n', but this may be overridden with the \nSEARCH_PARAM\n setting.\n\n\nFor more details, see the \nDjango documentation\n.\n\n\n\n\nOrderingFilter\n\n\nThe \nOrderingFilter\n class supports simple query parameter controlled ordering of results.\n\n\n\n\nBy default, the query parameter is named \n'ordering'\n, but this may by overridden with the \nORDERING_PARAM\n setting.\n\n\nFor example, to order users by username:\n\n\nhttp://example.com/api/users?ordering=username\n\n\n\nThe client may also specify reverse orderings by prefixing the field name with '-', like so:\n\n\nhttp://example.com/api/users?ordering=-username\n\n\n\nMultiple orderings may also be specified:\n\n\nhttp://example.com/api/users?ordering=account,username\n\n\n\nSpecifying which fields may be ordered against\n\n\nIt's recommended that you explicitly specify which fields the API should allowing in the ordering filter. You can do this by setting an \nordering_fields\n attribute on the view, like so:\n\n\nclass UserListView(generics.ListAPIView):\n queryset = User.objects.all()\n serializer_class = UserSerializer\n filter_backends = (filters.OrderingFilter,)\n ordering_fields = ('username', 'email')\n\n\n\nThis helps prevent unexpected data leakage, such as allowing users to order against a password hash field or other sensitive data.\n\n\nIf you \ndon't\n specify an \nordering_fields\n attribute on the view, the filter class will default to allowing the user to filter on any readable fields on the serializer specified by the \nserializer_class\n attribute.\n\n\nIf you are confident that the queryset being used by the view doesn't contain any sensitive data, you can also explicitly specify that a view should allow ordering on \nany\n model field or queryset aggregate, by using the special value \n'__all__'\n.\n\n\nclass BookingsListView(generics.ListAPIView):\n queryset = Booking.objects.all()\n serializer_class = BookingSerializer\n filter_backends = (filters.OrderingFilter,)\n ordering_fields = '__all__'\n\n\n\nSpecifying a default ordering\n\n\nIf an \nordering\n attribute is set on the view, this will be used as the default ordering.\n\n\nTypically you'd instead control this by setting \norder_by\n on the initial queryset, but using the \nordering\n parameter on the view allows you to specify the ordering in a way that it can then be passed automatically as context to a rendered template. This makes it possible to automatically render column headers differently if they are being used to order the results.\n\n\nclass UserListView(generics.ListAPIView):\n queryset = User.objects.all()\n serializer_class = UserSerializer\n filter_backends = (filters.OrderingFilter,)\n ordering_fields = ('username', 'email')\n ordering = ('username',)\n\n\n\nThe \nordering\n attribute may be either a string or a list/tuple of strings.\n\n\n\n\nDjangoObjectPermissionsFilter\n\n\nThe \nDjangoObjectPermissionsFilter\n is intended to be used together with the \ndjango-guardian\n package, with custom \n'view'\n permissions added. The filter will ensure that querysets only returns objects for which the user has the appropriate view permission.\n\n\nIf you're using \nDjangoObjectPermissionsFilter\n, you'll probably also want to add an appropriate object permissions class, to ensure that users can only operate on instances if they have the appropriate object permissions. The easiest way to do this is to subclass \nDjangoObjectPermissions\n and add \n'view'\n permissions to the \nperms_map\n attribute.\n\n\nA complete example using both \nDjangoObjectPermissionsFilter\n and \nDjangoObjectPermissions\n might look something like this.\n\n\npermissions.py\n:\n\n\nclass CustomObjectPermissions(permissions.DjangoObjectPermissions):\n \"\"\"\n Similar to `DjangoObjectPermissions`, but adding 'view' permissions.\n \"\"\"\n perms_map = {\n 'GET': ['%(app_label)s.view_%(model_name)s'],\n 'OPTIONS': ['%(app_label)s.view_%(model_name)s'],\n 'HEAD': ['%(app_label)s.view_%(model_name)s'],\n 'POST': ['%(app_label)s.add_%(model_name)s'],\n 'PUT': ['%(app_label)s.change_%(model_name)s'],\n 'PATCH': ['%(app_label)s.change_%(model_name)s'],\n 'DELETE': ['%(app_label)s.delete_%(model_name)s'],\n }\n\n\n\nviews.py\n:\n\n\nclass EventViewSet(viewsets.ModelViewSet):\n \"\"\"\n Viewset that only lists events if user has 'view' permissions, and only\n allows operations on individual events if user has appropriate 'view', 'add',\n 'change' or 'delete' permissions.\n \"\"\"\n queryset = Event.objects.all()\n serializer_class = EventSerializer\n filter_backends = (filters.DjangoObjectPermissionsFilter,)\n permission_classes = (myapp.permissions.CustomObjectPermissions,)\n\n\n\nFor more information on adding \n'view'\n permissions for models, see the \nrelevant section\n of the \ndjango-guardian\n documentation, and \nthis blogpost\n.\n\n\n\n\nCustom generic filtering\n\n\nYou can also provide your own generic filtering backend, or write an installable app for other developers to use.\n\n\nTo do so override \nBaseFilterBackend\n, and override the \n.filter_queryset(self, request, queryset, view)\n method. The method should return a new, filtered queryset.\n\n\nAs well as allowing clients to perform searches and filtering, generic filter backends can be useful for restricting which objects should be visible to any given request or user.\n\n\nExample\n\n\nFor example, you might need to restrict users to only being able to see objects they created.\n\n\nclass IsOwnerFilterBackend(filters.BaseFilterBackend):\n \"\"\"\n Filter that only allows users to see their own objects.\n \"\"\"\n def filter_queryset(self, request, queryset, view):\n return queryset.filter(owner=request.user)\n\n\n\nWe could achieve the same behavior by overriding \nget_queryset()\n on the views, but using a filter backend allows you to more easily add this restriction to multiple views, or to apply it across the entire API.\n\n\nCustomizing the interface\n\n\nGeneric filters may also present an interface in the browsable API. To do so you should implement a \nto_html()\n method which returns a rendered HTML representation of the filter. This method should have the following signature:\n\n\nto_html(self, request, queryset, view)\n\n\nThe method should return a rendered HTML string.\n\n\nPagination \n schemas\n\n\nYou can also make the filter controls available to the schema autogeneration\nthat REST framework provides, by implementing a \nget_schema_fields()\n method,\nwhich should return a list of \ncoreapi.Field\n instances.\n\n\nThird party packages\n\n\nThe following third party packages provide additional filter implementations.\n\n\nDjango REST framework filters package\n\n\nThe \ndjango-rest-framework-filters package\n works together with the \nDjangoFilterBackend\n class, and allows you to easily create filters across relationships, or create multiple filter lookup types for a given field.\n\n\nDjango REST framework full word search filter\n\n\nThe \ndjangorestframework-word-filter\n developed as alternative to \nfilters.SearchFilter\n which will search full word in text, or exact match.\n\n\nDjango URL Filter\n\n\ndjango-url-filter\n provides a safe way to filter data via human-friendly URLs. It works very similar to DRF serializers and fields in a sense that they can be nested except they are called filtersets and filters. That provides easy way to filter related data. Also this library is generic-purpose so it can be used to filter other sources of data and not only Django \nQuerySet\ns.\n\n\ndrf-url-filters\n\n\ndrf-url-filter\n is a simple Django app to apply filters on drf \nModelViewSet\n's \nQueryset\n in a clean, simple and configurable way. It also supports validations on incoming query params and their values. A beautiful python package \nVoluptuous\n is being used for validations on the incoming query parameters. The best part about voluptuous is you can define your own validations as per your query params requirements.", + "text": "Filtering\n\n\n\n\nThe root QuerySet provided by the Manager describes all objects in the database table. Usually, though, you'll need to select only a subset of the complete set of objects.\n\n\n \nDjango documentation\n\n\n\n\nThe default behavior of REST framework's generic list views is to return the entire queryset for a model manager. Often you will want your API to restrict the items that are returned by the queryset.\n\n\nThe simplest way to filter the queryset of any view that subclasses \nGenericAPIView\n is to override the \n.get_queryset()\n method.\n\n\nOverriding this method allows you to customize the queryset returned by the view in a number of different ways.\n\n\nFiltering against the current user\n\n\nYou might want to filter the queryset to ensure that only results relevant to the currently authenticated user making the request are returned.\n\n\nYou can do so by filtering based on the value of \nrequest.user\n.\n\n\nFor example:\n\n\nfrom myapp.models import Purchase\nfrom myapp.serializers import PurchaseSerializer\nfrom rest_framework import generics\n\nclass PurchaseList(generics.ListAPIView):\n serializer_class = PurchaseSerializer\n\n def get_queryset(self):\n \"\"\"\n This view should return a list of all the purchases\n for the currently authenticated user.\n \"\"\"\n user = self.request.user\n return Purchase.objects.filter(purchaser=user)\n\n\n\nFiltering against the URL\n\n\nAnother style of filtering might involve restricting the queryset based on some part of the URL.\n\n\nFor example if your URL config contained an entry like this:\n\n\nurl('^purchases/(?P\nusername\n.+)/$', PurchaseList.as_view()),\n\n\n\nYou could then write a view that returned a purchase queryset filtered by the username portion of the URL:\n\n\nclass PurchaseList(generics.ListAPIView):\n serializer_class = PurchaseSerializer\n\n def get_queryset(self):\n \"\"\"\n This view should return a list of all the purchases for\n the user as determined by the username portion of the URL.\n \"\"\"\n username = self.kwargs['username']\n return Purchase.objects.filter(purchaser__username=username)\n\n\n\nFiltering against query parameters\n\n\nA final example of filtering the initial queryset would be to determine the initial queryset based on query parameters in the url.\n\n\nWe can override \n.get_queryset()\n to deal with URLs such as \nhttp://example.com/api/purchases?username=denvercoder9\n, and filter the queryset only if the \nusername\n parameter is included in the URL:\n\n\nclass PurchaseList(generics.ListAPIView):\n serializer_class = PurchaseSerializer\n\n def get_queryset(self):\n \"\"\"\n Optionally restricts the returned purchases to a given user,\n by filtering against a `username` query parameter in the URL.\n \"\"\"\n queryset = Purchase.objects.all()\n username = self.request.query_params.get('username', None)\n if username is not None:\n queryset = queryset.filter(purchaser__username=username)\n return queryset\n\n\n\n\n\nGeneric Filtering\n\n\nAs well as being able to override the default queryset, REST framework also includes support for generic filtering backends that allow you to easily construct complex searches and filters.\n\n\nGeneric filters can also present themselves as HTML controls in the browsable API and admin API.\n\n\n\n\nSetting filter backends\n\n\nThe default filter backends may be set globally, using the \nDEFAULT_FILTER_BACKENDS\n setting. For example.\n\n\nREST_FRAMEWORK = {\n 'DEFAULT_FILTER_BACKENDS': ('django_filters.rest_framework.DjangoFilterBackend',)\n}\n\n\n\nYou can also set the filter backends on a per-view, or per-viewset basis,\nusing the \nGenericAPIView\n class-based views.\n\n\nimport django_filters\nfrom django.contrib.auth.models import User\nfrom myapp.serializers import UserSerializer\nfrom rest_framework import generics\n\nclass UserListView(generics.ListAPIView):\n queryset = User.objects.all()\n serializer_class = UserSerializer\n filter_backends = (django_filters.rest_framework.DjangoFilterBackend,)\n\n\n\nFiltering and object lookups\n\n\nNote that if a filter backend is configured for a view, then as well as being used to filter list views, it will also be used to filter the querysets used for returning a single object.\n\n\nFor instance, given the previous example, and a product with an id of \n4675\n, the following URL would either return the corresponding object, or return a 404 response, depending on if the filtering conditions were met by the given product instance:\n\n\nhttp://example.com/api/products/4675/?category=clothing\nmax_price=10.00\n\n\n\nOverriding the initial queryset\n\n\nNote that you can use both an overridden \n.get_queryset()\n and generic filtering together, and everything will work as expected. For example, if \nProduct\n had a many-to-many relationship with \nUser\n, named \npurchase\n, you might want to write a view like this:\n\n\nclass PurchasedProductsList(generics.ListAPIView):\n \"\"\"\n Return a list of all the products that the authenticated\n user has ever purchased, with optional filtering.\n \"\"\"\n model = Product\n serializer_class = ProductSerializer\n filter_class = ProductFilter\n\n def get_queryset(self):\n user = self.request.user\n return user.purchase_set.all()\n\n\n\n\n\nAPI Guide\n\n\nDjangoFilterBackend\n\n\nThe \ndjango-filter\n library includes a \nDjangoFilterBackend\n class which\nsupports highly customizable field filtering for REST framework.\n\n\nTo use \nDjangoFilterBackend\n, first install \ndjango-filter\n.\n\n\npip install django-filter\n\n\n\nYou should now either add the filter backend to your settings:\n\n\nREST_FRAMEWORK = {\n 'DEFAULT_FILTER_BACKENDS': ('django_filters.rest_framework.DjangoFilterBackend',)\n}\n\n\n\nOr add the filter backend to an individual View or ViewSet.\n\n\nfrom django_filters.rest_framework import DjangoFilterBackend\n\nclass UserListView(generics.ListAPIView):\n ...\n filter_backends = (DjangoFilterBackend,)\n\n\n\nIf you are using the browsable API or admin API you may also want to install \ndjango-crispy-forms\n, which will enhance the presentation of the filter forms in HTML views, by allowing them to render Bootstrap 3 HTML.\n\n\npip install django-crispy-forms\n\n\n\nWith crispy forms installed and added to Django's \nINSTALLED_APPS\n, the browsable API will present a filtering control for \nDjangoFilterBackend\n, like so:\n\n\n\n\nSpecifying filter fields\n\n\nIf all you need is simple equality-based filtering, you can set a \nfilter_fields\n attribute on the view, or viewset, listing the set of fields you wish to filter against.\n\n\nclass ProductList(generics.ListAPIView):\n queryset = Product.objects.all()\n serializer_class = ProductSerializer\n filter_backends = (filters.DjangoFilterBackend,)\n filter_fields = ('category', 'in_stock')\n\n\n\nThis will automatically create a \nFilterSet\n class for the given fields, and will allow you to make requests such as:\n\n\nhttp://example.com/api/products?category=clothing\nin_stock=True\n\n\n\nSpecifying a FilterSet\n\n\nFor more advanced filtering requirements you can specify a \nFilterSet\n class that should be used by the view. For example:\n\n\nimport django_filters\nfrom myapp.models import Product\nfrom myapp.serializers import ProductSerializer\nfrom rest_framework import generics\n\nclass ProductFilter(django_filters.rest_framework.FilterSet):\n min_price = django_filters.NumberFilter(name=\"price\", lookup_expr='gte')\n max_price = django_filters.NumberFilter(name=\"price\", lookup_expr='lte')\n class Meta:\n model = Product\n fields = ['category', 'in_stock', 'min_price', 'max_price']\n\nclass ProductList(generics.ListAPIView):\n queryset = Product.objects.all()\n serializer_class = ProductSerializer\n filter_backends = (django_filters.rest_framework.DjangoFilterBackend,)\n filter_class = ProductFilter\n\n\n\nWhich will allow you to make requests such as:\n\n\nhttp://example.com/api/products?category=clothing\nmax_price=10.00\n\n\n\nYou can also span relationships using \ndjango-filter\n, let's assume that each\nproduct has foreign key to \nManufacturer\n model, so we create filter that\nfilters using \nManufacturer\n name. For example:\n\n\nimport django_filters\nfrom myapp.models import Product\nfrom myapp.serializers import ProductSerializer\nfrom rest_framework import generics\n\nclass ProductFilter(django_filters.rest_framework.FilterSet):\n class Meta:\n model = Product\n fields = ['category', 'in_stock', 'manufacturer__name']\n\n\n\nThis enables us to make queries like:\n\n\nhttp://example.com/api/products?manufacturer__name=foo\n\n\n\nThis is nice, but it exposes the Django's double underscore convention as part of the API. If you instead want to explicitly name the filter argument you can instead explicitly include it on the \nFilterSet\n class:\n\n\nimport django_filters\nfrom myapp.models import Product\nfrom myapp.serializers import ProductSerializer\nfrom rest_framework import generics\n\nclass ProductFilter(django_filters.rest_framework.FilterSet):\n manufacturer = django_filters.CharFilter(name=\"manufacturer__name\")\n\n class Meta:\n model = Product\n fields = ['category', 'in_stock', 'manufacturer']\n\n\n\nAnd now you can execute:\n\n\nhttp://example.com/api/products?manufacturer=foo\n\n\n\nFor more details on using filter sets see the \ndjango-filter documentation\n.\n\n\n\n\nHints \n Tips\n\n\n\n\nBy default filtering is not enabled. If you want to use \nDjangoFilterBackend\n remember to make sure it is installed by using the \n'DEFAULT_FILTER_BACKENDS'\n setting.\n\n\nWhen using boolean fields, you should use the values \nTrue\n and \nFalse\n in the URL query parameters, rather than \n0\n, \n1\n, \ntrue\n or \nfalse\n. (The allowed boolean values are currently hardwired in Django's \nNullBooleanSelect implementation\n.)\n\n\ndjango-filter\n supports filtering across relationships, using Django's double-underscore syntax.\n\n\n\n\n\n\nSearchFilter\n\n\nThe \nSearchFilter\n class supports simple single query parameter based searching, and is based on the \nDjango admin's search functionality\n.\n\n\nWhen in use, the browsable API will include a \nSearchFilter\n control:\n\n\n\n\nThe \nSearchFilter\n class will only be applied if the view has a \nsearch_fields\n attribute set. The \nsearch_fields\n attribute should be a list of names of text type fields on the model, such as \nCharField\n or \nTextField\n.\n\n\nclass UserListView(generics.ListAPIView):\n queryset = User.objects.all()\n serializer_class = UserSerializer\n filter_backends = (filters.SearchFilter,)\n search_fields = ('username', 'email')\n\n\n\nThis will allow the client to filter the items in the list by making queries such as:\n\n\nhttp://example.com/api/users?search=russell\n\n\n\nYou can also perform a related lookup on a ForeignKey or ManyToManyField with the lookup API double-underscore notation:\n\n\nsearch_fields = ('username', 'email', 'profile__profession')\n\n\n\nBy default, searches will use case-insensitive partial matches. The search parameter may contain multiple search terms, which should be whitespace and/or comma separated. If multiple search terms are used then objects will be returned in the list only if all the provided terms are matched.\n\n\nThe search behavior may be restricted by prepending various characters to the \nsearch_fields\n.\n\n\n\n\n'^' Starts-with search.\n\n\n'=' Exact matches.\n\n\n'@' Full-text search. (Currently only supported Django's MySQL backend.)\n\n\n'$' Regex search.\n\n\n\n\nFor example:\n\n\nsearch_fields = ('=username', '=email')\n\n\n\nBy default, the search parameter is named \n'search\n', but this may be overridden with the \nSEARCH_PARAM\n setting.\n\n\nFor more details, see the \nDjango documentation\n.\n\n\n\n\nOrderingFilter\n\n\nThe \nOrderingFilter\n class supports simple query parameter controlled ordering of results.\n\n\n\n\nBy default, the query parameter is named \n'ordering'\n, but this may by overridden with the \nORDERING_PARAM\n setting.\n\n\nFor example, to order users by username:\n\n\nhttp://example.com/api/users?ordering=username\n\n\n\nThe client may also specify reverse orderings by prefixing the field name with '-', like so:\n\n\nhttp://example.com/api/users?ordering=-username\n\n\n\nMultiple orderings may also be specified:\n\n\nhttp://example.com/api/users?ordering=account,username\n\n\n\nSpecifying which fields may be ordered against\n\n\nIt's recommended that you explicitly specify which fields the API should allowing in the ordering filter. You can do this by setting an \nordering_fields\n attribute on the view, like so:\n\n\nclass UserListView(generics.ListAPIView):\n queryset = User.objects.all()\n serializer_class = UserSerializer\n filter_backends = (filters.OrderingFilter,)\n ordering_fields = ('username', 'email')\n\n\n\nThis helps prevent unexpected data leakage, such as allowing users to order against a password hash field or other sensitive data.\n\n\nIf you \ndon't\n specify an \nordering_fields\n attribute on the view, the filter class will default to allowing the user to filter on any readable fields on the serializer specified by the \nserializer_class\n attribute.\n\n\nIf you are confident that the queryset being used by the view doesn't contain any sensitive data, you can also explicitly specify that a view should allow ordering on \nany\n model field or queryset aggregate, by using the special value \n'__all__'\n.\n\n\nclass BookingsListView(generics.ListAPIView):\n queryset = Booking.objects.all()\n serializer_class = BookingSerializer\n filter_backends = (filters.OrderingFilter,)\n ordering_fields = '__all__'\n\n\n\nSpecifying a default ordering\n\n\nIf an \nordering\n attribute is set on the view, this will be used as the default ordering.\n\n\nTypically you'd instead control this by setting \norder_by\n on the initial queryset, but using the \nordering\n parameter on the view allows you to specify the ordering in a way that it can then be passed automatically as context to a rendered template. This makes it possible to automatically render column headers differently if they are being used to order the results.\n\n\nclass UserListView(generics.ListAPIView):\n queryset = User.objects.all()\n serializer_class = UserSerializer\n filter_backends = (filters.OrderingFilter,)\n ordering_fields = ('username', 'email')\n ordering = ('username',)\n\n\n\nThe \nordering\n attribute may be either a string or a list/tuple of strings.\n\n\n\n\nDjangoObjectPermissionsFilter\n\n\nThe \nDjangoObjectPermissionsFilter\n is intended to be used together with the \ndjango-guardian\n package, with custom \n'view'\n permissions added. The filter will ensure that querysets only returns objects for which the user has the appropriate view permission.\n\n\nIf you're using \nDjangoObjectPermissionsFilter\n, you'll probably also want to add an appropriate object permissions class, to ensure that users can only operate on instances if they have the appropriate object permissions. The easiest way to do this is to subclass \nDjangoObjectPermissions\n and add \n'view'\n permissions to the \nperms_map\n attribute.\n\n\nA complete example using both \nDjangoObjectPermissionsFilter\n and \nDjangoObjectPermissions\n might look something like this.\n\n\npermissions.py\n:\n\n\nclass CustomObjectPermissions(permissions.DjangoObjectPermissions):\n \"\"\"\n Similar to `DjangoObjectPermissions`, but adding 'view' permissions.\n \"\"\"\n perms_map = {\n 'GET': ['%(app_label)s.view_%(model_name)s'],\n 'OPTIONS': ['%(app_label)s.view_%(model_name)s'],\n 'HEAD': ['%(app_label)s.view_%(model_name)s'],\n 'POST': ['%(app_label)s.add_%(model_name)s'],\n 'PUT': ['%(app_label)s.change_%(model_name)s'],\n 'PATCH': ['%(app_label)s.change_%(model_name)s'],\n 'DELETE': ['%(app_label)s.delete_%(model_name)s'],\n }\n\n\n\nviews.py\n:\n\n\nclass EventViewSet(viewsets.ModelViewSet):\n \"\"\"\n Viewset that only lists events if user has 'view' permissions, and only\n allows operations on individual events if user has appropriate 'view', 'add',\n 'change' or 'delete' permissions.\n \"\"\"\n queryset = Event.objects.all()\n serializer_class = EventSerializer\n filter_backends = (filters.DjangoObjectPermissionsFilter,)\n permission_classes = (myapp.permissions.CustomObjectPermissions,)\n\n\n\nFor more information on adding \n'view'\n permissions for models, see the \nrelevant section\n of the \ndjango-guardian\n documentation, and \nthis blogpost\n.\n\n\n\n\nCustom generic filtering\n\n\nYou can also provide your own generic filtering backend, or write an installable app for other developers to use.\n\n\nTo do so override \nBaseFilterBackend\n, and override the \n.filter_queryset(self, request, queryset, view)\n method. The method should return a new, filtered queryset.\n\n\nAs well as allowing clients to perform searches and filtering, generic filter backends can be useful for restricting which objects should be visible to any given request or user.\n\n\nExample\n\n\nFor example, you might need to restrict users to only being able to see objects they created.\n\n\nclass IsOwnerFilterBackend(filters.BaseFilterBackend):\n \"\"\"\n Filter that only allows users to see their own objects.\n \"\"\"\n def filter_queryset(self, request, queryset, view):\n return queryset.filter(owner=request.user)\n\n\n\nWe could achieve the same behavior by overriding \nget_queryset()\n on the views, but using a filter backend allows you to more easily add this restriction to multiple views, or to apply it across the entire API.\n\n\nCustomizing the interface\n\n\nGeneric filters may also present an interface in the browsable API. To do so you should implement a \nto_html()\n method which returns a rendered HTML representation of the filter. This method should have the following signature:\n\n\nto_html(self, request, queryset, view)\n\n\nThe method should return a rendered HTML string.\n\n\nPagination \n schemas\n\n\nYou can also make the filter controls available to the schema autogeneration\nthat REST framework provides, by implementing a \nget_schema_fields()\n method,\nwhich should return a list of \ncoreapi.Field\n instances.\n\n\nThird party packages\n\n\nThe following third party packages provide additional filter implementations.\n\n\nDjango REST framework filters package\n\n\nThe \ndjango-rest-framework-filters package\n works together with the \nDjangoFilterBackend\n class, and allows you to easily create filters across relationships, or create multiple filter lookup types for a given field.\n\n\nDjango REST framework full word search filter\n\n\nThe \ndjangorestframework-word-filter\n developed as alternative to \nfilters.SearchFilter\n which will search full word in text, or exact match.\n\n\nDjango URL Filter\n\n\ndjango-url-filter\n provides a safe way to filter data via human-friendly URLs. It works very similar to DRF serializers and fields in a sense that they can be nested except they are called filtersets and filters. That provides easy way to filter related data. Also this library is generic-purpose so it can be used to filter other sources of data and not only Django \nQuerySet\ns.\n\n\ndrf-url-filters\n\n\ndrf-url-filter\n is a simple Django app to apply filters on drf \nModelViewSet\n's \nQueryset\n in a clean, simple and configurable way. It also supports validations on incoming query params and their values. A beautiful python package \nVoluptuous\n is being used for validations on the incoming query parameters. The best part about voluptuous is you can define your own validations as per your query params requirements.", "title": "Filtering" }, { @@ -2632,7 +2632,7 @@ }, { "location": "/api-guide/filtering/#setting-filter-backends", - "text": "The default filter backends may be set globally, using the DEFAULT_FILTER_BACKENDS setting. For example. REST_FRAMEWORK = {\n 'DEFAULT_FILTER_BACKENDS': ('rest_framework.filters.DjangoFilterBackend',)\n} You can also set the filter backends on a per-view, or per-viewset basis,\nusing the GenericAPIView class-based views. from django.contrib.auth.models import User\nfrom myapp.serializers import UserSerializer\nfrom rest_framework import filters\nfrom rest_framework import generics\n\nclass UserListView(generics.ListAPIView):\n queryset = User.objects.all()\n serializer_class = UserSerializer\n filter_backends = (filters.DjangoFilterBackend,)", + "text": "The default filter backends may be set globally, using the DEFAULT_FILTER_BACKENDS setting. For example. REST_FRAMEWORK = {\n 'DEFAULT_FILTER_BACKENDS': ('django_filters.rest_framework.DjangoFilterBackend',)\n} You can also set the filter backends on a per-view, or per-viewset basis,\nusing the GenericAPIView class-based views. import django_filters\nfrom django.contrib.auth.models import User\nfrom myapp.serializers import UserSerializer\nfrom rest_framework import generics\n\nclass UserListView(generics.ListAPIView):\n queryset = User.objects.all()\n serializer_class = UserSerializer\n filter_backends = (django_filters.rest_framework.DjangoFilterBackend,)", "title": "Setting filter backends" }, { @@ -2652,7 +2652,7 @@ }, { "location": "/api-guide/filtering/#djangofilterbackend", - "text": "The DjangoFilterBackend class supports highly customizable field filtering, using the django-filter package . To use REST framework's DjangoFilterBackend , first install django-filter . pip install django-filter If you are using the browsable API or admin API you may also want to install django-crispy-forms , which will enhance the presentation of the filter forms in HTML views, by allowing them to render Bootstrap 3 HTML. pip install django-crispy-forms With crispy forms installed and added to Django's INSTALLED_APPS , the browsable API will present a filtering control for DjangoFilterBackend , like so:", + "text": "The django-filter library includes a DjangoFilterBackend class which\nsupports highly customizable field filtering for REST framework. To use DjangoFilterBackend , first install django-filter . pip install django-filter You should now either add the filter backend to your settings: REST_FRAMEWORK = {\n 'DEFAULT_FILTER_BACKENDS': ('django_filters.rest_framework.DjangoFilterBackend',)\n} Or add the filter backend to an individual View or ViewSet. from django_filters.rest_framework import DjangoFilterBackend\n\nclass UserListView(generics.ListAPIView):\n ...\n filter_backends = (DjangoFilterBackend,) If you are using the browsable API or admin API you may also want to install django-crispy-forms , which will enhance the presentation of the filter forms in HTML views, by allowing them to render Bootstrap 3 HTML. pip install django-crispy-forms With crispy forms installed and added to Django's INSTALLED_APPS , the browsable API will present a filtering control for DjangoFilterBackend , like so:", "title": "DjangoFilterBackend" }, { @@ -2662,7 +2662,7 @@ }, { "location": "/api-guide/filtering/#specifying-a-filterset", - "text": "For more advanced filtering requirements you can specify a FilterSet class that should be used by the view. For example: import django_filters\nfrom myapp.models import Product\nfrom myapp.serializers import ProductSerializer\nfrom rest_framework import filters\nfrom rest_framework import generics\n\nclass ProductFilter(filters.FilterSet):\n min_price = django_filters.NumberFilter(name=\"price\", lookup_expr='gte')\n max_price = django_filters.NumberFilter(name=\"price\", lookup_expr='lte')\n class Meta:\n model = Product\n fields = ['category', 'in_stock', 'min_price', 'max_price']\n\nclass ProductList(generics.ListAPIView):\n queryset = Product.objects.all()\n serializer_class = ProductSerializer\n filter_backends = (filters.DjangoFilterBackend,)\n filter_class = ProductFilter Which will allow you to make requests such as: http://example.com/api/products?category=clothing max_price=10.00 You can also span relationships using django-filter , let's assume that each\nproduct has foreign key to Manufacturer model, so we create filter that\nfilters using Manufacturer name. For example: from myapp.models import Product\nfrom myapp.serializers import ProductSerializer\nfrom rest_framework import filters\nfrom rest_framework import generics\n\nclass ProductFilter(filters.FilterSet):\n class Meta:\n model = Product\n fields = ['category', 'in_stock', 'manufacturer__name'] This enables us to make queries like: http://example.com/api/products?manufacturer__name=foo This is nice, but it exposes the Django's double underscore convention as part of the API. If you instead want to explicitly name the filter argument you can instead explicitly include it on the FilterSet class: import django_filters\nfrom myapp.models import Product\nfrom myapp.serializers import ProductSerializer\nfrom rest_framework import filters\nfrom rest_framework import generics\n\nclass ProductFilter(filters.FilterSet):\n manufacturer = django_filters.CharFilter(name=\"manufacturer__name\")\n\n class Meta:\n model = Product\n fields = ['category', 'in_stock', 'manufacturer'] And now you can execute: http://example.com/api/products?manufacturer=foo For more details on using filter sets see the django-filter documentation . Hints Tips By default filtering is not enabled. If you want to use DjangoFilterBackend remember to make sure it is installed by using the 'DEFAULT_FILTER_BACKENDS' setting. When using boolean fields, you should use the values True and False in the URL query parameters, rather than 0 , 1 , true or false . (The allowed boolean values are currently hardwired in Django's NullBooleanSelect implementation .) django-filter supports filtering across relationships, using Django's double-underscore syntax.", + "text": "For more advanced filtering requirements you can specify a FilterSet class that should be used by the view. For example: import django_filters\nfrom myapp.models import Product\nfrom myapp.serializers import ProductSerializer\nfrom rest_framework import generics\n\nclass ProductFilter(django_filters.rest_framework.FilterSet):\n min_price = django_filters.NumberFilter(name=\"price\", lookup_expr='gte')\n max_price = django_filters.NumberFilter(name=\"price\", lookup_expr='lte')\n class Meta:\n model = Product\n fields = ['category', 'in_stock', 'min_price', 'max_price']\n\nclass ProductList(generics.ListAPIView):\n queryset = Product.objects.all()\n serializer_class = ProductSerializer\n filter_backends = (django_filters.rest_framework.DjangoFilterBackend,)\n filter_class = ProductFilter Which will allow you to make requests such as: http://example.com/api/products?category=clothing max_price=10.00 You can also span relationships using django-filter , let's assume that each\nproduct has foreign key to Manufacturer model, so we create filter that\nfilters using Manufacturer name. For example: import django_filters\nfrom myapp.models import Product\nfrom myapp.serializers import ProductSerializer\nfrom rest_framework import generics\n\nclass ProductFilter(django_filters.rest_framework.FilterSet):\n class Meta:\n model = Product\n fields = ['category', 'in_stock', 'manufacturer__name'] This enables us to make queries like: http://example.com/api/products?manufacturer__name=foo This is nice, but it exposes the Django's double underscore convention as part of the API. If you instead want to explicitly name the filter argument you can instead explicitly include it on the FilterSet class: import django_filters\nfrom myapp.models import Product\nfrom myapp.serializers import ProductSerializer\nfrom rest_framework import generics\n\nclass ProductFilter(django_filters.rest_framework.FilterSet):\n manufacturer = django_filters.CharFilter(name=\"manufacturer__name\")\n\n class Meta:\n model = Product\n fields = ['category', 'in_stock', 'manufacturer'] And now you can execute: http://example.com/api/products?manufacturer=foo For more details on using filter sets see the django-filter documentation . Hints Tips By default filtering is not enabled. If you want to use DjangoFilterBackend remember to make sure it is installed by using the 'DEFAULT_FILTER_BACKENDS' setting. When using boolean fields, you should use the values True and False in the URL query parameters, rather than 0 , 1 , true or false . (The allowed boolean values are currently hardwired in Django's NullBooleanSelect implementation .) django-filter supports filtering across relationships, using Django's double-underscore syntax.", "title": "Specifying a FilterSet" }, { @@ -3007,7 +3007,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 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\nRepresenting schemas internally\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\nOther schema formats such as \nOpen API\n (\"Swagger\"),\n\nJSON HyperSchema\n, or \nAPI Blueprint\n can\nalso be supported by implementing a custom renderer class.\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\nAdding a schema\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\nREST framework includes functionality for auto-generating a schema,\nor allows you to specify one explicitly. There are a few different ways to\nadd a schema to your API, depending on exactly 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\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/vnd.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\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.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\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: Create a new user.\n post: List all the users.\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\nAlternate schema formats\n\n\nIn order to support an alternate schema format, you need to implement a custom renderer\nclass that handles converting a \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\n\n\nAPI Reference\n\n\nSchemaGenerator\n\n\nA class that deals with introspecting your API views, which can be used to\ngenerate a schema.\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 - The name of the API. \nrequired\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()\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\nArguments:\n\n\n\n\nrequest\n - The incoming request. Optionally used if you want to apply per-user permissions to the schema-generation.\n\n\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.", + "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 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\nRepresenting schemas internally\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\nOther schema formats such as \nOpen API\n (\"Swagger\"),\n\nJSON HyperSchema\n, or \nAPI Blueprint\n can\nalso be supported by implementing a custom renderer class.\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\nAdding a schema\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\nREST framework includes functionality for auto-generating a schema,\nor allows you to specify one explicitly. There are a few different ways to\nadd a schema to your API, depending on exactly 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\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/vnd.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\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.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\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: Create a new user.\n post: List all the users.\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\nAlternate schema formats\n\n\nIn order to support an alternate schema format, you need to implement a custom renderer\nclass that handles converting a \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\n\n\nAPI Reference\n\n\nSchemaGenerator\n\n\nA class that deals with introspecting your API views, which can be used to\ngenerate a schema.\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\nget_link(self, path, method, view)\n\n\nReturns a \ncoreapi.Link\n instance corresponding to the given view.\n\n\nYou can override this if you need to provide custom behaviors for particular views.\n\n\nget_description(self, path, method, view)\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, view)\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, view):\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, view)\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, view\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, view)\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\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.", "title": "Schemas" }, { @@ -3097,13 +3097,53 @@ }, { "location": "/api-guide/schemas/#schemagenerator", - "text": "A class that deals with introspecting your API views, which can be used to\ngenerate a schema. Typically you'll instantiate SchemaGenerator with a single argument, like so: generator = SchemaGenerator(title='Stock Prices API') Arguments: title - The name of the API. required url - The root URL of the API schema. This option is not required unless the schema is included under path prefix. patterns - A list of URLs to inspect when generating the schema. Defaults to the project's URL conf. urlconf - A URL conf module name to use when generating the schema. Defaults to settings.ROOT_URLCONF .", + "text": "A class that deals with introspecting your API views, which can be used to\ngenerate a schema. Typically you'll instantiate SchemaGenerator with a single argument, like so: generator = SchemaGenerator(title='Stock Prices API') Arguments: title required - The name of the API. url - The root URL of the API schema. This option is not required unless the schema is included under path prefix. patterns - A list of URLs to inspect when generating the schema. Defaults to the project's URL conf. urlconf - A URL conf module name to use when generating the schema. Defaults to settings.ROOT_URLCONF .", "title": "SchemaGenerator" }, { - "location": "/api-guide/schemas/#get_schema", - "text": "Returns a coreapi.Document instance that represents the API schema. @api_view\n@renderer_classes([renderers.CoreJSONRenderer])\ndef schema_view(request):\n generator = schemas.SchemaGenerator(title='Bookings API')\n return Response(generator.get_schema()) Arguments: request - The incoming request. Optionally used if you want to apply per-user permissions to the schema-generation.", - "title": "get_schema()" + "location": "/api-guide/schemas/#get_schemaself-request", + "text": "Returns a coreapi.Document instance that represents the API schema. @api_view\n@renderer_classes([renderers.CoreJSONRenderer])\ndef schema_view(request):\n generator = schemas.SchemaGenerator(title='Bookings API')\n return Response(generator.get_schema()) The request argument is optional, and may be used if you want to apply per-user\npermissions to the resulting schema generation.", + "title": "get_schema(self, request)" + }, + { + "location": "/api-guide/schemas/#get_linksself-request", + "text": "Return a nested dictionary containing all the links that should be included in the API schema. This 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.", + "title": "get_links(self, request)" + }, + { + "location": "/api-guide/schemas/#get_linkself-path-method-view", + "text": "Returns a coreapi.Link instance corresponding to the given view. You can override this if you need to provide custom behaviors for particular views.", + "title": "get_link(self, path, method, view)" + }, + { + "location": "/api-guide/schemas/#get_descriptionself-path-method-view", + "text": "Returns 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.", + "title": "get_description(self, path, method, view)" + }, + { + "location": "/api-guide/schemas/#get_encodingself-path-method-view", + "text": "Returns a string to indicate the encoding for any request body, when interacting\nwith the given view. Eg. 'application/json' . May return a blank string for views\nthat do not expect a request body.", + "title": "get_encoding(self, path, method, view)" + }, + { + "location": "/api-guide/schemas/#get_path_fieldsself-path-method-view", + "text": "Return a list of coreapi.Link() instances. One for each path parameter in the URL.", + "title": "get_path_fields(self, path, method, view):" + }, + { + "location": "/api-guide/schemas/#get_serializer_fieldsself-path-method-view", + "text": "Return a list of coreapi.Link() instances. One for each field in the serializer class used by the view.", + "title": "get_serializer_fields(self, path, method, view)" + }, + { + "location": "/api-guide/schemas/#get_pagination_fieldsself-path-method-view", + "text": "Return a list of coreapi.Link() instances, as returned by the get_schema_fields() method on any pagination class used by the view.", + "title": "get_pagination_fields(self, path, method, view" + }, + { + "location": "/api-guide/schemas/#get_filter_fieldsself-path-method-view", + "text": "Return a list of coreapi.Link() instances, as returned by the get_schema_fields() method of any filter classes used by the view.", + "title": "get_filter_fields(self, path, method, view)" }, { "location": "/api-guide/schemas/#core-api", @@ -3362,7 +3402,7 @@ }, { "location": "/api-guide/testing/", - "text": "Testing\n\n\n\n\nCode without tests is broken as designed.\n\n\n \nJacob Kaplan-Moss\n\n\n\n\nREST framework includes a few helper classes that extend Django's existing test framework, and improve support for making API requests.\n\n\nAPIRequestFactory\n\n\nExtends \nDjango's existing \nRequestFactory\n class\n.\n\n\nCreating test requests\n\n\nThe \nAPIRequestFactory\n class supports an almost identical API to Django's standard \nRequestFactory\n class. This means that the standard \n.get()\n, \n.post()\n, \n.put()\n, \n.patch()\n, \n.delete()\n, \n.head()\n and \n.options()\n methods are all available.\n\n\nfrom rest_framework.test import APIRequestFactory\n\n# Using the standard RequestFactory API to create a form POST request\nfactory = APIRequestFactory()\nrequest = factory.post('/notes/', {'title': 'new idea'})\n\n\n\nUsing the \nformat\n argument\n\n\nMethods which create a request body, such as \npost\n, \nput\n and \npatch\n, include a \nformat\n argument, which make it easy to generate requests using a content type other than multipart form data. For example:\n\n\n# Create a JSON POST request\nfactory = APIRequestFactory()\nrequest = factory.post('/notes/', {'title': 'new idea'}, format='json')\n\n\n\nBy default the available formats are \n'multipart'\n and \n'json'\n. For compatibility with Django's existing \nRequestFactory\n the default format is \n'multipart'\n.\n\n\nTo support a wider set of request formats, or change the default format, \nsee the configuration section\n.\n\n\nExplicitly encoding the request body\n\n\nIf you need to explicitly encode the request body, you can do so by setting the \ncontent_type\n flag. For example:\n\n\nrequest = factory.post('/notes/', json.dumps({'title': 'new idea'}), content_type='application/json')\n\n\n\nPUT and PATCH with form data\n\n\nOne difference worth noting between Django's \nRequestFactory\n and REST framework's \nAPIRequestFactory\n is that multipart form data will be encoded for methods other than just \n.post()\n.\n\n\nFor example, using \nAPIRequestFactory\n, you can make a form PUT request like so:\n\n\nfactory = APIRequestFactory()\nrequest = factory.put('/notes/547/', {'title': 'remember to email dave'})\n\n\n\nUsing Django's \nRequestFactory\n, you'd need to explicitly encode the data yourself:\n\n\nfrom django.test.client import encode_multipart, RequestFactory\n\nfactory = RequestFactory()\ndata = {'title': 'remember to email dave'}\ncontent = encode_multipart('BoUnDaRyStRiNg', data)\ncontent_type = 'multipart/form-data; boundary=BoUnDaRyStRiNg'\nrequest = factory.put('/notes/547/', content, content_type=content_type)\n\n\n\nForcing authentication\n\n\nWhen testing views directly using a request factory, it's often convenient to be able to directly authenticate the request, rather than having to construct the correct authentication credentials.\n\n\nTo forcibly authenticate a request, use the \nforce_authenticate()\n method.\n\n\nfrom rest_framework.test import force_authenticate\n\nfactory = APIRequestFactory()\nuser = User.objects.get(username='olivia')\nview = AccountDetail.as_view()\n\n# Make an authenticated request to the view...\nrequest = factory.get('/accounts/django-superstars/')\nforce_authenticate(request, user=user)\nresponse = view(request)\n\n\n\nThe signature for the method is \nforce_authenticate(request, user=None, token=None)\n. When making the call, either or both of the user and token may be set.\n\n\nFor example, when forcibly authenticating using a token, you might do something like the following:\n\n\nuser = User.objects.get(username='olivia')\nrequest = factory.get('/accounts/django-superstars/')\nforce_authenticate(request, user=user, token=user.token)\n\n\n\n\n\nNote\n: When using \nAPIRequestFactory\n, the object that is returned is Django's standard \nHttpRequest\n, and not REST framework's \nRequest\n object, which is only generated once the view is called.\n\n\nThis means that setting attributes directly on the request object may not always have the effect you expect. For example, setting \n.token\n directly will have no effect, and setting \n.user\n directly will only work if session authentication is being used.\n\n\n# Request will only authenticate if `SessionAuthentication` is in use.\nrequest = factory.get('/accounts/django-superstars/')\nrequest.user = user\nresponse = view(request)\n\n\n\n\n\nForcing CSRF validation\n\n\nBy default, requests created with \nAPIRequestFactory\n will not have CSRF validation applied when passed to a REST framework view. If you need to explicitly turn CSRF validation on, you can do so by setting the \nenforce_csrf_checks\n flag when instantiating the factory.\n\n\nfactory = APIRequestFactory(enforce_csrf_checks=True)\n\n\n\n\n\nNote\n: It's worth noting that Django's standard \nRequestFactory\n doesn't need to include this option, because when using regular Django the CSRF validation takes place in middleware, which is not run when testing views directly. When using REST framework, CSRF validation takes place inside the view, so the request factory needs to disable view-level CSRF checks.\n\n\n\n\nAPIClient\n\n\nExtends \nDjango's existing \nClient\n class\n.\n\n\nMaking requests\n\n\nThe \nAPIClient\n class supports the same request interface as Django's standard \nClient\n class. This means the that standard \n.get()\n, \n.post()\n, \n.put()\n, \n.patch()\n, \n.delete()\n, \n.head()\n and \n.options()\n methods are all available. For example:\n\n\nfrom rest_framework.test import APIClient\n\nclient = APIClient()\nclient.post('/notes/', {'title': 'new idea'}, format='json')\n\n\n\nTo support a wider set of request formats, or change the default format, \nsee the configuration section\n.\n\n\nAuthenticating\n\n\n.login(**kwargs)\n\n\nThe \nlogin\n method functions exactly as it does with Django's regular \nClient\n class. This allows you to authenticate requests against any views which include \nSessionAuthentication\n.\n\n\n# Make all requests in the context of a logged in session.\nclient = APIClient()\nclient.login(username='lauren', password='secret')\n\n\n\nTo logout, call the \nlogout\n method as usual.\n\n\n# Log out\nclient.logout()\n\n\n\nThe \nlogin\n method is appropriate for testing APIs that use session authentication, for example web sites which include AJAX interaction with the API.\n\n\n.credentials(**kwargs)\n\n\nThe \ncredentials\n method can be used to set headers that will then be included on all subsequent requests by the test client.\n\n\nfrom rest_framework.authtoken.models import Token\nfrom rest_framework.test import APIClient\n\n# Include an appropriate `Authorization:` header on all requests.\ntoken = Token.objects.get(user__username='lauren')\nclient = APIClient()\nclient.credentials(HTTP_AUTHORIZATION='Token ' + token.key)\n\n\n\nNote that calling \ncredentials\n a second time overwrites any existing credentials. You can unset any existing credentials by calling the method with no arguments.\n\n\n# Stop including any credentials\nclient.credentials()\n\n\n\nThe \ncredentials\n method is appropriate for testing APIs that require authentication headers, such as basic authentication, OAuth1a and OAuth2 authentication, and simple token authentication schemes.\n\n\n.force_authenticate(user=None, token=None)\n\n\nSometimes you may want to bypass authentication, and simple force all requests by the test client to be automatically treated as authenticated.\n\n\nThis can be a useful shortcut if you're testing the API but don't want to have to construct valid authentication credentials in order to make test requests.\n\n\nuser = User.objects.get(username='lauren')\nclient = APIClient()\nclient.force_authenticate(user=user)\n\n\n\nTo unauthenticate subsequent requests, call \nforce_authenticate\n setting the user and/or token to \nNone\n.\n\n\nclient.force_authenticate(user=None)\n\n\n\nCSRF validation\n\n\nBy default CSRF validation is not applied when using \nAPIClient\n. If you need to explicitly enable CSRF validation, you can do so by setting the \nenforce_csrf_checks\n flag when instantiating the client.\n\n\nclient = APIClient(enforce_csrf_checks=True)\n\n\n\nAs usual CSRF validation will only apply to any session authenticated views. This means CSRF validation will only occur if the client has been logged in by calling \nlogin()\n.\n\n\n\n\nRequestsClient\n\n\nREST framework also includes a client for interacting with your application\nusing the popular Python library, \nrequests\n.\n\n\nThis exposes exactly the same interface as if you were using a requests session\ndirectly.\n\n\nclient = RequestsClient()\nresponse = client.get('http://testserver/users/')\n\n\n\nNote that the requests client requires you to pass fully qualified URLs.\n\n\nHeaders \n Authentication\n\n\nCustom headers and authentication credentials can be provided in the same way\nas \nwhen using a standard \nrequests.Session\n instance\n.\n\n\nfrom requests.auth import HTTPBasicAuth\n\nclient.auth = HTTPBasicAuth('user', 'pass')\nclient.headers.update({'x-test': 'true'})\n\n\n\nCSRF\n\n\nIf you're using \nSessionAuthentication\n then you'll need to include a CSRF token\nfor any \nPOST\n, \nPUT\n, \nPATCH\n or \nDELETE\n requests.\n\n\nYou can do so by following the same flow that a JavaScript based client would use.\nFirst make a \nGET\n request in order to obtain a CRSF token, then present that\ntoken in the following request.\n\n\nFor example...\n\n\nclient = RequestsClient()\n\n# Obtain a CSRF token.\nresponse = client.get('/homepage/')\nassert response.status_code == 200\ncsrftoken = response.cookies['csrftoken']\n\n# Interact with the API.\nresponse = client.post('/organisations/', json={\n 'name': 'MegaCorp',\n 'status': 'active'\n}, headers={'X-CSRFToken': csrftoken})\nassert response.status_code == 200\n\n\n\nLive tests\n\n\nWith careful usage both the \nRequestsClient\n and the \nCoreAPIClient\n provide\nthe ability to write test cases that can run either in development, or be run\ndirectly against your staging server or production environment.\n\n\nUsing this style to create basic tests of a few core piece of functionality is\na powerful way to validate your live service. Doing so may require some careful\nattention to setup and teardown to ensure that the tests run in a way that they\ndo not directly affect customer data.\n\n\n\n\nCoreAPIClient\n\n\nThe CoreAPIClient allows you to interact with your API using the Python\n\ncoreapi\n client library.\n\n\n# Fetch the API schema\nurl = reverse('schema')\nclient = CoreAPIClient()\nschema = client.get(url)\n\n# Create a new organisation\nparams = {'name': 'MegaCorp', 'status': 'active'}\nclient.action(schema, ['organisations', 'create'], params)\n\n# Ensure that the organisation exists in the listing\ndata = client.action(schema, ['organisations', 'list'])\nassert(len(data) == 1)\nassert(data == [{'name': 'MegaCorp', 'status': 'active'}])\n\n\n\nHeaders \n Authentication\n\n\nCustom headers and authentication may be used with \nCoreAPIClient\n in a\nsimilar way as with \nRequestsClient\n.\n\n\nfrom requests.auth import HTTPBasicAuth\n\nclient = CoreAPIClient()\nclient.session.auth = HTTPBasicAuth('user', 'pass')\nclient.session.headers.update({'x-test': 'true'})\n\n\n\n\n\nTest cases\n\n\nREST framework includes the following test case classes, that mirror the existing Django test case classes, but use \nAPIClient\n instead of Django's default \nClient\n.\n\n\n\n\nAPISimpleTestCase\n\n\nAPITransactionTestCase\n\n\nAPITestCase\n\n\nAPILiveServerTestCase\n\n\n\n\nExample\n\n\nYou can use any of REST framework's test case classes as you would for the regular Django test case classes. The \nself.client\n attribute will be an \nAPIClient\n instance.\n\n\nfrom django.urls import reverse\nfrom rest_framework import status\nfrom rest_framework.test import APITestCase\nfrom myproject.apps.core.models import Account\n\nclass AccountTests(APITestCase):\n def test_create_account(self):\n \"\"\"\n Ensure we can create a new account object.\n \"\"\"\n url = reverse('account-list')\n data = {'name': 'DabApps'}\n response = self.client.post(url, data, format='json')\n self.assertEqual(response.status_code, status.HTTP_201_CREATED)\n self.assertEqual(Account.objects.count(), 1)\n self.assertEqual(Account.objects.get().name, 'DabApps')\n\n\n\n\n\nTesting responses\n\n\nChecking the response data\n\n\nWhen checking the validity of test responses it's often more convenient to inspect the data that the response was created with, rather than inspecting the fully rendered response.\n\n\nFor example, it's easier to inspect \nresponse.data\n:\n\n\nresponse = self.client.get('/users/4/')\nself.assertEqual(response.data, {'id': 4, 'username': 'lauren'})\n\n\n\nInstead of inspecting the result of parsing \nresponse.content\n:\n\n\nresponse = self.client.get('/users/4/')\nself.assertEqual(json.loads(response.content), {'id': 4, 'username': 'lauren'})\n\n\n\nRendering responses\n\n\nIf you're testing views directly using \nAPIRequestFactory\n, the responses that are returned will not yet be rendered, as rendering of template responses is performed by Django's internal request-response cycle. In order to access \nresponse.content\n, you'll first need to render the response.\n\n\nview = UserDetail.as_view()\nrequest = factory.get('/users/4')\nresponse = view(request, pk='4')\nresponse.render() # Cannot access `response.content` without this.\nself.assertEqual(response.content, '{\"username\": \"lauren\", \"id\": 4}')\n\n\n\n\n\nConfiguration\n\n\nSetting the default format\n\n\nThe default format used to make test requests may be set using the \nTEST_REQUEST_DEFAULT_FORMAT\n setting key. For example, to always use JSON for test requests by default instead of standard multipart form requests, set the following in your \nsettings.py\n file:\n\n\nREST_FRAMEWORK = {\n ...\n 'TEST_REQUEST_DEFAULT_FORMAT': 'json'\n}\n\n\n\nSetting the available formats\n\n\nIf you need to test requests using something other than multipart or json requests, you can do so by setting the \nTEST_REQUEST_RENDERER_CLASSES\n setting.\n\n\nFor example, to add support for using \nformat='html'\n in test requests, you might have something like this in your \nsettings.py\n file.\n\n\nREST_FRAMEWORK = {\n ...\n 'TEST_REQUEST_RENDERER_CLASSES': (\n 'rest_framework.renderers.MultiPartRenderer',\n 'rest_framework.renderers.JSONRenderer',\n 'rest_framework.renderers.TemplateHTMLRenderer'\n )\n}", + "text": "Testing\n\n\n\n\nCode without tests is broken as designed.\n\n\n \nJacob Kaplan-Moss\n\n\n\n\nREST framework includes a few helper classes that extend Django's existing test framework, and improve support for making API requests.\n\n\nAPIRequestFactory\n\n\nExtends \nDjango's existing \nRequestFactory\n class\n.\n\n\nCreating test requests\n\n\nThe \nAPIRequestFactory\n class supports an almost identical API to Django's standard \nRequestFactory\n class. This means that the standard \n.get()\n, \n.post()\n, \n.put()\n, \n.patch()\n, \n.delete()\n, \n.head()\n and \n.options()\n methods are all available.\n\n\nfrom rest_framework.test import APIRequestFactory\n\n# Using the standard RequestFactory API to create a form POST request\nfactory = APIRequestFactory()\nrequest = factory.post('/notes/', {'title': 'new idea'})\n\n\n\nUsing the \nformat\n argument\n\n\nMethods which create a request body, such as \npost\n, \nput\n and \npatch\n, include a \nformat\n argument, which make it easy to generate requests using a content type other than multipart form data. For example:\n\n\n# Create a JSON POST request\nfactory = APIRequestFactory()\nrequest = factory.post('/notes/', {'title': 'new idea'}, format='json')\n\n\n\nBy default the available formats are \n'multipart'\n and \n'json'\n. For compatibility with Django's existing \nRequestFactory\n the default format is \n'multipart'\n.\n\n\nTo support a wider set of request formats, or change the default format, \nsee the configuration section\n.\n\n\nExplicitly encoding the request body\n\n\nIf you need to explicitly encode the request body, you can do so by setting the \ncontent_type\n flag. For example:\n\n\nrequest = factory.post('/notes/', json.dumps({'title': 'new idea'}), content_type='application/json')\n\n\n\nPUT and PATCH with form data\n\n\nOne difference worth noting between Django's \nRequestFactory\n and REST framework's \nAPIRequestFactory\n is that multipart form data will be encoded for methods other than just \n.post()\n.\n\n\nFor example, using \nAPIRequestFactory\n, you can make a form PUT request like so:\n\n\nfactory = APIRequestFactory()\nrequest = factory.put('/notes/547/', {'title': 'remember to email dave'})\n\n\n\nUsing Django's \nRequestFactory\n, you'd need to explicitly encode the data yourself:\n\n\nfrom django.test.client import encode_multipart, RequestFactory\n\nfactory = RequestFactory()\ndata = {'title': 'remember to email dave'}\ncontent = encode_multipart('BoUnDaRyStRiNg', data)\ncontent_type = 'multipart/form-data; boundary=BoUnDaRyStRiNg'\nrequest = factory.put('/notes/547/', content, content_type=content_type)\n\n\n\nForcing authentication\n\n\nWhen testing views directly using a request factory, it's often convenient to be able to directly authenticate the request, rather than having to construct the correct authentication credentials.\n\n\nTo forcibly authenticate a request, use the \nforce_authenticate()\n method.\n\n\nfrom rest_framework.test import force_authenticate\n\nfactory = APIRequestFactory()\nuser = User.objects.get(username='olivia')\nview = AccountDetail.as_view()\n\n# Make an authenticated request to the view...\nrequest = factory.get('/accounts/django-superstars/')\nforce_authenticate(request, user=user)\nresponse = view(request)\n\n\n\nThe signature for the method is \nforce_authenticate(request, user=None, token=None)\n. When making the call, either or both of the user and token may be set.\n\n\nFor example, when forcibly authenticating using a token, you might do something like the following:\n\n\nuser = User.objects.get(username='olivia')\nrequest = factory.get('/accounts/django-superstars/')\nforce_authenticate(request, user=user, token=user.token)\n\n\n\n\n\nNote\n: When using \nAPIRequestFactory\n, the object that is returned is Django's standard \nHttpRequest\n, and not REST framework's \nRequest\n object, which is only generated once the view is called.\n\n\nThis means that setting attributes directly on the request object may not always have the effect you expect. For example, setting \n.token\n directly will have no effect, and setting \n.user\n directly will only work if session authentication is being used.\n\n\n# Request will only authenticate if `SessionAuthentication` is in use.\nrequest = factory.get('/accounts/django-superstars/')\nrequest.user = user\nresponse = view(request)\n\n\n\n\n\nForcing CSRF validation\n\n\nBy default, requests created with \nAPIRequestFactory\n will not have CSRF validation applied when passed to a REST framework view. If you need to explicitly turn CSRF validation on, you can do so by setting the \nenforce_csrf_checks\n flag when instantiating the factory.\n\n\nfactory = APIRequestFactory(enforce_csrf_checks=True)\n\n\n\n\n\nNote\n: It's worth noting that Django's standard \nRequestFactory\n doesn't need to include this option, because when using regular Django the CSRF validation takes place in middleware, which is not run when testing views directly. When using REST framework, CSRF validation takes place inside the view, so the request factory needs to disable view-level CSRF checks.\n\n\n\n\nAPIClient\n\n\nExtends \nDjango's existing \nClient\n class\n.\n\n\nMaking requests\n\n\nThe \nAPIClient\n class supports the same request interface as Django's standard \nClient\n class. This means the that standard \n.get()\n, \n.post()\n, \n.put()\n, \n.patch()\n, \n.delete()\n, \n.head()\n and \n.options()\n methods are all available. For example:\n\n\nfrom rest_framework.test import APIClient\n\nclient = APIClient()\nclient.post('/notes/', {'title': 'new idea'}, format='json')\n\n\n\nTo support a wider set of request formats, or change the default format, \nsee the configuration section\n.\n\n\nAuthenticating\n\n\n.login(**kwargs)\n\n\nThe \nlogin\n method functions exactly as it does with Django's regular \nClient\n class. This allows you to authenticate requests against any views which include \nSessionAuthentication\n.\n\n\n# Make all requests in the context of a logged in session.\nclient = APIClient()\nclient.login(username='lauren', password='secret')\n\n\n\nTo logout, call the \nlogout\n method as usual.\n\n\n# Log out\nclient.logout()\n\n\n\nThe \nlogin\n method is appropriate for testing APIs that use session authentication, for example web sites which include AJAX interaction with the API.\n\n\n.credentials(**kwargs)\n\n\nThe \ncredentials\n method can be used to set headers that will then be included on all subsequent requests by the test client.\n\n\nfrom rest_framework.authtoken.models import Token\nfrom rest_framework.test import APIClient\n\n# Include an appropriate `Authorization:` header on all requests.\ntoken = Token.objects.get(user__username='lauren')\nclient = APIClient()\nclient.credentials(HTTP_AUTHORIZATION='Token ' + token.key)\n\n\n\nNote that calling \ncredentials\n a second time overwrites any existing credentials. You can unset any existing credentials by calling the method with no arguments.\n\n\n# Stop including any credentials\nclient.credentials()\n\n\n\nThe \ncredentials\n method is appropriate for testing APIs that require authentication headers, such as basic authentication, OAuth1a and OAuth2 authentication, and simple token authentication schemes.\n\n\n.force_authenticate(user=None, token=None)\n\n\nSometimes you may want to bypass authentication, and simple force all requests by the test client to be automatically treated as authenticated.\n\n\nThis can be a useful shortcut if you're testing the API but don't want to have to construct valid authentication credentials in order to make test requests.\n\n\nuser = User.objects.get(username='lauren')\nclient = APIClient()\nclient.force_authenticate(user=user)\n\n\n\nTo unauthenticate subsequent requests, call \nforce_authenticate\n setting the user and/or token to \nNone\n.\n\n\nclient.force_authenticate(user=None)\n\n\n\nCSRF validation\n\n\nBy default CSRF validation is not applied when using \nAPIClient\n. If you need to explicitly enable CSRF validation, you can do so by setting the \nenforce_csrf_checks\n flag when instantiating the client.\n\n\nclient = APIClient(enforce_csrf_checks=True)\n\n\n\nAs usual CSRF validation will only apply to any session authenticated views. This means CSRF validation will only occur if the client has been logged in by calling \nlogin()\n.\n\n\n\n\nRequestsClient\n\n\nREST framework also includes a client for interacting with your application\nusing the popular Python library, \nrequests\n.\n\n\nThis exposes exactly the same interface as if you were using a requests session\ndirectly.\n\n\nclient = RequestsClient()\nresponse = client.get('http://testserver/users/')\nassert response.status_code == 200\n\n\n\nNote that the requests client requires you to pass fully qualified URLs.\n\n\nHeaders \n Authentication\n\n\nCustom headers and authentication credentials can be provided in the same way\nas \nwhen using a standard \nrequests.Session\n instance\n.\n\n\nfrom requests.auth import HTTPBasicAuth\n\nclient.auth = HTTPBasicAuth('user', 'pass')\nclient.headers.update({'x-test': 'true'})\n\n\n\nCSRF\n\n\nIf you're using \nSessionAuthentication\n then you'll need to include a CSRF token\nfor any \nPOST\n, \nPUT\n, \nPATCH\n or \nDELETE\n requests.\n\n\nYou can do so by following the same flow that a JavaScript based client would use.\nFirst make a \nGET\n request in order to obtain a CRSF token, then present that\ntoken in the following request.\n\n\nFor example...\n\n\nclient = RequestsClient()\n\n# Obtain a CSRF token.\nresponse = client.get('/homepage/')\nassert response.status_code == 200\ncsrftoken = response.cookies['csrftoken']\n\n# Interact with the API.\nresponse = client.post('/organisations/', json={\n 'name': 'MegaCorp',\n 'status': 'active'\n}, headers={'X-CSRFToken': csrftoken})\nassert response.status_code == 200\n\n\n\nLive tests\n\n\nWith careful usage both the \nRequestsClient\n and the \nCoreAPIClient\n provide\nthe ability to write test cases that can run either in development, or be run\ndirectly against your staging server or production environment.\n\n\nUsing this style to create basic tests of a few core piece of functionality is\na powerful way to validate your live service. Doing so may require some careful\nattention to setup and teardown to ensure that the tests run in a way that they\ndo not directly affect customer data.\n\n\n\n\nCoreAPIClient\n\n\nThe CoreAPIClient allows you to interact with your API using the Python\n\ncoreapi\n client library.\n\n\n# Fetch the API schema\nclient = CoreAPIClient()\nschema = client.get('http://testserver/schema/')\n\n# Create a new organisation\nparams = {'name': 'MegaCorp', 'status': 'active'}\nclient.action(schema, ['organisations', 'create'], params)\n\n# Ensure that the organisation exists in the listing\ndata = client.action(schema, ['organisations', 'list'])\nassert(len(data) == 1)\nassert(data == [{'name': 'MegaCorp', 'status': 'active'}])\n\n\n\nHeaders \n Authentication\n\n\nCustom headers and authentication may be used with \nCoreAPIClient\n in a\nsimilar way as with \nRequestsClient\n.\n\n\nfrom requests.auth import HTTPBasicAuth\n\nclient = CoreAPIClient()\nclient.session.auth = HTTPBasicAuth('user', 'pass')\nclient.session.headers.update({'x-test': 'true'})\n\n\n\n\n\nTest cases\n\n\nREST framework includes the following test case classes, that mirror the existing Django test case classes, but use \nAPIClient\n instead of Django's default \nClient\n.\n\n\n\n\nAPISimpleTestCase\n\n\nAPITransactionTestCase\n\n\nAPITestCase\n\n\nAPILiveServerTestCase\n\n\n\n\nExample\n\n\nYou can use any of REST framework's test case classes as you would for the regular Django test case classes. The \nself.client\n attribute will be an \nAPIClient\n instance.\n\n\nfrom django.urls import reverse\nfrom rest_framework import status\nfrom rest_framework.test import APITestCase\nfrom myproject.apps.core.models import Account\n\nclass AccountTests(APITestCase):\n def test_create_account(self):\n \"\"\"\n Ensure we can create a new account object.\n \"\"\"\n url = reverse('account-list')\n data = {'name': 'DabApps'}\n response = self.client.post(url, data, format='json')\n self.assertEqual(response.status_code, status.HTTP_201_CREATED)\n self.assertEqual(Account.objects.count(), 1)\n self.assertEqual(Account.objects.get().name, 'DabApps')\n\n\n\n\n\nTesting responses\n\n\nChecking the response data\n\n\nWhen checking the validity of test responses it's often more convenient to inspect the data that the response was created with, rather than inspecting the fully rendered response.\n\n\nFor example, it's easier to inspect \nresponse.data\n:\n\n\nresponse = self.client.get('/users/4/')\nself.assertEqual(response.data, {'id': 4, 'username': 'lauren'})\n\n\n\nInstead of inspecting the result of parsing \nresponse.content\n:\n\n\nresponse = self.client.get('/users/4/')\nself.assertEqual(json.loads(response.content), {'id': 4, 'username': 'lauren'})\n\n\n\nRendering responses\n\n\nIf you're testing views directly using \nAPIRequestFactory\n, the responses that are returned will not yet be rendered, as rendering of template responses is performed by Django's internal request-response cycle. In order to access \nresponse.content\n, you'll first need to render the response.\n\n\nview = UserDetail.as_view()\nrequest = factory.get('/users/4')\nresponse = view(request, pk='4')\nresponse.render() # Cannot access `response.content` without this.\nself.assertEqual(response.content, '{\"username\": \"lauren\", \"id\": 4}')\n\n\n\n\n\nConfiguration\n\n\nSetting the default format\n\n\nThe default format used to make test requests may be set using the \nTEST_REQUEST_DEFAULT_FORMAT\n setting key. For example, to always use JSON for test requests by default instead of standard multipart form requests, set the following in your \nsettings.py\n file:\n\n\nREST_FRAMEWORK = {\n ...\n 'TEST_REQUEST_DEFAULT_FORMAT': 'json'\n}\n\n\n\nSetting the available formats\n\n\nIf you need to test requests using something other than multipart or json requests, you can do so by setting the \nTEST_REQUEST_RENDERER_CLASSES\n setting.\n\n\nFor example, to add support for using \nformat='html'\n in test requests, you might have something like this in your \nsettings.py\n file.\n\n\nREST_FRAMEWORK = {\n ...\n 'TEST_REQUEST_RENDERER_CLASSES': (\n 'rest_framework.renderers.MultiPartRenderer',\n 'rest_framework.renderers.JSONRenderer',\n 'rest_framework.renderers.TemplateHTMLRenderer'\n )\n}", "title": "Testing" }, { @@ -3442,7 +3482,7 @@ }, { "location": "/api-guide/testing/#requestsclient", - "text": "REST framework also includes a client for interacting with your application\nusing the popular Python library, requests . This exposes exactly the same interface as if you were using a requests session\ndirectly. client = RequestsClient()\nresponse = client.get('http://testserver/users/') Note that the requests client requires you to pass fully qualified URLs.", + "text": "REST framework also includes a client for interacting with your application\nusing the popular Python library, requests . This exposes exactly the same interface as if you were using a requests session\ndirectly. client = RequestsClient()\nresponse = client.get('http://testserver/users/')\nassert response.status_code == 200 Note that the requests client requires you to pass fully qualified URLs.", "title": "RequestsClient" }, { @@ -3462,7 +3502,7 @@ }, { "location": "/api-guide/testing/#coreapiclient", - "text": "The CoreAPIClient allows you to interact with your API using the Python coreapi client library. # Fetch the API schema\nurl = reverse('schema')\nclient = CoreAPIClient()\nschema = client.get(url)\n\n# Create a new organisation\nparams = {'name': 'MegaCorp', 'status': 'active'}\nclient.action(schema, ['organisations', 'create'], params)\n\n# Ensure that the organisation exists in the listing\ndata = client.action(schema, ['organisations', 'list'])\nassert(len(data) == 1)\nassert(data == [{'name': 'MegaCorp', 'status': 'active'}])", + "text": "The CoreAPIClient allows you to interact with your API using the Python coreapi client library. # Fetch the API schema\nclient = CoreAPIClient()\nschema = client.get('http://testserver/schema/')\n\n# Create a new organisation\nparams = {'name': 'MegaCorp', 'status': 'active'}\nclient.action(schema, ['organisations', 'create'], params)\n\n# Ensure that the organisation exists in the listing\ndata = client.action(schema, ['organisations', 'list'])\nassert(len(data) == 1)\nassert(data == [{'name': 'MegaCorp', 'status': 'active'}])", "title": "CoreAPIClient" }, { @@ -3857,7 +3897,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 \n 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\nPastebin API \"http://127.0.0.1:8000/\"\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\n GET /users/ HTTP/1.1\n\n Accept: application/vnd.coreapi+json, */*\n\n Authorization: Basic bWF4Om1heA==\n\n Host: 127.0.0.1\n\n User-Agent: coreapi\n\n 200 OK\n\n Allow: GET, HEAD, OPTIONS\n\n Content-Type: application/json\n\n Date: Thu, 30 Jun 2016 10:51:46 GMT\n\n Server: WSGIServer/0.1 Python/2.7.10\n\n Vary: Accept, Cookie\n\n\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 \n 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 \ndomain\n \ncredentials string\n\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 programatically 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\nthe internal representation of the interface that we are interacting with.\n\n\nNow that we have our schema \nDocument\n, we can now start 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 \nTODO\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 behaviour 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.", + "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 \n 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\nPastebin API \"http://127.0.0.1:8000/\"\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\n GET /users/ HTTP/1.1\n\n Accept: application/vnd.coreapi+json, */*\n\n Authorization: Basic bWF4Om1heA==\n\n Host: 127.0.0.1\n\n User-Agent: coreapi\n\n 200 OK\n\n Allow: GET, HEAD, OPTIONS\n\n Content-Type: application/json\n\n Date: Thu, 30 Jun 2016 10:51:46 GMT\n\n Server: WSGIServer/0.1 Python/2.7.10\n\n Vary: Accept, Cookie\n\n\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 \n 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 \ndomain\n \ncredentials string\n\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 programatically 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\nthe internal representation of the interface that we are interacting with.\n\n\nNow that we have our schema \nDocument\n, we can now start 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 behaviour 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.", "title": "API Clients" }, { @@ -3927,7 +3967,7 @@ }, { "location": "/topics/api-clients/#codecs_1", - "text": "Codecs are responsible for encoding or decoding Documents. The decoding process is used by a client to take a bytestring of an API schema\ndefinition, and returning the Core API Document that represents that interface. A codec should be associated with a particular media type, such as TODO . This media type is used by the server in the response Content-Type header,\nin order to indicate what kind of data is being returned in the response.", + "text": "Codecs are responsible for encoding or decoding Documents. The decoding process is used by a client to take a bytestring of an API schema\ndefinition, and returning the Core API Document that represents that interface. A codec should be associated with a particular media type, such as 'application/coreapi+json' . This media type is used by the server in the response Content-Type header,\nin order to indicate what kind of data is being returned in the response.", "title": "Codecs" }, { @@ -4012,7 +4052,7 @@ }, { "location": "/topics/html-and-forms/", - "text": "HTML \n Forms\n\n\nREST framework is suitable for returning both API style responses, and regular HTML pages. Additionally, serializers can used as HTML forms and rendered in templates.\n\n\nRendering HTML\n\n\nIn order to return HTML responses you'll need to either \nTemplateHTMLRenderer\n, or \nStaticHTMLRenderer\n.\n\n\nThe \nTemplateHTMLRenderer\n class expects the response to contain a dictionary of context data, and renders an HTML page based on a template that must be specified either in the view or on the response.\n\n\nThe \nStaticHTMLRender\n class expects the response to contain a string of the pre-rendered HTML content.\n\n\nBecause static HTML pages typically have different behavior from API responses you'll probably need to write any HTML views explicitly, rather than relying on the built-in generic views.\n\n\nHere's an example of a view that returns a list of \"Profile\" instances, rendered in an HTML template:\n\n\nviews.py\n:\n\n\nfrom my_project.example.models import Profile\nfrom rest_framework.renderers import TemplateHTMLRenderer\nfrom rest_framework.response import Response\nfrom rest_framework.views import APIView\n\n\nclass ProfileList(APIView):\n renderer_classes = [TemplateHTMLRenderer]\n template_name = 'profile_list.html'\n\n def get(self, request):\n queryset = Profile.objects.all()\n return Response({'profiles': queryset})\n\n\n\nprofile_list.html\n:\n\n\nhtml\nbody\n\n\nh1\nProfiles\n/h1\n\n\nul\n\n {% for profile in profiles %}\n \nli\n{{ profile.name }}\n/li\n\n {% endfor %}\n\n/ul\n\n\n/body\n/html\n\n\n\n\nRendering Forms\n\n\nSerializers may be rendered as forms by using the \nrender_form\n template tag, and including the serializer instance as context to the template.\n\n\nThe following view demonstrates an example of using a serializer in a template for viewing and updating a model instance:\n\n\nviews.py\n:\n\n\nfrom django.shortcuts import get_object_or_404\nfrom my_project.example.models import Profile\nfrom rest_framework.renderers import TemplateHTMLRenderer\nfrom rest_framework.views import APIView\n\n\nclass ProfileDetail(APIView):\n renderer_classes = [TemplateHTMLRenderer]\n template_name = 'profile_detail.html'\n\n def get(self, request, pk):\n profile = get_object_or_404(Profile, pk=pk)\n serializer = ProfileSerializer(profile)\n return Response({'serializer': serializer, 'profile': profile})\n\n def post(self, request, pk):\n profile = get_object_or_404(Profile, pk=pk)\n serializer = ProfileSerializer(profile, data=request.data)\n if not serializer.is_valid():\n return Response({'serializer': serializer, 'profile': profile})\n serializer.save()\n return redirect('profile-list')\n\n\n\nprofile_detail.html\n:\n\n\n{% load rest_framework %}\n\n\nhtml\nbody\n\n\n\nh1\nProfile - {{ profile.name }}\n/h1\n\n\n\nform action=\"{% url 'profile-detail' pk=profile.pk %}\" method=\"POST\"\n\n {% csrf_token %}\n {% render_form serializer %}\n \ninput type=\"submit\" value=\"Save\"\n\n\n/form\n\n\n\n/body\n/html\n\n\n\n\nUsing template packs\n\n\nThe \nrender_form\n tag takes an optional \ntemplate_pack\n argument, that specifies which template directory should be used for rendering the form and form fields.\n\n\nREST framework includes three built-in template packs, all based on Bootstrap 3. The built-in styles are \nhorizontal\n, \nvertical\n, and \ninline\n. The default style is \nhorizontal\n. To use any of these template packs you'll want to also include the Bootstrap 3 CSS.\n\n\nThe following HTML will link to a CDN hosted version of the Bootstrap 3 CSS:\n\n\nhead\n\n \u2026\n \nlink rel=\"stylesheet\" href=\"https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css\"\n\n\n/head\n\n\n\n\nThird party packages may include alternate template packs, by bundling a template directory containing the necessary form and field templates.\n\n\nLet's take a look at how to render each of the three available template packs. For these examples we'll use a single serializer class to present a \"Login\" form.\n\n\nclass LoginSerializer(serializers.Serializer):\n email = serializers.EmailField(\n max_length=100,\n style={'placeholder': 'Email'}\n )\n password = serializers.CharField(\n max_length=100,\n style={'input_type': 'password', 'placeholder': 'Password'}\n )\n remember_me = serializers.BooleanField()\n\n\n\n\n\nrest_framework/vertical\n\n\nPresents form labels above their corresponding control inputs, using the standard Bootstrap layout.\n\n\nThis is the default template pack.\n\n\n{% load rest_framework %}\n\n...\n\n\nform action=\"{% url 'login' %}\" method=\"post\" novalidate\n\n {% csrf_token %}\n {% render_form serializer template_pack='rest_framework/vertical' %}\n \nbutton type=\"submit\" class=\"btn btn-default\"\nSign in\n/button\n\n\n/form\n\n\n\n\n\n\n\n\nrest_framework/horizontal\n\n\nPresents labels and controls alongside each other, using a 2/10 column split.\n\n\nThis is the form style used in the browsable API and admin renderers.\n\n\n{% load rest_framework %}\n\n...\n\n\nform class=\"form-horizontal\" action=\"{% url 'login' %}\" method=\"post\" novalidate\n\n {% csrf_token %}\n {% render_form serializer %}\n \ndiv class=\"form-group\"\n\n \ndiv class=\"col-sm-offset-2 col-sm-10\"\n\n \nbutton type=\"submit\" class=\"btn btn-default\"\nSign in\n/button\n\n \n/div\n\n \n/div\n\n\n/form\n\n\n\n\n\n\n\n\nrest_framework/inline\n\n\nA compact form style that presents all the controls inline.\n\n\n{% load rest_framework %}\n\n...\n\n\nform class=\"form-inline\" action=\"{% url 'login' %}\" method=\"post\" novalidate\n\n {% csrf_token %}\n {% render_form serializer template_pack='rest_framework/inline' %}\n \nbutton type=\"submit\" class=\"btn btn-default\"\nSign in\n/button\n\n\n/form\n\n\n\n\n\n\nField styles\n\n\nSerializer fields can have their rendering style customized by using the \nstyle\n keyword argument. This argument is a dictionary of options that control the template and layout used.\n\n\nThe most common way to customize the field style is to use the \nbase_template\n style keyword argument to select which template in the template pack should be use.\n\n\nFor example, to render a \nCharField\n as an HTML textarea rather than the default HTML input, you would use something like this:\n\n\ndetails = serializers.CharField(\n max_length=1000,\n style={'base_template': 'textarea.html'}\n)\n\n\n\nIf you instead want a field to be rendered using a custom template that is \nnot part of an included template pack\n, you can instead use the \ntemplate\n style option, to fully specify a template name:\n\n\ndetails = serializers.CharField(\n max_length=1000,\n style={'template': 'my-field-templates/custom-input.html'}\n)\n\n\n\nField templates can also use additional style properties, depending on their type. For example, the \ntextarea.html\n template also accepts a \nrows\n property that can be used to affect the sizing of the control.\n\n\ndetails = serializers.CharField(\n max_length=1000,\n style={'base_template': 'textarea.html', 'rows': 10}\n)\n\n\n\nThe complete list of \nbase_template\n options and their associated style options is listed below.\n\n\n\n\n\n\n\n\nbase_template\n\n\nValid field types\n\n\nAdditional style options\n\n\n\n\n\n\n\n\n\n\ninput.html\n\n\nAny string, numeric or date/time field\n\n\ninput_type, placeholder, hide_label\n\n\n\n\n\n\ntextarea.html\n\n\nCharField\n\n\nrows, placeholder, hide_label\n\n\n\n\n\n\nselect.html\n\n\nChoiceField\n or relational field types\n\n\nhide_label\n\n\n\n\n\n\nradio.html\n\n\nChoiceField\n or relational field types\n\n\ninline, hide_label\n\n\n\n\n\n\nselect_multiple.html\n\n\nMultipleChoiceField\n or relational fields with \nmany=True\n\n\nhide_label\n\n\n\n\n\n\ncheckbox_multiple.html\n\n\nMultipleChoiceField\n or relational fields with \nmany=True\n\n\ninline, hide_label\n\n\n\n\n\n\ncheckbox.html\n\n\nBooleanField\n\n\nhide_label\n\n\n\n\n\n\nfieldset.html\n\n\nNested serializer\n\n\nhide_label\n\n\n\n\n\n\nlist_fieldset.html\n\n\nListField\n or nested serializer with \nmany=True\n\n\nhide_label", + "text": "HTML \n Forms\n\n\nREST framework is suitable for returning both API style responses, and regular HTML pages. Additionally, serializers can used as HTML forms and rendered in templates.\n\n\nRendering HTML\n\n\nIn order to return HTML responses you'll need to either \nTemplateHTMLRenderer\n, or \nStaticHTMLRenderer\n.\n\n\nThe \nTemplateHTMLRenderer\n class expects the response to contain a dictionary of context data, and renders an HTML page based on a template that must be specified either in the view or on the response.\n\n\nThe \nStaticHTMLRender\n class expects the response to contain a string of the pre-rendered HTML content.\n\n\nBecause static HTML pages typically have different behavior from API responses you'll probably need to write any HTML views explicitly, rather than relying on the built-in generic views.\n\n\nHere's an example of a view that returns a list of \"Profile\" instances, rendered in an HTML template:\n\n\nviews.py\n:\n\n\nfrom my_project.example.models import Profile\nfrom rest_framework.renderers import TemplateHTMLRenderer\nfrom rest_framework.response import Response\nfrom rest_framework.views import APIView\n\n\nclass ProfileList(APIView):\n renderer_classes = [TemplateHTMLRenderer]\n template_name = 'profile_list.html'\n\n def get(self, request):\n queryset = Profile.objects.all()\n return Response({'profiles': queryset})\n\n\n\nprofile_list.html\n:\n\n\nhtml\nbody\n\n\nh1\nProfiles\n/h1\n\n\nul\n\n {% for profile in profiles %}\n \nli\n{{ profile.name }}\n/li\n\n {% endfor %}\n\n/ul\n\n\n/body\n/html\n\n\n\n\nRendering Forms\n\n\nSerializers may be rendered as forms by using the \nrender_form\n template tag, and including the serializer instance as context to the template.\n\n\nThe following view demonstrates an example of using a serializer in a template for viewing and updating a model instance:\n\n\nviews.py\n:\n\n\nfrom django.shortcuts import get_object_or_404\nfrom my_project.example.models import Profile\nfrom rest_framework.renderers import TemplateHTMLRenderer\nfrom rest_framework.views import APIView\n\n\nclass ProfileDetail(APIView):\n renderer_classes = [TemplateHTMLRenderer]\n template_name = 'profile_detail.html'\n\n def get(self, request, pk):\n profile = get_object_or_404(Profile, pk=pk)\n serializer = ProfileSerializer(profile)\n return Response({'serializer': serializer, 'profile': profile})\n\n def post(self, request, pk):\n profile = get_object_or_404(Profile, pk=pk)\n serializer = ProfileSerializer(profile, data=request.data)\n if not serializer.is_valid():\n return Response({'serializer': serializer, 'profile': profile})\n serializer.save()\n return redirect('profile-list')\n\n\n\nprofile_detail.html\n:\n\n\n{% load rest_framework %}\n\n\nhtml\nbody\n\n\n\nh1\nProfile - {{ profile.name }}\n/h1\n\n\n\nform action=\"{% url 'profile-detail' pk=profile.pk %}\" method=\"POST\"\n\n {% csrf_token %}\n {% render_form serializer %}\n \ninput type=\"submit\" value=\"Save\"\n\n\n/form\n\n\n\n/body\n/html\n\n\n\n\nUsing template packs\n\n\nThe \nrender_form\n tag takes an optional \ntemplate_pack\n argument, that specifies which template directory should be used for rendering the form and form fields.\n\n\nREST framework includes three built-in template packs, all based on Bootstrap 3. The built-in styles are \nhorizontal\n, \nvertical\n, and \ninline\n. The default style is \nhorizontal\n. To use any of these template packs you'll want to also include the Bootstrap 3 CSS.\n\n\nThe following HTML will link to a CDN hosted version of the Bootstrap 3 CSS:\n\n\nhead\n\n \u2026\n \nlink rel=\"stylesheet\" href=\"https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css\"\n\n\n/head\n\n\n\n\nThird party packages may include alternate template packs, by bundling a template directory containing the necessary form and field templates.\n\n\nLet's take a look at how to render each of the three available template packs. For these examples we'll use a single serializer class to present a \"Login\" form.\n\n\nclass LoginSerializer(serializers.Serializer):\n email = serializers.EmailField(\n max_length=100,\n style={'placeholder': 'Email'}\n )\n password = serializers.CharField(\n max_length=100,\n style={'input_type': 'password', 'placeholder': 'Password'}\n )\n remember_me = serializers.BooleanField()\n\n\n\n\n\nrest_framework/vertical\n\n\nPresents form labels above their corresponding control inputs, using the standard Bootstrap layout.\n\n\nThis is the default template pack.\n\n\n{% load rest_framework %}\n\n...\n\n\nform action=\"{% url 'login' %}\" method=\"post\" novalidate\n\n {% csrf_token %}\n {% render_form serializer template_pack='rest_framework/vertical' %}\n \nbutton type=\"submit\" class=\"btn btn-default\"\nSign in\n/button\n\n\n/form\n\n\n\n\n\n\n\n\nrest_framework/horizontal\n\n\nPresents labels and controls alongside each other, using a 2/10 column split.\n\n\nThis is the form style used in the browsable API and admin renderers.\n\n\n{% load rest_framework %}\n\n...\n\n\nform class=\"form-horizontal\" action=\"{% url 'login' %}\" method=\"post\" novalidate\n\n {% csrf_token %}\n {% render_form serializer %}\n \ndiv class=\"form-group\"\n\n \ndiv class=\"col-sm-offset-2 col-sm-10\"\n\n \nbutton type=\"submit\" class=\"btn btn-default\"\nSign in\n/button\n\n \n/div\n\n \n/div\n\n\n/form\n\n\n\n\n\n\n\n\nrest_framework/inline\n\n\nA compact form style that presents all the controls inline.\n\n\n{% load rest_framework %}\n\n...\n\n\nform class=\"form-inline\" action=\"{% url 'login' %}\" method=\"post\" novalidate\n\n {% csrf_token %}\n {% render_form serializer template_pack='rest_framework/inline' %}\n \nbutton type=\"submit\" class=\"btn btn-default\"\nSign in\n/button\n\n\n/form\n\n\n\n\n\n\nField styles\n\n\nSerializer fields can have their rendering style customized by using the \nstyle\n keyword argument. This argument is a dictionary of options that control the template and layout used.\n\n\nThe most common way to customize the field style is to use the \nbase_template\n style keyword argument to select which template in the template pack should be use.\n\n\nFor example, to render a \nCharField\n as an HTML textarea rather than the default HTML input, you would use something like this:\n\n\ndetails = serializers.CharField(\n max_length=1000,\n style={'base_template': 'textarea.html'}\n)\n\n\n\nIf you instead want a field to be rendered using a custom template that is \nnot part of an included template pack\n, you can instead use the \ntemplate\n style option, to fully specify a template name:\n\n\ndetails = serializers.CharField(\n max_length=1000,\n style={'template': 'my-field-templates/custom-input.html'}\n)\n\n\n\nField templates can also use additional style properties, depending on their type. For example, the \ntextarea.html\n template also accepts a \nrows\n property that can be used to affect the sizing of the control.\n\n\ndetails = serializers.CharField(\n max_length=1000,\n style={'base_template': 'textarea.html', 'rows': 10}\n)\n\n\n\nThe complete list of \nbase_template\n options and their associated style options is listed below.\n\n\n\n\n\n\n\n\nbase_template\n\n\nValid field types\n\n\nAdditional style options\n\n\n\n\n\n\n\n\n\n\ninput.html\n\n\nAny string, numeric or date/time field\n\n\ninput_type, placeholder, hide_label\n\n\n\n\n\n\ntextarea.html\n\n\nCharField\n\n\nrows, placeholder, hide_label\n\n\n\n\n\n\nselect.html\n\n\nChoiceField\nor relational field types\n\n\nhide_label\n\n\n\n\n\n\nradio.html\n\n\nChoiceField\nor relational field types\n\n\ninline, hide_label\n\n\n\n\n\n\nselect_multiple.html\n\n\nMultipleChoiceField\nor relational fields with \nmany=True\n\n\nhide_label\n\n\n\n\n\n\ncheckbox_multiple.html\n\n\nMultipleChoiceField\nor relational fields with \nmany=True\n\n\ninline, hide_label\n\n\n\n\n\n\ncheckbox.html\n\n\nBooleanField\n\n\nhide_label\n\n\n\n\n\n\nfieldset.html\n\n\nNested serializer\n\n\nhide_label\n\n\n\n\n\n\nlist_fieldset.html\n\n\nListField\nor nested serializer with \nmany=True\n\n\nhide_label", "title": "HTML & Forms" }, { @@ -4052,7 +4092,7 @@ }, { "location": "/topics/html-and-forms/#field-styles", - "text": "Serializer fields can have their rendering style customized by using the style keyword argument. This argument is a dictionary of options that control the template and layout used. The most common way to customize the field style is to use the base_template style keyword argument to select which template in the template pack should be use. For example, to render a CharField as an HTML textarea rather than the default HTML input, you would use something like this: details = serializers.CharField(\n max_length=1000,\n style={'base_template': 'textarea.html'}\n) If you instead want a field to be rendered using a custom template that is not part of an included template pack , you can instead use the template style option, to fully specify a template name: details = serializers.CharField(\n max_length=1000,\n style={'template': 'my-field-templates/custom-input.html'}\n) Field templates can also use additional style properties, depending on their type. For example, the textarea.html template also accepts a rows property that can be used to affect the sizing of the control. details = serializers.CharField(\n max_length=1000,\n style={'base_template': 'textarea.html', 'rows': 10}\n) The complete list of base_template options and their associated style options is listed below. base_template Valid field types Additional style options input.html Any string, numeric or date/time field input_type, placeholder, hide_label textarea.html CharField rows, placeholder, hide_label select.html ChoiceField or relational field types hide_label radio.html ChoiceField or relational field types inline, hide_label select_multiple.html MultipleChoiceField or relational fields with many=True hide_label checkbox_multiple.html MultipleChoiceField or relational fields with many=True inline, hide_label checkbox.html BooleanField hide_label fieldset.html Nested serializer hide_label list_fieldset.html ListField or nested serializer with many=True hide_label", + "text": "Serializer fields can have their rendering style customized by using the style keyword argument. This argument is a dictionary of options that control the template and layout used. The most common way to customize the field style is to use the base_template style keyword argument to select which template in the template pack should be use. For example, to render a CharField as an HTML textarea rather than the default HTML input, you would use something like this: details = serializers.CharField(\n max_length=1000,\n style={'base_template': 'textarea.html'}\n) If you instead want a field to be rendered using a custom template that is not part of an included template pack , you can instead use the template style option, to fully specify a template name: details = serializers.CharField(\n max_length=1000,\n style={'template': 'my-field-templates/custom-input.html'}\n) Field templates can also use additional style properties, depending on their type. For example, the textarea.html template also accepts a rows property that can be used to affect the sizing of the control. details = serializers.CharField(\n max_length=1000,\n style={'base_template': 'textarea.html', 'rows': 10}\n) The complete list of base_template options and their associated style options is listed below. base_template Valid field types Additional style options input.html Any string, numeric or date/time field input_type, placeholder, hide_label textarea.html CharField rows, placeholder, hide_label select.html ChoiceField or relational field types hide_label radio.html ChoiceField or relational field types inline, hide_label select_multiple.html MultipleChoiceField or relational fields with many=True hide_label checkbox_multiple.html MultipleChoiceField or relational fields with many=True inline, hide_label checkbox.html BooleanField hide_label fieldset.html Nested serializer hide_label list_fieldset.html ListField or nested serializer with many=True hide_label", "title": "Field styles" }, { @@ -4527,7 +4567,7 @@ }, { "location": "/topics/3.0-announcement/", - "text": "Django REST framework 3.0\n\n\nThe 3.0 release of Django REST framework is the result of almost four years of iteration and refinement. It comprehensively addresses some of the previous remaining design issues in serializers, fields and the generic views.\n\n\nThis release is incremental in nature. There \nare\n some breaking API changes, and upgrading \nwill\n require you to read the release notes carefully, but the migration path should otherwise be relatively straightforward.\n\n\nThe difference in quality of the REST framework API and implementation should make writing, maintaining and debugging your application far easier.\n\n\n3.0 is the first of three releases that have been funded by our recent \nKickstarter campaign\n.\n\n\nAs ever, a huge thank you to our many \nwonderful sponsors\n. If you're looking for a Django gig, and want to work with smart community-minded folks, you should probably check out that list and see who's hiring.\n\n\n\n\nNew features\n\n\nNotable features of this new release include:\n\n\n\n\nPrintable representations on serializers that allow you to inspect exactly what fields are present on the instance.\n\n\nSimple model serializers that are vastly easier to understand and debug, and that make it easy to switch between the implicit \nModelSerializer\n class and the explicit \nSerializer\n class.\n\n\nA new \nBaseSerializer\n class, making it easier to write serializers for alternative storage backends, or to completely customize your serialization and validation logic.\n\n\nA cleaner fields API including new classes such as \nListField\n and \nMultipleChoiceField\n.\n\n\nSuper simple default implementations\n for the generic views.\n\n\nSupport for overriding how validation errors are handled by your API.\n\n\nA metadata API that allows you to customize how \nOPTIONS\n requests are handled by your API.\n\n\nA more compact JSON output with unicode style encoding turned on by default.\n\n\nTemplated based HTML form rendering for serializers. This will be finalized as public API in the upcoming 3.1 release.\n\n\n\n\nSignificant new functionality continues to be planned for the 3.1 and 3.2 releases. These releases will correspond to the two \nKickstarter stretch goals\n - \"Feature improvements\" and \"Admin interface\". Further 3.x releases will present simple upgrades, without the same level of fundamental API changes necessary for the 3.0 release.\n\n\n\n\nREST framework: Under the hood.\n\n\nThis talk from the \nDjango: Under the Hood\n event in Amsterdam, Nov 2014, gives some good background context on the design decisions behind 3.0.\n\n\n\n\n\n\n\nBelow is an in-depth guide to the API changes and migration notes for 3.0.\n\n\nRequest objects\n\n\nThe \n.data\n and \n.query_params\n properties.\n\n\nThe usage of \nrequest.DATA\n and \nrequest.FILES\n is now pending deprecation in favor of a single \nrequest.data\n attribute that contains \nall\n the parsed data.\n\n\nHaving separate attributes is reasonable for web applications that only ever parse url-encoded or multipart requests, but makes less sense for the general-purpose request parsing that REST framework supports.\n\n\nYou may now pass all the request data to a serializer class in a single argument:\n\n\n# Do this...\nExampleSerializer(data=request.data)\n\n\n\nInstead of passing the files argument separately:\n\n\n# Don't do this...\nExampleSerializer(data=request.DATA, files=request.FILES)\n\n\n\nThe usage of \nrequest.QUERY_PARAMS\n is now pending deprecation in favor of the lowercased \nrequest.query_params\n.\n\n\n\n\nSerializers\n\n\nSingle-step object creation.\n\n\nPreviously the serializers used a two-step object creation, as follows:\n\n\n\n\nValidating the data would create an object instance. This instance would be available as \nserializer.object\n.\n\n\nCalling \nserializer.save()\n would then save the object instance to the database.\n\n\n\n\nThis style is in-line with how the \nModelForm\n class works in Django, but is problematic for a number of reasons:\n\n\n\n\nSome data, such as many-to-many relationships, cannot be added to the object instance until after it has been saved. This type of data needed to be hidden in some undocumented state on the object instance, or kept as state on the serializer instance so that it could be used when \n.save()\n is called.\n\n\nInstantiating model instances directly means that you cannot use model manager classes for instance creation, e.g. \nExampleModel.objects.create(...)\n. Manager classes are an excellent layer at which to enforce business logic and application-level data constraints.\n\n\nThe two step process makes it unclear where to put deserialization logic. For example, should extra attributes such as the current user get added to the instance during object creation or during object save?\n\n\n\n\nWe now use single-step object creation, like so:\n\n\n\n\nValidating the data makes the cleaned data available as \nserializer.validated_data\n.\n\n\nCalling \nserializer.save()\n then saves and returns the new object instance.\n\n\n\n\nThe resulting API changes are further detailed below.\n\n\nThe \n.create()\n and \n.update()\n methods.\n\n\nThe \n.restore_object()\n method is now removed, and we instead have two separate methods, \n.create()\n and \n.update()\n. These methods work slightly different to the previous \n.restore_object()\n.\n\n\nWhen using the \n.create()\n and \n.update()\n methods you should both create \nand save\n the object instance. This is in contrast to the previous \n.restore_object()\n behavior that would instantiate the object but not save it.\n\n\nThese methods also replace the optional \n.save_object()\n method, which no longer exists.\n\n\nThe following example from the tutorial previously used \nrestore_object()\n to handle both creating and updating object instances.\n\n\ndef restore_object(self, attrs, instance=None):\n if instance:\n # Update existing instance\n instance.title = attrs.get('title', instance.title)\n instance.code = attrs.get('code', instance.code)\n instance.linenos = attrs.get('linenos', instance.linenos)\n instance.language = attrs.get('language', instance.language)\n instance.style = attrs.get('style', instance.style)\n return instance\n\n # Create new instance\n return Snippet(**attrs)\n\n\n\nThis would now be split out into two separate methods.\n\n\ndef update(self, instance, validated_data):\n instance.title = validated_data.get('title', instance.title)\n instance.code = validated_data.get('code', instance.code)\n instance.linenos = validated_data.get('linenos', instance.linenos)\n instance.language = validated_data.get('language', instance.language)\n instance.style = validated_data.get('style', instance.style)\n instance.save()\n return instance\n\ndef create(self, validated_data):\n return Snippet.objects.create(**validated_data)\n\n\n\nNote that these methods should return the newly created object instance.\n\n\nUse \n.validated_data\n instead of \n.object\n.\n\n\nYou must now use the \n.validated_data\n attribute if you need to inspect the data before saving, rather than using the \n.object\n attribute, which no longer exists.\n\n\nFor example the following code \nis no longer valid\n:\n\n\nif serializer.is_valid():\n name = serializer.object.name # Inspect validated field data.\n logging.info('Creating ticket \"%s\"' % name)\n serializer.object.user = request.user # Include the user when saving.\n serializer.save()\n\n\n\nInstead of using \n.object\n to inspect a partially constructed instance, you would now use \n.validated_data\n to inspect the cleaned incoming values. Also you can't set extra attributes on the instance directly, but instead pass them to the \n.save()\n method as keyword arguments.\n\n\nThe corresponding code would now look like this:\n\n\nif serializer.is_valid():\n name = serializer.validated_data['name'] # Inspect validated field data.\n logging.info('Creating ticket \"%s\"' % name)\n serializer.save(user=request.user) # Include the user when saving.\n\n\n\nUsing \n.is_valid(raise_exception=True)\n\n\nThe \n.is_valid()\n method now takes an optional boolean flag, \nraise_exception\n.\n\n\nCalling \n.is_valid(raise_exception=True)\n will cause a \nValidationError\n to be raised if the serializer data contains validation errors. This error will be handled by REST framework's default exception handler, allowing you to remove error response handling from your view code.\n\n\nThe handling and formatting of error responses may be altered globally by using the \nEXCEPTION_HANDLER\n settings key.\n\n\nThis change also means it's now possible to alter the style of error responses used by the built-in generic views, without having to include mixin classes or other overrides.\n\n\nUsing \nserializers.ValidationError\n.\n\n\nPreviously \nserializers.ValidationError\n error was simply a synonym for \ndjango.core.exceptions.ValidationError\n. This has now been altered so that it inherits from the standard \nAPIException\n base class.\n\n\nThe reason behind this is that Django's \nValidationError\n class is intended for use with HTML forms and its API makes using it slightly awkward with nested validation errors that can occur in serializers.\n\n\nFor most users this change shouldn't require any updates to your codebase, but it is worth ensuring that whenever raising validation errors you should prefer using the \nserializers.ValidationError\n exception class, and not Django's built-in exception.\n\n\nWe strongly recommend that you use the namespaced import style of \nimport serializers\n and not \nfrom serializers import ValidationError\n in order to avoid any potential confusion.\n\n\nChange to \nvalidate_\nfield_name\n.\n\n\nThe \nvalidate_\nfield_name\n method hooks that can be attached to serializer classes change their signature slightly and return type. Previously these would take a dictionary of all incoming data, and a key representing the field name, and would return a dictionary including the validated data for that field:\n\n\ndef validate_score(self, attrs, source):\n if attrs['score'] % 10 != 0:\n raise serializers.ValidationError('This field should be a multiple of ten.')\n return attrs\n\n\n\nThis is now simplified slightly, and the method hooks simply take the value to be validated, and return the validated value.\n\n\ndef validate_score(self, value):\n if value % 10 != 0:\n raise serializers.ValidationError('This field should be a multiple of ten.')\n return value\n\n\n\nAny ad-hoc validation that applies to more than one field should go in the \n.validate(self, attrs)\n method as usual.\n\n\nBecause \n.validate_\nfield_name\n would previously accept the complete dictionary of attributes, it could be used to validate a field depending on the input in another field. Now if you need to do this you should use \n.validate()\n instead.\n\n\nYou can either return \nnon_field_errors\n from the validate method by raising a simple \nValidationError\n\n\ndef validate(self, attrs):\n # serializer.errors == {'non_field_errors': ['A non field error']}\n raise serializers.ValidationError('A non field error')\n\n\n\nAlternatively if you want the errors to be against a specific field, use a dictionary of when instantiating the \nValidationError\n, like so:\n\n\ndef validate(self, attrs):\n # serializer.errors == {'my_field': ['A field error']}\n raise serializers.ValidationError({'my_field': 'A field error'})\n\n\n\nThis ensures you can still write validation that compares all the input fields, but that marks the error against a particular field.\n\n\nRemoval of \ntransform_\nfield_name\n.\n\n\nThe under-used \ntransform_\nfield_name\n on serializer classes is no longer provided. Instead you should just override \nto_representation()\n if you need to apply any modifications to the representation style.\n\n\nFor example:\n\n\ndef to_representation(self, instance):\n ret = super(UserSerializer, self).to_representation(instance)\n ret['username'] = ret['username'].lower()\n return ret\n\n\n\nDropping the extra point of API means there's now only one right way to do things. This helps with repetition and reinforcement of the core API, rather than having multiple differing approaches.\n\n\nIf you absolutely need to preserve \ntransform_\nfield_name\n behavior, for example, in order to provide a simpler 2.x to 3.0 upgrade, you can use a mixin, or serializer base class that add the behavior back in. For example:\n\n\nclass BaseModelSerializer(ModelSerializer):\n \"\"\"\n A custom ModelSerializer class that preserves 2.x style `transform_\nfield_name\n` behavior.\n \"\"\"\n def to_representation(self, instance):\n ret = super(BaseModelSerializer, self).to_representation(instance)\n for key, value in ret.items():\n method = getattr(self, 'transform_' + key, None)\n if method is not None:\n ret[key] = method(value)\n return ret\n\n\n\nDifferences between ModelSerializer validation and ModelForm.\n\n\nThis change also means that we no longer use the \n.full_clean()\n method on model instances, but instead perform all validation explicitly on the serializer. This gives a cleaner separation, and ensures that there's no automatic validation behavior on \nModelSerializer\n classes that can't also be easily replicated on regular \nSerializer\n classes.\n\n\nFor the most part this change should be transparent. Field validation and uniqueness checks will still be run as normal, but the implementation is a little different.\n\n\nThe one difference that you do need to note is that the \n.clean()\n method will not be called as part of serializer validation, as it would be if using a \nModelForm\n. Use the serializer \n.validate()\n method to perform a final validation step on incoming data where required.\n\n\nThere may be some cases where you really do need to keep validation logic in the model \n.clean()\n method, and cannot instead separate it into the serializer \n.validate()\n. You can do so by explicitly instantiating a model instance in the \n.validate()\n method.\n\n\ndef validate(self, attrs):\n instance = ExampleModel(**attrs)\n instance.clean()\n return attrs\n\n\n\nAgain, you really should look at properly separating the validation logic out of the model method if possible, but the above might be useful in some backwards compatibility cases, or for an easy migration path.\n\n\nWritable nested serialization.\n\n\nREST framework 2.x attempted to automatically support writable nested serialization, but the behavior was complex and non-obvious. Attempting to automatically handle these case is problematic:\n\n\n\n\nThere can be complex dependencies involved in order of saving multiple related model instances.\n\n\nIt's unclear what behavior the user should expect when related models are passed \nNone\n data.\n\n\nIt's unclear how the user should expect to-many relationships to handle updates, creations and deletions of multiple records.\n\n\n\n\nUsing the \ndepth\n option on \nModelSerializer\n will now create \nread-only nested serializers\n by default.\n\n\nIf you try to use a writable nested serializer without writing a custom \ncreate()\n and/or \nupdate()\n method you'll see an assertion error when you attempt to save the serializer. For example:\n\n\n class ProfileSerializer(serializers.ModelSerializer):\n\n class Meta:\n\n model = Profile\n\n fields = ('address', 'phone')\n\n\n\n class UserSerializer(serializers.ModelSerializer):\n\n profile = ProfileSerializer()\n\n class Meta:\n\n model = User\n\n fields = ('username', 'email', 'profile')\n\n\n\n data = {\n\n 'username': 'lizzy',\n\n 'email': 'lizzy@example.com',\n\n 'profile': {'address': '123 Acacia Avenue', 'phone': '01273 100200'}\n\n }\n\n\n\n serializer = UserSerializer(data=data)\n\n serializer.save()\nAssertionError: The `.create()` method does not support nested writable fields by default. Write an explicit `.create()` method for serializer `UserSerializer`, or set `read_only=True` on nested serializer fields.\n\n\n\nTo use writable nested serialization you'll want to declare a nested field on the serializer class, and write the \ncreate()\n and/or \nupdate()\n methods explicitly.\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\nThe single-step object creation makes this far simpler and more obvious than the previous \n.restore_object()\n behavior.\n\n\nPrintable serializer representations.\n\n\nSerializer instances now support a printable representation that allows you to inspect the fields present on the instance.\n\n\nFor instance, given the following example model:\n\n\nclass LocationRating(models.Model):\n location = models.CharField(max_length=100)\n rating = models.IntegerField()\n created_by = models.ForeignKey(User)\n\n\n\nLet's create a simple \nModelSerializer\n class corresponding to the \nLocationRating\n model.\n\n\nclass LocationRatingSerializer(serializer.ModelSerializer):\n class Meta:\n model = LocationRating\n\n\n\nWe can now inspect the serializer representation in the Django shell, using \npython manage.py shell\n...\n\n\n serializer = LocationRatingSerializer()\n\n print(serializer) # Or use `print serializer` in Python 2.x\nLocationRatingSerializer():\n id = IntegerField(label='ID', read_only=True)\n location = CharField(max_length=100)\n rating = IntegerField()\n created_by = PrimaryKeyRelatedField(queryset=User.objects.all())\n\n\n\nThe \nextra_kwargs\n option.\n\n\nThe \nwrite_only_fields\n option on \nModelSerializer\n has been moved to \nPendingDeprecation\n and replaced with a more generic \nextra_kwargs\n.\n\n\nclass MySerializer(serializer.ModelSerializer):\n class Meta:\n model = MyModel\n fields = ('id', 'email', 'notes', 'is_admin')\n extra_kwargs = {\n 'is_admin': {'write_only': True}\n }\n\n\n\nAlternatively, specify the field explicitly on the serializer class:\n\n\nclass MySerializer(serializer.ModelSerializer):\n is_admin = serializers.BooleanField(write_only=True)\n\n class Meta:\n model = MyModel\n fields = ('id', 'email', 'notes', 'is_admin')\n\n\n\nThe \nread_only_fields\n option remains as a convenient shortcut for the more common case.\n\n\nChanges to \nHyperlinkedModelSerializer\n.\n\n\nThe \nview_name\n and \nlookup_field\n options have been moved to \nPendingDeprecation\n. They are no longer required, as you can use the \nextra_kwargs\n argument instead:\n\n\nclass MySerializer(serializer.HyperlinkedModelSerializer):\n class Meta:\n model = MyModel\n fields = ('url', 'email', 'notes', 'is_admin')\n extra_kwargs = {\n 'url': {'lookup_field': 'uuid'}\n }\n\n\n\nAlternatively, specify the field explicitly on the serializer class:\n\n\nclass MySerializer(serializer.HyperlinkedModelSerializer):\n url = serializers.HyperlinkedIdentityField(\n view_name='mymodel-detail',\n lookup_field='uuid'\n )\n\n class Meta:\n model = MyModel\n fields = ('url', 'email', 'notes', 'is_admin')\n\n\n\nFields for model methods and properties.\n\n\nWith \nModelSerializer\n you can now specify field names in the \nfields\n option that refer to model methods or properties. For example, suppose you have the following model:\n\n\nclass Invitation(models.Model):\n created = models.DateTimeField()\n to_email = models.EmailField()\n message = models.CharField(max_length=1000)\n\n def expiry_date(self):\n return self.created + datetime.timedelta(days=30)\n\n\n\nYou can include \nexpiry_date\n as a field option on a \nModelSerializer\n class.\n\n\nclass InvitationSerializer(serializers.ModelSerializer):\n class Meta:\n model = Invitation\n fields = ('to_email', 'message', 'expiry_date')\n\n\n\nThese fields will be mapped to \nserializers.ReadOnlyField()\n instances.\n\n\n serializer = InvitationSerializer()\n\n print repr(serializer)\nInvitationSerializer():\n to_email = EmailField(max_length=75)\n message = CharField(max_length=1000)\n expiry_date = ReadOnlyField()\n\n\n\nThe \nListSerializer\n class.\n\n\nThe \nListSerializer\n class has now been added, and allows you to create base serializer classes for only accepting multiple inputs.\n\n\nclass MultipleUserSerializer(ListSerializer):\n child = UserSerializer()\n\n\n\nYou can also still use the \nmany=True\n argument to serializer classes. It's worth noting that \nmany=True\n argument transparently creates a \nListSerializer\n instance, allowing the validation logic for list and non-list data to be cleanly separated in the REST framework codebase.\n\n\nYou will typically want to \ncontinue to use the existing \nmany=True\n flag\n rather than declaring \nListSerializer\n classes explicitly, but declaring the classes explicitly can be useful if you need to write custom \ncreate\n or \nupdate\n methods for bulk updates, or provide for other custom behavior.\n\n\nSee also the new \nListField\n class, which validates input in the same way, but does not include the serializer interfaces of \n.is_valid()\n, \n.data\n, \n.save()\n and so on.\n\n\nThe \nBaseSerializer\n class.\n\n\nREST framework now includes a simple \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 an 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) \n 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 generic serializers with \nBaseSerializer\n.\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\nSerializer fields\n\n\nThe \nField\n and \nReadOnly\n field classes.\n\n\nThere are some minor tweaks to the field base classes.\n\n\nPreviously we had these two base classes:\n\n\n\n\nField\n as the base class for read-only fields. A default implementation was included for serializing data.\n\n\nWritableField\n as the base class for read-write fields.\n\n\n\n\nWe now use the following:\n\n\n\n\nField\n is the base class for all fields. It does not include any default implementation for either serializing or deserializing data.\n\n\nReadOnlyField\n is a concrete implementation for read-only fields that simply returns the attribute value without modification.\n\n\n\n\nThe \nrequired\n, \nallow_null\n, \nallow_blank\n and \ndefault\n arguments.\n\n\nREST framework now has more explicit and clear control over validating empty values for fields.\n\n\nPreviously the meaning of the \nrequired=False\n keyword argument was underspecified. In practice its use meant that a field could either be not included in the input, or it could be included, but be \nNone\n or the empty string.\n\n\nWe now have a better separation, with separate \nrequired\n, \nallow_null\n and \nallow_blank\n arguments.\n\n\nThe following set of arguments are used to control validation of empty values:\n\n\n\n\nrequired=False\n: The value does not need to be present in the input, and will not be passed to \n.create()\n or \n.update()\n if it is not seen.\n\n\ndefault=\nvalue\n: The value does not need to be present in the input, and a default value will be passed to \n.create()\n or \n.update()\n if it is not seen.\n\n\nallow_null=True\n: \nNone\n is a valid input.\n\n\nallow_blank=True\n: \n''\n is valid input. For \nCharField\n and subclasses only.\n\n\n\n\nTypically you'll want to use \nrequired=False\n if the corresponding model field has a default value, and additionally set either \nallow_null=True\n or \nallow_blank=True\n if required.\n\n\nThe \ndefault\n argument is also available and always implies that the field is not required to be in the input. It is unnecessary to use the \nrequired\n argument when a default is specified, and doing so will result in an error.\n\n\nCoercing output types.\n\n\nThe previous field implementations did not forcibly coerce returned values into the correct type in many cases. For example, an \nIntegerField\n would return a string output if the attribute value was a string. We now more strictly coerce to the correct return type, leading to more constrained and expected behavior.\n\n\nRemoval of \n.validate()\n.\n\n\nThe \n.validate()\n method is now removed from field classes. This method was in any case undocumented and not public API. You should instead simply override \nto_internal_value()\n.\n\n\nclass UppercaseCharField(serializers.CharField):\n def to_internal_value(self, data):\n value = super(UppercaseCharField, self).to_internal_value(data)\n if value != value.upper():\n raise serializers.ValidationError('The input should be uppercase only.')\n return value\n\n\n\nPreviously validation errors could be raised in either \n.to_native()\n or \n.validate()\n, making it non-obvious which should be used. Providing only a single point of API ensures more repetition and reinforcement of the core API.\n\n\nThe \nListField\n class.\n\n\nThe \nListField\n class has now been added. This field validates list input. It takes a \nchild\n keyword argument which is used to specify the field used to validate each item in the list. For example:\n\n\nscores = ListField(child=IntegerField(min_value=0, max_value=100))\n\n\n\nYou can also use a declarative style to create new subclasses of \nListField\n, like this:\n\n\nclass ScoresField(ListField):\n child = IntegerField(min_value=0, max_value=100)\n\n\n\nWe can now use the \nScoresField\n class inside another serializer:\n\n\nscores = ScoresField()\n\n\n\nSee also the new \nListSerializer\n class, which validates input in the same way, but also includes the serializer interfaces of \n.is_valid()\n, \n.data\n, \n.save()\n and so on.\n\n\nThe \nChoiceField\n class may now accept a flat list.\n\n\nThe \nChoiceField\n class may now accept a list of choices in addition to the existing style of using a list of pairs of \n(name, display_value)\n. The following is now valid:\n\n\ncolor = ChoiceField(choices=['red', 'green', 'blue'])\n\n\n\nThe \nMultipleChoiceField\n class.\n\n\nThe \nMultipleChoiceField\n class has been added. This field acts like \nChoiceField\n, but returns a set, which may include none, one or many of the valid choices.\n\n\nChanges to the custom field API.\n\n\nThe \nfrom_native(self, value)\n and \nto_native(self, data)\n method names have been replaced with the more obviously named \nto_internal_value(self, data)\n and \nto_representation(self, value)\n.\n\n\nThe \nfield_from_native()\n and \nfield_to_native()\n methods are removed. Previously you could use these methods if you wanted to customise the behaviour in a way that did not simply lookup the field value from the object. For example...\n\n\ndef field_to_native(self, obj, field_name):\n \"\"\"A custom read-only field that returns the class name.\"\"\"\n return obj.__class__.__name__\n\n\n\nNow if you need to access the entire object you'll instead need to override one or both of the following:\n\n\n\n\nUse \nget_attribute\n to modify the attribute value passed to \nto_representation()\n.\n\n\nUse \nget_value\n to modify the data value passed \nto_internal_value()\n.\n\n\n\n\nFor example:\n\n\ndef get_attribute(self, obj):\n # Pass the entire object through to `to_representation()`,\n # instead of the standard attribute lookup.\n return obj\n\ndef to_representation(self, value):\n return value.__class__.__name__\n\n\n\nExplicit \nqueryset\n required on relational fields.\n\n\nPreviously relational fields that were explicitly declared on a serializer class could omit the queryset argument if (and only if) they were declared on a \nModelSerializer\n.\n\n\nThis code \nwould be valid\n in \n2.4.3\n:\n\n\nclass AccountSerializer(serializers.ModelSerializer):\n organizations = serializers.SlugRelatedField(slug_field='name')\n\n class Meta:\n model = Account\n\n\n\nHowever this code \nwould not be valid\n in \n3.0\n:\n\n\n# Missing `queryset`\nclass AccountSerializer(serializers.Serializer):\n organizations = serializers.SlugRelatedField(slug_field='name')\n\n def restore_object(self, attrs, instance=None):\n # ...\n\n\n\nThe queryset argument is now always required for writable relational fields.\nThis removes some magic and makes it easier and more obvious to move between implicit \nModelSerializer\n classes and explicit \nSerializer\n classes.\n\n\nclass AccountSerializer(serializers.ModelSerializer):\n organizations = serializers.SlugRelatedField(\n slug_field='name',\n queryset=Organization.objects.all()\n )\n\n class Meta:\n model = Account\n\n\n\nThe \nqueryset\n argument is only ever required for writable fields, and is not required or valid for fields with \nread_only=True\n.\n\n\nOptional argument to \nSerializerMethodField\n.\n\n\nThe argument to \nSerializerMethodField\n is now optional, and defaults to \nget_\nfield_name\n. For example the following is valid:\n\n\nclass AccountSerializer(serializers.Serializer):\n # `method_name='get_billing_details'` by default.\n billing_details = serializers.SerializerMethodField()\n\n def get_billing_details(self, account):\n return calculate_billing(account)\n\n\n\nIn order to ensure a consistent code style an assertion error will be raised if you include a redundant method name argument that matches the default method name. For example, the following code \nwill raise an error\n:\n\n\nbilling_details = serializers.SerializerMethodField('get_billing_details')\n\n\n\nEnforcing consistent \nsource\n usage.\n\n\nI've see several codebases that unnecessarily include the \nsource\n argument, setting it to the same value as the field name. This usage is redundant and confusing, making it less obvious that \nsource\n is usually not required.\n\n\nThe following usage will \nnow raise an error\n:\n\n\nemail = serializers.EmailField(source='email')\n\n\n\nThe \nUniqueValidator\n and \nUniqueTogetherValidator\n classes.\n\n\nREST framework now provides new validators that allow you to ensure field uniqueness, while still using a completely explicit \nSerializer\n class instead of using \nModelSerializer\n.\n\n\nThe \nUniqueValidator\n should be applied to a serializer field, and takes a single \nqueryset\n argument.\n\n\nfrom rest_framework import serializers\nfrom rest_framework.validators import UniqueValidator\n\nclass OrganizationSerializer(serializers.Serializer):\n url = serializers.HyperlinkedIdentityField(view_name='organization_detail')\n created = serializers.DateTimeField(read_only=True)\n name = serializers.CharField(\n max_length=100,\n validators=UniqueValidator(queryset=Organization.objects.all())\n )\n\n\n\nThe \nUniqueTogetherValidator\n should be applied to a serializer, and takes a \nqueryset\n argument and a \nfields\n argument which should be a list or tuple of field names.\n\n\nclass RaceResultSerializer(serializers.Serializer):\n category = serializers.ChoiceField(['5k', '10k'])\n position = serializers.IntegerField()\n name = serializers.CharField(max_length=100)\n\n class Meta:\n validators = [UniqueTogetherValidator(\n queryset=RaceResult.objects.all(),\n fields=('category', 'position')\n )]\n\n\n\nThe \nUniqueForDateValidator\n classes.\n\n\nREST framework also now includes explicit validator classes for validating the \nunique_for_date\n, \nunique_for_month\n, and \nunique_for_year\n model field constraints. These are used internally instead of calling into \nModel.full_clean()\n.\n\n\nThese classes are documented in the \nValidators\n section of the documentation.\n\n\n\n\nGeneric views\n\n\nSimplification of view logic.\n\n\nThe view logic for the default method handlers has been significantly simplified, due to the new serializers API.\n\n\nChanges to pre/post save hooks.\n\n\nThe \npre_save\n and \npost_save\n hooks no longer exist, but are replaced with \nperform_create(self, serializer)\n and \nperform_update(self, serializer)\n.\n\n\nThese methods should save the object instance by calling \nserializer.save()\n, adding in any additional arguments as required. They may also perform any custom pre-save or post-save behavior.\n\n\nFor example:\n\n\ndef perform_create(self, serializer):\n # Include the owner attribute directly, rather than from request data.\n instance = serializer.save(owner=self.request.user)\n # Perform a custom post-save action.\n send_email(instance.to_email, instance.message)\n\n\n\nThe \npre_delete\n and \npost_delete\n hooks no longer exist, and are replaced with \n.perform_destroy(self, instance)\n, which should delete the instance and perform any custom actions.\n\n\ndef perform_destroy(self, instance):\n # Perform a custom pre-delete action.\n send_deletion_alert(user=instance.created_by, deleted=instance)\n # Delete the object instance.\n instance.delete()\n\n\n\nRemoval of view attributes.\n\n\nThe \n.object\n and \n.object_list\n attributes are no longer set on the view instance. Treating views as mutable object instances that store state during the processing of the view tends to be poor design, and can lead to obscure flow logic.\n\n\nI would personally recommend that developers treat view instances as immutable objects in their application code.\n\n\nPUT as create.\n\n\nAllowing \nPUT\n as create operations is problematic, as it necessarily exposes information about the existence or non-existence of objects. It's also not obvious that transparently allowing re-creating of previously deleted instances is necessarily a better default behavior than simply returning \n404\n responses.\n\n\nBoth styles \"\nPUT\n as 404\" and \"\nPUT\n as create\" can be valid in different circumstances, but we've now opted for the 404 behavior as the default, due to it being simpler and more obvious.\n\n\nIf you need to restore the previous behavior you may want to include \nthis \nAllowPUTAsCreateMixin\n class\n as a mixin to your views.\n\n\nCustomizing error responses.\n\n\nThe generic views now raise \nValidationFailed\n exception for invalid data. This exception is then dealt with by the exception handler, rather than the view returning a \n400 Bad Request\n response directly.\n\n\nThis change means that you can now easily customize the style of error responses across your entire API, without having to modify any of the generic views.\n\n\n\n\nThe metadata API\n\n\nBehavior for dealing with \nOPTIONS\n requests was previously built directly into the class-based views. This has now been properly separated out into a Metadata API that allows the same pluggable style as other API policies in REST framework.\n\n\nThis makes it far easier to use a different style for \nOPTIONS\n responses throughout your API, and makes it possible to create third-party metadata policies.\n\n\n\n\nSerializers as HTML forms\n\n\nREST framework 3.0 includes templated HTML form rendering for serializers.\n\n\nThis API should not yet be considered finalized, and will only be promoted to public API for the 3.1 release.\n\n\nSignificant changes that you do need to be aware of include:\n\n\n\n\nNested HTML forms are now supported, for example, a \nUserSerializer\n with a nested \nProfileSerializer\n will now render a nested \nfieldset\n when used in the browsable API.\n\n\nNested lists of HTML forms are not yet supported, but are planned for 3.1.\n\n\nBecause we now use templated HTML form generation, \nthe \nwidget\n option is no longer available for serializer fields\n. You can instead control the template that is used for a given field, by using the \nstyle\n dictionary.\n\n\n\n\nThe \nstyle\n keyword argument for serializer fields.\n\n\nThe \nstyle\n keyword argument can be used to pass through additional information from a serializer field, to the renderer class. In particular, the \nHTMLFormRenderer\n uses the \nbase_template\n key to determine which template to render the field with.\n\n\nFor example, to use a \ntextarea\n control instead of the default \ninput\n control, you would use the following\u2026\n\n\nadditional_notes = serializers.CharField(\n style={'base_template': 'textarea.html'}\n)\n\n\n\nSimilarly, to use a radio button control instead of the default \nselect\n control, you would use the following\u2026\n\n\ncolor_channel = serializers.ChoiceField(\n choices=['red', 'blue', 'green'],\n style={'base_template': 'radio.html'}\n)\n\n\n\nThis API should be considered provisional, and there may be minor alterations with the incoming 3.1 release.\n\n\n\n\nAPI style\n\n\nThere are some improvements in the default style we use in our API responses.\n\n\nUnicode JSON by default.\n\n\nUnicode JSON is now the default. The \nUnicodeJSONRenderer\n class no longer exists, and the \nUNICODE_JSON\n setting has been added. To revert this behavior use the new setting:\n\n\nREST_FRAMEWORK = {\n 'UNICODE_JSON': False\n}\n\n\n\nCompact JSON by default.\n\n\nWe now output compact JSON in responses by default. For example, we return:\n\n\n{\"email\":\"amy@example.com\",\"is_admin\":true}\n\n\n\nInstead of the following:\n\n\n{\"email\": \"amy@example.com\", \"is_admin\": true}\n\n\n\nThe \nCOMPACT_JSON\n setting has been added, and can be used to revert this behavior if needed:\n\n\nREST_FRAMEWORK = {\n 'COMPACT_JSON': False\n}\n\n\n\nFile fields as URLs\n\n\nThe \nFileField\n and \nImageField\n classes are now represented as URLs by default. You should ensure you set Django's \nstandard \nMEDIA_URL\n setting\n appropriately, and ensure your application \nserves the uploaded files\n.\n\n\nYou can revert this behavior, and display filenames in the representation by using the \nUPLOADED_FILES_USE_URL\n settings key:\n\n\nREST_FRAMEWORK = {\n 'UPLOADED_FILES_USE_URL': False\n}\n\n\n\nYou can also modify serializer fields individually, using the \nuse_url\n argument:\n\n\nuploaded_file = serializers.FileField(use_url=False)\n\n\n\nAlso note that you should pass the \nrequest\n object to the serializer as context when instantiating it, so that a fully qualified URL can be returned. Returned URLs will then be of the form \nhttps://example.com/url_path/filename.txt\n. For example:\n\n\ncontext = {'request': request}\nserializer = ExampleSerializer(instance, context=context)\nreturn Response(serializer.data)\n\n\n\nIf the request is omitted from the context, the returned URLs will be of the form \n/url_path/filename.txt\n.\n\n\nThrottle headers using \nRetry-After\n.\n\n\nThe custom \nX-Throttle-Wait-Second\n header has now been dropped in favor of the standard \nRetry-After\n header. You can revert this behavior if needed by writing a custom exception handler for your application.\n\n\nDate and time objects as ISO-8859-1 strings in serializer data.\n\n\nDate and Time objects are now coerced to strings by default in the serializer output. Previously they were returned as \nDate\n, \nTime\n and \nDateTime\n objects, and later coerced to strings by the renderer.\n\n\nYou can modify this behavior globally by settings the existing \nDATE_FORMAT\n, \nDATETIME_FORMAT\n and \nTIME_FORMAT\n settings keys. Setting these values to \nNone\n instead of their default value of \n'iso-8859-1'\n will result in native objects being returned in serializer data.\n\n\nREST_FRAMEWORK = {\n # Return native `Date` and `Time` objects in `serializer.data`\n 'DATETIME_FORMAT': None\n 'DATE_FORMAT': None\n 'TIME_FORMAT': None\n}\n\n\n\nYou can also modify serializer fields individually, using the \ndate_format\n, \ntime_format\n and \ndatetime_format\n arguments:\n\n\n# Return `DateTime` instances in `serializer.data`, not strings.\ncreated = serializers.DateTimeField(format=None)\n\n\n\nDecimals as strings in serializer data.\n\n\nDecimals are now coerced to strings by default in the serializer output. Previously they were returned as \nDecimal\n objects, and later coerced to strings by the renderer.\n\n\nYou can modify this behavior globally by using the \nCOERCE_DECIMAL_TO_STRING\n settings key.\n\n\nREST_FRAMEWORK = {\n 'COERCE_DECIMAL_TO_STRING': False\n}\n\n\n\nOr modify it on an individual serializer field, using the \ncoerce_to_string\n keyword argument.\n\n\n# Return `Decimal` instances in `serializer.data`, not strings.\namount = serializers.DecimalField(\n max_digits=10,\n decimal_places=2,\n coerce_to_string=False\n)\n\n\n\nThe default JSON renderer will return float objects for un-coerced \nDecimal\n instances. This allows you to easily switch between string or float representations for decimals depending on your API design needs.\n\n\n\n\nMiscellaneous notes\n\n\n\n\nThe serializer \nChoiceField\n does not currently display nested choices, as was the case in 2.4. This will be address as part of 3.1.\n\n\nDue to the new templated form rendering, the 'widget' option is no longer valid. This means there's no easy way of using third party \"autocomplete\" widgets for rendering select inputs that contain a large number of choices. You'll either need to use a regular select or a plain text input. We may consider addressing this in 3.1 or 3.2 if there's sufficient demand.\n\n\nSome of the default validation error messages were rewritten and might no longer be pre-translated. You can still \ncreate language files with Django\n if you wish to localize them.\n\n\nAPIException\n subclasses could previously take any arbitrary type in the \ndetail\n argument. These exceptions now use translatable text strings, and as a result call \nforce_text\n on the \ndetail\n argument, which \nmust be a string\n. If you need complex arguments to an \nAPIException\n class, you should subclass it and override the \n__init__()\n method. Typically you'll instead want to use a custom exception handler to provide for non-standard error responses.\n\n\n\n\n\n\nWhat's coming next\n\n\n3.0 is an incremental release, and there are several upcoming features that will build on the baseline improvements that it makes.\n\n\nThe 3.1 release is planned to address improvements in the following components:\n\n\n\n\nPublic API for using serializers as HTML forms.\n\n\nRequest parsing, mediatypes \n the implementation of the browsable API.\n\n\nIntroduction of a new pagination API.\n\n\nBetter support for API versioning.\n\n\n\n\nThe 3.2 release is planned to introduce an alternative admin-style interface to the browsable API.\n\n\nYou can follow development on the GitHub site, where we use \nmilestones to indicate planning timescales\n.", + "text": "Django REST framework 3.0\n\n\nThe 3.0 release of Django REST framework is the result of almost four years of iteration and refinement. It comprehensively addresses some of the previous remaining design issues in serializers, fields and the generic views.\n\n\nThis release is incremental in nature. There \nare\n some breaking API changes, and upgrading \nwill\n require you to read the release notes carefully, but the migration path should otherwise be relatively straightforward.\n\n\nThe difference in quality of the REST framework API and implementation should make writing, maintaining and debugging your application far easier.\n\n\n3.0 is the first of three releases that have been funded by our recent \nKickstarter campaign\n.\n\n\nAs ever, a huge thank you to our many \nwonderful sponsors\n. If you're looking for a Django gig, and want to work with smart community-minded folks, you should probably check out that list and see who's hiring.\n\n\n\n\nNew features\n\n\nNotable features of this new release include:\n\n\n\n\nPrintable representations on serializers that allow you to inspect exactly what fields are present on the instance.\n\n\nSimple model serializers that are vastly easier to understand and debug, and that make it easy to switch between the implicit \nModelSerializer\n class and the explicit \nSerializer\n class.\n\n\nA new \nBaseSerializer\n class, making it easier to write serializers for alternative storage backends, or to completely customize your serialization and validation logic.\n\n\nA cleaner fields API including new classes such as \nListField\n and \nMultipleChoiceField\n.\n\n\nSuper simple default implementations\n for the generic views.\n\n\nSupport for overriding how validation errors are handled by your API.\n\n\nA metadata API that allows you to customize how \nOPTIONS\n requests are handled by your API.\n\n\nA more compact JSON output with unicode style encoding turned on by default.\n\n\nTemplated based HTML form rendering for serializers. This will be finalized as public API in the upcoming 3.1 release.\n\n\n\n\nSignificant new functionality continues to be planned for the 3.1 and 3.2 releases. These releases will correspond to the two \nKickstarter stretch goals\n - \"Feature improvements\" and \"Admin interface\". Further 3.x releases will present simple upgrades, without the same level of fundamental API changes necessary for the 3.0 release.\n\n\n\n\nREST framework: Under the hood.\n\n\nThis talk from the \nDjango: Under the Hood\n event in Amsterdam, Nov 2014, gives some good background context on the design decisions behind 3.0.\n\n\n\n\n\n\n\nBelow is an in-depth guide to the API changes and migration notes for 3.0.\n\n\nRequest objects\n\n\n.query_params\n properties.\nThe \n.data\n and \n\n\nThe usage of \nrequest.DATA\n and \nrequest.FILES\n is now pending deprecation in favor of a single \nrequest.data\n attribute that contains \nall\n the parsed data.\n\n\nHaving separate attributes is reasonable for web applications that only ever parse url-encoded or multipart requests, but makes less sense for the general-purpose request parsing that REST framework supports.\n\n\nYou may now pass all the request data to a serializer class in a single argument:\n\n\n# Do this...\nExampleSerializer(data=request.data)\n\n\n\nInstead of passing the files argument separately:\n\n\n# Don't do this...\nExampleSerializer(data=request.DATA, files=request.FILES)\n\n\n\nThe usage of \nrequest.QUERY_PARAMS\n is now pending deprecation in favor of the lowercased \nrequest.query_params\n.\n\n\n\n\nSerializers\n\n\nSingle-step object creation.\n\n\nPreviously the serializers used a two-step object creation, as follows:\n\n\n\n\nValidating the data would create an object instance. This instance would be available as \nserializer.object\n.\n\n\nCalling \nserializer.save()\n would then save the object instance to the database.\n\n\n\n\nThis style is in-line with how the \nModelForm\n class works in Django, but is problematic for a number of reasons:\n\n\n\n\nSome data, such as many-to-many relationships, cannot be added to the object instance until after it has been saved. This type of data needed to be hidden in some undocumented state on the object instance, or kept as state on the serializer instance so that it could be used when \n.save()\n is called.\n\n\nInstantiating model instances directly means that you cannot use model manager classes for instance creation, e.g. \nExampleModel.objects.create(...)\n. Manager classes are an excellent layer at which to enforce business logic and application-level data constraints.\n\n\nThe two step process makes it unclear where to put deserialization logic. For example, should extra attributes such as the current user get added to the instance during object creation or during object save?\n\n\n\n\nWe now use single-step object creation, like so:\n\n\n\n\nValidating the data makes the cleaned data available as \nserializer.validated_data\n.\n\n\nCalling \nserializer.save()\n then saves and returns the new object instance.\n\n\n\n\nThe resulting API changes are further detailed below.\n\n\n.update()\n methods.\nThe \n.create()\n and \n\n\nThe \n.restore_object()\n method is now removed, and we instead have two separate methods, \n.create()\n and \n.update()\n. These methods work slightly different to the previous \n.restore_object()\n.\n\n\nWhen using the \n.create()\n and \n.update()\n methods you should both create \nand save\n the object instance. This is in contrast to the previous \n.restore_object()\n behavior that would instantiate the object but not save it.\n\n\nThese methods also replace the optional \n.save_object()\n method, which no longer exists.\n\n\nThe following example from the tutorial previously used \nrestore_object()\n to handle both creating and updating object instances.\n\n\ndef restore_object(self, attrs, instance=None):\n if instance:\n # Update existing instance\n instance.title = attrs.get('title', instance.title)\n instance.code = attrs.get('code', instance.code)\n instance.linenos = attrs.get('linenos', instance.linenos)\n instance.language = attrs.get('language', instance.language)\n instance.style = attrs.get('style', instance.style)\n return instance\n\n # Create new instance\n return Snippet(**attrs)\n\n\n\nThis would now be split out into two separate methods.\n\n\ndef update(self, instance, validated_data):\n instance.title = validated_data.get('title', instance.title)\n instance.code = validated_data.get('code', instance.code)\n instance.linenos = validated_data.get('linenos', instance.linenos)\n instance.language = validated_data.get('language', instance.language)\n instance.style = validated_data.get('style', instance.style)\n instance.save()\n return instance\n\ndef create(self, validated_data):\n return Snippet.objects.create(**validated_data)\n\n\n\nNote that these methods should return the newly created object instance.\n\n\n.object\n.\nUse \n.validated_data\n instead of \n\n\nYou must now use the \n.validated_data\n attribute if you need to inspect the data before saving, rather than using the \n.object\n attribute, which no longer exists.\n\n\nFor example the following code \nis no longer valid\n:\n\n\nif serializer.is_valid():\n name = serializer.object.name # Inspect validated field data.\n logging.info('Creating ticket \"%s\"' % name)\n serializer.object.user = request.user # Include the user when saving.\n serializer.save()\n\n\n\nInstead of using \n.object\n to inspect a partially constructed instance, you would now use \n.validated_data\n to inspect the cleaned incoming values. Also you can't set extra attributes on the instance directly, but instead pass them to the \n.save()\n method as keyword arguments.\n\n\nThe corresponding code would now look like this:\n\n\nif serializer.is_valid():\n name = serializer.validated_data['name'] # Inspect validated field data.\n logging.info('Creating ticket \"%s\"' % name)\n serializer.save(user=request.user) # Include the user when saving.\n\n\n\nUsing \n.is_valid(raise_exception=True)\n\n\nThe \n.is_valid()\n method now takes an optional boolean flag, \nraise_exception\n.\n\n\nCalling \n.is_valid(raise_exception=True)\n will cause a \nValidationError\n to be raised if the serializer data contains validation errors. This error will be handled by REST framework's default exception handler, allowing you to remove error response handling from your view code.\n\n\nThe handling and formatting of error responses may be altered globally by using the \nEXCEPTION_HANDLER\n settings key.\n\n\nThis change also means it's now possible to alter the style of error responses used by the built-in generic views, without having to include mixin classes or other overrides.\n\n\nUsing \nserializers.ValidationError\n.\n\n\nPreviously \nserializers.ValidationError\n error was simply a synonym for \ndjango.core.exceptions.ValidationError\n. This has now been altered so that it inherits from the standard \nAPIException\n base class.\n\n\nThe reason behind this is that Django's \nValidationError\n class is intended for use with HTML forms and its API makes using it slightly awkward with nested validation errors that can occur in serializers.\n\n\nFor most users this change shouldn't require any updates to your codebase, but it is worth ensuring that whenever raising validation errors you should prefer using the \nserializers.ValidationError\n exception class, and not Django's built-in exception.\n\n\nWe strongly recommend that you use the namespaced import style of \nimport serializers\n and not \nfrom serializers import ValidationError\n in order to avoid any potential confusion.\n\n\nChange to \nvalidate_\nfield_name\n.\n\n\nThe \nvalidate_\nfield_name\n method hooks that can be attached to serializer classes change their signature slightly and return type. Previously these would take a dictionary of all incoming data, and a key representing the field name, and would return a dictionary including the validated data for that field:\n\n\ndef validate_score(self, attrs, source):\n if attrs['score'] % 10 != 0:\n raise serializers.ValidationError('This field should be a multiple of ten.')\n return attrs\n\n\n\nThis is now simplified slightly, and the method hooks simply take the value to be validated, and return the validated value.\n\n\ndef validate_score(self, value):\n if value % 10 != 0:\n raise serializers.ValidationError('This field should be a multiple of ten.')\n return value\n\n\n\nAny ad-hoc validation that applies to more than one field should go in the \n.validate(self, attrs)\n method as usual.\n\n\nBecause \n.validate_\nfield_name\n would previously accept the complete dictionary of attributes, it could be used to validate a field depending on the input in another field. Now if you need to do this you should use \n.validate()\n instead.\n\n\nYou can either return \nnon_field_errors\n from the validate method by raising a simple \nValidationError\n\n\ndef validate(self, attrs):\n # serializer.errors == {'non_field_errors': ['A non field error']}\n raise serializers.ValidationError('A non field error')\n\n\n\nAlternatively if you want the errors to be against a specific field, use a dictionary of when instantiating the \nValidationError\n, like so:\n\n\ndef validate(self, attrs):\n # serializer.errors == {'my_field': ['A field error']}\n raise serializers.ValidationError({'my_field': 'A field error'})\n\n\n\nThis ensures you can still write validation that compares all the input fields, but that marks the error against a particular field.\n\n\nRemoval of \ntransform_\nfield_name\n.\n\n\nThe under-used \ntransform_\nfield_name\n on serializer classes is no longer provided. Instead you should just override \nto_representation()\n if you need to apply any modifications to the representation style.\n\n\nFor example:\n\n\ndef to_representation(self, instance):\n ret = super(UserSerializer, self).to_representation(instance)\n ret['username'] = ret['username'].lower()\n return ret\n\n\n\nDropping the extra point of API means there's now only one right way to do things. This helps with repetition and reinforcement of the core API, rather than having multiple differing approaches.\n\n\nIf you absolutely need to preserve \ntransform_\nfield_name\n behavior, for example, in order to provide a simpler 2.x to 3.0 upgrade, you can use a mixin, or serializer base class that add the behavior back in. For example:\n\n\nclass BaseModelSerializer(ModelSerializer):\n \"\"\"\n A custom ModelSerializer class that preserves 2.x style `transform_\nfield_name\n` behavior.\n \"\"\"\n def to_representation(self, instance):\n ret = super(BaseModelSerializer, self).to_representation(instance)\n for key, value in ret.items():\n method = getattr(self, 'transform_' + key, None)\n if method is not None:\n ret[key] = method(value)\n return ret\n\n\n\nDifferences between ModelSerializer validation and ModelForm.\n\n\nThis change also means that we no longer use the \n.full_clean()\n method on model instances, but instead perform all validation explicitly on the serializer. This gives a cleaner separation, and ensures that there's no automatic validation behavior on \nModelSerializer\n classes that can't also be easily replicated on regular \nSerializer\n classes.\n\n\nFor the most part this change should be transparent. Field validation and uniqueness checks will still be run as normal, but the implementation is a little different.\n\n\nThe one difference that you do need to note is that the \n.clean()\n method will not be called as part of serializer validation, as it would be if using a \nModelForm\n. Use the serializer \n.validate()\n method to perform a final validation step on incoming data where required.\n\n\nThere may be some cases where you really do need to keep validation logic in the model \n.clean()\n method, and cannot instead separate it into the serializer \n.validate()\n. You can do so by explicitly instantiating a model instance in the \n.validate()\n method.\n\n\ndef validate(self, attrs):\n instance = ExampleModel(**attrs)\n instance.clean()\n return attrs\n\n\n\nAgain, you really should look at properly separating the validation logic out of the model method if possible, but the above might be useful in some backwards compatibility cases, or for an easy migration path.\n\n\nWritable nested serialization.\n\n\nREST framework 2.x attempted to automatically support writable nested serialization, but the behavior was complex and non-obvious. Attempting to automatically handle these case is problematic:\n\n\n\n\nThere can be complex dependencies involved in order of saving multiple related model instances.\n\n\nIt's unclear what behavior the user should expect when related models are passed \nNone\n data.\n\n\nIt's unclear how the user should expect to-many relationships to handle updates, creations and deletions of multiple records.\n\n\n\n\nUsing the \ndepth\n option on \nModelSerializer\n will now create \nread-only nested serializers\n by default.\n\n\nIf you try to use a writable nested serializer without writing a custom \ncreate()\n and/or \nupdate()\n method you'll see an assertion error when you attempt to save the serializer. For example:\n\n\n class ProfileSerializer(serializers.ModelSerializer):\n\n class Meta:\n\n model = Profile\n\n fields = ('address', 'phone')\n\n\n\n class UserSerializer(serializers.ModelSerializer):\n\n profile = ProfileSerializer()\n\n class Meta:\n\n model = User\n\n fields = ('username', 'email', 'profile')\n\n\n\n data = {\n\n 'username': 'lizzy',\n\n 'email': 'lizzy@example.com',\n\n 'profile': {'address': '123 Acacia Avenue', 'phone': '01273 100200'}\n\n }\n\n\n\n serializer = UserSerializer(data=data)\n\n serializer.save()\nAssertionError: The `.create()` method does not support nested writable fields by default. Write an explicit `.create()` method for serializer `UserSerializer`, or set `read_only=True` on nested serializer fields.\n\n\n\nTo use writable nested serialization you'll want to declare a nested field on the serializer class, and write the \ncreate()\n and/or \nupdate()\n methods explicitly.\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\nThe single-step object creation makes this far simpler and more obvious than the previous \n.restore_object()\n behavior.\n\n\nPrintable serializer representations.\n\n\nSerializer instances now support a printable representation that allows you to inspect the fields present on the instance.\n\n\nFor instance, given the following example model:\n\n\nclass LocationRating(models.Model):\n location = models.CharField(max_length=100)\n rating = models.IntegerField()\n created_by = models.ForeignKey(User)\n\n\n\nLet's create a simple \nModelSerializer\n class corresponding to the \nLocationRating\n model.\n\n\nclass LocationRatingSerializer(serializer.ModelSerializer):\n class Meta:\n model = LocationRating\n\n\n\nWe can now inspect the serializer representation in the Django shell, using \npython manage.py shell\n...\n\n\n serializer = LocationRatingSerializer()\n\n print(serializer) # Or use `print serializer` in Python 2.x\nLocationRatingSerializer():\n id = IntegerField(label='ID', read_only=True)\n location = CharField(max_length=100)\n rating = IntegerField()\n created_by = PrimaryKeyRelatedField(queryset=User.objects.all())\n\n\n\nThe \nextra_kwargs\n option.\n\n\nThe \nwrite_only_fields\n option on \nModelSerializer\n has been moved to \nPendingDeprecation\n and replaced with a more generic \nextra_kwargs\n.\n\n\nclass MySerializer(serializer.ModelSerializer):\n class Meta:\n model = MyModel\n fields = ('id', 'email', 'notes', 'is_admin')\n extra_kwargs = {\n 'is_admin': {'write_only': True}\n }\n\n\n\nAlternatively, specify the field explicitly on the serializer class:\n\n\nclass MySerializer(serializer.ModelSerializer):\n is_admin = serializers.BooleanField(write_only=True)\n\n class Meta:\n model = MyModel\n fields = ('id', 'email', 'notes', 'is_admin')\n\n\n\nThe \nread_only_fields\n option remains as a convenient shortcut for the more common case.\n\n\nChanges to \nHyperlinkedModelSerializer\n.\n\n\nThe \nview_name\n and \nlookup_field\n options have been moved to \nPendingDeprecation\n. They are no longer required, as you can use the \nextra_kwargs\n argument instead:\n\n\nclass MySerializer(serializer.HyperlinkedModelSerializer):\n class Meta:\n model = MyModel\n fields = ('url', 'email', 'notes', 'is_admin')\n extra_kwargs = {\n 'url': {'lookup_field': 'uuid'}\n }\n\n\n\nAlternatively, specify the field explicitly on the serializer class:\n\n\nclass MySerializer(serializer.HyperlinkedModelSerializer):\n url = serializers.HyperlinkedIdentityField(\n view_name='mymodel-detail',\n lookup_field='uuid'\n )\n\n class Meta:\n model = MyModel\n fields = ('url', 'email', 'notes', 'is_admin')\n\n\n\nFields for model methods and properties.\n\n\nWith \nModelSerializer\n you can now specify field names in the \nfields\n option that refer to model methods or properties. For example, suppose you have the following model:\n\n\nclass Invitation(models.Model):\n created = models.DateTimeField()\n to_email = models.EmailField()\n message = models.CharField(max_length=1000)\n\n def expiry_date(self):\n return self.created + datetime.timedelta(days=30)\n\n\n\nYou can include \nexpiry_date\n as a field option on a \nModelSerializer\n class.\n\n\nclass InvitationSerializer(serializers.ModelSerializer):\n class Meta:\n model = Invitation\n fields = ('to_email', 'message', 'expiry_date')\n\n\n\nThese fields will be mapped to \nserializers.ReadOnlyField()\n instances.\n\n\n serializer = InvitationSerializer()\n\n print repr(serializer)\nInvitationSerializer():\n to_email = EmailField(max_length=75)\n message = CharField(max_length=1000)\n expiry_date = ReadOnlyField()\n\n\n\nThe \nListSerializer\n class.\n\n\nThe \nListSerializer\n class has now been added, and allows you to create base serializer classes for only accepting multiple inputs.\n\n\nclass MultipleUserSerializer(ListSerializer):\n child = UserSerializer()\n\n\n\nYou can also still use the \nmany=True\n argument to serializer classes. It's worth noting that \nmany=True\n argument transparently creates a \nListSerializer\n instance, allowing the validation logic for list and non-list data to be cleanly separated in the REST framework codebase.\n\n\nYou will typically want to \ncontinue to use the existing \nmany=True\n flag\n rather than declaring \nListSerializer\n classes explicitly, but declaring the classes explicitly can be useful if you need to write custom \ncreate\n or \nupdate\n methods for bulk updates, or provide for other custom behavior.\n\n\nSee also the new \nListField\n class, which validates input in the same way, but does not include the serializer interfaces of \n.is_valid()\n, \n.data\n, \n.save()\n and so on.\n\n\nThe \nBaseSerializer\n class.\n\n\nREST framework now includes a simple \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 an 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) \n 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 generic serializers with \nBaseSerializer\n.\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\nSerializer fields\n\n\nReadOnly\n field classes.\nThe \nField\n and \n\n\nThere are some minor tweaks to the field base classes.\n\n\nPreviously we had these two base classes:\n\n\n\n\nField\n as the base class for read-only fields. A default implementation was included for serializing data.\n\n\nWritableField\n as the base class for read-write fields.\n\n\n\n\nWe now use the following:\n\n\n\n\nField\n is the base class for all fields. It does not include any default implementation for either serializing or deserializing data.\n\n\nReadOnlyField\n is a concrete implementation for read-only fields that simply returns the attribute value without modification.\n\n\n\n\nallow_null\n, \ndefault\n arguments.\nThe \nrequired\n, \nallow_blank\n and \n\n\nREST framework now has more explicit and clear control over validating empty values for fields.\n\n\nPreviously the meaning of the \nrequired=False\n keyword argument was underspecified. In practice its use meant that a field could either be not included in the input, or it could be included, but be \nNone\n or the empty string.\n\n\nWe now have a better separation, with separate \nrequired\n, \nallow_null\n and \nallow_blank\n arguments.\n\n\nThe following set of arguments are used to control validation of empty values:\n\n\n\n\nrequired=False\n: The value does not need to be present in the input, and will not be passed to \n.create()\n or \n.update()\n if it is not seen.\n\n\ndefault=\nvalue\n: The value does not need to be present in the input, and a default value will be passed to \n.create()\n or \n.update()\n if it is not seen.\n\n\nallow_null=True\n: \nNone\n is a valid input.\n\n\nallow_blank=True\n: \n''\n is valid input. For \nCharField\n and subclasses only.\n\n\n\n\nTypically you'll want to use \nrequired=False\n if the corresponding model field has a default value, and additionally set either \nallow_null=True\n or \nallow_blank=True\n if required.\n\n\nThe \ndefault\n argument is also available and always implies that the field is not required to be in the input. It is unnecessary to use the \nrequired\n argument when a default is specified, and doing so will result in an error.\n\n\nCoercing output types.\n\n\nThe previous field implementations did not forcibly coerce returned values into the correct type in many cases. For example, an \nIntegerField\n would return a string output if the attribute value was a string. We now more strictly coerce to the correct return type, leading to more constrained and expected behavior.\n\n\nRemoval of \n.validate()\n.\n\n\nThe \n.validate()\n method is now removed from field classes. This method was in any case undocumented and not public API. You should instead simply override \nto_internal_value()\n.\n\n\nclass UppercaseCharField(serializers.CharField):\n def to_internal_value(self, data):\n value = super(UppercaseCharField, self).to_internal_value(data)\n if value != value.upper():\n raise serializers.ValidationError('The input should be uppercase only.')\n return value\n\n\n\nPreviously validation errors could be raised in either \n.to_native()\n or \n.validate()\n, making it non-obvious which should be used. Providing only a single point of API ensures more repetition and reinforcement of the core API.\n\n\nThe \nListField\n class.\n\n\nThe \nListField\n class has now been added. This field validates list input. It takes a \nchild\n keyword argument which is used to specify the field used to validate each item in the list. For example:\n\n\nscores = ListField(child=IntegerField(min_value=0, max_value=100))\n\n\n\nYou can also use a declarative style to create new subclasses of \nListField\n, like this:\n\n\nclass ScoresField(ListField):\n child = IntegerField(min_value=0, max_value=100)\n\n\n\nWe can now use the \nScoresField\n class inside another serializer:\n\n\nscores = ScoresField()\n\n\n\nSee also the new \nListSerializer\n class, which validates input in the same way, but also includes the serializer interfaces of \n.is_valid()\n, \n.data\n, \n.save()\n and so on.\n\n\nThe \nChoiceField\n class may now accept a flat list.\n\n\nThe \nChoiceField\n class may now accept a list of choices in addition to the existing style of using a list of pairs of \n(name, display_value)\n. The following is now valid:\n\n\ncolor = ChoiceField(choices=['red', 'green', 'blue'])\n\n\n\nThe \nMultipleChoiceField\n class.\n\n\nThe \nMultipleChoiceField\n class has been added. This field acts like \nChoiceField\n, but returns a set, which may include none, one or many of the valid choices.\n\n\nChanges to the custom field API.\n\n\nThe \nfrom_native(self, value)\n and \nto_native(self, data)\n method names have been replaced with the more obviously named \nto_internal_value(self, data)\n and \nto_representation(self, value)\n.\n\n\nThe \nfield_from_native()\n and \nfield_to_native()\n methods are removed. Previously you could use these methods if you wanted to customise the behaviour in a way that did not simply lookup the field value from the object. For example...\n\n\ndef field_to_native(self, obj, field_name):\n \"\"\"A custom read-only field that returns the class name.\"\"\"\n return obj.__class__.__name__\n\n\n\nNow if you need to access the entire object you'll instead need to override one or both of the following:\n\n\n\n\nUse \nget_attribute\n to modify the attribute value passed to \nto_representation()\n.\n\n\nUse \nget_value\n to modify the data value passed \nto_internal_value()\n.\n\n\n\n\nFor example:\n\n\ndef get_attribute(self, obj):\n # Pass the entire object through to `to_representation()`,\n # instead of the standard attribute lookup.\n return obj\n\ndef to_representation(self, value):\n return value.__class__.__name__\n\n\n\nExplicit \nqueryset\n required on relational fields.\n\n\nPreviously relational fields that were explicitly declared on a serializer class could omit the queryset argument if (and only if) they were declared on a \nModelSerializer\n.\n\n\nThis code \nwould be valid\n in \n2.4.3\n:\n\n\nclass AccountSerializer(serializers.ModelSerializer):\n organizations = serializers.SlugRelatedField(slug_field='name')\n\n class Meta:\n model = Account\n\n\n\nHowever this code \nwould not be valid\n in \n3.0\n:\n\n\n# Missing `queryset`\nclass AccountSerializer(serializers.Serializer):\n organizations = serializers.SlugRelatedField(slug_field='name')\n\n def restore_object(self, attrs, instance=None):\n # ...\n\n\n\nThe queryset argument is now always required for writable relational fields.\nThis removes some magic and makes it easier and more obvious to move between implicit \nModelSerializer\n classes and explicit \nSerializer\n classes.\n\n\nclass AccountSerializer(serializers.ModelSerializer):\n organizations = serializers.SlugRelatedField(\n slug_field='name',\n queryset=Organization.objects.all()\n )\n\n class Meta:\n model = Account\n\n\n\nThe \nqueryset\n argument is only ever required for writable fields, and is not required or valid for fields with \nread_only=True\n.\n\n\nOptional argument to \nSerializerMethodField\n.\n\n\nThe argument to \nSerializerMethodField\n is now optional, and defaults to \nget_\nfield_name\n. For example the following is valid:\n\n\nclass AccountSerializer(serializers.Serializer):\n # `method_name='get_billing_details'` by default.\n billing_details = serializers.SerializerMethodField()\n\n def get_billing_details(self, account):\n return calculate_billing(account)\n\n\n\nIn order to ensure a consistent code style an assertion error will be raised if you include a redundant method name argument that matches the default method name. For example, the following code \nwill raise an error\n:\n\n\nbilling_details = serializers.SerializerMethodField('get_billing_details')\n\n\n\nEnforcing consistent \nsource\n usage.\n\n\nI've see several codebases that unnecessarily include the \nsource\n argument, setting it to the same value as the field name. This usage is redundant and confusing, making it less obvious that \nsource\n is usually not required.\n\n\nThe following usage will \nnow raise an error\n:\n\n\nemail = serializers.EmailField(source='email')\n\n\n\nUniqueTogetherValidator\n classes.\nThe \nUniqueValidator\n and \n\n\nREST framework now provides new validators that allow you to ensure field uniqueness, while still using a completely explicit \nSerializer\n class instead of using \nModelSerializer\n.\n\n\nThe \nUniqueValidator\n should be applied to a serializer field, and takes a single \nqueryset\n argument.\n\n\nfrom rest_framework import serializers\nfrom rest_framework.validators import UniqueValidator\n\nclass OrganizationSerializer(serializers.Serializer):\n url = serializers.HyperlinkedIdentityField(view_name='organization_detail')\n created = serializers.DateTimeField(read_only=True)\n name = serializers.CharField(\n max_length=100,\n validators=UniqueValidator(queryset=Organization.objects.all())\n )\n\n\n\nThe \nUniqueTogetherValidator\n should be applied to a serializer, and takes a \nqueryset\n argument and a \nfields\n argument which should be a list or tuple of field names.\n\n\nclass RaceResultSerializer(serializers.Serializer):\n category = serializers.ChoiceField(['5k', '10k'])\n position = serializers.IntegerField()\n name = serializers.CharField(max_length=100)\n\n class Meta:\n validators = [UniqueTogetherValidator(\n queryset=RaceResult.objects.all(),\n fields=('category', 'position')\n )]\n\n\n\nThe \nUniqueForDateValidator\n classes.\n\n\nREST framework also now includes explicit validator classes for validating the \nunique_for_date\n, \nunique_for_month\n, and \nunique_for_year\n model field constraints. These are used internally instead of calling into \nModel.full_clean()\n.\n\n\nThese classes are documented in the \nValidators\n section of the documentation.\n\n\n\n\nGeneric views\n\n\nSimplification of view logic.\n\n\nThe view logic for the default method handlers has been significantly simplified, due to the new serializers API.\n\n\nChanges to pre/post save hooks.\n\n\nThe \npre_save\n and \npost_save\n hooks no longer exist, but are replaced with \nperform_create(self, serializer)\n and \nperform_update(self, serializer)\n.\n\n\nThese methods should save the object instance by calling \nserializer.save()\n, adding in any additional arguments as required. They may also perform any custom pre-save or post-save behavior.\n\n\nFor example:\n\n\ndef perform_create(self, serializer):\n # Include the owner attribute directly, rather than from request data.\n instance = serializer.save(owner=self.request.user)\n # Perform a custom post-save action.\n send_email(instance.to_email, instance.message)\n\n\n\nThe \npre_delete\n and \npost_delete\n hooks no longer exist, and are replaced with \n.perform_destroy(self, instance)\n, which should delete the instance and perform any custom actions.\n\n\ndef perform_destroy(self, instance):\n # Perform a custom pre-delete action.\n send_deletion_alert(user=instance.created_by, deleted=instance)\n # Delete the object instance.\n instance.delete()\n\n\n\nRemoval of view attributes.\n\n\nThe \n.object\n and \n.object_list\n attributes are no longer set on the view instance. Treating views as mutable object instances that store state during the processing of the view tends to be poor design, and can lead to obscure flow logic.\n\n\nI would personally recommend that developers treat view instances as immutable objects in their application code.\n\n\nPUT as create.\n\n\nAllowing \nPUT\n as create operations is problematic, as it necessarily exposes information about the existence or non-existence of objects. It's also not obvious that transparently allowing re-creating of previously deleted instances is necessarily a better default behavior than simply returning \n404\n responses.\n\n\nBoth styles \"\nPUT\n as 404\" and \"\nPUT\n as create\" can be valid in different circumstances, but we've now opted for the 404 behavior as the default, due to it being simpler and more obvious.\n\n\nIf you need to restore the previous behavior you may want to include \nthis \nAllowPUTAsCreateMixin\n class\n as a mixin to your views.\n\n\nCustomizing error responses.\n\n\nThe generic views now raise \nValidationFailed\n exception for invalid data. This exception is then dealt with by the exception handler, rather than the view returning a \n400 Bad Request\n response directly.\n\n\nThis change means that you can now easily customize the style of error responses across your entire API, without having to modify any of the generic views.\n\n\n\n\nThe metadata API\n\n\nBehavior for dealing with \nOPTIONS\n requests was previously built directly into the class-based views. This has now been properly separated out into a Metadata API that allows the same pluggable style as other API policies in REST framework.\n\n\nThis makes it far easier to use a different style for \nOPTIONS\n responses throughout your API, and makes it possible to create third-party metadata policies.\n\n\n\n\nSerializers as HTML forms\n\n\nREST framework 3.0 includes templated HTML form rendering for serializers.\n\n\nThis API should not yet be considered finalized, and will only be promoted to public API for the 3.1 release.\n\n\nSignificant changes that you do need to be aware of include:\n\n\n\n\nNested HTML forms are now supported, for example, a \nUserSerializer\n with a nested \nProfileSerializer\n will now render a nested \nfieldset\n when used in the browsable API.\n\n\nNested lists of HTML forms are not yet supported, but are planned for 3.1.\n\n\nBecause we now use templated HTML form generation, \nthe \nwidget\n option is no longer available for serializer fields\n. You can instead control the template that is used for a given field, by using the \nstyle\n dictionary.\n\n\n\n\nThe \nstyle\n keyword argument for serializer fields.\n\n\nThe \nstyle\n keyword argument can be used to pass through additional information from a serializer field, to the renderer class. In particular, the \nHTMLFormRenderer\n uses the \nbase_template\n key to determine which template to render the field with.\n\n\nFor example, to use a \ntextarea\n control instead of the default \ninput\n control, you would use the following\u2026\n\n\nadditional_notes = serializers.CharField(\n style={'base_template': 'textarea.html'}\n)\n\n\n\nSimilarly, to use a radio button control instead of the default \nselect\n control, you would use the following\u2026\n\n\ncolor_channel = serializers.ChoiceField(\n choices=['red', 'blue', 'green'],\n style={'base_template': 'radio.html'}\n)\n\n\n\nThis API should be considered provisional, and there may be minor alterations with the incoming 3.1 release.\n\n\n\n\nAPI style\n\n\nThere are some improvements in the default style we use in our API responses.\n\n\nUnicode JSON by default.\n\n\nUnicode JSON is now the default. The \nUnicodeJSONRenderer\n class no longer exists, and the \nUNICODE_JSON\n setting has been added. To revert this behavior use the new setting:\n\n\nREST_FRAMEWORK = {\n 'UNICODE_JSON': False\n}\n\n\n\nCompact JSON by default.\n\n\nWe now output compact JSON in responses by default. For example, we return:\n\n\n{\"email\":\"amy@example.com\",\"is_admin\":true}\n\n\n\nInstead of the following:\n\n\n{\"email\": \"amy@example.com\", \"is_admin\": true}\n\n\n\nThe \nCOMPACT_JSON\n setting has been added, and can be used to revert this behavior if needed:\n\n\nREST_FRAMEWORK = {\n 'COMPACT_JSON': False\n}\n\n\n\nFile fields as URLs\n\n\nThe \nFileField\n and \nImageField\n classes are now represented as URLs by default. You should ensure you set Django's \nstandard \nMEDIA_URL\n setting\n appropriately, and ensure your application \nserves the uploaded files\n.\n\n\nYou can revert this behavior, and display filenames in the representation by using the \nUPLOADED_FILES_USE_URL\n settings key:\n\n\nREST_FRAMEWORK = {\n 'UPLOADED_FILES_USE_URL': False\n}\n\n\n\nYou can also modify serializer fields individually, using the \nuse_url\n argument:\n\n\nuploaded_file = serializers.FileField(use_url=False)\n\n\n\nAlso note that you should pass the \nrequest\n object to the serializer as context when instantiating it, so that a fully qualified URL can be returned. Returned URLs will then be of the form \nhttps://example.com/url_path/filename.txt\n. For example:\n\n\ncontext = {'request': request}\nserializer = ExampleSerializer(instance, context=context)\nreturn Response(serializer.data)\n\n\n\nIf the request is omitted from the context, the returned URLs will be of the form \n/url_path/filename.txt\n.\n\n\nThrottle headers using \nRetry-After\n.\n\n\nThe custom \nX-Throttle-Wait-Second\n header has now been dropped in favor of the standard \nRetry-After\n header. You can revert this behavior if needed by writing a custom exception handler for your application.\n\n\nDate and time objects as ISO-8859-1 strings in serializer data.\n\n\nDate and Time objects are now coerced to strings by default in the serializer output. Previously they were returned as \nDate\n, \nTime\n and \nDateTime\n objects, and later coerced to strings by the renderer.\n\n\nYou can modify this behavior globally by settings the existing \nDATE_FORMAT\n, \nDATETIME_FORMAT\n and \nTIME_FORMAT\n settings keys. Setting these values to \nNone\n instead of their default value of \n'iso-8859-1'\n will result in native objects being returned in serializer data.\n\n\nREST_FRAMEWORK = {\n # Return native `Date` and `Time` objects in `serializer.data`\n 'DATETIME_FORMAT': None\n 'DATE_FORMAT': None\n 'TIME_FORMAT': None\n}\n\n\n\nYou can also modify serializer fields individually, using the \ndate_format\n, \ntime_format\n and \ndatetime_format\n arguments:\n\n\n# Return `DateTime` instances in `serializer.data`, not strings.\ncreated = serializers.DateTimeField(format=None)\n\n\n\nDecimals as strings in serializer data.\n\n\nDecimals are now coerced to strings by default in the serializer output. Previously they were returned as \nDecimal\n objects, and later coerced to strings by the renderer.\n\n\nYou can modify this behavior globally by using the \nCOERCE_DECIMAL_TO_STRING\n settings key.\n\n\nREST_FRAMEWORK = {\n 'COERCE_DECIMAL_TO_STRING': False\n}\n\n\n\nOr modify it on an individual serializer field, using the \ncoerce_to_string\n keyword argument.\n\n\n# Return `Decimal` instances in `serializer.data`, not strings.\namount = serializers.DecimalField(\n max_digits=10,\n decimal_places=2,\n coerce_to_string=False\n)\n\n\n\nThe default JSON renderer will return float objects for un-coerced \nDecimal\n instances. This allows you to easily switch between string or float representations for decimals depending on your API design needs.\n\n\n\n\nMiscellaneous notes\n\n\n\n\nThe serializer \nChoiceField\n does not currently display nested choices, as was the case in 2.4. This will be address as part of 3.1.\n\n\nDue to the new templated form rendering, the 'widget' option is no longer valid. This means there's no easy way of using third party \"autocomplete\" widgets for rendering select inputs that contain a large number of choices. You'll either need to use a regular select or a plain text input. We may consider addressing this in 3.1 or 3.2 if there's sufficient demand.\n\n\nSome of the default validation error messages were rewritten and might no longer be pre-translated. You can still \ncreate language files with Django\n if you wish to localize them.\n\n\nAPIException\n subclasses could previously take any arbitrary type in the \ndetail\n argument. These exceptions now use translatable text strings, and as a result call \nforce_text\n on the \ndetail\n argument, which \nmust be a string\n. If you need complex arguments to an \nAPIException\n class, you should subclass it and override the \n__init__()\n method. Typically you'll instead want to use a custom exception handler to provide for non-standard error responses.\n\n\n\n\n\n\nWhat's coming next\n\n\n3.0 is an incremental release, and there are several upcoming features that will build on the baseline improvements that it makes.\n\n\nThe 3.1 release is planned to address improvements in the following components:\n\n\n\n\nPublic API for using serializers as HTML forms.\n\n\nRequest parsing, mediatypes \n the implementation of the browsable API.\n\n\nIntroduction of a new pagination API.\n\n\nBetter support for API versioning.\n\n\n\n\nThe 3.2 release is planned to introduce an alternative admin-style interface to the browsable API.\n\n\nYou can follow development on the GitHub site, where we use \nmilestones to indicate planning timescales\n.", "title": "3.0 Announcement" }, { @@ -4947,7 +4987,7 @@ }, { "location": "/topics/3.4-announcement/", - "text": ".promo li a {\n float: left;\n width: 130px;\n height: 20px;\n text-align: center;\n margin: 10px 30px;\n padding: 150px 0 0 0;\n background-position: 0 50%;\n background-size: 130px auto;\n background-repeat: no-repeat;\n font-size: 120%;\n color: black;\n}\n.promo li {\n list-style: none;\n}\n\n\n\n\nDjango REST framework 3.4\n\n\nThe 3.4 release is the first in a planned series that will be addressing schema\ngeneration, hypermedia support, API clients, and finally realtime support.\n\n\n\n\nFunding\n\n\nThe 3.4 release has been made possible a recent \nMozilla grant\n, and by our\n\ncollaborative funding model\n. If you use REST framework commercially, and would\nlike to see this work continue, we strongly encourage you to invest in its\ncontinued development by \nsigning up for a paid plan\n.\n\n\nThe initial aim is to provide a single full-time position on REST framework.\nRight now we're over 60% of the way towards achieving that.\n\nEvery single sign-up makes a significant impact.\n\n\n\n \nRover.com\n\n \nSentry\n\n \nStream\n\n\n\n\n\n\n\n\nMany thanks to all our \nawesome sponsors\n, and in particular to our premium backers, \nRover\n, \nSentry\n, and \nStream\n.\n\n\n\n\nSchemas \n client libraries\n\n\nREST framework 3.4 brings built-in support for generating API schemas.\n\n\nWe provide this support by using \nCore API\n, a Document Object Model\nfor describing APIs.\n\n\nBecause Core API represents the API schema in an format-independent\nmanner, we're able to render the Core API \nDocument\n object into many different\nschema formats, by allowing the renderer class to determine how the internal\nrepresentation maps onto the external schema format.\n\n\nThis approach should also open the door to a range of auto-generated API\ndocumentation options in the future, by rendering the \nDocument\n object into\nHTML documentation pages.\n\n\nAlongside the built-in schema support, we're also now providing the following:\n\n\n\n\nA \ncommand line tool\n for interacting with APIs.\n\n\nA \nPython client library\n for interacting with APIs.\n\n\n\n\nThese API clients are dynamically driven, and able to interact with any API\nthat exposes a supported schema format.\n\n\nDynamically driven clients allow you to interact with an API at an application\nlayer interface, rather than a network layer interface, while still providing\nthe benefits of RESTful Web API design.\n\n\nWe're expecting to expand the range of languages that we provide client libraries\nfor over the coming months.\n\n\nFurther work on maturing the API schema support is also planned, including\ndocumentation on supporting file upload and download, and improved support for\ndocumentation generation and parameter annotation.\n\n\n\n\nCurrent support for schema formats is as follows:\n\n\n\n\n\n\n\n\nName\n\n\nSupport\n\n\nPyPI package\n\n\n\n\n\n\n\n\n\n\nCore JSON\n\n\nSchema generation \n client support.\n\n\nBuilt-in support in \ncoreapi\n.\n\n\n\n\n\n\nSwagger / OpenAPI\n\n\nSchema generation \n client support.\n\n\nThe \nopenapi-codec\n package.\n\n\n\n\n\n\nJSON Hyper-Schema\n\n\nCurrrently client support only.\n\n\nThe \nhyperschema-codec\n package.\n\n\n\n\n\n\nAPI Blueprint\n\n\nNot yet available.\n\n\nNot yet available.\n\n\n\n\n\n\n\n\n\n\nYou can read more about any of this new functionality in the following:\n\n\n\n\nNew tutorial section on \nschemas \n client libraries\n.\n\n\nDocumentation page on \nschema generation\n.\n\n\nTopic page on \nAPI clients\n.\n\n\n\n\nIt is also worth noting that Marc Gibbons is currently working towards a 2.0 release of\nthe popular Django REST Swagger package, which will tie in with our new built-in support.\n\n\n\n\nSupported versions\n\n\nThe 3.4.0 release adds support for Django 1.10.\n\n\nThe following versions of Python and Django are now supported:\n\n\n\n\nDjango versions 1.8, 1.9, and 1.10.\n\n\nPython versions 2.7, 3.2(*), 3.3(*), 3.4, 3.5.\n\n\n\n\n(*) Note that Python 3.2 and 3.3 are not supported from Django 1.9 onwards.\n\n\n\n\nDeprecations and changes\n\n\nThe 3.4 release includes very limited deprecation or behavioral changes, and\nshould present a straightforward upgrade.\n\n\nUse fields or exclude on serializer classes.\n\n\nThe following change in 3.3.0 is now escalated from \"pending deprecation\" to\n\"deprecated\". Its usage will continue to function but will raise warnings:\n\n\nModelSerializer\n and \nHyperlinkedModelSerializer\n should include either a \nfields\n\noption, or an \nexclude\n option. The \nfields = '__all__'\n shortcut may be used\nto explicitly include all fields.\n\n\nMicrosecond precision when returning time or datetime.\n\n\nUsing the default JSON renderer and directly returning a \ndatetime\n or \ntime\n\ninstance will now render with microsecond precision (6 digits), rather than\nmillisecond precision (3 digits). This makes the output format consistent with the\ndefault string output of \nserializers.DateTimeField\n and \nserializers.TimeField\n.\n\n\nThis change \ndoes not affect the default behavior when using serializers\n,\nwhich is to serialize \ndatetime\n and \ntime\n instances into strings with\nmicrosecond precision.\n\n\nThe serializer behavior can be modified if needed, using the \nDATETIME_FORMAT\n\nand \nTIME_FORMAT\n settings.\n\n\nThe renderer behavior can be modified by setting a custom \nencoder_class\n\nattribute on a \nJSONRenderer\n subclass.\n\n\nRelational choices no longer displayed in OPTIONS requests.\n\n\nMaking an \nOPTIONS\n request to views that have a serializer choice field\nwill result in a list of the available choices being returned in the response.\n\n\nIn cases where there is a relational field, the previous behavior would be\nto return a list of available instances to choose from for that relational field.\n\n\nIn order to minimise exposed information the behavior now is to \nnot\n return\nchoices information for relational fields.\n\n\nIf you want to override this new behavior you'll need to \nimplement a custom\nmetadata class\n.\n\n\nSee \nissue #3751\n for more information on this behavioral change.\n\n\n\n\nOther improvements\n\n\nThis release includes further work from a huge number of \npull requests and issues\n.\n\n\nMany thanks to all our contributors who've been involved in the release, either through raising issues, giving feedback, improving the documentation, or suggesting and implementing code changes.\n\n\nThe full set of itemized release notes \nare available here\n.", + "text": ".promo li a {\n float: left;\n width: 130px;\n height: 20px;\n text-align: center;\n margin: 10px 30px;\n padding: 150px 0 0 0;\n background-position: 0 50%;\n background-size: 130px auto;\n background-repeat: no-repeat;\n font-size: 120%;\n color: black;\n}\n.promo li {\n list-style: none;\n}\n\n\n\n\nDjango REST framework 3.4\n\n\nThe 3.4 release is the first in a planned series that will be addressing schema\ngeneration, hypermedia support, API clients, and finally realtime support.\n\n\n\n\nFunding\n\n\nThe 3.4 release has been made possible a recent \nMozilla grant\n, and by our\n\ncollaborative funding model\n. If you use REST framework commercially, and would\nlike to see this work continue, we strongly encourage you to invest in its\ncontinued development by \nsigning up for a paid plan\n.\n\n\nThe initial aim is to provide a single full-time position on REST framework.\nRight now we're over 60% of the way towards achieving that.\n\nEvery single sign-up makes a significant impact.\n\n\n\n \nRover.com\n\n \nSentry\n\n \nStream\n\n\n\n\n\n\n\n\nMany thanks to all our \nawesome sponsors\n, and in particular to our premium backers, \nRover\n, \nSentry\n, and \nStream\n.\n\n\n\n\nSchemas \n client libraries\n\n\nREST framework 3.4 brings built-in support for generating API schemas.\n\n\nWe provide this support by using \nCore API\n, a Document Object Model\nfor describing APIs.\n\n\nBecause Core API represents the API schema in an format-independent\nmanner, we're able to render the Core API \nDocument\n object into many different\nschema formats, by allowing the renderer class to determine how the internal\nrepresentation maps onto the external schema format.\n\n\nThis approach should also open the door to a range of auto-generated API\ndocumentation options in the future, by rendering the \nDocument\n object into\nHTML documentation pages.\n\n\nAlongside the built-in schema support, we're also now providing the following:\n\n\n\n\nA \ncommand line tool\n for interacting with APIs.\n\n\nA \nPython client library\n for interacting with APIs.\n\n\n\n\nThese API clients are dynamically driven, and able to interact with any API\nthat exposes a supported schema format.\n\n\nDynamically driven clients allow you to interact with an API at an application\nlayer interface, rather than a network layer interface, while still providing\nthe benefits of RESTful Web API design.\n\n\nWe're expecting to expand the range of languages that we provide client libraries\nfor over the coming months.\n\n\nFurther work on maturing the API schema support is also planned, including\ndocumentation on supporting file upload and download, and improved support for\ndocumentation generation and parameter annotation.\n\n\n\n\nCurrent support for schema formats is as follows:\n\n\n\n\n\n\n\n\nName\n\n\nSupport\n\n\nPyPI package\n\n\n\n\n\n\n\n\n\n\nCore JSON\n\n\nSchema generation \n client support.\n\n\nBuilt-in support in \ncoreapi\n\n\n\n\n\n\nSwagger / OpenAPI\n\n\nSchema generation \n client support.\n\n\nThe \nopenapi-codec\npackage.\n\n\n\n\n\n\nJSON Hyper-Schema\n\n\nCurrrently client support only.\n\n\nThe \nhyperschema-codec\npackage.\n\n\n\n\n\n\nAPI Blueprint\n\n\nNot yet available.\n\n\nNot yet available.\n\n\n\n\n\n\n\n\n\n\nYou can read more about any of this new functionality in the following:\n\n\n\n\nNew tutorial section on \nschemas \n client libraries\n.\n\n\nDocumentation page on \nschema generation\n.\n\n\nTopic page on \nAPI clients\n.\n\n\n\n\nIt is also worth noting that Marc Gibbons is currently working towards a 2.0 release of\nthe popular Django REST Swagger package, which will tie in with our new built-in support.\n\n\n\n\nSupported versions\n\n\nThe 3.4.0 release adds support for Django 1.10.\n\n\nThe following versions of Python and Django are now supported:\n\n\n\n\nDjango versions 1.8, 1.9, and 1.10.\n\n\nPython versions 2.7, 3.2(*), 3.3(*), 3.4, 3.5.\n\n\n\n\n(*) Note that Python 3.2 and 3.3 are not supported from Django 1.9 onwards.\n\n\n\n\nDeprecations and changes\n\n\nThe 3.4 release includes very limited deprecation or behavioral changes, and\nshould present a straightforward upgrade.\n\n\nUse fields or exclude on serializer classes.\n\n\nThe following change in 3.3.0 is now escalated from \"pending deprecation\" to\n\"deprecated\". Its usage will continue to function but will raise warnings:\n\n\nModelSerializer\n and \nHyperlinkedModelSerializer\n should include either a \nfields\n\noption, or an \nexclude\n option. The \nfields = '__all__'\n shortcut may be used\nto explicitly include all fields.\n\n\nMicrosecond precision when returning time or datetime.\n\n\nUsing the default JSON renderer and directly returning a \ndatetime\n or \ntime\n\ninstance will now render with microsecond precision (6 digits), rather than\nmillisecond precision (3 digits). This makes the output format consistent with the\ndefault string output of \nserializers.DateTimeField\n and \nserializers.TimeField\n.\n\n\nThis change \ndoes not affect the default behavior when using serializers\n,\nwhich is to serialize \ndatetime\n and \ntime\n instances into strings with\nmicrosecond precision.\n\n\nThe serializer behavior can be modified if needed, using the \nDATETIME_FORMAT\n\nand \nTIME_FORMAT\n settings.\n\n\nThe renderer behavior can be modified by setting a custom \nencoder_class\n\nattribute on a \nJSONRenderer\n subclass.\n\n\nRelational choices no longer displayed in OPTIONS requests.\n\n\nMaking an \nOPTIONS\n request to views that have a serializer choice field\nwill result in a list of the available choices being returned in the response.\n\n\nIn cases where there is a relational field, the previous behavior would be\nto return a list of available instances to choose from for that relational field.\n\n\nIn order to minimise exposed information the behavior now is to \nnot\n return\nchoices information for relational fields.\n\n\nIf you want to override this new behavior you'll need to \nimplement a custom\nmetadata class\n.\n\n\nSee \nissue #3751\n for more information on this behavioral change.\n\n\n\n\nOther improvements\n\n\nThis release includes further work from a huge number of \npull requests and issues\n.\n\n\nMany thanks to all our contributors who've been involved in the release, either through raising issues, giving feedback, improving the documentation, or suggesting and implementing code changes.\n\n\nThe full set of itemized release notes \nare available here\n.", "title": "3.4 Announcement" }, { @@ -4962,7 +5002,7 @@ }, { "location": "/topics/3.4-announcement/#schemas-client-libraries", - "text": "REST framework 3.4 brings built-in support for generating API schemas. We provide this support by using Core API , a Document Object Model\nfor describing APIs. Because Core API represents the API schema in an format-independent\nmanner, we're able to render the Core API Document object into many different\nschema formats, by allowing the renderer class to determine how the internal\nrepresentation maps onto the external schema format. This approach should also open the door to a range of auto-generated API\ndocumentation options in the future, by rendering the Document object into\nHTML documentation pages. Alongside the built-in schema support, we're also now providing the following: A command line tool for interacting with APIs. A Python client library for interacting with APIs. These API clients are dynamically driven, and able to interact with any API\nthat exposes a supported schema format. Dynamically driven clients allow you to interact with an API at an application\nlayer interface, rather than a network layer interface, while still providing\nthe benefits of RESTful Web API design. We're expecting to expand the range of languages that we provide client libraries\nfor over the coming months. Further work on maturing the API schema support is also planned, including\ndocumentation on supporting file upload and download, and improved support for\ndocumentation generation and parameter annotation. Current support for schema formats is as follows: Name Support PyPI package Core JSON Schema generation client support. Built-in support in coreapi . Swagger / OpenAPI Schema generation client support. The openapi-codec package. JSON Hyper-Schema Currrently client support only. The hyperschema-codec package. API Blueprint Not yet available. Not yet available. You can read more about any of this new functionality in the following: New tutorial section on schemas client libraries . Documentation page on schema generation . Topic page on API clients . It is also worth noting that Marc Gibbons is currently working towards a 2.0 release of\nthe popular Django REST Swagger package, which will tie in with our new built-in support.", + "text": "REST framework 3.4 brings built-in support for generating API schemas. We provide this support by using Core API , a Document Object Model\nfor describing APIs. Because Core API represents the API schema in an format-independent\nmanner, we're able to render the Core API Document object into many different\nschema formats, by allowing the renderer class to determine how the internal\nrepresentation maps onto the external schema format. This approach should also open the door to a range of auto-generated API\ndocumentation options in the future, by rendering the Document object into\nHTML documentation pages. Alongside the built-in schema support, we're also now providing the following: A command line tool for interacting with APIs. A Python client library for interacting with APIs. These API clients are dynamically driven, and able to interact with any API\nthat exposes a supported schema format. Dynamically driven clients allow you to interact with an API at an application\nlayer interface, rather than a network layer interface, while still providing\nthe benefits of RESTful Web API design. We're expecting to expand the range of languages that we provide client libraries\nfor over the coming months. Further work on maturing the API schema support is also planned, including\ndocumentation on supporting file upload and download, and improved support for\ndocumentation generation and parameter annotation. Current support for schema formats is as follows: Name Support PyPI package Core JSON Schema generation client support. Built-in support in coreapi Swagger / OpenAPI Schema generation client support. The openapi-codec package. JSON Hyper-Schema Currrently client support only. The hyperschema-codec package. API Blueprint Not yet available. Not yet available. You can read more about any of this new functionality in the following: New tutorial section on schemas client libraries . Documentation page on schema generation . Topic page on API clients . It is also worth noting that Marc Gibbons is currently working towards a 2.0 release of\nthe popular Django REST Swagger package, which will tie in with our new built-in support.", "title": "Schemas & client libraries" }, { @@ -4995,6 +5035,91 @@ "text": "This release includes further work from a huge number of pull requests and issues . Many thanks to all our contributors who've been involved in the release, either through raising issues, giving feedback, improving the documentation, or suggesting and implementing code changes. The full set of itemized release notes are available here .", "title": "Other improvements" }, + { + "location": "/topics/3.5-announcement/", + "text": ".promo li a {\n float: left;\n width: 130px;\n height: 20px;\n text-align: center;\n margin: 10px 30px;\n padding: 150px 0 0 0;\n background-position: 0 50%;\n background-size: 130px auto;\n background-repeat: no-repeat;\n font-size: 120%;\n color: black;\n}\n.promo li {\n list-style: none;\n}\n\n\n\n\nDjango REST framework 3.5\n\n\nThe 3.5 release is the second in a planned series that is addressing schema\ngeneration, hypermedia support, API client libraries, and finally realtime support.\n\n\n\n\nFunding\n\n\nThe 3.5 release would not have been possible without our \ncollaborative funding model\n.\nIf you use REST framework commercially and would like to see this work continue,\nwe strongly encourage you to invest in its continued development by\n\nsigning up for a paid\nplan\n.\n\n\n\n \nRover.com\n\n \nSentry\n\n \nStream\n\n \nMachinalis\n\n\n\n\n\n\n\n\nMany thanks to all our \nsponsors\n, and in particular to our premium backers, \nRover\n, \nSentry\n, \nStream\n, and \nMachinalis\n.\n\n\n\n\nImproved schema generation\n\n\nDocstrings on views are now pulled through into schema definitions, allowing\nyou to \nuse the schema definition to document your\nAPI\n.\n\n\nThere is now also a shortcut function, \nget_schema_view()\n, which makes it easier to\n\nadding schema views\n to your API.\n\n\nFor example, to include a swagger schema to your API, you would do the following:\n\n\n\n\n\n\nRun \npip install django-rest-swagger\n.\n\n\n\n\n\n\nAdd \n'rest_framework_swagger'\n to your \nINSTALLED_APPS\n setting.\n\n\n\n\n\n\nInclude the schema view in your URL conf:\n\n\n\n\n\n\nfrom rest_framework.schemas import get_schema_view\nfrom rest_framework_swagger.renderers import OpenAPIRenderer, SwaggerUIRenderer\n\nschema_view = get_schema_view(\n title='Example API',\n renderer_classes=[OpenAPIRenderer, SwaggerUIRenderer]\n)\n\nurlpatterns = [\n url(r'^swagger/$', schema_view),\n ...\n]\n\n\n\n\nThere have been a large number of fixes to the schema generation. These should\nresolve issues for anyone using the latest version of the \ndjango-rest-swagger\n\npackage.\n\n\nSome of these changes do affect the resulting schema structure,\nso if you're already using schema generation you should make sure to review\n\nthe deprecation notes\n, particularly if you're currently using\na dynamic client library to interact with your API.\n\n\nFinally, we're also now exposing the schema generation as a\n\npublicly documented API\n, allowing you to more easily\noverride the behaviour.\n\n\nRequests test client\n\n\nYou can now test your project using the \nrequests\n library.\n\n\nThis exposes exactly the same interface as if you were using a standard\nrequests session instance.\n\n\nclient = RequestsClient()\nresponse = client.get('http://testserver/users/')\nassert response.status_code == 200\n\n\n\nRather than sending any HTTP requests to the network, this interface will\ncoerce all outgoing requests into WSGI, and call into your application directly.\n\n\nCore API client\n\n\nYou can also now test your project by interacting with it using the \ncoreapi\n\nclient library.\n\n\n# Fetch the API schema\nclient = CoreAPIClient()\nschema = client.get('http://testserver/schema/')\n\n# Create a new organisation\nparams = {'name': 'MegaCorp', 'status': 'active'}\nclient.action(schema, ['organisations', 'create'], params)\n\n# Ensure that the organisation exists in the listing\ndata = client.action(schema, ['organisations', 'list'])\nassert(len(data) == 1)\nassert(data == [{'name': 'MegaCorp', 'status': 'active'}])\n\n\n\nAgain, this will call directly into the application using the WSGI interface,\nrather than making actual network calls.\n\n\nThis is a good option if you are planning for clients to mainly interact with\nyour API using the \ncoreapi\n client library, or some other auto-generated client.\n\n\nLive tests\n\n\nOne interesting aspect of both the \nrequests\n client and the \ncoreapi\n client\nis that they allow you to write tests in such a way that they can also be made\nto run against a live service.\n\n\nBy switching the WSGI based client instances to actual instances of \nrequests.Session\n\nor \ncoreapi.Client\n you can have the test cases make actual network calls.\n\n\nBeing able to write test cases that can exercise your staging or production\nenvironment is a powerful tool. However in order to do this, you'll need to pay\nclose attention to how you handle setup and teardown to ensure a strict isolation\nof test data from other live or staging data.\n\n\nRAML support\n\n\nWe now have preliminary support for \nRAML documentation generation\n.\n\n\n\n\nFurther work on the encoding and documentation generation is planned, in order to\nmake features such as the 'Try it now' support available at a later date.\n\n\nThis work also now means that you can use the Core API client libraries to interact\nwith APIs that expose a RAML specification. The \nRAML codec\n gives some examples of\ninteracting with the Spotify API in this way.\n\n\nValidation codes\n\n\nExceptions raised by REST framework now include short code identifiers.\nWhen used together with our customizable error handling, this now allows you to\nmodify the style of API error messages.\n\n\nAs an example, this allows for the following style of error responses:\n\n\n{\n \"message\": \"You do not have permission to perform this action.\",\n \"code\": \"permission_denied\"\n}\n\n\n\nThis is particularly useful with validation errors, which use appropriate\ncodes to identify differing kinds of failure...\n\n\n{\n \"name\": {\"message\": \"This field is required.\", \"code\": \"required\"},\n \"age\": {\"message\": \"A valid integer is required.\", \"code\": \"invalid\"}\n}\n\n\n\nClient upload \n download support\n\n\nThe Python \ncoreapi\n client library and the Core API command line tool both\nnow fully support file \nuploads\n and \ndownloads\n.\n\n\n\n\nDeprecations\n\n\nGenerating schemas from Router\n\n\nThe router arguments for generating a schema view, such as \nschema_title\n,\nare now pending deprecation.\n\n\nInstead of using \nDefaultRouter(schema_title='Example API')\n, you should use\nthe \nget_schema_view()\n function, and include the view in your URL conf.\n\n\nMake sure to include the view before your router urls. For example:\n\n\nfrom rest_framework.schemas import get_schema_view\nfrom my_project.routers import router\n\nschema_view = get_schema_view(title='Example API')\n\nurlpatterns = [\n url('^$', schema_view),\n url(r'^', include(router.urls)),\n]\n\n\n\nSchema path representations\n\n\nThe \n'pk'\n identifier in schema paths is now mapped onto the actually model field\nname by default. This will typically be \n'id'\n.\n\n\nThis gives a better external representation for schemas, with less implementation\ndetail being exposed. It also reflects the behaviour of using a ModelSerializer\nclass with \nfields = '__all__'\n.\n\n\nYou can revert to the previous behaviour by setting \n'SCHEMA_COERCE_PATH_PK': False\n\nin the REST framework settings.\n\n\nSchema action name representations\n\n\nThe internal \nretrieve()\n and \ndestroy()\n method names are now coerced to an\nexternal representation of \nread\n and \ndelete\n.\n\n\nYou can revert to the previous behaviour by setting \n'SCHEMA_COERCE_METHOD_NAMES': {}\n\nin the REST framework settings.\n\n\nDjangoFilterBackend\n\n\nThe functionality of the built-in \nDjangoFilterBackend\n is now completely\nincluded by the \ndjango-filter\n package.\n\n\nYou should change your imports and REST framework filter settings as follows:\n\n\n\n\nrest_framework.filters.DjangoFilterBackend\n becomes \ndjango_filters.rest_framework.DjangoFilterBackend\n.\n\n\nrest_framework.filters.FilterSet\n becomes \ndjango_filters.rest_framework.FilterSet\n.\n\n\n\n\nThe existing imports will continue to work but are now pending deprecation.\n\n\nCoreJSON media type\n\n\nThe media type for \nCoreJSON\n is now \napplication/json+coreapi\n, rather than\nthe previous \napplication/vnd.json+coreapi\n. This brings it more into line with\nother custom media types, such as those used by Swagger and RAML.\n\n\nThe clients currently accept either media type. The old style-media type will\nbe deprecated at a later date.\n\n\nModelSerializer 'fields' and 'exclude'\n\n\nModelSerializer and HyperlinkedModelSerializer must include either a fields\noption, or an exclude option. The fields = '\nall\n' shortcut may be used to\nexplicitly include all fields.\n\n\nFailing to set either \nfields\n or \nexclude\n raised a pending deprecation warning\nin version 3.3 and raised a deprecation warning in 3.4. Its usage is now mandatory.", + "title": "3.5 Announcement" + }, + { + "location": "/topics/3.5-announcement/#django-rest-framework-35", + "text": "The 3.5 release is the second in a planned series that is addressing schema\ngeneration, hypermedia support, API client libraries, and finally realtime support.", + "title": "Django REST framework 3.5" + }, + { + "location": "/topics/3.5-announcement/#funding", + "text": "The 3.5 release would not have been possible without our collaborative funding model .\nIf you use REST framework commercially and would like to see this work continue,\nwe strongly encourage you to invest in its continued development by signing up for a paid plan . \n Rover.com \n Sentry \n Stream \n Machinalis Many thanks to all our sponsors , and in particular to our premium backers, Rover , Sentry , Stream , and Machinalis .", + "title": "Funding" + }, + { + "location": "/topics/3.5-announcement/#improved-schema-generation", + "text": "Docstrings on views are now pulled through into schema definitions, allowing\nyou to use the schema definition to document your API . There is now also a shortcut function, get_schema_view() , which makes it easier to adding schema views to your API. For example, to include a swagger schema to your API, you would do the following: Run pip install django-rest-swagger . Add 'rest_framework_swagger' to your INSTALLED_APPS setting. Include the schema view in your URL conf: from rest_framework.schemas import get_schema_view\nfrom rest_framework_swagger.renderers import OpenAPIRenderer, SwaggerUIRenderer\n\nschema_view = get_schema_view(\n title='Example API',\n renderer_classes=[OpenAPIRenderer, SwaggerUIRenderer]\n)\n\nurlpatterns = [\n url(r'^swagger/$', schema_view),\n ...\n] There have been a large number of fixes to the schema generation. These should\nresolve issues for anyone using the latest version of the django-rest-swagger \npackage. Some of these changes do affect the resulting schema structure,\nso if you're already using schema generation you should make sure to review the deprecation notes , particularly if you're currently using\na dynamic client library to interact with your API. Finally, we're also now exposing the schema generation as a publicly documented API , allowing you to more easily\noverride the behaviour.", + "title": "Improved schema generation" + }, + { + "location": "/topics/3.5-announcement/#requests-test-client", + "text": "You can now test your project using the requests library. This exposes exactly the same interface as if you were using a standard\nrequests session instance. client = RequestsClient()\nresponse = client.get('http://testserver/users/')\nassert response.status_code == 200 Rather than sending any HTTP requests to the network, this interface will\ncoerce all outgoing requests into WSGI, and call into your application directly.", + "title": "Requests test client" + }, + { + "location": "/topics/3.5-announcement/#core-api-client", + "text": "You can also now test your project by interacting with it using the coreapi \nclient library. # Fetch the API schema\nclient = CoreAPIClient()\nschema = client.get('http://testserver/schema/')\n\n# Create a new organisation\nparams = {'name': 'MegaCorp', 'status': 'active'}\nclient.action(schema, ['organisations', 'create'], params)\n\n# Ensure that the organisation exists in the listing\ndata = client.action(schema, ['organisations', 'list'])\nassert(len(data) == 1)\nassert(data == [{'name': 'MegaCorp', 'status': 'active'}]) Again, this will call directly into the application using the WSGI interface,\nrather than making actual network calls. This is a good option if you are planning for clients to mainly interact with\nyour API using the coreapi client library, or some other auto-generated client.", + "title": "Core API client" + }, + { + "location": "/topics/3.5-announcement/#live-tests", + "text": "One interesting aspect of both the requests client and the coreapi client\nis that they allow you to write tests in such a way that they can also be made\nto run against a live service. By switching the WSGI based client instances to actual instances of requests.Session \nor coreapi.Client you can have the test cases make actual network calls. Being able to write test cases that can exercise your staging or production\nenvironment is a powerful tool. However in order to do this, you'll need to pay\nclose attention to how you handle setup and teardown to ensure a strict isolation\nof test data from other live or staging data.", + "title": "Live tests" + }, + { + "location": "/topics/3.5-announcement/#raml-support", + "text": "We now have preliminary support for RAML documentation generation . Further work on the encoding and documentation generation is planned, in order to\nmake features such as the 'Try it now' support available at a later date. This work also now means that you can use the Core API client libraries to interact\nwith APIs that expose a RAML specification. The RAML codec gives some examples of\ninteracting with the Spotify API in this way.", + "title": "RAML support" + }, + { + "location": "/topics/3.5-announcement/#validation-codes", + "text": "Exceptions raised by REST framework now include short code identifiers.\nWhen used together with our customizable error handling, this now allows you to\nmodify the style of API error messages. As an example, this allows for the following style of error responses: {\n \"message\": \"You do not have permission to perform this action.\",\n \"code\": \"permission_denied\"\n} This is particularly useful with validation errors, which use appropriate\ncodes to identify differing kinds of failure... {\n \"name\": {\"message\": \"This field is required.\", \"code\": \"required\"},\n \"age\": {\"message\": \"A valid integer is required.\", \"code\": \"invalid\"}\n}", + "title": "Validation codes" + }, + { + "location": "/topics/3.5-announcement/#client-upload-download-support", + "text": "The Python coreapi client library and the Core API command line tool both\nnow fully support file uploads and downloads .", + "title": "Client upload & download support" + }, + { + "location": "/topics/3.5-announcement/#deprecations", + "text": "", + "title": "Deprecations" + }, + { + "location": "/topics/3.5-announcement/#generating-schemas-from-router", + "text": "The router arguments for generating a schema view, such as schema_title ,\nare now pending deprecation. Instead of using DefaultRouter(schema_title='Example API') , you should use\nthe get_schema_view() function, and include the view in your URL conf. Make sure to include the view before your router urls. For example: from rest_framework.schemas import get_schema_view\nfrom my_project.routers import router\n\nschema_view = get_schema_view(title='Example API')\n\nurlpatterns = [\n url('^$', schema_view),\n url(r'^', include(router.urls)),\n]", + "title": "Generating schemas from Router" + }, + { + "location": "/topics/3.5-announcement/#schema-path-representations", + "text": "The 'pk' identifier in schema paths is now mapped onto the actually model field\nname by default. This will typically be 'id' . This gives a better external representation for schemas, with less implementation\ndetail being exposed. It also reflects the behaviour of using a ModelSerializer\nclass with fields = '__all__' . You can revert to the previous behaviour by setting 'SCHEMA_COERCE_PATH_PK': False \nin the REST framework settings.", + "title": "Schema path representations" + }, + { + "location": "/topics/3.5-announcement/#schema-action-name-representations", + "text": "The internal retrieve() and destroy() method names are now coerced to an\nexternal representation of read and delete . You can revert to the previous behaviour by setting 'SCHEMA_COERCE_METHOD_NAMES': {} \nin the REST framework settings.", + "title": "Schema action name representations" + }, + { + "location": "/topics/3.5-announcement/#djangofilterbackend", + "text": "The functionality of the built-in DjangoFilterBackend is now completely\nincluded by the django-filter package. You should change your imports and REST framework filter settings as follows: rest_framework.filters.DjangoFilterBackend becomes django_filters.rest_framework.DjangoFilterBackend . rest_framework.filters.FilterSet becomes django_filters.rest_framework.FilterSet . The existing imports will continue to work but are now pending deprecation.", + "title": "DjangoFilterBackend" + }, + { + "location": "/topics/3.5-announcement/#corejson-media-type", + "text": "The media type for CoreJSON is now application/json+coreapi , rather than\nthe previous application/vnd.json+coreapi . This brings it more into line with\nother custom media types, such as those used by Swagger and RAML. The clients currently accept either media type. The old style-media type will\nbe deprecated at a later date.", + "title": "CoreJSON media type" + }, + { + "location": "/topics/3.5-announcement/#modelserializer-fields-and-exclude", + "text": "ModelSerializer and HyperlinkedModelSerializer must include either a fields\noption, or an exclude option. The fields = ' all ' shortcut may be used to\nexplicitly include all fields. Failing to set either fields or exclude raised a pending deprecation warning\nin version 3.3 and raised a deprecation warning in 3.4. Its usage is now mandatory.", + "title": "ModelSerializer 'fields' and 'exclude'" + }, { "location": "/topics/kickstarter-announcement/", "text": "Kickstarting Django REST framework 3\n\n\n\n\n \n\n\n\n\n\nIn order to continue to drive the project forward, I'm launching a Kickstarter campaign to help fund the development of a major new release - Django REST framework 3.\n\n\nProject details\n\n\nThis new release will allow us to comprehensively address some of the shortcomings of the framework, and will aim to include the following:\n\n\n\n\nFaster, simpler and easier-to-use serializers.\n\n\nAn alternative admin-style interface for the browsable API.\n\n\nSearch and filtering controls made accessible in the browsable API.\n\n\nAlternative API pagination styles.\n\n\nDocumentation around API versioning.\n\n\nTriage of outstanding tickets.\n\n\nImproving the ongoing quality and maintainability of the project.\n\n\n\n\nFull details are available now on the \nproject page\n.\n\n\nIf you're interested in helping make sustainable open source development a reality please \nvisit the Kickstarter page\n and consider funding the project.\n\n\nI can't wait to see where this takes us!\n\n\nMany thanks to everyone for your support so far,\n\n\nTom Christie :)\n\n\n\n\nSponsors\n\n\nWe've now blazed way past all our goals, with a staggering \u00a330,000 (~$50,000), meaning I'll be in a position to work on the project significantly beyond what we'd originally planned for. I owe a huge debt of gratitude to all the wonderful companies and individuals who have been backing the project so generously, and making this possible.\n\n\n\n\nPlatinum sponsors\n\n\nOur platinum sponsors have each made a hugely substantial contribution to the future development of Django REST framework, and I simply can't thank them enough.\n\n\n\n\nEventbrite\n\n\n\n\n\n\n\nDivio\n\n\nLulu\n\n\nPotato\n\n\nWiredrive\n\n\nCyan\n\n\nRunscope\n\n\nSimple Energy\n\n\nVOKAL Interactive\n\n\nPurple Bit\n\n\nKuwaitNET\n\n\n\n\n\n\n\n\n\n\nGold sponsors\n\n\nOur gold sponsors include companies large and small. Many thanks for their significant funding of the project and their commitment to sustainable open-source development.\n\n\n\n\nLaterPay\n\n\nSchuberg Philis\n\n\nProReNata AB\n\n\nSGA Websites\n\n\nSirono\n\n\nVinta Software Studio\n\n\nRapasso\n\n\nMirus Research\n\n\nHipo\n\n\nByte\n\n\nLightning Kite\n\n\nOpbeat\n\n\nKoordinates\n\n\nPulsecode Inc.\n\n\nSinging Horse Studio Ltd.\n\n\nHeroku\n\n\nRheinwerk Verlag\n\n\nSecurity Compass\n\n\nDjango Software Foundation\n\n\nHipflask\n\n\nCrate\n\n\nCryptico Corp\n\n\nNextHub\n\n\nCompile\n\n\nWusaWork\n\n\nEnvision Linux\n\n\n\n\n\n\n\n\n\n\nSilver sponsors\n\n\nThe serious financial contribution that our silver sponsors have made is very much appreciated. I'd like to say a particular thank\nyou to individuals who have choosen to privately support the project at this level.\n\n\n\n\nIMT Computer Services\n\n\nWildfish\n\n\nThermondo GmbH\n\n\nProvidenz\n\n\nalwaysdata.com\n\n\nTriggered Messaging\n\n\nPushPull Technology Ltd\n\n\nTranscode\n\n\nGarfo\n\n\nShippo\n\n\nGizmag\n\n\nTivix\n\n\nSafari\n\n\nBright Loop\n\n\nABA Systems\n\n\nbeefarm.ru\n\n\nVzzual.com\n\n\nInfinite Code\n\n\nCrossword Tracker\n\n\nPkgFarm\n\n\nLife. The Game.\n\n\nBlimp\n\n\nPathwright\n\n\nFluxility\n\n\nTeonite\n\n\nTrackMaven\n\n\nPhurba\n\n\nNephila\n\n\nAditium\n\n\nOpenEye Scientific Software\n\n\nHolvi\n\n\nCantemo\n\n\nMakeSpace\n\n\nAX Semantics\n\n\nISL\n\n\n\n\n\n\n\n\nIndividual backers\n: Paul Hallett, \nPaul Whipp\n, Dylan Roy, Jannis Leidel, \nXavier Ordoquy\n, \nJohannes Spielmann\n, \nRob Spectre\n, \nChris Heisel\n, Marwan Alsabbagh, Haris Ali, Tuomas Toivonen.\n\n\n\n\nAdvocates\n\n\nThe following individuals made a significant financial contribution to the development of Django REST framework 3, for which I can only offer a huge, warm and sincere thank you!\n\n\nIndividual backers\n: Jure Cuhalev, Kevin Brolly, Ferenc Szalai, Dougal Matthews, Stefan Foulis, Carlos Hernando, Alen Mujezinovic, Ross Crawford-d'Heureuse, George Kappel, Alasdair Nicol, John Carr, Steve Winton, Trey, Manuel Miranda, David Horn, Vince Mi, Daniel Sears, Jamie Matthews, Ryan Currah, Marty Kemka, Scott Nixon, Moshin Elahi, Kevin Campbell, Jose Antonio Leiva Izquierdo, Kevin Stone, Andrew Godwin, Tijs Teulings, Roger Boardman, Xavier Antoviaque, Darian Moody, Lujeni, Jon Dugan, Wiley Kestner, Daniel C. Silverstein, Daniel Hahler, Subodh Nijsure, Philipp Weidenhiller, Yusuke Muraoka, Danny Roa, Reto Aebersold, Kyle Getrost, D\u00e9c\u00e9bal Hormuz, James Dacosta, Matt Long, Mauro Rocco, Tyrel Souza, Ryan Campbell, Ville Jyrkk\u00e4, Charalampos Papaloizou, Nikolai R\u00f8ed Kristiansen, Antoni Aloy L\u00f3pez, Celia Oakley, Micha\u0142 Krawczak, Ivan VenOsdel, Tim Watts, Martin Warne, Nicola Jordan, Ryan Kaskel.\n\n\nCorporate backers\n: Savannah Informatics, Prism Skylabs, Musical Operating Devices.\n\n\n\n\nSupporters\n\n\nThere were also almost 300 further individuals choosing to help fund the project at other levels or choosing to give anonymously. Again, thank you, thank you, thank you!", @@ -5102,7 +5227,7 @@ }, { "location": "/topics/release-notes/", - "text": "Release Notes\n\n\n\n\nRelease Early, Release Often\n\n\n 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.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 fallaback 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 \n 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 \n 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 \n 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 adjustements. (\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 \n 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=\nmethod\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 certains 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 \n 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\nDont 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 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.5.x series\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 fallaback 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 \n 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 \n 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 \n 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 adjustements. (\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 \n 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=\nmethod\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 certains 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 \n 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\nDont 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" }, { @@ -5125,6 +5250,16 @@ "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", "title": "Upgrading" }, + { + "location": "/topics/release-notes/#35x-series", + "text": "", + "title": "3.5.x series" + }, + { + "location": "/topics/release-notes/#350", + "text": "Date : 20th October 2016", + "title": "3.5.0" + }, { "location": "/topics/release-notes/#34x-series", "text": "", diff --git a/sitemap.xml b/sitemap.xml index 29000312b..36617e375 100644 --- a/sitemap.xml +++ b/sitemap.xml @@ -4,7 +4,7 @@ http://www.django-rest-framework.org// - 2016-10-14 + 2016-10-20 daily @@ -13,49 +13,49 @@ http://www.django-rest-framework.org//tutorial/quickstart/ - 2016-10-14 + 2016-10-20 daily http://www.django-rest-framework.org//tutorial/1-serialization/ - 2016-10-14 + 2016-10-20 daily http://www.django-rest-framework.org//tutorial/2-requests-and-responses/ - 2016-10-14 + 2016-10-20 daily http://www.django-rest-framework.org//tutorial/3-class-based-views/ - 2016-10-14 + 2016-10-20 daily http://www.django-rest-framework.org//tutorial/4-authentication-and-permissions/ - 2016-10-14 + 2016-10-20 daily http://www.django-rest-framework.org//tutorial/5-relationships-and-hyperlinked-apis/ - 2016-10-14 + 2016-10-20 daily http://www.django-rest-framework.org//tutorial/6-viewsets-and-routers/ - 2016-10-14 + 2016-10-20 daily http://www.django-rest-framework.org//tutorial/7-schemas-and-client-libraries/ - 2016-10-14 + 2016-10-20 daily @@ -65,163 +65,163 @@ http://www.django-rest-framework.org//api-guide/requests/ - 2016-10-14 + 2016-10-20 daily http://www.django-rest-framework.org//api-guide/responses/ - 2016-10-14 + 2016-10-20 daily http://www.django-rest-framework.org//api-guide/views/ - 2016-10-14 + 2016-10-20 daily http://www.django-rest-framework.org//api-guide/generic-views/ - 2016-10-14 + 2016-10-20 daily http://www.django-rest-framework.org//api-guide/viewsets/ - 2016-10-14 + 2016-10-20 daily http://www.django-rest-framework.org//api-guide/routers/ - 2016-10-14 + 2016-10-20 daily http://www.django-rest-framework.org//api-guide/parsers/ - 2016-10-14 + 2016-10-20 daily http://www.django-rest-framework.org//api-guide/renderers/ - 2016-10-14 + 2016-10-20 daily http://www.django-rest-framework.org//api-guide/serializers/ - 2016-10-14 + 2016-10-20 daily http://www.django-rest-framework.org//api-guide/fields/ - 2016-10-14 + 2016-10-20 daily http://www.django-rest-framework.org//api-guide/relations/ - 2016-10-14 + 2016-10-20 daily http://www.django-rest-framework.org//api-guide/validators/ - 2016-10-14 + 2016-10-20 daily http://www.django-rest-framework.org//api-guide/authentication/ - 2016-10-14 + 2016-10-20 daily http://www.django-rest-framework.org//api-guide/permissions/ - 2016-10-14 + 2016-10-20 daily http://www.django-rest-framework.org//api-guide/throttling/ - 2016-10-14 + 2016-10-20 daily http://www.django-rest-framework.org//api-guide/filtering/ - 2016-10-14 + 2016-10-20 daily http://www.django-rest-framework.org//api-guide/pagination/ - 2016-10-14 + 2016-10-20 daily http://www.django-rest-framework.org//api-guide/versioning/ - 2016-10-14 + 2016-10-20 daily http://www.django-rest-framework.org//api-guide/content-negotiation/ - 2016-10-14 + 2016-10-20 daily http://www.django-rest-framework.org//api-guide/metadata/ - 2016-10-14 + 2016-10-20 daily http://www.django-rest-framework.org//api-guide/schemas/ - 2016-10-14 + 2016-10-20 daily http://www.django-rest-framework.org//api-guide/format-suffixes/ - 2016-10-14 + 2016-10-20 daily http://www.django-rest-framework.org//api-guide/reverse/ - 2016-10-14 + 2016-10-20 daily http://www.django-rest-framework.org//api-guide/exceptions/ - 2016-10-14 + 2016-10-20 daily http://www.django-rest-framework.org//api-guide/status-codes/ - 2016-10-14 + 2016-10-20 daily http://www.django-rest-framework.org//api-guide/testing/ - 2016-10-14 + 2016-10-20 daily http://www.django-rest-framework.org//api-guide/settings/ - 2016-10-14 + 2016-10-20 daily @@ -231,121 +231,127 @@ http://www.django-rest-framework.org//topics/documenting-your-api/ - 2016-10-14 + 2016-10-20 daily http://www.django-rest-framework.org//topics/api-clients/ - 2016-10-14 + 2016-10-20 daily http://www.django-rest-framework.org//topics/internationalization/ - 2016-10-14 + 2016-10-20 daily http://www.django-rest-framework.org//topics/ajax-csrf-cors/ - 2016-10-14 + 2016-10-20 daily http://www.django-rest-framework.org//topics/html-and-forms/ - 2016-10-14 + 2016-10-20 daily http://www.django-rest-framework.org//topics/browser-enhancements/ - 2016-10-14 + 2016-10-20 daily http://www.django-rest-framework.org//topics/browsable-api/ - 2016-10-14 + 2016-10-20 daily http://www.django-rest-framework.org//topics/rest-hypermedia-hateoas/ - 2016-10-14 + 2016-10-20 daily http://www.django-rest-framework.org//topics/third-party-resources/ - 2016-10-14 + 2016-10-20 daily http://www.django-rest-framework.org//topics/contributing/ - 2016-10-14 + 2016-10-20 daily http://www.django-rest-framework.org//topics/project-management/ - 2016-10-14 + 2016-10-20 daily http://www.django-rest-framework.org//topics/3.0-announcement/ - 2016-10-14 + 2016-10-20 daily http://www.django-rest-framework.org//topics/3.1-announcement/ - 2016-10-14 + 2016-10-20 daily http://www.django-rest-framework.org//topics/3.2-announcement/ - 2016-10-14 + 2016-10-20 daily http://www.django-rest-framework.org//topics/3.3-announcement/ - 2016-10-14 + 2016-10-20 daily http://www.django-rest-framework.org//topics/3.4-announcement/ - 2016-10-14 + 2016-10-20 + daily + + + + http://www.django-rest-framework.org//topics/3.5-announcement/ + 2016-10-20 daily http://www.django-rest-framework.org//topics/kickstarter-announcement/ - 2016-10-14 + 2016-10-20 daily http://www.django-rest-framework.org//topics/mozilla-grant/ - 2016-10-14 + 2016-10-20 daily http://www.django-rest-framework.org//topics/funding/ - 2016-10-14 + 2016-10-20 daily http://www.django-rest-framework.org//topics/release-notes/ - 2016-10-14 + 2016-10-20 daily diff --git a/topics/3.0-announcement/index.html b/topics/3.0-announcement/index.html index 33b84e41f..26af42476 100644 --- a/topics/3.0-announcement/index.html +++ b/topics/3.0-announcement/index.html @@ -302,6 +302,10 @@ 3.4 Announcement +
  • + 3.5 Announcement +
  • +
  • Kickstarter Announcement
  • @@ -450,7 +454,7 @@

    Below is an in-depth guide to the API changes and migration notes for 3.0.

    Request objects

    -

    The .data and .query_params properties.

    +

    .query_params properties.The .data and

    The usage of request.DATA and request.FILES is now pending deprecation in favor of a single request.data attribute that contains all the parsed data.

    Having separate attributes is reasonable for web applications that only ever parse url-encoded or multipart requests, but makes less sense for the general-purpose request parsing that REST framework supports.

    You may now pass all the request data to a serializer class in a single argument:

    @@ -482,7 +486,7 @@ ExampleSerializer(data=request.DATA, files=request.FILES)
  • Calling serializer.save() then saves and returns the new object instance.
  • The resulting API changes are further detailed below.

    -

    The .create() and .update() methods.

    +

    .update() methods.The .create() and

    The .restore_object() method is now removed, and we instead have two separate methods, .create() and .update(). These methods work slightly different to the previous .restore_object().

    When using the .create() and .update() methods you should both create and save the object instance. This is in contrast to the previous .restore_object() behavior that would instantiate the object but not save it.

    These methods also replace the optional .save_object() method, which no longer exists.

    @@ -514,7 +518,7 @@ def create(self, validated_data): return Snippet.objects.create(**validated_data)

    Note that these methods should return the newly created object instance.

    -

    Use .validated_data instead of .object.

    +

    .object.Use .validated_data instead of

    You must now use the .validated_data attribute if you need to inspect the data before saving, rather than using the .object attribute, which no longer exists.

    For example the following code is no longer valid:

    if serializer.is_valid():
    @@ -862,7 +866,7 @@ def all_high_scores(request):
     

    Serializer fields

    -

    The Field and ReadOnly field classes.

    +

    ReadOnly field classes.The Field and

    There are some minor tweaks to the field base classes.

    Previously we had these two base classes:

      @@ -874,7 +878,7 @@ def all_high_scores(request):
    • Field is the base class for all fields. It does not include any default implementation for either serializing or deserializing data.
    • ReadOnlyField is a concrete implementation for read-only fields that simply returns the attribute value without modification.
    -

    The required, allow_null, allow_blank and default arguments.

    +

    allow_null, default arguments.The required, allow_blank and

    REST framework now has more explicit and clear control over validating empty values for fields.

    Previously the meaning of the required=False keyword argument was underspecified. In practice its use meant that a field could either be not included in the input, or it could be included, but be None or the empty string.

    We now have a better separation, with separate required, allow_null and allow_blank arguments.

    @@ -984,7 +988,7 @@ This removes some magic and makes it easier and more obvious to move between imp

    The following usage will now raise an error:

    email = serializers.EmailField(source='email')
     
    -

    The UniqueValidator and UniqueTogetherValidator classes.

    +

    UniqueTogetherValidator classes.The UniqueValidator and

    REST framework now provides new validators that allow you to ensure field uniqueness, while still using a completely explicit Serializer class instead of using ModelSerializer.

    The UniqueValidator should be applied to a serializer field, and takes a single queryset argument.

    from rest_framework import serializers
    diff --git a/topics/3.1-announcement/index.html b/topics/3.1-announcement/index.html
    index 745fce51f..d99144ab4 100644
    --- a/topics/3.1-announcement/index.html
    +++ b/topics/3.1-announcement/index.html
    @@ -302,6 +302,10 @@
                         3.4 Announcement
                       
                       
    +                  
  • + 3.5 Announcement +
  • +
  • Kickstarter Announcement
  • diff --git a/topics/3.2-announcement/index.html b/topics/3.2-announcement/index.html index 39aaecf1d..9345ca4e1 100644 --- a/topics/3.2-announcement/index.html +++ b/topics/3.2-announcement/index.html @@ -302,6 +302,10 @@ 3.4 Announcement +
  • + 3.5 Announcement +
  • +
  • Kickstarter Announcement
  • diff --git a/topics/3.3-announcement/index.html b/topics/3.3-announcement/index.html index fd37cf1f6..396fbcb4d 100644 --- a/topics/3.3-announcement/index.html +++ b/topics/3.3-announcement/index.html @@ -302,6 +302,10 @@ 3.4 Announcement +
  • + 3.5 Announcement +
  • +
  • Kickstarter Announcement
  • diff --git a/topics/3.4-announcement/index.html b/topics/3.4-announcement/index.html index ec590cecf..355ea6bef 100644 --- a/topics/3.4-announcement/index.html +++ b/topics/3.4-announcement/index.html @@ -58,7 +58,7 @@