Search code examples
djangodjango-rest-frameworkdjango-jsonfield

Validate Json in Django - Django Rest Framework


I need to validate the following JSON:

{
    "monday": [
        //List of MyClass object
    ],
    "tuesday": [
        //List of MyClass Object
    ],
    "wednesday": [
        //List of MyClass Object
    ],
    ......
}

I need to check if it contains any key that is not a day of the week (mondai, thudai for example). Also MyClass is defined as:

class MyClass(models.Model):
    type = models.CharField(unique=True, max_length=20)
    value = models.IntegerField()

The fieldvalue must be a positive integer and cannot exceed 10000. Also, type must be either cost or benefit In Scala I would use the following:

object MyClass {
  val ALLOWED_TYPES = Seq[String]("cost", "benefit")
  implicit val openingHourReads: Reads[OpeningHour] = (
    (JsPath \ "type").read[String].filter(JsonValidationError("Type must be cost or benefit"))(ALLOWED_TYPES.contains(_))  and
      (JsPath \ "value").read[Int](min(1).keepAnd(max(10000)))

    )(MyClass.apply _)

Is there an equivalent approach in Django?


Solution

  • Yes there is a similar approach in django:

    Limiting input data on model level (Question#1):

    # models.py
    from django.core.validators import MaxValueValidator
    
    class MyClass(models.Model):
        VALUE_CHOICES = [
            ('COST', 'cost'),
            ('BENEFIT', 'benefit')
        ]
        class_type = models.CharField(choices=VALUE_CHOICES,unique=True)
        value = models.IntegerField(validators=[MaxValueValidator(limit_value=10000)])
    

    Limiting input data on serializer level (Question#2):

    # serializers.py
    from .models import MyClass
    from rest_framework import serializers
    class MyClassSerializer(serializers.ModelSerializer):
        class Meta:
            model = MyClass
            fields = '__all__'
    
    class MainSerializer(serializers.Serializer):
        day = serializers.ChoiceField(choices=['monday', 'tuesday', 'wednesday'])
        my_class = serializers.ListField(child=MyClassSerializer(many=True))
    

    And finally you need to encapsulate your data to make it generic:

    # views.py or any other place you like
    from .serializers import MainSerializer
    
    your_json = {
        "monday": [
           //List of MyClass object
        ],
        "tuesday": [
            //List of MyClass Object
        ],
        "wednesday": [
            //List of MyClass Object
        ],
        ......
    }
    json_array = []
    
    for key, value in your_json:
        json_array.append({'day':key, 'my_class':value})
    
    serializer = MainSerializer(data=json_array, many=True)
    
    serializer.is_valid() # this will tell you if your data is valid or not