简体   繁体   English

Django模型字段验证

[英]Django model fields validation

Where should the validation of model fields go in django? 模型字段的验证应该在哪里进行django?

I could name at least two possible choices: in the overloaded .save() method of the model or in the .to_python() method of the models.Field subclass (obviously for that to work you must write custom fields). 我可以命名至少两个可能的选择:在模型的重载.save()方法或models.Field子类的.to_python()方法中(显然,为了工作,你必须编写自定义字段)。

Possible use cases: 可能的用例:

  • when it is absolutely neccessary to ensure, that an empty string doesn't get written into the database (blank=False keyword argument doesn't work here, it is for form validation only) 当绝对需要确保时,空字符串不会写入数据库(空白= False关键字参数在此处不起作用,仅用于表单验证)
  • when it is neccessary to ensure, that "choices" keyword argument gets respected on a db-level and not only in admin interface (kind of emulating a enum datatype) 当需要确保时,“选择”关键字参数在数据库级别上得到尊重,而不仅仅在管理接口中(仿真枚举数据类型)

There is also a class-level attribute empty_strings_allowed in the models.Field base class definition and derived classes happily override it, however it doesn't seem to produce any effect on the database level, meaning I can still construct a model with empty-string fields and save it to the database. models.Field基类定义中的类级别属性empty_strings_allowed和派生类愉快地覆盖它,但它似乎不会对数据库级别产生任何影响,这意味着我仍然可以使用空字符串构造模型字段并将其保存到数据库中。 Which I want to avoid (yes, it is neccessary). 我想避免(是的,这是必要的)。

Possible implementations are 可能的实现是

on the field level: 在现场一级:

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)

on the model level: 在模型级别:

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)

Perhaps, I am missing something and this can be done easier (and cleaner)? 也许,我错过了一些东西,这可以做得更容易(也更清洁)?

Django has a model validation system in place since version 1.2. 自版本1.2以来,Django已经建立了模型验证系统。

In comments sebpiq says "Ok, now there is a place to put model validation ... except that it is run only when using a ModelForm! So the question remains, when it is necessary to ensure that validation is respected at the db-level, what should you do? Where to call full_clean?" 在评论中sebpiq说“好的,现在有一个地方可以进行模型验证......除了它只在使用ModelForm时运行!所以问题仍然存在,当有必要确保在db级别遵守验证时你应该怎么做?在哪里打电话给full_clean?“

It's not possible via Python-level validation to ensure that validation is respected on the db level. 通过Python级验证无法确保在数据库级别上遵守验证。 The closest is probably to call full_clean in an overridden save method. 最接近的可能是在重写的save方法中调用full_clean This isn't done by default, because it means everybody who calls that save method had now better be prepared to catch and handle ValidationError . 默认情况下不会这样做,因为这意味着调用save方法的每个人现在都已准备好捕获并处理ValidationError

But even if you do this, someone can still update model instances in bulk using queryset.update() , which will bypass this validation. 但即使你这样做,有人仍然可以使用queryset.update()批量更新模型实例,这将绕过此验证。 There is no way Django could implement a reasonably-efficient queryset.update() that could still perform Python-level validation on every updated object. Django无法实现一个合理有效的queryset.update() ,它仍然可以对每个更新的对象执行Python级验证。

The only way to really guarantee db-level integrity is through db-level constraints; 真正保证数据库级完整性的唯一方法是通过数据库级​​约束; any validation you do through the ORM requires the writer of app code to be aware of when validation is enforced (and handle validation failures). 通过ORM进行的任何验证都要求应用程序代码的编写者了解何时强制执行验证(并处理验证失败)。

This is why model validation is by default only enforced in ModelForm - because in a ModelForm there is already an obvious way to handle a ValidationError . 这就是默认情况下模型验证仅在ModelForm强制执行的ModelForm - 因为在ModelForm中已经有一种处理ValidationError的明显方法。

I think you want this -> 我想你想要这个 - >

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')

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

The root issue for this, is that the validation should happen on models. 对此的根本问题是验证应该在模型上进行。 This has been discussed for quite some time in django (search form model aware validation on the dev mailing list). 这已经在django中讨论了很长时间(在dev邮件列表上搜索表单模型识别验证)。 It leads to either duplication or things escaping validation before hitting the db. 它会导致重复或在达到db之前逃避验证的事情。

While that doesn't hit trunk, Malcolm's "poor man's model validation solution" is probably the cleanest solution to avoid repeating yourself. 虽然这不会影响主干,但Malcolm的“穷人的模型验证解决方案”可能是避免重复自己的最干净的解决方案。

如果我“清楚地”理解你 - 你必须覆盖函数get_db_prep_save而不是to_python

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM