Search code examples
djangodjango-modelsdjango-rest-frameworkdjango-viewsdrf-queryset

DRF using prefetch_related


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


Solution

  • 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__'