5

我正在尝试将所有与业务逻辑相关的验证移动到模型中,而不是将它们留在表单中。但是在这里我遇到了一个棘手的情况,我想咨询 SO 社区。

在我的 SignupForm(模型表单)中,我进行了以下特定于字段的验证,以确保输入的电子邮件不存在。

def clean_email(self):
    email = self.cleaned_data['email']

    if ExtendedUser.objects.filter(email=email).exists():
        raise ValidationError('This email address already exists.')
    return email

如果我要将此验证移至模型,根据官方文档,我会将其放入clean()相应的模型中,ExtendedUser. 但是文档还提到了以下内容:

由 Model.clean() 引发的任何 ValidationError 异常都将存储在一个特殊的键错误字典键 NON_FIELD_ERRORS 中,该键用于与整个模型而不是特定字段相关的错误

这意味着,clean()我无法将由此引发的错误与特定字段相关联。我想知道模型是否提供类似于 forms' 的东西clean_<fieldname>()。如果不是,您会将这个验证逻辑放在哪里,为什么?

4

2 回答 2

3

您可以将您的 clean 方法转换为 avalidator并在声明该字段时包含它。

另一种选择是对模型字段进行子类化并覆盖其 clean 方法。

但是,没有直接等同于定义clean_<field name>方法的方式,就像您可以为表单所做的那样。您甚至不能将错误分配给单个字段,就像您对表单所做的那样

于 2012-03-22T00:11:48.410 回答
1

如评论中所述,我相信您应该在模型表单级别处理此验证。如果您仍然觉得更接近模型会更好,并且由于它们无法更改,我建议直接在 db 级别进行更改:

ALTER TABLE auth_user ADD UNIQUE (email)

这是在没有猴子修补身份验证的情况下将unique=True约束添加到模型的糟糕方法。User

根据要求,我认为应该通过从基本模型表单继承来定制不同表单的好方法。在django-registration中可以找到一个很好的例子。唯一的区别是,不是从forms.Form您继承的父表单将使其成为模型表单:

class MyBaseModelForm(ModelForm):
    class Meta:
        model = MyModel

然后,您可以从它继承并从此基本模型制作不同的形式:

class OtherFormWithCustomClean(MyBaseModelForm):
    def clean_email(self):
       email = self.cleaned_data['email']
       if ExtendedUser.objects.filter(email=email).exists():
          raise ValidationError('This email address already exists.')
    return email
于 2012-03-22T00:35:13.950 回答