lukik
lukik

Reputation: 4060

Using DRF serializer to validate a list of dictionaries

How do I write a serializer that validates a list of dictionaries?

Sample payload being sent is:

"payment_discount": [
    {
        "discount_rule_id": 1,
        "discount_rule_name": "10 day early payment",
        "discount_earned": "298.00"
    },
    {
        "discount_rule_id": 2,
        "discount_rule_name": "Store discount",
        "discount_earned": "5.50"
    },
]

Taking from this SO answer and this:

class PaymentDiscountSerializer(serializers.DictField):

    discount_rule_id = serializers.IntegerField(required=False)
    discount_rule_name = serializers.CharField(max_length=50)
    discount_earned = serializers.DecimalField(max_digits=10, decimal_places=3)

class PaymentDiscountListSerializer(serializers.ListField):
    """Serialize discount object"""
    child = PaymentDiscountSerializer()

class PaymentSerializer(serializers.ModelSerializer):
    payment_discount = PaymentDiscountListSerializer()
    # Other model fields

With this, I can get access to the payment_discount object in the payload using serializer.data but unfortunately no validations are being done against the dictionary if e.g. the payload includes discount_earned value of that is not of type Decimal

using: Django==1.10.2 & djangorestframework==3.5.1

Upvotes: 3

Views: 7505

Answers (1)

F. Caron
F. Caron

Reputation: 648

I think you can simplify your serializers... Haven't tested it but you could use something like this:

class PaymentDiscountSerializer(serializers.Serializer):
    """Serialize discounts"""
    discount_rule_id = serializers.IntegerField(required=False)
    discount_rule_name = serializers.CharField(max_length=50)
    discount_earned = serializers.DecimalField(max_digits=10, decimal_places=3)

class PaymentSerializer(serializers.ModelSerializer):
    payment_discount = PaymentDiscountSerializer(many=True)
    # Other model fields

It should give you a list of object like you want.

For the validation, it should work right out of the box like this.

But again, I haven't tested it. If you are having problems with your validations, you can define your own. Example:

class PaymentDiscountSerializer(serializers.Serializer):
    """Serialize discounts"""
    discount_rule_id = serializers.IntegerField(required=False)
    discount_rule_name = serializers.CharField(max_length=50)
    discount_earned = serializers.DecimalField(max_digits=10, decimal_places=3)

    def validate_discount_rule_id(self, value):
        # Validation logic of the discount_rule_id field
        #
        return value

    def validate(self, attrs):
        # Validation logic of all the fields
        #
        return attrs

see http://www.django-rest-framework.org/api-guide/serializers/#field-level-validation for more infos.

Upvotes: 10

Related Questions