Search code examples
pythondjangodjango-modelspydanticdjango-jsonfield

Type Validation in Django's JSONField


Problem Statement

I have a Django model containing a JSONField among other fields:

class MetaData(models.Model):
     main = models.ForeignKey()
     name = models.CharField()
     dict_field = models.JSONField()

Where dict_field is a "data dump" for any remaining metadata that i don't want to include as a standalone field.

Although it's a data "dump", I still want it to have basic type-validation. How can I validate the inputs of this JSONField such that it only accepts a pre-defined list of keys and their associated types, as follows:

"key1": bool
"key2": int
"key3": Optional[int]

Does django have functionality built in for this type of problem? If not, what other solutions can you recommend? (pydantic, etc.)


Solution

  • You can write a validator for that:

    from django.core.exceptions import ValidationError
    from django.utils.deconstruct import deconstructible
    
    
    @deconstructible
    class BasicJsonValidator:
        def __init__(self, types):
            self.types = types
    
        def __call__(self, mydict):
            if not isinstance(mydict, dict):
                raise ValidationError("Value must be a dictionary.")
            for key, value in mydict.items():
                if key not in self.types:
                    raise ValidationError(f"key {key} should not be present")
                if not isinstance(value, self.types[key]):
                    raise ValidationError(
                        f"for {key}, {value} should be a {self.types[key]}"
                    )
    

    Then you can use a validator with:

    class MetaData(models.Model):
        main = models.ForeignKey()
        name = models.CharField()
        dict_field = models.JSONField(
            validators=[
                BasicJsonValidator({'key1': bool, 'key2': int, 'key3': Optional[int]})
            ]
        )