Django - 如何指定验证失败的字段?

Posted

技术标签:

【中文标题】Django - 如何指定验证失败的字段?【英文标题】:Django - How to specify which field a validation fails on? 【发布时间】:2011-09-14 02:14:32 【问题描述】:

我在管理页面中显示了这个模型:

class Dog(models.Model):
    bark_volume = models.DecimalField(...
    unladen_speed = models.DecimalField(...

    def clean(self):
        if self.bark_volume < 5:
            raise ValidationError("must be louder!")

如您所见,我对模型进行了验证。但是我想要让管理页面在 bark_volume 字段旁边显示错误,而不是像现在这样的一般错误。有没有办法指定验证失败的字段?

非常感谢。

【问题讨论】:

【参考方案1】:

缩写,来自django docs:

def clean(self):
    data = self.cleaned_data
    subject = data.get("subject")

    if subject and "help" not in subject:
        msg = "Must put 'help' in subject."
        self.add_error('subject', msg)

    return data

【讨论】:

【参考方案2】:

验证这种特殊情况的最简单方法是:

from django.core.validators import MinValueValidator
from django.utils.translation import ugettext_lazy as _

class Dog(models.Model):
    bark_volume = models.DecimalField(
        ..., validators=[MinValueValidator(5, message=_("Must be louder!"))]

Django 关于验证器的文档:https://docs.djangoproject.com/en/dev/ref/validators/

【讨论】:

这是一个惯用的解决方案:) 刚刚意识到我之前的解决方案中没有消息,所以也添加了它:)【参考方案3】:

提醒任何可能在更新版本的 Django 中遇到此问题的人 - 已接受答案中的 clean_fields 方法现在需要一个“排除”参数。另外-我相信接受的答案也缺少对其超级功能的调用。我使用的最终代码是:

def clean_fields(self, exclude=None):
    super(Model, self).clean_fields(exclude)

    if self.field_name and not self.field_name_required:
        raise ValidationError('field_name_required':["You selected a field, so field_name_required is required"])

【讨论】:

我认为exclude参数应该被验证代码所尊重,所以像clean_fileds(model, exclude=["field_name"])这样的调用即使在需要field_name时也不会引发异常。【参考方案4】:

好的,我想通了from this answer。

你必须这样做:

class Dog(models.Model):
    bark_volume = models.DecimalField(...
    unladen_speed = models.DecimalField(...

    def clean_fields(self):
        if self.bark_volume < 5:
            raise ValidationError('bark_volume': ["Must be louder!",])

【讨论】:

如果不需要翻译,使用字符串作为消息就足够了,不需要列表:raise ValidationError('bark_volume': 'Must be louder!')。使用 Django 1.9.5。【参考方案5】:

使用特定于该字段的clean_ 方法:

class DogForm(forms.ModelForm):
    class Meta:
        model = Dog

    def clean_bark_volume(self):
        if self.cleaned_data['bark_volume'] < 5:
            raise ValidationError("must be louder!")

查看Form Validation 页面的clean&lt;fieldname&gt; 部分。另外,请确保使用cleaned_data 而不是表单字段本身;后者可能有旧数据。最后,在表单而不是模型上执行此操作。

【讨论】:

首先,他在 model 上使用clean 方法而不是表单。所以,在那种情况下没有cleaned_data。其次,clean_FOO 仅适用于您仅针对该特定字段进行验证的情况。如果涉及多个字段,您必须使用clean clean_&lt;fieldname&gt; 方法可以有多个;将依次检查每个错误,并将它们的错误附加到相关字段。 这有什么关系?您无法在一个 clean_ 方法中验证多个字段。无法保证 clean_data 在另一个字段的 clean 方法中的可用性。如果您的验证涉及多个字段,您必须改用clean【参考方案6】:
class Dog(models.Model):
    bark_volume = models.DecimalField(...
    unladen_speed = models.DecimalField(...

    def clean(self):
        if self.bark_volume < 5:
            if not self._errors.has_key('bark_volume'):
                from django.forms.util import ErrorList
                self._errors['bark_volume'] = ErrorList()
            self._errors['bark_volume'].append('must be louder!')

这至少适用于表单。从未在模型本身上尝试过,但方法应该是相同的。但是,来自 Django 文档:

当您使用 ModelForm 时,对 is_valid() 的调用将对表单中包含的所有字段执行这些验证步骤。 (有关详细信息,请参阅 ModelForm 文档。)如果您计划自己处理验证错误,或者如果您从 ModelForm 中排除了需要验证的字段,则只需要调用模型的 full_clean() 方法。

还有……

请注意,当您调用模型的 save() 方法时,不会自动调用 full_clean(),也不会作为 ModelForm 验证的结果。当您想在 ModelForm 之外运行模型验证时,您需要手动调用它。

因此,基本上,除非您有充分的理由对模型进行字段清理,否则您应该改为在表单上进行。代码如下:

class DogForm(forms.ModelForm):

    def clean(self):
        bark_volume = self.cleaned_data.get('bark_volume')
        if bark_volume < 5:
            if not self._errors.has_key('bark_volume'):
                from django.forms.util import ErrorList
                self._errors['bark_volume'] = ErrorList()
            self._errors['bark_volume'].append('must be louder!')

        return self.cleaned_data

这肯定会奏效。

【讨论】:

您还需要引发 ValidationError 吗?还是 Django 在调用 clean 方法后检查 self._errors? 实际上引发 ValidationError 只是将项目添加到 self._errors。它是表单上所有错误的主列表。 在模型中使用它会给我这个错误:'Dog' object has no attribute '_errors' 好的,那么看来您不能使用相同的方法。如果涉及多个字段,我建议对您的表单进行验证。该方法适用于表单。 "也不是 ModelForm 验证的结果。"这不是真的,或者至少不再是真的。 self.instance.instance.full_clean()ModelForm._post_clean方法中调用,在ModelForm.is_valid中调用。此引用也已从文档中删除。

以上是关于Django - 如何指定验证失败的字段?的主要内容,如果未能解决你的问题,请参考以下文章

如果验证失败,如何关注错误的文本字段

数据当用户在验证失败(Python,Django)时被重定向回表单时如何保留表单?

Django“自动对焦”表单验证错误

Django 管理员身份验证失败

Django 1.2.4 CSRF 验证失败

管理面板的 Django CSRF 验证失败