I have a django-rest-api application with models Record, Tag and Weight, where Record and Tag have many-to-many relation through the Weight model:
# models.py
class Tag(models.Model):
image = models.ImageField(upload_to='tag_images', null=True, blank=True)
class Record(models.Model):
file = models.FileField(upload_to='record_files', null=True, blank=True)
class Weight(models.Model):
record = models.ForeignKey(
Record,
related_name='weights',
on_delete=models.CASCADE
)
tag = models.ForeignKey(
Tag,
related_name='weights',
on_delete=models.CASCADE
)
value = models.IntegerField()
class Meta:
unique_together = ('record', 'tag',)
Both Record and Tag models have a FileField/ImageField parameter. In my REST API view I would like to display Record detail with its full file url and all related Tags with their full image url. This is how my serializers look like:
# serializers.py
class RecordSerializer(serializers.ModelSerializer):
tags = serializers.SerializerMethodField()
class Meta:
model = Record
fields = ('id', 'file', 'tags')
def get_tags(self, obj):
return TagSerializer(Tag.objects.filter(weights__in=obj.weights.all()), many=True).data
class TagSerializer(serializers.ModelSerializer):
class Meta:
model = Tag
fields = ('id', 'image')
The problem is that when I see record detail view its file url is complete but tag image urls are not:
# record detail results
{
"id": 1,
"file": "http://127.0.0.1:8080/media/record_files/record00.mp3",
"tags": [
{
"id": 4,
"image": "/media/tag_images/image04.jpg"
},
{
"id": 10,
"image": "/media/tag_images/image10.jpg"
}
]
}
In the end I have bypassed the problem by creating a separate tag list view and now the urls are complete even though a haven't changed a bit in my serializers.py.
# record tag list results
[
{
"id": 4,
"image": "http://127.0.0.1:8080/media/tag_images/image04.jpg"
},
{
"id": 10,
"image": "http://127.0.0.1:8080/media/tag_images/image10.jpg"
}
]
I suppose this is a cleaner rest api solution anyway (even though I am pretty sure I will not need record detail and its tags separately). Nevertheless, it still bugs me why the urls are incomplete when the data are part of a nested serializer. Is this how its meant to be or what do I do wrong?
Seems like you may have found a better solution, but just in case you are still curious: the problem with your initial attempt was that you put the "nested" serializer call inside a SerializerMethodField
. The usual way to declare a nested serializer is to initialize the serializer when setting the actual field. In your case it would look something like this:
class RecordSerializer(serializers.ModelSerializer):
tags = TagSerializer()
When you do it this way, the TagSerializer
can infer context from the parent serializer, and part of that context is the request. This is then used in to_representation
in a call to build_absolute_uri
to generate the full url you were hoping for.