CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-djangorestframework-jsonapi

A Django REST framework API adapter for the JSON:API spec.

Pending
Overview
Eval results
Files

relations.mddocs/

Relations

Resource relationship fields that handle JSON:API resource identifier objects, hyperlinked relationships, and relationship data management with support for both to-one and to-many relationships.

Capabilities

ResourceRelatedField

Main relationship field for JSON:API resource relationships.

class ResourceRelatedField(RelatedField):
    """
    JSON:API resource relationship field.
    
    Handles relationships as resource identifier objects:
    {"type": "resource-type", "id": "123"}
    
    Supports both to-one and to-many relationships with proper
    JSON:API formatting and validation.
    """
    
    queryset = None           # QuerySet for related objects
    many = False             # True for to-many relationships
    read_only = False        # Whether field is read-only
    required = True          # Whether field is required
    allow_null = False       # Whether null values are allowed
    
    def __init__(self, **kwargs):
        """
        Initialize resource relationship field.
        
        Args:
            queryset: QuerySet for related objects
            many: True for to-many relationships
            read_only: Whether field is read-only
            required: Whether field is required
            allow_null: Whether null values allowed
        """
    
    def to_representation(self, value):
        """
        Convert related object(s) to resource identifier object(s).
        
        Args:
            value: Related Django model instance or QuerySet
            
        Returns:
            dict or list: Resource identifier object(s)
        """
    
    def to_internal_value(self, data):
        """
        Convert resource identifier object(s) to Django model instance(s).
        
        Args:
            data: Resource identifier object(s)
            
        Returns:
            Model instance or list of instances
            
        Raises:
            ValidationError: If resource type doesn't match or objects don't exist
        """
    
    def get_attribute(self, instance):
        """Get related object(s) from model instance."""

Usage example:

from rest_framework_json_api import serializers
from rest_framework_json_api.relations import ResourceRelatedField
from myapp.models import Article, Author, Tag

class ArticleSerializer(serializers.ModelSerializer):
    author = ResourceRelatedField(queryset=Author.objects.all())
    tags = ResourceRelatedField(queryset=Tag.objects.all(), many=True)
    
    class Meta:
        model = Article
        fields = ['title', 'content', 'author', 'tags']

# Generates relationships:
# {
#   "relationships": {
#     "author": {
#       "data": {"type": "authors", "id": "5"}
#     },
#     "tags": {
#       "data": [
#         {"type": "tags", "id": "1"},
#         {"type": "tags", "id": "2"}
#       ]
#     }
#   }
# }

HyperlinkedMixin

Mixin that adds hyperlink support to relationship fields.

class HyperlinkedMixin:
    """
    Mixin for hyperlinked relationship fields.
    
    Adds self and related links to relationship objects:
    {
      "data": {"type": "authors", "id": "5"},
      "links": {
        "self": "/articles/1/relationships/author",
        "related": "/articles/1/author"
      }
    }
    """
    
    self_link_view_name = None      # View name for self link
    related_link_view_name = None   # View name for related link
    related_link_lookup_field = 'pk'  # Lookup field for related link
    related_link_url_kwarg = None   # URL kwarg name
    
    def __init__(self, self_link_view_name=None, related_link_view_name=None, **kwargs):
        """
        Initialize hyperlinked mixin.
        
        Args:
            self_link_view_name: View name for relationship self link
            related_link_view_name: View name for related resource link
        """
    
    def get_url(self, name, view_name, kwargs, request):
        """
        Generate URL for hyperlinked relationship.
        
        Args:
            name: Link name ('self' or 'related')
            view_name: Django URL view name
            kwargs: URL kwargs
            request: HTTP request object
            
        Returns:
            str or None: Generated URL
        """
    
    def get_links(self, obj=None, lookup_field='pk'):
        """
        Generate links dict for relationship.
        
        Args:
            obj: Related object instance
            lookup_field: Field to use for lookup
            
        Returns:
            dict: Links with self and/or related URLs
        """

SerializerMethodResourceRelatedField

Resource relationship field that uses a serializer method.

class SerializerMethodResourceRelatedField(Field):
    """
    Resource relationship field that gets its value from a serializer method.
    
    Similar to SerializerMethodField but for relationships.
    Returns resource identifier objects.
    """
    
    def __init__(self, method_name=None, **kwargs):
        """
        Initialize method-based resource field.
        
        Args:
            method_name: Name of serializer method to call
        """
    
    def to_representation(self, obj):
        """
        Get relationship value from serializer method.
        
        Args:
            obj: Object being serialized
            
        Returns:
            dict or list: Resource identifier object(s)
        """

Usage example:

class ArticleSerializer(serializers.ModelSerializer):
    featured_comments = SerializerMethodResourceRelatedField()
    
    def get_featured_comments(self, obj):
        # Return featured comments for this article
        return obj.comments.filter(featured=True)

ManySerializerMethodResourceRelatedField

Many-to-many version of SerializerMethodResourceRelatedField.

class ManySerializerMethodResourceRelatedField(SerializerMethodResourceRelatedField):
    """
    Many-to-many version of SerializerMethodResourceRelatedField.
    
    Always returns a list of resource identifier objects.
    """
    
    many = True  # Always True for this field type

SkipDataMixin

Mixin that skips data rendering for performance optimization.

class SkipDataMixin:
    """
    Mixin that skips "data" rendering in relationships for performance.
    
    Useful when you only want to include relationship links
    without the actual relationship data to save database queries.
    """
    
    def get_attribute(self, instance):
        """Skip field to avoid database queries."""
        raise SkipField
    
    def to_representation(self, *args):
        """Not implemented - data is skipped."""
        raise NotImplementedError

PolymorphicResourceRelatedField

Resource relationship field for polymorphic models.

class PolymorphicResourceRelatedField(ResourceRelatedField):
    """
    Resource relationship field for polymorphic models.
    
    Handles relationships to polymorphic models that can represent
    multiple resource types with proper type detection.
    """

HyperlinkedRelatedField

Hyperlinked relationship field that only provides links.

class HyperlinkedRelatedField(HyperlinkedMixin, SkipDataMixin, RelatedField):
    """
    Hyperlinked relationship field that skips data and only provides links.
    
    Useful for providing relationship links without fetching relationship data
    for performance optimization.
    """

SerializerMethodHyperlinkedRelatedField

Hyperlinked relationship field that uses a serializer method.

class SerializerMethodHyperlinkedRelatedField(HyperlinkedMixin, SerializerMethodFieldBase):
    """
    Hyperlinked relationship field that gets its value from a serializer method.
    
    Combines method-based value retrieval with hyperlink generation.
    """

ManySerializerMethodHyperlinkedRelatedField

Many-to-many version of SerializerMethodHyperlinkedRelatedField.

class ManySerializerMethodHyperlinkedRelatedField(SerializerMethodHyperlinkedRelatedField):
    """
    Many-to-many version of SerializerMethodHyperlinkedRelatedField.
    
    Always returns a list of hyperlinked relationships.
    """
    
    many = True

ManyRelatedFieldWithNoData

Many-to-many field that skips data rendering.

class ManyRelatedFieldWithNoData(SkipDataMixin, DRFManyRelatedField):
    """
    Many-to-many relationship field that skips data for performance.
    
    Only includes relationship links, not the actual relationship data.
    Useful for relationships that would cause expensive database queries.
    """

Relationship Types

To-One Relationships

# ForeignKey field
class ArticleSerializer(serializers.ModelSerializer):
    author = ResourceRelatedField(queryset=Author.objects.all())

# Generates:
# {
#   "relationships": {
#     "author": {
#       "data": {"type": "authors", "id": "5"}
#     }
#   }
# }

To-Many Relationships

# ManyToMany or reverse ForeignKey field
class ArticleSerializer(serializers.ModelSerializer):
    tags = ResourceRelatedField(queryset=Tag.objects.all(), many=True)
    comments = ResourceRelatedField(source='comment_set', many=True, read_only=True)

# Generates:
# {
#   "relationships": {
#     "tags": {
#       "data": [
#         {"type": "tags", "id": "1"},
#         {"type": "tags", "id": "2"}
#       ]
#     },
#     "comments": {
#       "data": [
#         {"type": "comments", "id": "10"},
#         {"type": "comments", "id": "11"}
#       ]
#     }
#   }
# }

Hyperlinked Relationships

class ArticleAuthorField(HyperlinkedMixin, ResourceRelatedField):
    self_link_view_name = 'article-relationships-author'
    related_link_view_name = 'article-author'

class ArticleSerializer(serializers.ModelSerializer):
    author = ArticleAuthorField(queryset=Author.objects.all())

# Generates:
# {
#   "relationships": {
#     "author": {
#       "data": {"type": "authors", "id": "5"},
#       "links": {
#         "self": "/articles/1/relationships/author",
#         "related": "/articles/1/author"
#       }
#     }
#   }
# }

Null Relationships

# Allow null relationships
class ArticleSerializer(serializers.ModelSerializer):
    author = ResourceRelatedField(
        queryset=Author.objects.all(), 
        allow_null=True,
        required=False
    )

# When author is None:
# {
#   "relationships": {
#     "author": {
#       "data": null
#     }
#   }
# }

Performance Optimization

# Skip relationship data for performance
class ArticleSerializer(serializers.ModelSerializer):
    # Only include links, not data
    expensive_relation = ManyRelatedFieldWithNoData()
    
    # Or use custom field with SkipDataMixin
    class OptimizedRelationField(SkipDataMixin, ResourceRelatedField):
        pass
    
    author = OptimizedRelationField()

# Generates relationship with links only:
# {
#   "relationships": {
#     "author": {
#       "links": {
#         "self": "/articles/1/relationships/author",
#         "related": "/articles/1/author"
#       }
#     }
#   }
# }

Error Handling

Relationship fields provide proper validation errors:

# Invalid resource type:
# {
#   "errors": [{
#     "detail": "Incorrect model type. Expected authors, received users.",
#     "source": {"pointer": "/data/relationships/author"}
#   }]
# }

# Object doesn't exist:
# {
#   "errors": [{
#     "detail": "Invalid pk \"999\" - object does not exist.",
#     "source": {"pointer": "/data/relationships/author"}
#   }]
# }

Types

from rest_framework_json_api.relations import (
    ResourceRelatedField,
    HyperlinkedMixin,
    SerializerMethodResourceRelatedField,
    ManySerializerMethodResourceRelatedField,
    SkipDataMixin,
    ManyRelatedFieldWithNoData
)

# Constants
LINKS_PARAMS = [
    "self_link_view_name",
    "related_link_view_name", 
    "related_link_lookup_field",
    "related_link_url_kwarg"
]

Install with Tessl CLI

npx tessl i tessl/pypi-djangorestframework-jsonapi

docs

exceptions-utilities.md

filtering.md

index.md

pagination.md

relations.md

renderers-parsers.md

serializers.md

views.md

tile.json