Skip to content

Serializers Reference

Serializers handle conversion between Django model instances and JSON-LD representations for ActivityPub federation. They use field-based configuration to control how data is embedded or referenced.

Core Serializer Classes

ContextModelSerializer

activitypub.serializers.linked_data.ContextModelSerializer

Bases: Serializer

Generic serializer that converts any context model to expanded JSON-LD.

Automatically uses LINKED_DATA_FIELDS from the context model. Handles access control via optional show_() methods.

to_representation(instance)

Convert context model instance to expanded JSON-LD.

Supports explicit field overrides - fields defined in the serializer class will be used instead of automatic introspection for those fields.

Returns dict with full predicate URIs as keys.

Serializes individual context model instances to expanded JSON-LD. Uses the model's LINKED_DATA_FIELDS mapping to convert Django fields to RDF predicates.

Access Control:

Serializers support optional show_<field_name>() methods for field-level access control:

class ActorContextSerializer(ContextModelSerializer):
    def show_followers(self, instance, viewer):
        # Only show followers to the actor themselves
        return viewer and viewer.uri == instance.reference.uri

LinkedDataSerializer

activitypub.serializers.linked_data.LinkedDataSerializer

Bases: BaseSerializer

Serializer for linked data models. Given a reference, find all the associated context models that have data and produces the merged JSON-LD.

Supports embedded mode for simplified representation when referenced from other documents.

__init__(instance, embedded=False, **kwargs)

Initialize the serializer.

Parameters:

Name Type Description Default
instance

Reference object to serialize

required
embedded

If True, uses simplified embedded serializers

False
**kwargs

Additional arguments passed to parent

{}

get_compact_context(instance)

Build the @context array for JSON-LD compaction.

Collects context URLs and EXTRA_CONTEXT from context models that have data. Orders contexts as: AS2 first, other contexts, then extensions dict.

Returns:

Type Description

List representing the @context array

Main serializer that coordinates multiple context models for a reference. Automatically discovers which context models have data and merges their output.

Usage:

from activitypub.serializers import LinkedDataSerializer

serializer = LinkedDataSerializer(
    instance=reference,
    context={'viewer': viewer, 'request': request}
)
expanded_data = serializer.data

Embedded vs Referenced Serialization:

The serializer can use different serializers for main subjects vs embedded objects:

serializer = LinkedDataSerializer(
    instance=reference,
    context={'viewer': viewer},
    embedded=False  # Main subject - shows all fields
)

# For embedded objects, automatically uses embedded variant if configured
embedded_serializer = LinkedDataSerializer(
    instance=reference,
    context={'viewer': viewer},
    embedded=True  # Embedded - omits collection endpoints
)

Collection Serializers

CollectionContextSerializer

activitypub.serializers.as2.CollectionContextSerializer

Bases: ContextModelSerializer

Collection serializer that embeds the first page.

When viewing a collection, the first page is embedded so clients can immediately see some items without an additional request.

Specialized serializer for collection contexts. Handles pagination and item serialization.

NodeInfo Serializer

activitypub.serializers.nodeinfo.NodeInfoSerializer

Bases: Serializer

Serializes server metadata for the NodeInfo protocol.

Custom Serialization

The toolkit supports custom serializers for specific context models:

FEDERATION = {
    'CUSTOM_SERIALIZERS': {
        ObjectContext: CustomObjectSerializer,
    }
}

Custom serializers must inherit from ContextModelSerializer and implement the same interface:

from activitypub.serializers import ContextModelSerializer

class CustomObjectSerializer(ContextModelSerializer):
    def to_representation(self, instance):
        data = super().to_representation(instance)
        # Add custom fields or transformations
        return data

    def show_sensitive_field(self, instance, viewer):
        # Custom access control
        return viewer and self.can_view(viewer, instance)

Serialization Pipeline

The complete serialization pipeline involves two stages:

  1. Serialization - LinkedDataSerializer produces expanded JSON-LD with full predicate URIs. Field definitions control whether related objects are embedded, referenced, or omitted.
  2. Compaction - JSON-LD compaction produces readable output with short keys and @context
# In a view
serializer = LinkedDataSerializer(instance=reference, context={'viewer': viewer})
expanded = serializer.data

# Get compact context and compact the document
context = serializer.get_compact_context(reference)
compacted = jsonld.compact(expanded, context)

This separation of concerns allows each stage to focus on its responsibility: - Serializers extract and convert data, using field types to control structure - Compaction provides readability

Access Control Patterns

Field-Level Control

def show_inbox(self, instance, viewer):
    # Only show inbox URL to owner
    return viewer and viewer.uri == instance.reference.uri

Viewer-Aware Serialization

The viewer parameter in the context represents the authenticated actor viewing the resource:

serializer = LinkedDataSerializer(
    instance=actor_ref,
    context={'viewer': requesting_actor_ref}
)

Serializers can use this to filter fields:

def show_followers(self, instance, viewer):
    if not viewer:
        return False  # Anonymous viewers can't see followers
    if viewer.uri == instance.reference.uri:
        return True  # Actor can see their own followers
    return False  # Others can't see followers

Field-Level Exclusion

Access control happens at serialization time, completely excluding fields from the document before they are even serialized.

Performance Considerations

Serialization involves: - Querying context models for a reference - Walking through LINKED_DATA_FIELDS mappings - Resolving references for foreign keys - Potentially recursing for embedded objects (via EmbeddedReferenceField)

For high-traffic endpoints, consider:

  1. Caching - Cache serialized output for public resources
  2. Selective Loading - Use select_related and prefetch_related when querying references
  3. Depth Limits - EmbeddedReferenceField has a max_depth parameter to prevent expensive recursion
  4. Lazy Evaluation - Serializers evaluate lazily; access .data only when needed