I am trying to view nested annotate (aggregated/calculated) fields in Django REST Framework serializers. This would allow to work more cleanly with annotated fields. This post is similar to Aggregate (and other annotated) fields in Django Rest Framework serializers however I would like a similar technique to work nested. Below the methodology is visible on how this works without nesting and how it doesn't seem to work with nesting.
I know this could be achieved manually (with a Django View) or by using methods that overload the database which I am not interested in. But maybe there is a performant and elegant solution for this problem.
The following works (not nested)
Models
class IceCreamCompany(models.Model):
name = models.CharField(max_length=255)
class IceCreamTruck(models.Model):
company = models.ForeignKey('IceCreamCompany', related_name='trucks')
capacity = models.IntegerField()
class IceCreamTruckDriver(models.Model):
name = models.CharField(max_length=255)
first_name = models.CharField(max_length=255)
truck = models.ForeignKey('IceCreamTruck', related_name='drivers')
Serializers
class IceCreamTruckDriverSerializer(serializers.ModelSerializer):
class Meta:
model = IceCreamTruckDriver
fields = ('name', 'first_name')
class IceCreamTruckSerializer(serializers.ModelSerializer):
drivers = IceCreamTruckDriverSerializer(many=True, read_only=True)
class Meta:
model = IceCreamTruck
fields = ('capacity', 'drivers')
class IceCreamCompanySerializer(serializers.ModelSerializer):
trucks = IceCreamTruckSerializer(many=True, read_only=True)
amount_of_trucks = serializers.IntegerField()
class Meta:
model = IceCreamCompany
fields = ('name', 'trucks', 'amount_of_trucks')
Viewset
class IceCreamCompanyViewSet(viewsets.ModelViewSet):
queryset = IceCreamCompany.objects.prefetch_related('trucks', 'trucks__drivers')\
.annotate(amount_of_trucks=Count('trucks'))\
.all()
serializer_class = IceCreamCompanySerializer
Result
"results": [
{
"name": "Pete Ice Cream",
"trucks": [
{
"capacity": 35,
"drivers": [
{
"name": "Damian",
"first_name": "Ashley"
},
{
"name": "Wilfrid",
"first_name": "Lesley"
}
]
},
{
"capacity": 30,
"drivers": [
{
"name": "Stevens",
"first_name": "Joseph"
}
]
},
{
"capacity": 30,
"drivers": []
}
],
"amount_of_trucks": 3
}
]
The following does not work (nested)
Same models
Serializers
class IceCreamTruckDriverSerializer(serializers.ModelSerializer):
class Meta:
model = IceCreamTruckDriver
fields = ('name', 'first_name')
class IceCreamTruckSerializer(serializers.ModelSerializer):
drivers = IceCreamTruckDriverSerializer(many=True, read_only=True)
amount_of_drivers = serializers.IntegerField()
class Meta:
model = IceCreamTruck
fields = ('capacity', 'drivers', 'amount_of_drivers')
class IceCreamCompanySerializer(serializers.ModelSerializer):
trucks = IceCreamTruckSerializer(many=True, read_only=True)
class Meta:
model = IceCreamCompany
fields = ('name', 'trucks')
Viewset
class IceCreamCompanyViewSet(viewsets.ModelViewSet):
queryset = IceCreamCompany.objects.prefetch_related('trucks', 'trucks__drivers')\
.annotate(trucks__amount_of_drivers=Count('trucks__drivers'))\
.all()
serializer_class = IceCreamCompanySerializer
Result
AttributeError at /ice/
Got AttributeError when attempting to get a value for field `amount_of_drivers` on serializer `IceCreamTruckSerializer`.
The serializer field might be named incorrectly and not match any attribute or key on the `IceCreamTruck` instance.
Original exception text was: 'IceCreamTruck' object has no attribute 'amount_of_drivers'.
SerializerMethodField
? – Luigiluigino