如何要求Django JSONField仅存储字典值并拦截标量值?
如何让Django的JSONField仅存储字典类型值
数据库层面强制执行(优先推荐)
批量插入等操作可能绕过Django的模型验证,所以在数据库层面加约束是最可靠的方案,不同数据库实现如下:
PostgreSQL
在模型的Meta类中添加CHECK约束,利用PostgreSQL的jsonb_typeof函数判断JSON类型是否为object(对应字典):
from django.db import models class YourModel(models.Model): data = models.JSONField() class Meta: constraints = [ models.CheckConstraint( check=models.RawSQL('jsonb_typeof(data) = %s', ('object',)), name='data_must_be_dict' ) ]
当插入非字典类型的JSON值时,数据库会直接抛出错误,拦截非法数据。
MySQL 8.0+
MySQL可通过JSON_TYPE函数判断类型,同样添加CHECK约束:
class YourModel(models.Model): data = models.JSONField() class Meta: constraints = [ models.CheckConstraint( check=models.RawSQL('JSON_TYPE(data) = %s', ('OBJECT',)), name='data_must_be_dict' ) ]
注意这里JSON_TYPE返回的类型是大写的OBJECT。
Django层面处理
如果数据库不支持CHECK约束(比如旧版本数据库),可以在Django模型层做验证:
模型clean方法验证
在模型的clean方法中检查字段类型:
from django.core.exceptions import ValidationError from django.db import models class YourModel(models.Model): data = models.JSONField() def clean(self): super().clean() if not isinstance(self.data, dict): raise ValidationError({'data': '必须是字典类型'})
注意:bulk_create默认不会调用clean方法,批量插入前需要手动验证每个实例。
自定义仅支持字典的JSONField
如果想让所有使用该字段的地方自动验证,可以自定义字段:
from django.core.exceptions import ValidationError from django.db import models class DictOnlyJSONField(models.JSONField): def validate(self, value, model_instance): super().validate(value, model_instance) if not isinstance(value, dict): raise ValidationError('必须是字典类型') def to_python(self, value): value = super().to_python(value) if not isinstance(value, dict): raise ValidationError('必须是字典类型') return value
之后在模型中使用这个自定义字段即可:
class YourModel(models.Model): data = DictOnlyJSONField()
这种方式会在赋值、表单提交等场景触发验证,但bulk_create仍需手动验证才能确保数据合法。
内容的提问来源于stack exchange,提问作者Johnny Metz
相关产品推荐
相关产品推荐

