idik
idik

Reputation: 882

Nested Serializers in Django rest framework

The code

I have these models :

class Activity(models.Model):
    is_child_friendly = models.BooleanField()
    free_wifi = models.BooleanField()
    parking_avilable = models.BooleanField()

class RouteOrdering(models.Model):
    route_id = models.ForeignKey(Route, on_delete=models.CASCADE)
    activity_id = models.ForeignKey(Activity, on_delete=models.CASCADE, related_name='tracks')
    day = models.IntegerField()
    order = models.IntegerField()

    class Meta:
        ordering = ['order']

And these Serializers:

class ActivitySerializer(serializers.ModelSerializer):
    class Meta:
        model = Activity

class RouteOrderingSerializer(serializers.ModelSerializer):
    class Meta:
        model = RouteOrdering
        fields = ('id','day','order','route_id','activity_id','tracks')

The problem

I want the RouteOrderingSerializer to return also the activity with the same activity_id. For this I thought I should use nested serializers.

What I've tried

I've tried adding a nested serializer like so:

activity = ActivitySerializer( read_only=True)

But this resulted no output in the endpoint. I know this is not the use case presented in the documentation, and this is probably why its noy working.

Ill be glad to see what code will work to get this done :)

Upvotes: 0

Views: 896

Answers (2)

Jonathan Richards
Jonathan Richards

Reputation: 1444

I'm not sure why you got an error when you tried the following code. I assumed it was a bug related to the _id ending, but everything works fine when I run it.

class ActivitySerializer(serializers.ModelSerializer):
    class Meta:
        model = Activity

class RouteOrderingSerializer(serializers.ModelSerializer):
    activity_id = ActivitySerializer( read_only=True)
    class Meta:
        model = RouteOrdering
        fields = ('id','day','order','route_id','activity_id','tracks')

While you can, I don't recommend using a name ending in _id for a relation in Django. The issue is that Django internally stores all foreign keys under their <relation_name>_id. This allows various nice things, such as setting <object>.<relation_name>_id to an integer id and saving the object vs setting <object>.<relation_name> to the entire related object (which may require a db lookup to get in the first place). The one place I find this behaviour not intuitive is in serializers, where the default is to represent the relation as "<relation_name>": <id> instead of "<relation_name>_id": <id>, though you can explicitly declare the <relation_name>_id field and either remove or nest the <relation_name> field separately.

If you rename your relations to not have the trailing _id, the following will work:

class ActivitySerializer(serializers.ModelSerializer):
    class Meta:
        model = Activity

class RouteOrderingSerializer(serializers.ModelSerializer):
    activity = ActivitySerializer( read_only=True)
    class Meta:
        model = RouteOrdering
        fields = ('id','day','order','route_id','activity','tracks')

(Note that declaring route instead of route_id would be more in line with the default behaviour, but less clear in my opinion)

Upvotes: 2

Dawn T Cherian
Dawn T Cherian

Reputation: 5436

Try this:

class ActivitySerializer(serializers.ModelSerializer):
    class Meta:
        model = Activity

class RouteOrderingSerializer(serializers.ModelSerializer):
    activity_id = ActivitySerializer()
    class Meta:
        model = RouteOrdering
        fields = ('id','day','order','route_id','activity_id')

Upvotes: 1

Related Questions