Django模型字段验证

shy*_*ent 59 python django django-models

模型字段的验证应该在哪里进行django?

我可以命名至少两个可能的选择:在模型的重载.save()方法或models.Field子类的.to_python()方法中(显然,为了工作,你必须编写自定义字段).

可能的用例:

  • 当绝对需要确保时,空字符串不会写入数据库(空白= False关键字参数在此处不起作用,仅用于表单验证)
  • 当需要确保时,"choices"关键字参数在数据库级别上得到尊重,而不仅仅在管理接口中(仿真枚举数据类型)

empty_strings_allowedmodels.Field基类定义和派生类中还有一个类级别属性,它可以很好地覆盖它,但它似乎不会对数据库级别产生任何影响,这意味着我仍然可以使用空字符串字段构建模型并将其保存到数据库中.我想避免(是的,这是必要的).

可能的实现是

在现场一级:

class CustomField(models.CharField):
    __metaclass__ = models.SubfieldBase
    def to_python(self, value):
        if not value:
            raise IntegrityError(_('Empty string not allowed'))
        return models.CharField.to_python(self, value)
Run Code Online (Sandbox Code Playgroud)

在模型级别:

class MyModel(models.Model)
    FIELD1_CHOICES = ['foo', 'bar', 'baz']
    field1 = models.CharField(max_length=255, 
               choices=[(item,item) for item in FIELD1_CHOICES])

    def save(self, force_insert=False, force_update=False):
        if self.field1 not in MyModel.FIELD1_CHOICES:
            raise IntegrityError(_('Invalid value of field1'))
        # this can, of course, be made more generic
        models.Model.save(self, force_insert, force_update)
Run Code Online (Sandbox Code Playgroud)

也许,我错过了一些东西,这可以做得更容易(也更清洁)?

Car*_*yer 63

自版本1.2以来,Django已经建立了模型验证系统.

在评论中sebpiq说"好的,现在有一个地方可以进行模型验证......除了它只在使用ModelForm时运行!所以问题仍然存在,当有必要确保在db级别遵守验证时你应该怎么做?在哪里打电话给full_clean?"

通过Python级验证无法确保在数据库级别上遵守验证.最接近的可能是调用full_clean重写save方法.默认情况下不会这样做,因为这意味着调用save方法的每个人现在都可以更好地捕获和处理ValidationError.

但即使你这样做,有人仍然可以使用批量更新模型实例queryset.update(),这将绕过此验证.Django无法实现一个合理有效的方法queryset.update(),它仍然可以对每个更新的对象执行Python级别的验证.

真正保证数据库级完整性的唯一方法是通过数据库级​​约束; 通过ORM进行的任何验证都要求应用程序代码的编写者了解何时强制执行验证(并处理验证失败).

这就是默认情况下仅强制执行模型验证的原因ModelForm- 因为在ModelForm中已经有一种明显的方法来处理ValidationError.

  • 签出该分支,确保安装了docutils和Sphinx,然后进入docs /目录并运行"make html".这应该像在Django网站上一样构建HTML格式的文档,您可以在本地访问它们. (2认同)

Dar*_*ius 7

我想你想要这个 - >

from django.db.models.signals import pre_save

def validate_model(sender, **kwargs):
    if 'raw' in kwargs and not kwargs['raw']:
        kwargs['instance'].full_clean()

pre_save.connect(validate_model, dispatch_uid='validate_models')
Run Code Online (Sandbox Code Playgroud)

(复制自http://djangosnippets.org/snippets/2319/)

  • 我不这么认为,因为验证器在保存时不会运行,所以它会让你添加不验证的东西.来自http://docs.djangoproject.com/en/dev/releases/1.2/#model-validation"只需调用模型实例的save()方法就不会对实例的数据进行任何验证." 虽然也许我误解了OP想要什么,但是*我*肯定会想要一种方法来保存()验证的东西:) (2认同)