# django-rest-framework-json-api, a JSON:API renderer for Django REST framework

> This package makes Django REST framework speak JSON:API, replacing the default paginated envelope with a document of links, data, attributes and meta. It keeps the framework's view, serializer and filter model intact, ships a full example app, and targets recent Python, Django and DRF series.

**django-json-api/django-rest-framework-json-api** — JSON:API support for Django REST framework

- Repository: https://github.com/django-json-api/django-rest-framework-json-api
- Website: https://django-rest-framework-json-api.readthedocs.org/
- Stars: 1,256 · Forks: 303
- Language: Python
- License: BSD-2-Clause
- Published: 2026-10-19 · Updated: 2026-10-19 · Language: en
- Canonical page: https://hysenlabs.com/projects/django-json-api-django-rest-framework-json-api

## Why the default DRF envelope is not JSON:API

The package exists because the response Django REST framework produces by default does not match the JSON:API format. A stock DRF paginated list response is an object with `count`, `next` and `previous` keys and a `results` array holding plain objects with their fields inline. The JSON:API equivalent of the same identity model is a document with a top-level `links` object, a `data` array whose entries carry a `type` and an `id`, an `attributes` object per entry, and a `meta` object that holds the pagination count.

```json
{
    "links": {
        "prev": "https://example.com/api/1.0/identities",
        "self": "https://example.com/api/1.0/identities?page=2",
        "next": "https://example.com/api/1.0/identities?page=3",
    },
    "data": [{
        "type": "identities",
        "id": "3",
        "attributes": {
            "username": "john",
            "full-name": "John Coltrane"
        }
    }]
}
```

Two details in that example show how much the formats differ. The identifier becomes a string under `id` rather than a number, and the field name `full_name` becomes `full-name`, with a hyphen, inside `attributes`. That hyphenation is not cosmetic: an attribute whose Python name contains an underscore has to be transformed into a hyphenated member name. The package handles that inflection automatically, and it also handles relationships, links, extra top level data through nested serializers, paginators, filters and shortcuts.

## Five goals, one of which is a refusal to work around DRF

The project states its goals as a numbered list, and the second one is the most telling: be as compatible with Django REST framework as possible, with issues in the framework to be fixed upstream rather than worked around in this package. That is a design stance, not a feature list, and it explains the shape of the code. There is no alternative view base class and no fork of the framework. There is a JSON:API renderer and parser that slot into the existing pipeline, a pagination class, an exception handler, a metadata class and a set of filter backends. The other goals are support for the JSON:API specification to compliance, sane defaults so the package is easy to pick up, being solid and tested with good coverage, and being performant. The package assumes you are using class-based views, which is the other structural assumption everything else rests on. The pagination count does not disappear in the new shape, it moves into the metadata object.

```json
{
    "meta": {
        "pagination": {
          "count": 20
        }
    }
}
```

## Installing it and wiring it into settings

Installation from PyPI is a single pip command, and there is an extra for the optional Django Filter integration. From source, the documented path is to clone the repository, change into the directory and install in editable mode. Then one line goes into the Django settings, and its position matters: the package goes into `INSTALLED_APPS` below `rest_framework`.

```bash
$ pip install djangorestframework-jsonapi
$ # for optional package integrations
$ pip install djangorestframework-jsonapi['django-filter']
```

The settings entry is unremarkable but the ordering is called out explicitly.

```python
INSTALLED_APPS = [
    ...
    'rest_framework',
    'rest_framework_json_api',
    ...
]
```

## The settings block that replaces the framework defaults

The substantive configuration is the `REST_FRAMEWORK` dict, and the package ships a full example of it. It overrides the exception handler with the package one, swaps the default pagination class for `JsonApiPageNumberPagination`, and replaces the default parser and renderer classes with the JSON:API versions while keeping the form and multipart parsers and the browsable API renderer. It sets the default metadata class to `JSONAPIMetadata`, and the default filter backends to a stack: a query parameter validation filter, an ordering filter from the package, a Django filter backend from the package, and the framework's search filter.

```python
REST_FRAMEWORK = {
    'PAGE_SIZE': 10,
    'EXCEPTION_HANDLER': 'rest_framework_json_api.exceptions.exception_handler',
    'DEFAULT_PAGINATION_CLASS':
        'rest_framework_json_api.pagination.JsonApiPageNumberPagination',
    'DEFAULT_METADATA_CLASS': 'rest_framework_json_api.metadata.JSONAPIMetadata',
    'SEARCH_PARAM': 'filter[search]',
    'TEST_REQUEST_DEFAULT_FORMAT': 'vnd.api+json'
}
```

Two entries in that block are worth noticing because they change the shape of requests. The search parameter is `filter[search]` rather than the framework default, and the test request format is set to `vnd.api+json`, which is the media type JSON:API uses. The parser and renderer can also be added to individual view sets instead of overriding the settings globally.

## The example app is the fastest way to see the output

The repository ships a complete example project, and the documentation walks through running it after cloning, assuming a virtualenv is already created and activated. The steps install the requirements, run the migrations against the example settings with the current directory on the Python path, load the `drf_example` fixture, and start the development server.

```bash
$ git clone https://github.com/django-json-api/django-rest-framework-json-api.git
$ cd django-rest-framework-json-api
$ pip install -Ur requirements.txt
$ django-admin migrate --settings=example.settings --pythonpath .
$ django-admin loaddata drf_example --settings=example.settings --pythonpath .
$ django-admin runserver --settings=example.settings --pythonpath .
```

The root URL then lists the available collections, and the documentation notes with a parenthetical that this listing is in a non-JSON:API format, which is a useful detail because it shows the package changes the API responses without changing the plain Django views. The example app is laid out in the usual Django way, with `models.py`, `serializers.py`, `views.py`, `urls.py`, a `factories.py`, a `fixtures/` directory, a `migrations/` directory and its own `tests/` and `settings/` subpackages, so it doubles as a worked example of how the pieces are meant to be used together.

## Version support is a moving target, and the packaging says so

The requirements section is unusually specific, and it is the part most likely to bite a team upgrading an existing application. The supported Python versions are 3.11 through 3.15, the supported Django versions are 5.2, 6.0 and 6.1, and the supported Django REST framework versions are 3.17 and 3.18. The recommendation is to use only the latest patch release of each series, and the general policy is that Python and Django series are supported until their official end of life while the last two DRF series are supported. Optional dependencies such as Django Filter get official support only at their latest release, even though lower versions should work. The packaging metadata is built by hand rather than by a modern backend. The `setup.py` file reads the version out of the package `__init__.py` with a regular expression, walks the directory tree to find packages and package data, and even contains a publish mode that shells out to `python setup.py sdist upload` and then prints the tag and push commands for you to run.

```python
needs_wheel = {"bdist_wheel"}.intersection(sys.argv)
wheel = ["wheel"] if needs_wheel else []
```

The requirements file follows the same hand-managed philosophy, splitting the base set into separate files under `requirements/` so that tox runs only the relevant sets and the dependencies are declared in one place.

## Where the JSON:API route gets expensive

Three costs are visible from the configuration and the format itself. The first is that the spec is opinionated in places where the framework was not. The dash in member names, the string identifier, the required `type` and `id` fields and the `links` and `meta` top-level objects all have consequences for any client you have not already written against JSON:API, and a `full_name` attribute arriving as `full-name` will break consumers that were written for the framework's own output. The second is the filter stack: the query parameter validation filter and the `filter[search]` parameter name mean a client that constructs query strings the Django REST framework way will get different results, including rejections, once the package is in charge. The third is that compliance is asserted rather than demonstrated. The stated goal is to support the JSON:API specification to compliance, but the documentation does not enumerate which optional parts of the specification are implemented, so a team with a strict conformance requirement still has to test the specific features it depends on. None of this makes the package a poor choice; it makes it a choice with a migration attached.

## Conclusion

Adopt this package when you have to publish a JSON:API compliant API from an existing Django REST framework codebase and want the pagination, filtering and error handling to keep working rather than being rewritten, and skip it if you are starting a new API with no requirement for the spec, because the default Django REST framework response shape is simpler and cheaper. Verify three things before you commit: that your Python, Django and DRF versions fall inside the supported window of Python 3.11 to 3.15, Django 5.2 to 6.1 and DRF 3.17 to 3.18; that the `rest_framework_json_api` entry sits below `rest_framework` in `INSTALLED_APPS`, since the documentation is explicit about that order; and that the `vnd.api+json` request format is what your clients actually send, because the test settings default to it.

## FAQ

### What does django-rest-framework-json-api do?

It adds JSON:API support to Django REST framework. Instead of the default paginated envelope, responses use a document with top-level `links`, `data` and `meta`, where each data entry has a `type`, a string `id` and an `attributes` object.

### How do I install and configure it?

Run `pip install djangorestframework-jsonapi`, add `rest_framework_json_api` to `INSTALLED_APPS` below `rest_framework`, and set the `REST_FRAMEWORK` settings to use the package's renderer, parser, pagination class, exception handler, metadata class and filter backends. The optional Django Filter integration is installed with the `django-filter` extra.

### Which Python, Django and DRF versions are supported?

Python 3.11 through 3.15, Django 5.2, 6.0 and 6.1, and Django REST framework 3.17 and 3.18. The project recommends the latest patch release of each series, and supports optional dependencies such as Django Filter only at their latest release.

### Does the package require me to rewrite my views?

No. It assumes you use class-based views and keeps the framework's model intact, providing a renderer, parser, pagination class, exception handler, metadata class and filter backends instead of alternative view or serializer classes. The parser and renderer can also be added to individual view sets rather than configured globally.

### How do I run the bundled example application?

Clone the repository, create and activate a virtualenv, install the requirements with `pip install -Ur requirements.txt`, then run the migrations, load the `drf_example` fixture and start the server, each with `--settings=example.settings --pythonpath .`. The root URL lists the available collections.

## Sources

- [django-json-api/django-rest-framework-json-api on GitHub](https://github.com/django-json-api/django-rest-framework-json-api)
- [License: BSD-2-Clause](https://github.com/django-json-api/django-rest-framework-json-api/blob/main/LICENSE)
- [Project website](https://django-rest-framework-json-api.readthedocs.org/)
- [README](https://github.com/django-json-api/django-rest-framework-json-api/blob/main/README.md)
- [Releases](https://github.com/django-json-api/django-rest-framework-json-api/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/django-json-api-django-rest-framework-json-api
