【问题标题】:Django - How to specify which field a validation fails on?Django - 如何指定验证失败的字段?
【发布时间】: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 字段旁边显示错误,而不是像现在这样的一般错误。有没有办法指定验证失败的字段?

非常感谢。

【问题讨论】:

    标签: django django-models django-admin


    【解决方案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中调用。此引用也已从文档中删除。
      猜你喜欢
      • 2017-03-20
      • 1970-01-01
      • 2023-04-06
      • 2011-01-26
      • 2020-08-03
      • 1970-01-01
      • 1970-01-01
      • 2012-09-08
      • 2015-06-02
      相关资源
      最近更新 更多