Django - How to specify which field a validation fails on?

后端 未结 6 1360
太阳男子
太阳男子 2021-01-31 01:43

I have this model I\'m showing in the admin page:

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


        
相关标签:
6条回答
  • 2021-01-31 02:12

    abbreviated, from the 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
    
    0 讨论(0)
  • 2021-01-31 02:17

    The simplest way to validate this particular case would be:

    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's documentation about validators: https://docs.djangoproject.com/en/dev/ref/validators/

    0 讨论(0)
  • 2021-01-31 02:22

    OK, I figured it out from this answer.

    You have to do something like this:

    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!",]})
    
    0 讨论(0)
  • 2021-01-31 02:24

    Use a clean_ method that is specific to the field:

    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!")
    

    See the clean<fieldname> part of the Form Validation page. Also, make sure to use cleaned_data instead of the form field itself; the latter may have old data. Finally, do this on the form and not the model.

    0 讨论(0)
  • 2021-01-31 02:36
    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!')
    

    That works on forms, at least. Never tried it on the model itself, but the methodology should be the same. However, from the Django docs:

    When you use a ModelForm, the call to is_valid() will perform these validation steps for all the fields that are included on the form. (See the ModelForm documentation for more information.) You should only need to call a model’s full_clean() method if you plan to handle validation errors yourself, or if you have excluded fields from the ModelForm that require validation.

    And...

    Note that full_clean() will not be called automatically when you call your model’s save() method, nor as a result of ModelForm validation. You’ll need to call it manually when you want to run model validation outside of a ModelForm.

    So, basically, unless you have a really good reason to do field cleaning on the model, you should do it on the form instead. The code for that would look like:

    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
    

    And that will work, for sure.

    0 讨论(0)
  • 2021-01-31 02:36

    To note for anyone that may come across this with a newer version of Django - the clean_fields method from the accepted answer now requires an "exclude" param. Also - I believe the accepted answer is also missing a call to it's super function. The final code that I used was:

    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"]})
    
    0 讨论(0)
提交回复
热议问题