django-处理模型创建中的验证检查的最佳方法

时间:2019-05-21 15:55:37

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

我试图弄清楚在Django中创建对象时如何使用验证。

从我的POV看,有两种方法:

  1. 覆盖DRF序列化程序的默认$scope方法。
  2. 将字段级验证器添加到模型中,并在序列化程序调用模型的validate_field方法时捕获任何IntegrityError或ValidationError异常。

两种方法似乎都有缺点。

通过使用方法1 ,除序列化程序外,其他任何.save()模型调用都使我的模型不受“保护”。 方法2 处理了上述问题,但由于在序列化程序的.create()方法中必须进行异常处理,因此使代码更加复杂。

有没有人遇到过类似的问题和/或找到了一种“清洁”的方式来解决这一问题?

2 个答案:

答案 0 :(得分:2)

据我了解,您需要Django模型验证。您可以尝试这种方法(我想这正是您想要的)。

from django.core.exceptions import ValidationError

class Foo(models.Model):
    name = models.CharField(max_length=255)

    def clean(self):
        raise ValidationError('Problem during validation')

f = Foo(name='test')
f.full_clean() # This is what you need. f.clean() will be enough, but f.full_clean() will make field level validations (run validators) and checking about uniqueness also.
f.save()

通常, Django 在创建模型期间从不进行模型级别的验证(不调用full_clean())。

f = Foo(**fields_dict)
f.save() # no validation performed.

如果需要,请自己叫

f = Foo(**fields_dict)
f.full_clean() # validation performed
f.save()
如果使用full_clean()类,则会自动执行

ModelForm方法。这是 Django 的附加钩子。

答案 1 :(得分:0)

我认为将验证下移至模型是确保最高级别可靠性的最安全方法,因为只要通过 Django 完成验证,就将应用验证您使用序列化程序,如果 Django Rest Framework 被跳过,则验证将无效”。

模型级别的验证可以是:

Field level validations :您创建进行验证的方法,并将该方法设置为字段验证器:

from django.core.exceptions import ValidationError
from django.utils.translation import gettext_lazy as _

def validate_even(value):
    if value % 2 != 0:
        raise ValidationError(
            _('%(value)s is not an even number'),
            params={'value': value},
        )

from django.db import models

class MyModel(models.Model):
    even_field = models.IntegerField(validators=[validate_even])

Model level validations :您覆盖模型的clean()方法并执行所需的验证:

import datetime
from django.core.exceptions import ValidationError
from django.db import models
from django.utils.translation import gettext_lazy as _

class Article(models.Model):
    ...
    def clean(self):
        # Don't allow draft entries to have a pub_date.
        if self.status == 'draft' and self.pub_date is not None:
            raise ValidationError(_('Draft entries may not have a publication date.'))
        # Set the pub_date for published items if it hasn't been set already.
        if self.status == 'published' and self.pub_date is None:
            self.pub_date = datetime.date.today()