Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Get reverse relation in Django Serializer

Models:

class MaterialRequest(models.Model):

    owner = models.ForeignKey(User, on_delete=models.CASCADE, related_name='owner')
    linked = models.CharField(max_length=50, default="-", blank=True, null=True)
    flows = models.ManyToManyField(MaterialRequestFlow)
    is_allocated = models.BooleanField(default=False)
    delivery_required_on = models.DateTimeField(default=datetime.now)
    raised_by = models.CharField(max_length=1000, default="__________", blank=True, null=True)
    created_at = models.DateTimeField(auto_now_add=True)

class Allotment(models.Model):

    transaction_no = models.IntegerField(default=0)
    sales_order = models.ForeignKey(MaterialRequest, on_delete=models.CASCADE)
    is_delivered = models.BooleanField(default=False)
    document_available = models.BooleanField(default=False)

Now to show my Material Request table I am doing something like this:

class MREmpTableAPIView(APIView):
    permission_classes = (permissions.IsAuthenticated, MRViewPermission)

    def get(self, request, *args, **kwargs):
        items = MaterialRequest.objects.all().order_by('-id')
        serializer = EMaterialRequestTableListSerializer(items, many=True)
        return Response(serializer.data, status=status.HTTP_201_CREATED)

Serializer:

class EMaterialRequestTableListSerializer(serializers.ModelSerializer):

    owner = serializers.SlugRelatedField(read_only=True, slug_field='full_name')

    class Meta:
        model = MaterialRequest
        exclude = ('flows',)

Where I get all the detaila of Material Requests but I also want to show the transaction_no of the linked Allotment in Material Request Table. How do I do that?

Edit:

A single Material Request is linked with a single allotment(transaction_no), I want to show the Transaction no on the same table

Output I am getting:

created_at: "2021-09-22T10:28:44.248034Z"
delivery_required_on: "2021-09-22T09:08:43.968000Z"
id: 739
is_allocated: false
linked: "729-3"
owner: "Lumax Mannoh Allied Technologies Limited"

Desired Output:

created_at: "2021-09-22T10:28:44.248034Z"
delivery_required_on: "2021-09-22T09:08:43.968000Z"
id: 739
is_allocated: false
linked: "729-3"
owner: "Lumax Mannoh Allied Technologies Limited"
transaction_no: foo
like image 350
Yantra Logistics Avatar asked Jun 25 '26 18:06

Yantra Logistics


1 Answers

A straightforward way to solve this is to use a SerializerMethodField like this:

class EMaterialRequestTableListSerializer(serializers.ModelSerializer):
    owner = serializers.SlugRelatedField(read_only=True, slug_field='full_name')
    transaction_no = serializers.SerializerMethodField()

    class Meta:
        model = MaterialRequest
        exclude = ('flows',)

    def get_transaction_no(self, obj)
        allotment = obj.allotment_set.first()
        return allotment.transaction_no if allotment else None

But this will try to hit the database per MaterialRequest instance just to get the related allotments.

To make this more efficient, you can prefetch the related allotments of each material request like this:

items = MaterialRequest.objects.all().order_by('-id').prefetch_related('allotment_set')

And then do something like this in your serializer:

class EMaterialRequestTableListSerializer(serializers.ModelSerializer):
    owner = serializers.SlugRelatedField(read_only=True, slug_field='full_name')
    transaction_no = serializers.SerializerMethodField()

    class Meta:
        model = MaterialRequest
        exclude = ('flows',)

    def get_transaction_no(self, obj)
        if obj.allotment_set.all():
            return obj.allotment_set.all()[0].transaction_no
        return None
like image 134
Brian Destura Avatar answered Jun 28 '26 09:06

Brian Destura