Relational fields are used to represent model relationships. They can be applied to ForeignKey, ManyToManyField and OneToOneField relationships, as well as reverse relationships and custom relationships.
Common Arguments
All relational fields accept the following arguments:
Queryset for model instance lookups. Required for writable fields.
Apply to a to-many relationship.
Accept None for nullable relationships.
Field is used for serialization only.
Field is used for deserialization only.
Field must be present in input data.
Represents the target using its __str__ method.
Class Signature
StringRelatedField(many=False)
Properties:
- Read-only
- Returns string representation of related object
Example
class AlbumSerializer(serializers.ModelSerializer):
tracks = serializers.StringRelatedField(many=True)
class Meta:
model = Album
fields = ['album_name', 'artist', 'tracks']
Output:
{
"album_name": "Things We Lost In The Fire",
"artist": "Low",
"tracks": [
"1: Sunflower",
"2: Whitetail",
"3: Dinosaur Act"
]
}
Represents the target using its primary key.
Class Signature
PrimaryKeyRelatedField(
queryset=None,
many=False,
allow_null=False,
pk_field=None
)
Queryset for model instance lookups. Required unless read_only=True.
Apply to a to-many relationship.
Accept None for nullable relationships.
Field instance to control serialization/deserialization of primary key value.
Properties:
- Read-write by default
- Returns primary key value
Example
class AlbumSerializer(serializers.ModelSerializer):
tracks = serializers.PrimaryKeyRelatedField(many=True, read_only=True)
class Meta:
model = Album
fields = ['album_name', 'artist', 'tracks']
Output:
{
"album_name": "Undun",
"artist": "The Roots",
"tracks": [89, 90, 91]
}
Custom Primary Key
owner = serializers.PrimaryKeyRelatedField(
queryset=User.objects.all(),
pk_field=serializers.UUIDField(format='hex')
)
Represents the target using a hyperlink.
Class Signature
HyperlinkedRelatedField(
view_name,
queryset=None,
many=False,
allow_null=False,
lookup_field='pk',
lookup_url_kwarg=None,
format=None
)
View name for URL reversal. Format: <modelname>-detail.
Queryset for model instance lookups. Required unless read_only=True.
Apply to a to-many relationship.
Accept None for nullable relationships.
Field on target for lookup.
URL keyword argument name. Defaults to lookup_field.
Format suffix for hyperlinks.
Properties:
- Read-write by default
- Requires
request in serializer context
- Returns absolute URL
Example
class AlbumSerializer(serializers.ModelSerializer):
tracks = serializers.HyperlinkedRelatedField(
many=True,
read_only=True,
view_name='track-detail'
)
class Meta:
model = Album
fields = ['album_name', 'artist', 'tracks']
Output:
{
"album_name": "Graceland",
"artist": "Paul Simon",
"tracks": [
"http://www.example.com/api/tracks/45/",
"http://www.example.com/api/tracks/46/"
]
}
Custom Hyperlink
class CustomerHyperlink(serializers.HyperlinkedRelatedField):
view_name = 'customer-detail'
queryset = Customer.objects.all()
def get_url(self, obj, view_name, request, format):
url_kwargs = {
'organization_slug': obj.organization.slug,
'customer_pk': obj.pk
}
return reverse(view_name, kwargs=url_kwargs, request=request, format=format)
def get_object(self, view_name, view_args, view_kwargs):
lookup_kwargs = {
'organization__slug': view_kwargs['organization_slug'],
'pk': view_kwargs['customer_pk']
}
return self.get_queryset().get(**lookup_kwargs)
Represents the target using a field on the target.
Class Signature
SlugRelatedField(
slug_field,
queryset=None,
many=False,
allow_null=False
)
Field on target to represent it. Should be unique.
Queryset for model instance lookups. Required unless read_only=True.
Apply to a to-many relationship.
Accept None for nullable relationships.
Properties:
- Read-write by default
- Returns value of specified field
Example
class AlbumSerializer(serializers.ModelSerializer):
tracks = serializers.SlugRelatedField(
many=True,
read_only=True,
slug_field='title'
)
class Meta:
model = Album
fields = ['album_name', 'artist', 'tracks']
Output:
{
"album_name": "Dear John",
"artist": "Loney Dear",
"tracks": [
"Airport Surroundings",
"Everything Turns to You",
"I Was Only Going Out"
]
}
Nested Relationship
author_email = serializers.SlugRelatedField(
slug_field='author__email',
queryset=Book.objects.all()
)
HyperlinkedIdentityField
Represents the identity URL for an object.
Class Signature
HyperlinkedIdentityField(
view_name,
lookup_field='pk',
lookup_url_kwarg=None,
format=None
)
View name for URL reversal.
Field on target for lookup.
URL keyword argument name. Defaults to lookup_field.
Format suffix for hyperlinks.
Properties:
- Always read-only
- Uses
source='*' to pass entire object
- Requires
request in serializer context
Example
class AlbumSerializer(serializers.HyperlinkedModelSerializer):
track_listing = serializers.HyperlinkedIdentityField(view_name='track-list')
class Meta:
model = Album
fields = ['album_name', 'artist', 'track_listing']
Output:
{
"album_name": "The Eraser",
"artist": "Thom Yorke",
"track_listing": "http://www.example.com/api/track_list/12/"
}
Wrapper field for to-many relationships.
Class Signature
ManyRelatedField(
child_relation=None,
allow_empty=True,
html_cutoff=None,
html_cutoff_text=None
)
The relational field instance for individual items.
Maximum choices displayed in HTML select.
Text indicator for cutoff choices.
Note: Usually created automatically when many=True is set on a relational field.
Nested Relationships
Use serializers as fields to create nested representations.
Example
class TrackSerializer(serializers.ModelSerializer):
class Meta:
model = Track
fields = ['order', 'title', 'duration']
class AlbumSerializer(serializers.ModelSerializer):
tracks = TrackSerializer(many=True, read_only=True)
class Meta:
model = Album
fields = ['album_name', 'artist', 'tracks']
Output:
{
"album_name": "The Gray Album",
"artist": "Danger Mouse",
"tracks": [
{"order": 1, "title": "Public Service Announcement", "duration": 245},
{"order": 2, "title": "What More Can I Say", "duration": 264}
]
}
Writable Nested Serializer
class AlbumSerializer(serializers.ModelSerializer):
tracks = TrackSerializer(many=True)
class Meta:
model = Album
fields = ['album_name', 'artist', 'tracks']
def create(self, validated_data):
tracks_data = validated_data.pop('tracks')
album = Album.objects.create(**validated_data)
for track_data in tracks_data:
Track.objects.create(album=album, **track_data)
return album
Custom Relational Fields
Create custom relational fields by subclassing RelatedField.
Example
import time
class TrackListingField(serializers.RelatedField):
def to_representation(self, value):
duration = time.strftime('%M:%S', time.gmtime(value.duration))
return 'Track %d: %s (%s)' % (value.order, value.title, duration)
class AlbumSerializer(serializers.ModelSerializer):
tracks = TrackListingField(many=True, read_only=True)
class Meta:
model = Album
fields = ['album_name', 'artist', 'tracks']
Output:
{
"album_name": "Sometimes I Wish We Were an Eagle",
"artist": "Bill Callahan",
"tracks": [
"Track 1: Jim Cain (04:39)",
"Track 2: Eid Ma Clack Shaw (04:19)"
]
}
Writable Custom Field
class TrackListingField(serializers.RelatedField):
def to_representation(self, value):
return value.title
def to_internal_value(self, data):
try:
return Track.objects.get(title=data)
except Track.DoesNotExist:
raise serializers.ValidationError(
f'Track with title "{data}" does not exist.'
)
def get_queryset(self):
return Track.objects.all()
Display Customization
Custom String Representation
class TrackPrimaryKeyRelatedField(serializers.PrimaryKeyRelatedField):
def display_value(self, instance):
return 'Track: %s' % (instance.title)
HTML Select Cutoff
assigned_to = serializers.SlugRelatedField(
queryset=User.objects.all(),
slug_field='username',
html_cutoff=100,
html_cutoff_text='More than {count} users...'
)
Or disable HTML select:
assigned_to = serializers.SlugRelatedField(
queryset=User.objects.all(),
slug_field='username',
style={'base_template': 'input.html'}
)