DRF using prefetch_related

414 views Asked by At

I have two classes Vessels and Components, each vessel has several components. I just want to fetch all vessels and all their related components in one query, I thought prefretch_related does that trick but in DRF in the api i am only receiving the vessels without their related components

models.py

class Vessel(models.Model):
    name = models.CharField(max_length=255, null=True, blank=True)
    imo = models.CharField(max_length=255, null=True, blank=True)

    def __str__(self):
        return self.name

class Component(models.Model):
    vessel = models.ForeignKey(
        Vessel, blank=True, null=True, on_delete=models.CASCADE, related_name='vessel_components')
    name = models.CharField(max_length=200, blank=True, null=True)
    manufacturer = models.CharField(max_length=200, blank=True, null=True)
    model = models.CharField(max_length=200, blank=True, null=True)
    type = models.CharField(max_length=200, blank=True, null=True)
    remarks = models.TextField(blank=True, null=True)

    def __str__(self):
        return self.name

serializers.py

class VesselSerializer(serializers.ModelSerializer):
    class Meta:
        model = Vessel
        fields = '__all__'
class ComponentSerializer(serializers.ModelSerializer):
    class Meta:
        model = Component
        fields = '__all__'

the view :

@api_view(['GET'])
def getVessels(request):
    vessels = Vessel.objects.all().prefetch_related('vessel_components')
    vSerializer = VesselSerializer(vessels, many=True)
    return Response(vSerializer.data)

the result i am getting : enter image description here

1

There are 1 answers

0
willeM_ Van Onsem On BEST ANSWER

I thought prefretch_related does that trick but in DRF.

This will fetch the Components for the Vessels, but since your serializers do not serialize these components, these will not end up in the result.

You should define the ComponentSerializer as subserializer for VesselSerializer, so:

class ComponentSerializer(serializers.ModelSerializer):
    class Meta:
        model = Component
        fields = '__all__'

class VesselSerializer(serializers.ModelSerializer):
    vessel_components = ComponentSerializer(many=True)  # 🖘 subserializer
    
    class Meta:
        model = Vessel
        fields = '__all__'