#22921: Model.clean_fields incorrectly skips validation for fields where null 
value
is not allowed
-------------------------------------+-------------------------------------
     Reporter:  silveroff@…          |                    Owner:  nobody
         Type:                       |                   Status:  new
  Cleanup/optimization               |                  Version:  master
    Component:  Database layer       |               Resolution:
  (models, ORM)                      |             Triage Stage:
     Severity:  Normal               |  Unreviewed
     Keywords:  field validation,    |      Needs documentation:  0
  model                              |  Patch needs improvement:  0
    Has patch:  0                    |                    UI/UX:  0
  Needs tests:  0                    |
Easy pickings:  0                    |
-------------------------------------+-------------------------------------

Comment (by anonymous):

 Sure,

 {{{
 # Model
 class Example(models.Model):
     optional_decimal = models.DecimalField(
         blank=True,
         null=False,   # so I want this field to be optional in my forms,
 but I dont want null values in db
         default=Decimal(0),
         validators=[MinValueValidator(0)],
         max_digits=8,
         decimal_places=2,
     )

 # Form
 class ExampleForm(ModelForm):
     class Meta:
         model = Example
 }}}

 Now if one create object using this form without providing value for
 optional_decimal field this would result in IntegrityError: (1048, "Column
 'optional_decimal' cannot be null")
 So developer has to create ExampleForm.clean_optional_decimal method to
 handle this issue, and thats not DRY and wouldn't be needed if
 model.clean_fields run validation at the first place. Something like this
 would suffice:


 {{{
 def clean_fields(self, exclude=None):
         """
         Cleans all fields and raises a ValidationError containing
 message_dict
         of all validation errors if any occur.
         """
         if exclude is None:
             exclude = []

         errors = {}
         for f in self._meta.fields:
             if f.name in exclude:
                 continue
             # Skip validation for empty fields with blank=True. The
 developer
             # is responsible for making sure they have a valid value.
             raw_value = getattr(self, f.attname)
             if f.blank and raw_value in f.empty_values:
                 # do not skip validation if raw_value is None and field
 does not accept null values to be saved!
                 if raw_value is None and not f.null:
                     pass
                 else:
                     continue
             try:
                 setattr(self, f.attname, f.clean(raw_value, self))
             except ValidationError as e:
                 errors[f.name] = e.error_list

         if errors:
             raise ValidationError(errors)
 }}}

-- 
Ticket URL: <https://code.djangoproject.com/ticket/22921#comment:2>
Django <https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.

-- 
You received this message because you are subscribed to the Google Groups 
"Django updates" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to django-updates+unsubscr...@googlegroups.com.
To post to this group, send email to django-updates@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/django-updates/077.8ee2ceb17dfa674cd20f2f1313dd2866%40djangoproject.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to