验证Django模型对象的正确方法?

时间:2012-10-23 17:51:48

标签: django django-models

我仍在尝试了解在模型级别使用自定义验证器验证Django模型对象的正确方法。我知道验证通常是在表单或模型中完成的。但是,如果我通过Python shell中的ORM与它进行交互,我想在模型级别确保数据的完整性。这是我目前的做法:

from django.db import models
from django.core import validators
from django.core exceptions import ValidationError


def validate_gender(value):
    """ Custom validator """
    if not value in ('m', 'f', 'M', 'F'):
        raise ValidationError(u'%s is not a valid value for gender.' % value)


class Person(models.Model):
    name = models.CharField(max_length=128)
    age = models.IntegerField()
    gender = models.CharField(maxlength=1, validators=[validate_gender])

    def save(self, *args, **kwargs):
        """ Override Person's save """
        self.full_clean(exclude=None)
        super(Person, self).save(*args, **kwargs)

以下是我的问题:

  1. 我应该创建自定义验证函数,将其指定为验证器,然后覆盖Person的save()函数,就像我上面所做的那样? (顺便说一句,我知道我可以使用'choices'字段选项验证我的性别选择,但我为了说明的目的创建了'validate_gender'。

  2. 如果我确实想要确保数据的完整性,我是否应该在模型层编写用于测试的Django单元测试,还应该使用Python /等效的数据库级单元测试Psycopg?我注意到,引发ValidationErrors的Django单元测试只测试模型使用数据库副本对数据库模式的理解。即使我使用South进行迁移,任何数据库级约束都限于Django可以理解并转换为Postgres约束。如果我需要一个Django无法复制的自定义约束,如果我直接通过psql终端与数据库进行交互,我可能会将数据输入到我的数据库中而违反该约束。

  3. 谢谢!

1 个答案:

答案 0 :(得分:18)

当我第一次使用Django时,我对ORM有类似的误解。

1)不,不要将self.full_clean()放在save内。任

A)使用ModelForm(这将导致所有相同的验证发生 - 注意:ModelForm.is_valid()不会显式调用Model.full_clean,但会执行与{Model.full_clean完全相同的检查{1}})。例如:

class PersonForm(forms.ModelForm):
    class Meta:
        model = Person

def add_person(request):
    if request.method == 'POST':
        form = PersonForm(request.POST, request.FILES)
        if form.is_valid():  # Performs your validation, including ``validate_gender``
            person = form.save()
            return redirect('some-other-view')
    else:
        form = PersonForm()
        # ... return response with ``form`` in the context for rendering in a template

另请注意,表单不仅适用于在模板中呈现它们的视图 - 它们非常适合任何类型的使用,包括API等。运行form.is_valid()并获取错误后,您' ll有form.errors这是一个包含表单中所有错误的字典,包括一个名为'__all__'的密钥,它将包含非字段错误。

B)只需在视图(或其他逻辑应用程序层)中使用model_instance.full_clean(),而不是使用表单,但表单是一个很好的抽象。

2)我真的没有解决方案,但我从来没有遇到过这样的问题,即使在大型项目中(我与公司合作的当前项目有146个表)我不怀疑在你的情况下,这也是一个问题。