Progger Progger - 2 months ago 18
JSON Question

Django REST Framework Serializer returning object instead of data

I am writing a simple database for the condo I live in which has a list of people, units, unit type (home vs parking space), and unitholder (join table for many-to-many relationship between a person and a unit) - one person can be the owner of a unit type of "home" while renting a parking space.

This is my model:

class Person(models.Model):
first_name = models.CharField(max_length=30, null=False)
last_name = models.CharField(max_length=30, null=False)
phone = models.CharField(max_length=20)
email = models.EmailField(max_length=20)

class UnitType(models.Model):
description = models.CharField(max_length=30)

class Unit(models.Model):
unit_number = models.IntegerField(null=False, unique=True)
unit_type = models.ForeignKey(UnitType, null=False)
unitholders = models.ManyToManyField(Person, through='UnitHolder')

class UnitHolderType(models.Model):
description = models.CharField(max_length=30)

class UnitHolder(models.Model):
person = models.ForeignKey(Person)
unit = models.ForeignKey(Unit)
unitholder_type = models.ForeignKey(UnitHolderType)


This is my view:

class PersonViewSet(viewsets.ModelViewSet):
queryset = Person.objects.all()
serializer_class = PersonSerializer

class UnitHolderTypeViewSet(viewsets.ModelViewSet):
queryset = UnitHolderType.objects.all()
serializer_class = UnitHolderTypeSerializer

class UnitViewSet(viewsets.ModelViewSet):
queryset = Unit.objects.all()
serializer_class = UnitSerializer

class UnitHolderViewSet(viewsets.ModelViewSet):
queryset = UnitHolder.objects.all()
serializer_class = UnitHolderSerializer

class UnitTypeViewSet(viewsets.ModelViewSet):
queryset = UnitType.objects.all()
serializer_class = UnitTypeSerializer


This is my serializer:

class UnitSerializer(serializers.ModelSerializer):
unit_type = serializers.SlugRelatedField(
queryset=UnitType.objects.all(), slug_field='description'
)

class Meta:
model = Unit
fields = ('unit_number', 'unit_type', 'unitholders')

class UnitTypeSerializer(serializers.ModelSerializer):

class Meta:
model = UnitType

class PersonSerializer(serializers.ModelSerializer):
class Meta:
model = Person

class UnitHolderSerializer(serializers.ModelSerializer):
person = serializers.PrimaryKeyRelatedField(many=False, read_only=True)
unit = serializers.PrimaryKeyRelatedField(many=False, read_only=True)

class Meta:
model = UnitHolder
fields = ('person', 'unit', 'unitholder_type')

class UnitHolderTypeSerializer(serializers.ModelSerializer):
class Meta:
model = UnitHolderType


The problem:

When I query the /units endpoint like the following:

u = requests.get('http://localhost:8000/units').json()


My response looks like this:

[{'unit_type': 'Home', 'unit_number': 614, 'unitholders': [1]}]


What I want back is something like this:

[
{
'unit_type': 'Home',
'unit_number': 614,
'unitholders': [
{
'id: 1,
'first_name': 'myfirstname',
'last_name': 'mylastname',
'unitholder_type': 'renter'
}
]
}
]


I'm pretty sure my problem is in my UnitSerializer but I am brand new to DRF and read the through the documentation but still can't seem to figure it out.

Answer

An easy solution would be using depth option:

class UnitSerializer(serializers.ModelSerializer):
    unit_type = serializers.SlugRelatedField(
        queryset=UnitType.objects.all(), slug_field='description'
    )

    class Meta:
        model = Unit
        fields = ('unit_number', 'unit_type', 'unitholders')
        depth = 1

This will serialize all nested relations 1 level deep. If you want to have fine control over how each nested field gets serialized, you can list their serializers explicitly:

class UnitSerializer(serializers.ModelSerializer):
    unit_type = serializers.SlugRelatedField(
        queryset=UnitType.objects.all(), slug_field='description'
    )
    unitholders = UnitHolderSerializer(many=True)

    class Meta:
        model = Unit
        fields = ('unit_number', 'unit_type', 'unitholders')

Also as a side note, you need to look into modifying your querysets inside views to prefetch related objects, otherwise you will destroy the app performance very quickly (using something like django-debug-toolbar for monitoring generated queries is very convenient):

class UnitViewSet(viewsets.ModelViewSet):
    queryset = Unit.objects.all().select_related('unit_type').prefetch_related('unitholders')
    serializer_class = UnitSerializer
Comments