isAif
isAif

Reputation: 2334

How to validate child serializer that requires data from parent in django rest framework nested serializer?

I am using DRF Writable Nested to create writable nested serializer.

I need to validate 'ItemDetail' but it requires 'product_id' which is present in the parent serializer i.e. 'InvoiceItem'.

Models

class InvoiceItem(models.Model):
    product = models.ForeignKey(
        Product, on_delete=models.CASCADE, related_name="invoice_items"
    )


class ItemDetail(models.Model):
    invoice_item = models.ForeignKey(
        InvoiceItem, on_delete=models.CASCADE, related_name="item_details"
    )
    size = models.ForeignKey(
        Size, on_delete=models.CASCADE, related_name="item_details"
    )
    quantity = models.PositiveIntegerField()

Serializers

class InvoiceItemSerializer(WritableNestedModelSerializer):
    product = ProductMiniSerializer(read_only=True)
    product_id = serializers.IntegerField(write_only=True)
    item_details = ItemDetailSerializer(many=True)

    class Meta:
        model = InvoiceItem
        fields = [
            "id",
            "product_id",
            "product",
            "item_details",
        ]


class ItemDetailSerializer(serializers.ModelSerializer):

    class Meta:
        model = ItemDetail
        fields = [
            "id",
            "size",
            "quantity",
        ]

    def validate(self, data):
        return item_detail_validate(self, data)

Validator

def item_detail_validate(self, data):
    # How to get product_id here so I can use it in a query
    return data

Upvotes: 9

Views: 3067

Answers (2)

vaZark
vaZark

Reputation: 115

This is a little late but for anyone else coming here, use the following when dealing with many=True

def validate(self, data):
    product_id = self.parent.parent.initial_data['product_id']
    return item_detail_validate(self, data)

Usually when making a related reference, self.parent.initial_data can fetch the data from the parent serializer. However, when we use many=True, DRF implicitly calls the ListSerializer. It passes the child serializer to ListSerializer, which is then passed to the parent serializer

Reference: https://www.django-rest-framework.org/api-guide/serializers/#listserializer

Upvotes: 8

JPG
JPG

Reputation: 88499

Access the initial_data attribute of serializer's parent,

def validate(self, data):
    product_id = self.parent.initial_data['product_id']
    return item_detail_validate(self, data)

Upvotes: 3

Related Questions