Django模型:向自定义字段添加验证

时间:2015-11-01 09:13:23

标签: django django-models django-rest-framework django-jsonfield

TLDR;

如何提供封装在字段类中的自定义,模型级别,字段验证?

休息

我正在玩两个JSONField实现,(firstsecond)。我正在为我的应用程序使用Django和Django REST框架的组合。我在表单级别上没有做任何事情,只有公开该模型的Web API。

理想情况下,我想在一个地方编写此验证,并在串行器级别+模型级别上运行(就像我传递validators=[x]时)。我不能使用通常的validators=[x],因为我需要允许blank=True,但也要验证空白值类型:|。

我有一个用例,我想验证JSONField的内容(键,值的类型)。使用validictory,我可以这样做:

  • 强制拨打self.full_clean()
  • 中的save()
  • 在我的模型上覆盖clean()并在那里进行验证

但是,我 想要做的是:将此验证添加到JSONField的子类中。我想留下尽可能多的父Field课来做这件事。到目前为止,我有:

from django.db import models
from jsonfield import JSONField

class myValidatorField(JSONField):
    def validate(self, *args, **kwargs):
        # do some validation here
        super(myValidatorField, self).validate(*args, **kwargs)

class MyModel(models.Model):
    jsonstuff = myValidatorField(default=[])

    def save(self, *args, **kwargs):
        self.full_clean()
        super(MyModel, self).save(*args, **kwargs)

然而,我无法让它发挥作用。这个validate()方法不会针对second实施运行,而对于first,它会运行4次。

混淆。

1 个答案:

答案 0 :(得分:1)

我最终得到了这个代码,似乎可以解决这个问题。

仅供参考,在我的用例中,我必须实现一个自定义的django rest框架异常处理程序来捕获我的所有模型级别ValidationError错误并将其转换为网络400错误。

# fields.py
import validictory
from jsonfield import JSONField

class JSONSchemaField(JSONField):
    """A field that will ensure the data entered into it is valid JSON *and*
    internally validate to a JSON schema of your choice."""
    def __init__(self, *args, **kwargs):
        self.schema = kwargs.pop('schema', {})
        super(JSONSchemaField, self).__init__(*args, **kwargs)

    def clean(self, raw_value, model_instance):
        try:
            validictory.validate(raw_value, self.schema)
        except (validictory.FieldValidationError,
                validictory.SchemaError,
                validictory.validator.RequiredFieldValidationError) as err:
            raise ValidationError(err)
        return super(JSONSchemaField, self).clean(raw_value, model_instance)

# mixins.py
class ModelValidationMixin(object):
"""Django currently doesn't force validation on the model level
for compatibility reasons. We enforce here, that on each save,
a full valdation run will be done the for model instance"""
def save(self, *args, **kwargs):
    self.full_clean()
    super(ModelValidationMixin, self).save(*args, **kwargs)

# models.py
class MyModel(ModelValidationMixin):
    json = JSONSchemaField(default='[]', schema=SCHEMA)