Welcome to Django REST Framework JSON API

Contents:

Getting Started

Note: this package is named Django REST Framework JSON API to follow the naming convention of other Django REST Framework packages. Since that’s quite a bit to say or type this package will be referred to as DJA elsewhere in these docs.

By default, Django REST Framework produces a response like:

{
    "count": 20,
    "next": "http://example.com/api/1.0/identities/?page=3",
    "previous": "http://example.com/api/1.0/identities/?page=1",
    "results": [{
        "id": 3,
        "username": "john",
        "full_name": "John Coltrane"
    }]
}

However, for the same identity model in JSON API format the response should look like the following:

{
    "links": {
        "first": "http://example.com/api/1.0/identities",
        "last": "http://example.com/api/1.0/identities?page=5",
        "next": "http://example.com/api/1.0/identities?page=3",
        "prev": "http://example.com/api/1.0/identities",
    },
    "data": [{
        "type": "identities",
        "id": 3,
        "attributes": {
            "username": "john",
            "full-name": "John Coltrane"
        }
    }],
    "meta": {
        "pagination": {
          "page": "2",
          "pages": "5",
          "count": "20"
        }
    }
}

Requirements

  1. Python (3.5, 3.6, 3.7, 3.8)

  2. Django (1.11, 2.1, 2.2, 3.0)

  3. Django REST Framework (3.10, 3.11)

We highly recommend and only officially support the latest patch release of each Python, Django and REST Framework series.

Installation

From PyPI

pip install djangorestframework-jsonapi
# for optional package integrations
pip install djangorestframework-jsonapi['django-filter']
pip install djangorestframework-jsonapi['django-polymorphic']

From Source

git clone https://github.com/django-json-api/django-rest-framework-json-api.git
cd django-rest-framework-json-api && pip install -e .

Running the example app

git clone https://github.com/django-json-api/django-rest-framework-json-api.git
cd django-rest-framework-json-api
python3 -m venv env
source env/bin/activate
pip install -Ur requirements.txt
django-admin migrate --settings=example.settings
django-admin loaddata drf_example --settings=example.settings
django-admin runserver --settings=example.settings

Browse to http://localhost:8000

Running Tests

pip install tox
tox

Usage

The DJA package implements a custom renderer, parser, exception handler, query filter backends, and pagination. To get started enable the pieces in settings.py that you want to use.

Many features of the JSON:API format standard have been implemented using Mixin classes in serializers.py. The easiest way to make use of those features is to import ModelSerializer variants from rest_framework_json_api instead of the usual rest_framework

Configuration

We suggest that you copy the settings block below and modify it if necessary.

REST_FRAMEWORK = {
    'PAGE_SIZE': 10,
    'EXCEPTION_HANDLER': 'rest_framework_json_api.exceptions.exception_handler',
    'DEFAULT_PAGINATION_CLASS':
        'rest_framework_json_api.pagination.JsonApiPageNumberPagination',
    'DEFAULT_PARSER_CLASSES': (
        'rest_framework_json_api.parsers.JSONParser',
        'rest_framework.parsers.FormParser',
        'rest_framework.parsers.MultiPartParser'
    ),
    'DEFAULT_RENDERER_CLASSES': (
        'rest_framework_json_api.renderers.JSONRenderer',
        # If you're performance testing, you will want to use the browseable API
        # without forms, as the forms can generate their own queries.
        # If performance testing, enable:
        # 'example.utils.BrowsableAPIRendererWithoutForms',
        # Otherwise, to play around with the browseable API, enable:
        'rest_framework.renderers.BrowsableAPIRenderer'
    ),
    'DEFAULT_METADATA_CLASS': 'rest_framework_json_api.metadata.JSONAPIMetadata',
    'DEFAULT_FILTER_BACKENDS': (
        'rest_framework_json_api.filters.QueryParameterValidationFilter',
        'rest_framework_json_api.filters.OrderingFilter',
        'rest_framework_json_api.django_filters.DjangoFilterBackend',
        'rest_framework.filters.SearchFilter',
    ),
    'SEARCH_PARAM': 'filter[search]',
    'TEST_REQUEST_RENDERER_CLASSES': (
        'rest_framework_json_api.renderers.JSONRenderer',
    ),
    'TEST_REQUEST_DEFAULT_FORMAT': 'vnd.api+json'
}

Filter Backends

Following are descriptions of JSON:API-specific filter backends and documentation on suggested usage for a standard DRF keyword-search filter backend that makes it consistent with JSON:API.

QueryParameterValidationFilter

QueryParameterValidationFilter validates query parameters to be one of the defined JSON:API query parameters (sort, include, filter, fields, page) and returns a 400 Bad Request if a non-matching query parameter is used. This can help the client identify misspelled query parameters, for example.

If you want to change the list of valid query parameters, override the .query_regex attribute:

# compiled regex that matches the allowed http://jsonapi.org/format/#query-parameters
# `sort` and `include` stand alone; `filter`, `fields`, and `page` have []'s
query_regex = re.compile(r'^(sort|include)$|^(filter|fields|page)(\[[\w\.\-]+\])?$')

For example:

import re
from rest_framework_json_api.filters import QueryParameterValidationFilter

class MyQPValidator(QueryParameterValidationFilter):
    query_regex = re.compile(r'^(sort|include|page|page_size)$|^(filter|fields|page)(\[[\w\.\-]+\])?$')

If you don’t care if non-JSON:API query parameters are allowed (and potentially silently ignored), simply don’t use this filter backend.

OrderingFilter

OrderingFilter implements the JSON:API sort and uses DRF’s ordering filter.

Per the JSON:API specification, “If the server does not support sorting as specified in the query parameter sort, it MUST return 400 Bad Request.” For example, for ?sort=abc,foo,def where foo is a valid field name and the other two are not valid:

{
    "errors": [
        {
            "detail": "invalid sort parameters: abc,def",
            "source": {
                "pointer": "/data"
            },
            "status": "400"
        }
    ]
}

If you want to silently ignore bad sort fields, just use rest_framework.filters.OrderingFilter and set ordering_param to sort.

DjangoFilterBackend

DjangoFilterBackend implements a Django ORM-style JSON:API filter using the django-filter package.

This filter is not part of the JSON:API standard per-se, other than the requirement to use the filter keyword: It is an optional implementation of a style of filtering in which each filter is an ORM expression as implemented by DjangoFilterBackend and seems to be in alignment with an interpretation of the JSON:API recommendations, including relationship chaining.

Filters can be:

  • A resource field equality test: ?filter[qty]=123

  • Apply other field lookup operators: ?filter[name.icontains]=bar or ?filter[name.isnull]=true

  • Membership in a list of values: ?filter[name.in]=abc,123,zzz (name in ['abc','123','zzz'])

  • Filters can be combined for intersection (AND): ?filter[qty]=123&filter[name.in]=abc,123,zzz&filter[...] or ?filter[authors.id]=1&filter[authors.id]=2

  • A related resource path can be used: ?filter[inventory.item.partNum]=123456 (where inventory.item is the relationship path)

The filter returns a 400 Bad Request error for invalid filter query parameters as in this example for GET http://127.0.0.1:8000/nopage-entries?filter[bad]=1:

{
    "errors": [
        {
            "detail": "invalid filter[bad]",
            "source": {
                "pointer": "/data"
            },
            "status": "400"
        }
    ]
}

As this feature depends on django-filter you need to run

pip install djangorestframework-jsonapi['django-filter']

SearchFilter

To comply with JSON:API query parameter naming standards, DRF’s SearchFilter should be configured to use a filter[_something_] query parameter. This can be done by default by adding the SearchFilter to REST_FRAMEWORK['DEFAULT_FILTER_BACKENDS'] and setting REST_FRAMEWORK['SEARCH_PARAM'] or adding the .search_param attribute to a custom class derived from SearchFilter. If you do this and also use DjangoFilterBackend, make sure you set the same values for both classes.

Configuring Filter Backends

You can configure the filter backends either by setting the REST_FRAMEWORK['DEFAULT_FILTER_BACKENDS'] as shown in the example settings or individually add them as .filter_backends View attributes:

from rest_framework_json_api import filters
from rest_framework_json_api import django_filters
from rest_framework import SearchFilter
from models import MyModel

class MyViewset(ModelViewSet):
   queryset = MyModel.objects.all()
   serializer_class = MyModelSerializer
   filter_backends = (filters.QueryParameterValidationFilter, filters.OrderingFilter,
                      django_filters.DjangoFilterBackend, SearchFilter)
   filterset_fields = {
       'id': ('exact', 'lt', 'gt', 'gte', 'lte', 'in'),
       'descriptuon': ('icontains', 'iexact', 'contains'),
       'tagline': ('icontains', 'iexact', 'contains'),
   }
   search_fields = ('id', 'description', 'tagline',)

Exception handling

For the exception_handler class, if the optional JSON_API_UNIFORM_EXCEPTIONS is set to True, all exceptions will respond with the JSON API error format.

When JSON_API_UNIFORM_EXCEPTIONS is False (the default), non-JSON API views will respond with the normal DRF error format.

Performance Testing

If you are trying to see if your viewsets are configured properly to optimize performance, it is preferable to use example.utils.BrowsableAPIRendererWithoutForms instead of the default BrowsableAPIRenderer to remove queries introduced by the forms themselves.

Serializers

It is recommended to import the base serializer classes from this package rather than from vanilla DRF. For example,

from rest_framework_json_api import serializers

class MyModelSerializer(serializers.ModelSerializer):
    # ...

Setting the resource_name

You may manually set the resource_name property on views, serializers, or models to specify the type key in the json output. In the case of setting the resource_name property for models you must include the property inside a JSONAPIMeta class on the model. It is automatically set for you as the plural of the view or model name except on resources that do not subclass rest_framework.viewsets.ModelViewSet:

Example - resource_name on View:

class Me(generics.GenericAPIView):
    """
    Current user's identity endpoint.

    GET /me
    """
    resource_name = 'users'
    serializer_class = identity_serializers.IdentitySerializer
    allowed_methods = ['GET']
    permission_classes = (permissions.IsAuthenticated, )

If you set the resource_name property on the object to False the data will be returned without modification.

Example - resource_name on Model:

class Me(models.Model):
    """
    A simple model
    """
    name = models.CharField(max_length=100)

    class JSONAPIMeta:
        resource_name = "users"

If you set the resource_name on a combination of model, serializer, or view in the same hierarchy, the name will be resolved as following: view > serializer > model. (Ex: A view resource_name will always override a resource_name specified on a serializer or model). Setting the resource_name on the view should be used sparingly as serializers and models are shared between multiple endpoints. Setting the resource_name on views may result in a different type being set depending on which endpoint the resource is fetched from.

Inflecting object and relation keys

This package includes the ability (off by default) to automatically convert json api field names of requests and responses from the python/rest_framework’s preferred underscore to a format of your choice. To hook this up include the following setting in your project settings:

JSON_API_FORMAT_FIELD_NAMES = 'dasherize'

Possible values:

  • dasherize

  • camelize (first letter is lowercase)

  • capitalize (camelize but with first letter uppercase)

  • underscore

Note: due to the way the inflector works address_1 can camelize to address1 on output but it cannot convert address1 back to address_1 on POST or PATCH. Keep this in mind when naming fields with numbers in them.

Example - Without format conversion:

{
    "data": [{
        "type": "identities",
        "id": 3,
        "attributes": {
            "username": "john",
            "first_name": "John",
            "last_name": "Coltrane",
            "full_name": "John Coltrane"
        },
    }],
    "meta": {
        "pagination": {
          "count": 20
        }
    }
}

Example - With format conversion set to dasherize:

{
    "data": [{
        "type": "identities",
        "id": 3,
        "attributes": {
            "username": "john",
            "first-name": "John",
            "last-name": "Coltrane",
            "full-name": "John Coltrane"
        },
    }],
    "meta": {
        "pagination": {
          "count": 20
        }
    }
}

Types

A similar option to JSON_API_FORMAT_FIELD_NAMES can be set for the types:

JSON_API_FORMAT_TYPES = 'dasherize'

Example without format conversion:

{
	"data": [{
        "type": "blog_identity",
        "id": 3,
        "attributes": {
                ...
        },
        "relationships": {
            "home_town": {
                "data": [{
                    "type": "home_town",
                    "id": 3
                }]
            }
        }
    }]
}

When set to dasherize:

{
	"data": [{
        "type": "blog-identity",
        "id": 3,
        "attributes": {
                ...
        },
        "relationships": {
            "home_town": {
                "data": [{
                    "type": "home-town",
                    "id": 3
                }]
            }
        }
    }]
}

It is also possible to pluralize the types like so:

JSON_API_PLURALIZE_TYPES = True

Example without pluralization:

{
	"data": [{
        "type": "identity",
        "id": 3,
        "attributes": {
                ...
        },
        "relationships": {
            "home_towns": {
                "data": [{
                    "type": "home_town",
                    "id": 3
                }]
            }
        }
    }]
}

When set to pluralize:

{
	"data": [{
        "type": "identities",
        "id": 3,
        "attributes": {
                ...
        },
        "relationships": {
            "home_towns": {
                "data": [{
                    "type": "home_towns",
                    "id": 3
                }]
            }
        }
    }]
}

RelationshipView

rest_framework_json_api.views.RelationshipView is used to build relationship views (see the JSON:API spec). The self link on a relationship object should point to the corresponding relationship view.

The relationship view is fairly simple because it only serializes Resource Identifier Objects rather than full resource objects. In most cases the following is sufficient:

from rest_framework_json_api.views import RelationshipView

from myapp.models import Order


class OrderRelationshipView(RelationshipView):
    queryset = Order.objects

The urlconf would need to contain a route like the following:

url(
    regex=r'^orders/(?P<pk>[^/.]+)/relationships/(?P<related_field>[^/.]+)$',
    view=OrderRelationshipView.as_view(),
    name='order-relationships'
)

The related_field kwarg specifies which relationship to use, so if we are interested in the relationship represented by the related model field Order.line_items on the Order with pk 3, the url would be /orders/3/relationships/line_items. On HyperlinkedModelSerializer, the ResourceRelatedField will construct the url based on the provided self_link_view_name keyword argument, which should match the name= provided in the urlconf, and will use the name of the field for the related_field kwarg. Also we can override related_field in the url. Let’s say we want the url to be: /order/3/relationships/order_items - all we need to do is just add field_name_mapping dict to the class:

field_name_mapping = {
        'order_items': 'line_items'
    }

Working with polymorphic resources

Polymorphic resources allow you to use specialized subclasses without requiring special endpoints to expose the specialized versions. For example, if you had a Project that could be either an ArtProject or a ResearchProject, you can have both kinds at the same URL.

DJA tests its polymorphic support against django-polymorphic. The polymorphic feature should also work with other popular libraries like django-polymodels or django-typed-models.

As this feature depends on django-polymorphic you need to run

pip install djangorestframework-jsonapi['django-polymorphic']

Writing polymorphic resources

A polymorphic endpoint can be set up if associated with a polymorphic serializer. A polymorphic serializer takes care of (de)serializing the correct instances types and can be defined like this:

class ProjectSerializer(serializers.PolymorphicModelSerializer):
    polymorphic_serializers = [ArtProjectSerializer, ResearchProjectSerializer]

    class Meta:
        model = models.Project

It must inherit from serializers.PolymorphicModelSerializer and define the polymorphic_serializers list. This attribute defines the accepted resource types.

Polymorphic relations can also be handled with relations.PolymorphicResourceRelatedField like this:

class CompanySerializer(serializers.ModelSerializer):
    current_project = relations.PolymorphicResourceRelatedField(
        ProjectSerializer, queryset=models.Project.objects.all())
    future_projects = relations.PolymorphicResourceRelatedField(
        ProjectSerializer, queryset=models.Project.objects.all(), many=True)

    class Meta:
        model = models.Company

They must be explicitly declared with the polymorphic_serializer (first positional argument) correctly defined. It must be a subclass of serializers.PolymorphicModelSerializer.

Note: Polymorphic resources are not compatible with resource_name defined on the view.

Meta

You may add metadata to the rendered json in two different ways: meta_fields and get_root_meta.

On any rest_framework_json_api.serializers.ModelSerializer you may add a meta_fields property to the Meta class. This behaves in the same manner as the default fields property and will cause SerializerMethodFields or model values to be added to the meta object within the same data as the serializer.

To add metadata to the top level meta object add:

def get_root_meta(self, resource, many):
    if many:
      # Dealing with a list request
      return {
          'size': len(resource)
      }
    else:
      # Dealing with a detail request
      return {
        'foo': 'bar'
      }

to the serializer. It must return a dict and will be merged with the existing top level meta.

To access metadata in incoming requests, the JSONParser will add the metadata under a top level _meta key in the parsed data dictionary. For instance, to access meta data from a serializer object, you may use serializer.initial_data.get("_meta"). To customize the _meta key, see here.

Included

JSON API can include additional resources in a single network request. The specification refers to this feature as Compound Documents. Compound Documents can reduce the number of network requests which can lead to a better performing web application. To accomplish this, the specification permits a top level included key. The list of content within this key are the extra resources that are related to the primary resource.

To make a Compound Document, you need to modify your ModelSerializer. included_serializers is required to inform DJA of what and how you would like to include. included_resources tells DJA what you want to include by default.

For example, suppose you are making an app to go on quests, and you would like to fetch your chosen knight along with the quest. You could accomplish that with:

class KnightSerializer(serializers.ModelSerializer):
    class Meta:
        model = Knight
        fields = ('id', 'name', 'strength', 'dexterity', 'charisma')


class QuestSerializer(serializers.ModelSerializer):
    included_serializers = {
        'knight': KnightSerializer,
    }

    class Meta:
        model = Quest
        fields = ('id', 'title', 'reward', 'knight')

    class JSONAPIMeta:
        included_resources = ['knight']

Performance improvements

Be aware that using included resources without any form of prefetching WILL HURT PERFORMANCE as it will introduce m*(n+1) queries.

A viewset helper was therefore designed to automatically preload data when possible. Such is automatically available when subclassing ModelViewSet.

It also allows to define custom select_related and prefetch_related for each requested include when needed in special cases:

rest_framework_json_api.views.ModelViewSet:

from rest_framework_json_api import views

# When MyViewSet is called with ?include=author it will dynamically prefetch author and author.bio
class MyViewSet(views.ModelViewSet):
    queryset = Book.objects.all()
    select_for_includes = {
        'author': ['author__bio'],
    }
    prefetch_for_includes = {
        '__all__': [],
        'all_authors': [Prefetch('all_authors', queryset=Author.objects.select_related('bio'))],
        'category.section': ['category']
    }

An additional convenience DJA class exists for read-only views, just as it does in DRF.

from rest_framework_json_api import views

class MyReadOnlyViewSet(views.ReadOnlyModelViewSet):
    # ...

The special keyword __all__ can be used to specify a prefetch which should be done regardless of the include, similar to making the prefetch yourself on the QuerySet.

Using the helper to prefetch, rather than attempting to minimise queries via select_related might give you better performance depending on the characteristics of your data and database.

For example:

If you have a single model, e.g. Book, which has four relations e.g. Author, Publisher, CopyrightHolder, Category.

To display 25 books and related models, you would need to either do:

a) 1 query via selected_related, e.g. SELECT * FROM books LEFT JOIN author LEFT JOIN publisher LEFT JOIN CopyrightHolder LEFT JOIN Category

b) 4 small queries via prefetch_related.

If you have 1M books, 50k authors, 10k categories, 10k copyrightholders in the select_related scenario, you’ve just created a in-memory table with 1e18 rows which will likely exhaust any available memory and slow your database to crawl.

The prefetch_related case will issue 4 queries, but they will be small and fast queries.

API Reference

This API reference is autogenerated from the Python docstrings – which need to be improved!

rest_framework_json_api package

Subpackages

rest_framework_json_api.django_filters package
Submodules
rest_framework_json_api.django_filters.backends module
class rest_framework_json_api.django_filters.backends.DjangoFilterBackend

Bases: django_filters.rest_framework.backends.DjangoFilterBackend

A Django-style ORM filter implementation, using django-filter.

This is not part of the jsonapi standard per-se, other than the requirement to use the filter keyword: This is an optional implementation of style of filtering in which each filter is an ORM expression as implemented by DjangoFilterBackend and seems to be in alignment with an interpretation of http://jsonapi.org/recommendations/#filtering, including relationship chaining. It also returns a 400 error for invalid filters.

Filters can be:

  • A resource field equality test:

    ?filter[qty]=123

  • Apply other https://docs.djangoproject.com/en/stable/ref/models/querysets/#field-lookups operators:

    ?filter[name.icontains]=bar or ?filter[name.isnull]=true...

  • Membership in a list of values:

    ?filter[name.in]=abc,123,zzz (name in [‘abc’,‘123’,’zzz’])

  • Filters can be combined for intersection (AND):

    ?filter[qty]=123&filter[name.in]=abc,123,zzz&filter[...]

  • A related resource path can be used:

    ?filter[inventory.item.partNum]=123456 (where inventory.item is the relationship path)

If you are also using rest_framework.filters.SearchFilter you’ll want to customize the name of the query parameter for searching to make sure it doesn’t conflict with a field name defined in the filterset. The recommended value is: search_param=”filter[search]” but just make sure it’s filter[<something>] to comply with the jsonapi spec requirement to use the filter keyword. The default is “search” unless overriden but it’s used here just to make sure we don’t complain about it being an invalid filter.

search_param = 'filter[search]'
filter_regex = re.compile('^filter(?P<ldelim>\\[?)(?P<assoc>[\\w\\.\\-]*)(?P<rdelim>\\]?$)')
get_filterset(request, queryset, view)

Sometimes there’s no filterset_class defined yet the client still requests a filter. Make sure they see an error too. This means we have to get_filterset_kwargs() even if there’s no filterset_class.

get_filterset_kwargs(request, queryset, view)

Turns filter[<field>]=<value> into <field>=<value> which is what DjangoFilterBackend expects

Raises

ValidationError – for bad filter syntax

Submodules

rest_framework_json_api.exceptions module
rest_framework_json_api.exceptions.rendered_with_json_api(view)
rest_framework_json_api.exceptions.exception_handler(exc, context)
exception rest_framework_json_api.exceptions.Conflict(detail=None, code=None)

Bases: rest_framework.exceptions.APIException

status_code = 409
default_detail = 'Conflict.'
rest_framework_json_api.filters module
class rest_framework_json_api.filters.OrderingFilter

Bases: rest_framework.filters.OrderingFilter

A backend filter that implements http://jsonapi.org/format/#fetching-sorting and raises a 400 error if any sort field is invalid.

If you prefer not to report 400 errors for invalid sort fields, just use rest_framework.filters.OrderingFilter with ordering_param = “sort”

Also applies DJA format_value() to convert (e.g. camelcase) to underscore. (See JSON_API_FORMAT_FIELD_NAMES in docs/usage.md)

ordering_param = 'sort'

override rest_framework.filters.OrderingFilter.ordering_param with JSON:API-compliant query parameter name.

remove_invalid_fields(queryset, fields, view, request)

Extend rest_framework.filters.OrderingFilter.remove_invalid_fields() to validate that all provided sort fields exist (as contrasted with the super’s behavior which is to silently remove invalid fields).

Raises

ValidationError – if a sort field is invalid.

class rest_framework_json_api.filters.QueryParameterValidationFilter

Bases: rest_framework.filters.BaseFilterBackend

A backend filter that performs strict validation of query parameters for JSON:API spec conformance and raises a 400 error if non-conforming usage is found.

If you want to add some additional non-standard query parameters, override query_regex adding the new parameters. Make sure to comply with the rules at http://jsonapi.org/format/#query-parameters.

query_regex = re.compile('^(sort|include)$|^(?P<type>filter|fields|page)(\\[[\\w\\.\\-]+\\])?$')

compiled regex that matches the allowed http://jsonapi.org/format/#query-parameters: sort and include stand alone; filter, fields, and page have []’s

validate_query_params(request)

Validate that query params are in the list of valid query keywords in query_regex

Raises

ValidationError – if not.

filter_queryset(request, queryset, view)

Overrides BaseFilterBackend.filter_queryset() by first validating the query params with validate_query_params()

rest_framework_json_api.metadata module
class rest_framework_json_api.metadata.JSONAPIMetadata

Bases: rest_framework.metadata.SimpleMetadata

This is the JSON:API metadata implementation. It returns an ad-hoc set of information about the view. There are not any formalized standards for OPTIONS responses for us to base this on.

type_lookup = <rest_framework.utils.field_mapping.ClassLookupDict object>
relation_type_lookup = <rest_framework.utils.field_mapping.ClassLookupDict object>
determine_metadata(request, view)
get_serializer_info(serializer)

Given an instance of a serializer, return a dictionary of metadata about its fields.

get_field_info(field)

Given an instance of a serializer field, return a dictionary of metadata about it.

rest_framework_json_api.pagination module

Pagination fields

class rest_framework_json_api.pagination.JsonApiPageNumberPagination

Bases: rest_framework.pagination.PageNumberPagination

A json-api compatible pagination format.

page_query_param = 'page[number]'
page_size_query_param = 'page[size]'
max_page_size = 100
get_paginated_response(data)
class rest_framework_json_api.pagination.JsonApiLimitOffsetPagination

Bases: rest_framework.pagination.LimitOffsetPagination

A limit/offset based style. For example:

http://api.example.org/accounts/?page[limit]=100
http://api.example.org/accounts/?page[offset]=400&page[limit]=100
limit_query_param = 'page[limit]'
offset_query_param = 'page[offset]'
max_limit = 100
get_paginated_response(data)
rest_framework_json_api.parsers module

Parsers

class rest_framework_json_api.parsers.JSONParser

Bases: rest_framework.parsers.JSONParser

Similar to JSONRenderer, the JSONParser you may override the following methods if you need highly custom parsing control.

A JSON API client will send a payload that looks like this:

{
    "data": {
        "type": "identities",
        "id": 1,
        "attributes": {
            "first_name": "John",
            "last_name": "Coltrane"
        }
    }
}

We extract the attributes so that DRF serializers can work as normal.

media_type = 'application/vnd.api+json'
renderer_class

alias of rest_framework_json_api.renderers.JSONRenderer

static parse_attributes(data)
static parse_relationships(data)
static parse_metadata(result)

Returns a dictionary which will be merged into parsed data of the request. By default, it reads the meta content in the request body and returns it in a dictionary with a _meta top level key.

parse(stream, media_type=None, parser_context=None)

Parses the incoming bytestream as JSON and returns the resulting data

rest_framework_json_api.relations module
class rest_framework_json_api.relations.SkipDataMixin(*args, **kwargs)

Bases: object

This workaround skips “data” rendering for relationships in order to save some sql queries and improve performance

get_attribute(instance)
to_representation(*args)
class rest_framework_json_api.relations.ManyRelatedFieldWithNoData(*args, **kwargs)

Bases: rest_framework_json_api.relations.SkipDataMixin, rest_framework.relations.ManyRelatedField

class rest_framework_json_api.relations.HyperlinkedMixin(self_link_view_name=None, related_link_view_name=None, **kwargs)

Bases: object

get_url(name, view_name, kwargs, request)

Given a name, view name and kwargs, return the URL that hyperlinks to the object.

May raise a NoReverseMatch if the view_name and lookup_field attributes are not configured to correctly match the URL conf.

class rest_framework_json_api.relations.HyperlinkedRelatedField(*args, **kwargs)

Bases: rest_framework_json_api.relations.HyperlinkedMixin, rest_framework_json_api.relations.SkipDataMixin, rest_framework.relations.RelatedField

classmethod many_init(*args, **kwargs)

This method handles creating a parent ManyRelatedField instance when the many=True keyword argument is passed.

Typically you won’t need to override this method.

Note that we’re over-cautious in passing most arguments to both parent and child classes in order to try to cover the general case. If you’re overriding this method you’ll probably want something much simpler, eg:

@classmethod
def many_init(cls, *args, **kwargs):
    kwargs['child'] = cls()
    return CustomManyRelatedField(*args, **kwargs)
class rest_framework_json_api.relations.ResourceRelatedField(*args, **kwargs)

Bases: rest_framework_json_api.relations.HyperlinkedMixin, rest_framework.relations.PrimaryKeyRelatedField

default_error_messages = {'does_not_exist': 'Invalid pk "{pk_value}" - object does not exist.', 'incorrect_relation_type': 'Incorrect relation type. Expected {relation_type}, received {received_type}.', 'incorrect_type': 'Incorrect type. Expected resource identifier object, received {data_type}.', 'missing_id': "Invalid resource identifier object: missing 'id' attribute", 'missing_type': "Invalid resource identifier object: missing 'type' attribute", 'no_match': 'Invalid hyperlink - No URL match.', 'required': 'This field is required.'}
use_pk_only_optimization()
conflict(key, **kwargs)

A helper method that simply raises a validation error.

to_internal_value(data)
to_representation(value)
get_resource_type_from_included_serializer()

Check to see it this resource has a different resource_name when included and return that name, or None

get_parent_serializer()
is_serializer(candidate)
get_choices(cutoff=None)
class rest_framework_json_api.relations.PolymorphicResourceRelatedField(*args, **kwargs)

Bases: rest_framework_json_api.relations.ResourceRelatedField

Inform DRF that the relation must be considered polymorphic. Takes a polymorphic_serializer as the first positional argument to retrieve then validate the accepted types set.

default_error_messages = {'does_not_exist': 'Invalid pk "{pk_value}" - object does not exist.', 'incorrect_relation_type': 'Incorrect relation type. Expected one of [{relation_type}], received {received_type}.', 'incorrect_type': 'Incorrect type. Expected resource identifier object, received {data_type}.', 'missing_id': "Invalid resource identifier object: missing 'id' attribute", 'missing_type': "Invalid resource identifier object: missing 'type' attribute", 'no_match': 'Invalid hyperlink - No URL match.', 'required': 'This field is required.'}
use_pk_only_optimization()
to_internal_value(data)
class rest_framework_json_api.relations.SerializerMethodFieldBase(*args, **kwargs)

Bases: rest_framework.fields.Field

bind(field_name, parent)
get_attribute(instance)
class rest_framework_json_api.relations.ManySerializerMethodResourceRelatedField(*args, **kwargs)

Bases: rest_framework_json_api.relations.SerializerMethodFieldBase, rest_framework_json_api.relations.ResourceRelatedField

to_representation(value)
class rest_framework_json_api.relations.SerializerMethodResourceRelatedField(*args, **kwargs)

Bases: rest_framework_json_api.relations.SerializerMethodFieldBase, rest_framework_json_api.relations.ResourceRelatedField

Allows us to use serializer method RelatedFields with return querysets

many_kwargs = ['read_only', 'write_only', 'required', 'default', 'initial', 'source', 'label', 'help_text', 'style', 'error_messages', 'allow_empty', 'html_cutoff', 'html_cutoff_text', 'self_link_view_name', 'related_link_view_name', 'related_link_lookup_field', 'related_link_url_kwarg', 'method_name', 'model']
many_cls

alias of ManySerializerMethodResourceRelatedField

classmethod many_init(*args, **kwargs)
class rest_framework_json_api.relations.ManySerializerMethodHyperlinkedRelatedField(*args, **kwargs)

Bases: rest_framework_json_api.relations.SkipDataMixin, rest_framework_json_api.relations.ManySerializerMethodResourceRelatedField

class rest_framework_json_api.relations.SerializerMethodHyperlinkedRelatedField(*args, **kwargs)

Bases: rest_framework_json_api.relations.SkipDataMixin, rest_framework_json_api.relations.SerializerMethodResourceRelatedField

many_cls

alias of ManySerializerMethodHyperlinkedRelatedField

rest_framework_json_api.renderers module

Renderers

class rest_framework_json_api.renderers.JSONRenderer

Bases: rest_framework.renderers.JSONRenderer

The JSONRenderer exposes a number of methods that you may override if you need highly custom rendering control.

Render a JSON response per the JSON API spec:

{
  "data": [
    {
      "type": "companies",
      "id": 1,
      "attributes": {
        "name": "Mozilla",
        "slug": "mozilla",
        "date-created": "2014-03-13 16:33:37"
      }
    }
  ]
}
media_type = 'application/vnd.api+json'
format = 'vnd.api+json'
classmethod extract_attributes(fields, resource)

Builds the attributes object of the JSON API resource object.

classmethod extract_relationships(fields, resource, resource_instance)

Builds the relationships top level object based on related serializers.

classmethod extract_relation_instance(field, resource_instance)

Determines what instance represents given relation and extracts it.

Relation instance is determined exactly same way as it determined in parent serializer

classmethod extract_included(fields, resource, resource_instance, included_resources, included_cache)

Adds related data to the top level included key when the request includes ?include=example,example_field2

classmethod extract_meta(serializer, resource)

Gathers the data from serializer fields specified in meta_fields and adds it to the meta object.

classmethod extract_root_meta(serializer, resource)

Calls a get_root_meta function on a serializer, if it exists.

classmethod build_json_resource_obj(fields, resource, resource_instance, resource_name, force_type_resolution=False)

Builds the resource object (type, id, attributes) and extracts relationships.

render_relationship_view(data, accepted_media_type=None, renderer_context=None)
render_errors(data, accepted_media_type=None, renderer_context=None)
render(data, accepted_media_type=None, renderer_context=None)
rest_framework_json_api.serializers module
class rest_framework_json_api.serializers.ResourceIdentifierObjectSerializer(*args, **kwargs)

Bases: rest_framework.serializers.BaseSerializer

default_error_messages = {'does_not_exist': 'Invalid pk "{pk_value}" - object does not exist.', 'incorrect_model_type': 'Incorrect model type. Expected {model_type}, received {received_type}.', 'incorrect_type': 'Incorrect type. Expected pk value, received {data_type}.'}
model_class = None
to_representation(instance)
to_internal_value(data)
class rest_framework_json_api.serializers.SparseFieldsetsMixin(*args, **kwargs)

Bases: object

class rest_framework_json_api.serializers.IncludedResourcesValidationMixin(*args, **kwargs)

Bases: object

class rest_framework_json_api.serializers.SerializerMetaclass(name, bases, attrs)

Bases: rest_framework.serializers.SerializerMetaclass

class rest_framework_json_api.serializers.Serializer(*args, **kwargs)

Bases: rest_framework_json_api.serializers.IncludedResourcesValidationMixin, rest_framework_json_api.serializers.SparseFieldsetsMixin, rest_framework.serializers.Serializer

class rest_framework_json_api.serializers.HyperlinkedModelSerializer(*args, **kwargs)

Bases: rest_framework_json_api.serializers.IncludedResourcesValidationMixin, rest_framework_json_api.serializers.SparseFieldsetsMixin, rest_framework.serializers.HyperlinkedModelSerializer

A type of ModelSerializer that uses hyperlinked relationships instead of primary key relationships. Specifically:

  • A ‘url’ field is included instead of the ‘id’ field.

  • Relationships to other instances are hyperlinks, instead of primary keys.

Included Mixins:

  • A mixin class to enable sparse fieldsets is included

  • A mixin class to enable validation of included resources is included

class rest_framework_json_api.serializers.ModelSerializer(*args, **kwargs)

Bases: rest_framework_json_api.serializers.IncludedResourcesValidationMixin, rest_framework_json_api.serializers.SparseFieldsetsMixin, rest_framework.serializers.ModelSerializer

A ModelSerializer is just a regular Serializer, except that:

  • A set of default fields are automatically populated.

  • A set of default validators are automatically populated.

  • Default .create() and .update() implementations are provided.

The process of automatically determining a set of serializer fields based on the model fields is reasonably complex, but you almost certainly don’t need to dig into the implementation.

If the ModelSerializer class doesn’t generate the set of fields that you need you should either declare the extra/differing fields explicitly on the serializer class, or simply use a Serializer class.

Included Mixins:

  • A mixin class to enable sparse fieldsets is included

  • A mixin class to enable validation of included resources is included

alias of rest_framework_json_api.relations.ResourceRelatedField

get_field_names(declared_fields, info)

We override the parent to omit explicity defined meta fields (such as SerializerMethodFields) from the list of declared fields

to_representation(instance)

Object instance -> Dict of primitive datatypes.

class rest_framework_json_api.serializers.PolymorphicSerializerMetaclass(name, bases, attrs)

Bases: rest_framework_json_api.serializers.SerializerMetaclass

This metaclass ensures that the polymorphic_serializers is correctly defined on a PolymorphicSerializer class and make a cache of model/serializer/type mappings.

class rest_framework_json_api.serializers.PolymorphicModelSerializer(*args, **kwargs)

Bases: rest_framework_json_api.serializers.ModelSerializer

A serializer for polymorphic models. Useful for “lazy” parent models. Leaves should be represented with a regular serializer.

get_fields()

Return an exhaustive list of the polymorphic serializer fields.

classmethod get_polymorphic_serializer_for_instance(instance)

Return the polymorphic serializer associated with the given instance/model. Raise NotImplementedError if no serializer is found for the given model. This usually means that a serializer is missing in the class’s polymorphic_serializers attribute.

classmethod get_polymorphic_model_for_serializer(serializer)

Return the polymorphic model associated with the given serializer. Raise NotImplementedError if no model is found for the given serializer. This usually means that a serializer is missing in the class’s polymorphic_serializers attribute.

classmethod get_polymorphic_serializer_for_type(obj_type)

Return the polymorphic serializer associated with the given type. Raise NotImplementedError if no serializer is found for the given type. This usually means that a serializer is missing in the class’s polymorphic_serializers attribute.

classmethod get_polymorphic_model_for_type(obj_type)

Return the polymorphic model associated with the given type. Raise NotImplementedError if no model is found for the given type. This usually means that a serializer is missing in the class’s polymorphic_serializers attribute.

classmethod get_polymorphic_types()

Return the list of accepted types.

to_representation(instance)

Retrieve the appropriate polymorphic serializer and use this to handle representation.

to_internal_value(data)

Ensure that the given type is one of the expected polymorphic types, then retrieve the appropriate polymorphic serializer and use this to handle internal value.

rest_framework_json_api.settings module

This module provides the json_api_settings object that is used to access JSON API REST framework settings, checking for user settings first, then falling back to the defaults.

class rest_framework_json_api.settings.JSONAPISettings(user_settings=<LazySettings "example.settings">, defaults={'FORMAT_FIELD_NAMES': False, 'FORMAT_TYPES': False, 'PLURALIZE_TYPES': False, 'SERIALIZE_NESTED_SERIALIZERS_AS_ATTRIBUTE': False, 'UNIFORM_EXCEPTIONS': False})

Bases: object

A settings object that allows json api settings to be access as properties.

rest_framework_json_api.settings.reload_json_api_settings(*args, **kwargs)
rest_framework_json_api.utils module
rest_framework_json_api.utils.get_resource_name(context, expand_polymorphic_types=False)

Return the name of a resource.

rest_framework_json_api.utils.get_serializer_fields(serializer)
rest_framework_json_api.utils.format_field_names(obj, format_type=None)

Takes a dict and returns it with formatted keys as set in format_type or JSON_API_FORMAT_FIELD_NAMES

Format_type

Either ‘dasherize’, ‘camelize’, ‘capitalize’ or ‘underscore’

rest_framework_json_api.utils.format_value(value, format_type=None)
rest_framework_json_api.utils.format_resource_type(value, format_type=None, pluralize=None)
rest_framework_json_api.utils.get_resource_type_from_model(model)
rest_framework_json_api.utils.get_resource_type_from_queryset(qs)
rest_framework_json_api.utils.get_resource_type_from_instance(instance)
rest_framework_json_api.utils.get_resource_type_from_manager(manager)
rest_framework_json_api.utils.get_resource_type_from_serializer(serializer)
rest_framework_json_api.utils.get_included_resources(request, serializer=None)

Build a list of included resources.

rest_framework_json_api.utils.get_default_included_resources_from_serializer(serializer)
rest_framework_json_api.utils.get_included_serializers(serializer)
rest_framework_json_api.utils.get_relation_instance(resource_instance, source, serializer)

Bases: str

A string like object that additionally has an associated name. We use this for hyperlinked URLs that may render as a named link in some contexts, or render as a plain URL in others.

Comes from Django REST framework 3.2 https://github.com/tomchristie/django-rest-framework

rest_framework_json_api.utils.format_drf_errors(response, context, exc)
rest_framework_json_api.utils.format_error_object(message, pointer, response)
rest_framework_json_api.utils.format_errors(data)
rest_framework_json_api.views module
class rest_framework_json_api.views.PreloadIncludesMixin

Bases: object

This mixin provides a helper attributes to select or prefetch related models based on the include specified in the URL.

__all__ can be used to specify a prefetch which should be done regardless of the include

# When MyViewSet is called with ?include=author it will prefetch author and authorbio
class MyViewSet(viewsets.ModelViewSet):
    queryset = Book.objects.all()
    prefetch_for_includes = {
        '__all__': [],
        'category.section': ['category']
    }
    select_for_includes = {
        '__all__': [],
        'author': ['author', 'author__authorbio'],
    }
get_queryset(*args, **kwargs)
class rest_framework_json_api.views.AutoPrefetchMixin

Bases: object

get_queryset(*args, **kwargs)

This mixin adds automatic prefetching for OneToOne and ManyToMany fields.

class rest_framework_json_api.views.RelatedMixin

Bases: object

This mixin handles all related entities, whose Serializers are declared in “related_serializers”

get_serializer_class()
class rest_framework_json_api.views.ModelViewSet(**kwargs)

Bases: rest_framework_json_api.views.AutoPrefetchMixin, rest_framework_json_api.views.PreloadIncludesMixin, rest_framework_json_api.views.RelatedMixin, rest_framework.viewsets.ModelViewSet

http_method_names = ['get', 'post', 'patch', 'delete', 'head', 'options']
class rest_framework_json_api.views.ReadOnlyModelViewSet(**kwargs)

Bases: rest_framework_json_api.views.AutoPrefetchMixin, rest_framework_json_api.views.RelatedMixin, rest_framework.viewsets.ReadOnlyModelViewSet

http_method_names = ['get', 'post', 'patch', 'delete', 'head', 'options']
class rest_framework_json_api.views.RelationshipView(**kwargs)

Bases: rest_framework.generics.GenericAPIView

serializer_class

alias of rest_framework_json_api.serializers.ResourceIdentifierObjectSerializer

field_name_mapping = {}
http_method_names = ['get', 'post', 'patch', 'delete', 'head', 'options']
get_serializer_class()
get_url(name, view_name, kwargs, request)

Given a name, view name and kwargs, return the URL that hyperlinks to the object.

May raise a NoReverseMatch if the view_name and lookup_field attributes are not configured to correctly match the URL conf.

get(request, *args, **kwargs)
remove_relationships(instance_manager, field)
patch(request, *args, **kwargs)
post(request, *args, **kwargs)
delete(request, *args, **kwargs)
get_resource_name()
set_resource_name(value)
property resource_name

Contributing

DJA should be easy to contribute to. If anything is unclear about how to contribute, please submit an issue on GitHub so that we can fix it!

How

Before writing any code, have a conversation on a GitHub issue to see if the proposed change makes sense for the project.

Fork DJA on GitHub and submit a Pull Request when you’re ready.

For maintainers

To upload a release (using version 1.2.3 as the example):

(venv)$ python setup.py sdist bdist_wheel
(venv)$ twine upload dist/*
(venv)$ git tag -a v1.2.3 -m 'Release 1.2.3'
(venv)$ git push --tags

Indices and tables