'Referencing relation's relations in Django Serializer
Let's say I have some models:
class A(models.Model):
...
class B(models.Model):
my_reference_to_a = models.ForeignKey(A)
b_field_1 = ...
b_field_2 = ...
class C(models.Model):
my_reference_to_b = models.ForeignKey(B)
c_field_1 = ...
...
In my serializer for C, I want to include all of the fields in C, all the fields in B, as well as the reference to A in B (but not the reference to B in C), so the JSON API output would be something like this:
{
"data": [{
"type": "C",
"id": "1",
"attributes": {
"b_field_1": "...",
"b_field_2": "...",
"c_field_1": "..."
},
"relationships": {
"a": {
"data": {
"type": "A",
"id": "1"
}
}
}
}],
...
}
How would I go about this? I've already tried doing something like this inside my serializer for C:
A = ASerializer(source='my_reference_to_b.my_reference_to_a')
But that doesn't work, as DRF doesn't seem to support dotted paths for sources. I've also tried supplying a method that returns the proper model (the model is valid inside the method) as the source, but that outputs the reference in the JSON as:
"a": {
"data": null
}
On my A model, I also have a reference to another model, D, that is not explicitly stated in A, but is instead defined in D as a OneToMany relationship (Many D models to one A model) with a resource_name on the ForeignKey declared in D, and trying to reference this in C to include that relationship in the JSON doesn't work, either. I get this error (trying to reference it by doing D = DSerializer(source='B.D')):
'RelatedManager' object has no attribute 'B'
Any help would be greatly appreciated.
Solution 1:[1]
I figured it out. Just answering my own question in case anyone lands on this page and they need help.
You need to use the SerializerMethodResourceRelatedField from the Django Rest Framework JSON API. I had tried the regular ResourceRelatedField without it working, looking through the source code showed me that ResourceRelatedField doesn't support dotted paths. Instead, use SerializerMethodResourceRelatedField with a source pointing to a method that returns the desired relation.
Solution 2:[2]
# Model
from django.db import models
class Album(models.Model):
album_name = models.CharField(max_length=100)
artist = models.CharField(max_length=100)
class Track(models.Model):
album = models.ForeignKey(Album, related_name='tracks',on_delete=models.DO_NOTHING)
order = models.IntegerField()
title = models.CharField(max_length=100)
duration = models.IntegerField()
class Meta:
unique_together = ('album', 'order')
ordering = ['order']
def __unicode__(self):
return '%d: %s' % (self.order, self.title)
# View
from rest_framework import generics,viewsets
from api.models import Album
from api.serializers import AlbumSerializer
class TracksView(generics.ListAPIView):
queryset = Album.objects.all()
serializer_class = AlbumSerializer
class TracksView(generics.CreateAPIView):
queryset = Album.objects.all()
serializer_class = AlbumSerializer
# serializers
from rest_framework import serializers
from api.models import Album
class AlbumSerializer(serializers.ModelSerializer):
tracks = serializers.StringRelatedField(many=True,)
class Meta:
model = Album
fields = ('album_name', 'artist', 'tracks')
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | kaleissin |
| Solution 2 | Ardalan |
