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<fieldname>
部分。另外,请确保使用cleaned_data
而不是表单字段本身;后者可能有旧数据。最后,在表单而不是模型上执行此操作。
【讨论】:
首先,他在 model 上使用clean
方法而不是表单。所以,在那种情况下没有cleaned_data
。其次,clean_FOO
仅适用于您仅针对该特定字段进行验证的情况。如果涉及多个字段,您必须使用clean
clean_<fieldname>
方法可以有多个;将依次检查每个错误,并将它们的错误附加到相关字段。
这有什么关系?您无法在一个 clean_clean
。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 - 如何指定验证失败的字段?的主要内容,如果未能解决你的问题,请参考以下文章