【问题标题】:Correct Way to Validate Django Model Objects?验证 Django 模型对象的正确方法?
【发布时间】:2012-10-13 17:33:34
【问题描述】:

我仍在尝试了解在模型级别使用自定义验证器验证 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 编写等效的数据库级单元测试/心理医生?我注意到引发 ValidationErrors 的 Django 单元测试仅使用数据库副本测试模型对数据库模式的理解。即使我要使用 South 进行迁移,任何数据库级别的约束都仅限于 Django 可以理解并转换为 Postgres 约束的内容。如果我需要一个 Django 无法复制的自定义约束,如果我直接通过 psql 终端与数据库交互,我可能会在我的数据库中输入违反该约束的数据。

谢谢!

【问题讨论】:

  • 我不确定问题 1 与您之前关于此主题的问题有何不同。请注意,它仍然不能阻止您使用 ORM 插入无效数据。考虑Person.objects.update(gender='a')
  • 您是对的,只是在我之前的问题中,我没有像这里那样包含自定义验证器功能。至于您对 .update 的其他观察,我想我现在还有一个问题,这增加了我的困惑。我真的很难理解这样做的正确方法是什么。虽然 Django 文档非常好,但恕我直言,他们很喜欢 sn-ps 和“挥手”,但缺少完整的示例来帮助像我这样的“新手”理解解决这个问题的正确方法。不幸的是,我一个人工作,没有更多经验丰富的开发人员可以讨论这个问题。

标签: django django-models


【解决方案1】:

刚开始接触 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(),而不是使用表单,但表单是一个很好的抽象。

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

【讨论】:

  • 您是说我应该使用表单或模型表单来验证我的数据模型,即使我实际上并没有以实际模板表单中的模型对象呈现给用户?谢谢。
  • @RobertF。 - 这是正确的。 ModelForm 类是模型验证的一个不错的抽象,无论是更新还是创建实例,即使您不打算在模板中显示表单。
  • 您对 A) 说要这样做,选项 B 是什么?
  • By B) 你的意思是例如model_instance = Person('Natalie'); model_instance.full_clean(); model_instance.save();
  • @chefarov 是的,除非没有分号(不要在 Python 中使用分号),而且您还需要 Person(name=‘Natalie’)(而不是简单地将名称作为有序参数传递)。
猜你喜欢
  • 1970-01-01
  • 2012-03-30
  • 1970-01-01
  • 2012-09-04
  • 2014-10-25
  • 2011-02-12
  • 2013-07-12
  • 2011-12-20
  • 1970-01-01
相关资源
最近更新 更多