A Django REST framework API adapter for the JSON:API spec.
—
Enhanced Django REST framework views with JSON:API features including automatic include parameter handling, relationship views, prefetching optimization, and JSON:API response formatting.
Enhanced ModelViewSet with JSON:API features and automatic optimization.
class ModelViewSet(PreloadIncludesMixin, viewsets.ModelViewSet):
"""
JSON:API compatible ModelViewSet with automatic include handling and optimization.
Inherits all Django REST framework ModelViewSet functionality while adding:
- Automatic prefetching based on include parameter
- JSON:API response formatting
- Relationship endpoint support
- Resource type detection
"""
queryset = None # QuerySet for this viewset
serializer_class = None # Serializer class
resource_name = None # Override resource type name
# Optimization configuration
prefetch_for_includes = {} # Prefetch config for include paths
select_for_includes = {} # Select_related config for include pathsUsage example:
from rest_framework_json_api import views
from myapp.models import Article
from myapp.serializers import ArticleSerializer
class ArticleViewSet(views.ModelViewSet):
queryset = Article.objects.all()
serializer_class = ArticleSerializer
# Optimize queries for common includes
prefetch_for_includes = {
'__all__': [], # Always prefetch these
'author': ['author'],
'comments': ['comments'],
'comments.user': ['comments__user']
}
select_for_includes = {
'author': ['author'],
'category': ['category']
}
# Automatically handles: GET /articles?include=author,comments
# And optimizes database queries accordinglyRead-only version of ModelViewSet for read-only API endpoints.
class ReadOnlyModelViewSet(PreloadIncludesMixin, viewsets.ReadOnlyModelViewSet):
"""
JSON:API compatible ReadOnlyModelViewSet.
Provides list and retrieve actions only with JSON:API features:
- Include parameter support
- Automatic query optimization
- JSON:API response formatting
"""
queryset = None
serializer_class = None
resource_name = NoneSpecialized view for JSON:API relationship endpoints.
class RelationshipView(generics.GenericAPIView):
"""
View for JSON:API relationship endpoints.
Handles relationship manipulation endpoints like:
- GET /articles/1/relationships/author
- POST /articles/1/relationships/tags
- PATCH /articles/1/relationships/author
- DELETE /articles/1/relationships/tags
"""
queryset = None
serializer_class = None
related_field = None # Name of the related field
def get(self, request, *args, **kwargs):
"""Get relationship data."""
def post(self, request, *args, **kwargs):
"""Add to relationship (for to-many relationships)."""
def patch(self, request, *args, **kwargs):
"""Replace relationship data."""
def delete(self, request, *args, **kwargs):
"""Remove from relationship (for to-many relationships)."""Usage example:
from django.urls import path
from rest_framework_json_api.views import RelationshipView
class ArticleAuthorRelationshipView(RelationshipView):
queryset = Article.objects.all()
related_field = 'author'
# In urls.py:
urlpatterns = [
path('articles/<int:pk>/relationships/author/',
ArticleAuthorRelationshipView.as_view()),
]Base mixin that provides related field handling functionality.
class RelatedMixin:
"""
Base mixin for handling related field operations in JSON:API views.
Provides utilities for getting related instances and handling
relationship operations.
"""
def get_related_instance(self):
"""Get related instance for relationship operations."""
def get_relation_instance(self, resource_instance, source, serializer):
"""Get specific relation instance from resource."""Mixin that provides automatic query optimization based on include parameters.
class PreloadIncludesMixin:
"""
Mixin for automatic query optimization based on include parameter.
Configuration attributes:
- prefetch_for_includes: Dict mapping include paths to prefetch_related() args
- select_for_includes: Dict mapping include paths to select_related() args
Special key '__all__' applies to all requests regardless of include parameter.
"""
prefetch_for_includes = {} # Include path -> prefetch list mapping
select_for_includes = {} # Include path -> select_related list mapping
def get_select_related(self, include):
"""
Get select_related args for an include path.
Args:
include: Include path string (e.g., 'author', 'comments.user')
Returns:
list or None: Arguments for select_related()
"""
def get_prefetch_related(self, include):
"""
Get prefetch_related args for an include path.
Args:
include: Include path string
Returns:
list or None: Arguments for prefetch_related()
"""
def get_queryset(self, *args, **kwargs):
"""
Enhanced get_queryset with automatic optimization.
Analyzes include parameter and applies appropriate
select_related and prefetch_related optimizations.
"""Usage example:
class ArticleViewSet(PreloadIncludesMixin, viewsets.ModelViewSet):
queryset = Article.objects.all()
serializer_class = ArticleSerializer
# When ?include=author is requested, select_related('author')
select_for_includes = {
'author': ['author'],
'category': ['category'],
'author.profile': ['author__profile']
}
# When ?include=comments is requested, prefetch_related('comments')
prefetch_for_includes = {
'comments': ['comments'],
'tags': ['tags'],
'comments.user': ['comments__user']
}Mixin that automatically detects and prefetches relationships.
class AutoPrefetchMixin:
"""
Mixin for automatic prefetching of OneToOne and ManyToMany relationships.
Automatically analyzes include parameter and applies appropriate
prefetching for detected relationship types without manual configuration.
"""
def get_queryset(self, *args, **kwargs):
"""
Enhanced get_queryset with automatic relationship detection.
Automatically detects relationship types and applies:
- select_related for ForeignKey and OneToOne
- prefetch_related for ManyToMany and reverse ForeignKey
"""Views automatically handle the JSON:API include parameter:
# GET /articles?include=author,comments,tags
# Automatically includes related resources in response:
{
"data": [{
"type": "articles",
"id": "1",
"relationships": {
"author": {"data": {"type": "authors", "id": "5"}},
"comments": {"data": [{"type": "comments", "id": "10"}]},
"tags": {"data": [{"type": "tags", "id": "2"}]}
}
}],
"included": [
{"type": "authors", "id": "5", "attributes": {...}},
{"type": "comments", "id": "10", "attributes": {...}},
{"type": "tags", "id": "2", "attributes": {...}}
]
}Views provide sophisticated query optimization:
class ArticleViewSet(views.ModelViewSet):
queryset = Article.objects.all()
# Manual optimization configuration
prefetch_for_includes = {
'__all__': ['tags'], # Always prefetch tags
'author': ['author'],
'comments': ['comments'],
'comments.user': ['comments__user'],
'category.section': ['category'] # Nested relationships
}
select_for_includes = {
'author': ['author', 'author__profile'],
'category': ['category'],
'category.parent': ['category__parent']
}
# Or use AutoPrefetchMixin for automatic detection:
class ArticleViewSet(AutoPrefetchMixin, views.ModelViewSet):
queryset = Article.objects.all()
# No manual configuration neededViews support custom resource names:
class ArticleViewSet(views.ModelViewSet):
queryset = Article.objects.all()
resource_name = 'blog-posts' # Override default 'articles'
# Results in resource type 'blog-posts' instead of 'articles'Views integrate with JSON:API error formatting:
# 404 errors become:
{
"errors": [{
"status": "404",
"detail": "Not found."
}]
}
# Validation errors become:
{
"errors": [{
"status": "400",
"detail": "This field is required.",
"source": {"pointer": "/data/attributes/title"}
}]
}from rest_framework_json_api.views import (
ModelViewSet,
ReadOnlyModelViewSet,
RelationshipView,
PreloadIncludesMixin,
AutoPrefetchMixin
)
# Base classes from Django REST framework
from rest_framework import viewsets, genericsInstall with Tessl CLI
npx tessl i tessl/pypi-djangorestframework-jsonapi