我仍在试图理解在模型级别使用自定义验证器验证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’字段选项验证我的性别 Select ,但出于说明的目的,我创建了‘VALIDATE_GENAME’).

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

谢谢!

推荐答案

当我第一次接触Django时,我对ORM也有类似的误解.

  1. 不,不要把self.full_clean()放在save里面.任何一个

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

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()并得到错误之后,您将拥有form.errors,这是一个包含表单中所有错误的字典,其中包括一个名为'__all__'的键,它将包含非字段错误.

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

  1. 我真的没有解决方案,但我从来没有遇到过这样的问题,即使是在大型项目中(我目前与公司合作的项目有146张表),我也不怀疑这对您来说也不会是一个问题.

Django相关问答推荐

如何在管理页面创建实例时只在ManyToManyField字段中显示超级用户

批量删除多对多条目?

Django:无法分配必须是实例(&Q;X),不想获取对象(&Q;)

为什么Docker compose没有这样的文件或目录?

覆盖保存以创建范围的多个对象()

一次请求中更新整个Django模型

Django Rest Framework 速率限制动态基于用户类型

Django rest框架覆盖ViewSet中的page_size

当我告诉它时,如何使用 Django 的记录器来记录回溯?

Django Rest Framework 中的 to_representation() 可以访问普通字段吗

Django:无法从另一个应用程序导入模型

在 PyCharm 中运行 Django 测试

django 管理员登录突然要求 csrf 令牌

如何从 django 自定义中间件类返回 rest_framework.response 对象?

如何将 Django forms.ChoiceField 呈现为 Twitter Bootstrap 下拉菜单

导入错误无法在windows环境下导入名称execute_manager

Django manage.py:在其依赖之前应用迁移

Django 发送邮箱

django.db.utils.OperationalError 无法连接到服务器

在 Python 中生成 API KEY 和 SECRET 的最简单和最安全的方法是什么