Landon
Landon

Reputation: 183

Django Rest Framework nested serializer not showing related data

I have a basic setup using the Django Rest Framework. I have two models and a nested serializer setup:

models.py

from django.db import models

class Plan(models.Model):
    name = models.CharField(max_length='100')

    def __unicode__(self):
        return u'%s' % (self.name)

class Group(models.Model):
    plan = models.ForeignKey('plan')
    name = models.CharField(max_length='50')
    weight = models.SmallIntegerField()

    def __unicode__(self):
        return u'%s - %s' % (self.name, self.plan.name)

serializers.py

from plans.models import Plan, Group
from rest_framework import serializers

class GroupSerializer(serializers.ModelSerializer):
    class Meta:
        model = Group
        fields = ('name', 'weight')

class PlanSerializer(serializers.ModelSerializer):
    group = GroupSerializer(many=True, read_only=True)

    class Meta:
        model = Plan
        fields = ('name', 'group')

views.py

from rest_framework import viewsets

from plans.models import Plan
from plans.serializers import PlanSerializer

class PlanViewSet(viewsets.ModelViewSet):
    queryset = Plan.objects.all()
    serializer_class = PlanSerializer

When I view the serializers relationships in Django's Shell it shows the relationship correctly:

PlanSerializer():
name = CharField(max_length='100')
group = GroupSerializer(many=True, read_only=True):
    name = CharField(max_length='50')
    weight = IntegerField()

What I end up getting back via cURL is:

[
    {
        name: Test Plan
    }
]

What I expect to get back is:

[
    {
        name: Test Plan,
        group: [
                {
                    name: Test Group,
                    weight: 1
                }
        ] 
    }
]

There is no nested data coming through. I'm at a lose for what I've not setup correctly here. Can anyone point me in the correct direction?

Upvotes: 16

Views: 8605

Answers (3)

djvg
djvg

Reputation: 14355

Although not directly applicable to the OP, this may help others that end up here based on the title:

DRF nested serializer not showing related data

This problem also arises if you specify an invalid source value.

For example, if you accidentally try to use django filter notation (a__b) when specifying related objects:

class MySerializer(...):
    ...
    my_field = MyOtherSerializer(
        source='my_related_field__some_set', many=True, read_only=True
    )

In DRF 3.15.2, this does not produce an error. Instead it fails silently: my_field simply does not show up in the serialized data.

To fix this, use dotted notation, as mentioned in the docs:

source='my_related_field.some_set'

This does work, but beware: If my_related_field is null, we still get a missing my_field.

Upvotes: 0

Jeevan Rupacha
Jeevan Rupacha

Reputation: 5866

Never forget to give related name for the foreign key. for eg

In models

plan = modles.ForeignKey(Plan, related_name="plan")

In Serializers

plan = PlanSerializers(many = True, read_only = True)

Upvotes: 3

Todor
Todor

Reputation: 16050

The problem comes from your queryset: queryset = Plan.objects.all(). None of the items in this queryset has .group attribute that's why your result is empty. By default Django creates a reverse relation of the plan ForeignKey called group_set (unless you don't rename it via related_name) (this means that every plan item in the queryset have a group_set attribute which is a queryset containing all the groups of this plan). You can use this attribute in order to get a proper serialization. This means to change:

class PlanSerializer(serializers.ModelSerializer):
    group_set = GroupSerializer(many=True, read_only=True)

    class Meta:
        model = Plan
        fields = ('name', 'group_set')

If you really want to stick with group (btw this is a very bad name for a list of groups). You can hack it with prefetch_related like so:

queryset = Plan.objects.prefetch_related('group_set', to_attr='group')

this way every plan item will have a group attribute - a queryset containing all the groups for this plan.

Upvotes: 23

Related Questions