Efficient way to get relationship data

I have a Modal ABC and a field named GROUP which is a foreign key, and this model Abc is also used as a foreign key in another model XYZ.

My requirement is that when I view the list of XYZ with filters such as (whse="01" and abc="02") I want to get the name of the group(from model abc) along with the list data of the XYZ model.

class ABC(models.Model):
    group = models.ForeignKey(Group, on_delete=models.CASCADE)


class XYZ(models.Model):
    abc = models.ForeignKey(ABC, on_delete=models.CASCADE)
    whse = models.ForeignKey(WHSE, on_delete=models.CASCADE)
    qty = models.CharField()

What I do right now is - in serializer I define a SerializerMethodField() fields.

here is the code -

class XYZSerializer(serializers.ModelSerializer):
    groupName = serializers.SerializerMethodField()

    def get_groupName(self, instance):
        return instance.abc.group.name if instance.abc else ''

    class Meta:
        model = ZYX
        fields = '__all__'

I get my desired result but you can see that my filter requirement is always (whse="01" and abc="02") on the XYZ model and so the value of get_groupName is always going to remain the same for each of my requests (my abc is always the same in the output list, so will be the group name).

How can I format my data, serializer to reduce the database query, (to find groupName) for each list item?

EDIT - EDIT -

here is my view

class XYZ_View(generics.ListAPIView):
    permission_classes = [IsAuthenticated]
    serializer_class = XYZSerializer

    def get_queryset(self):
        abcId = self.request.GET.get('abc')
        whseId = self.request.GET.get('whse')
        if abcId and whseId is not None:
            qs = ZYX.objects.filter(abc = itemId, whse = whseId)
            return qs
        return ZYX.objects.none()

You fetch the Group along with it with .select_related(…) [Django-doc]:

class XYZ_View(generics.ListAPIView):
    permission_classes = [IsAuthenticated]
    serializer_class = XYZSerializer

    def get_queryset(self):
        abcId = self.request.GET.get('abc')
        whseId = self.request.GET.get('whse')
        if abcId and whseId is not None:
            return XYZ.objects.filter(abc=itemId, whse=whseId).select_related(
                'abc__group'
            )
        return XYZ.objects.none()

You can rewrite the serializer to:

class XYZSerializer(serializers.ModelSerializer):
    groupName = serializers.CharField(read_only=True, source='abc.group.name')

    class Meta:
        model = XYZ
        fields = '__all__'
Вернуться на верх