Opened 9 years ago
Last modified 9 years ago
#24988 closed Cleanup/optimization
ValidationError fails to set code — at Version 2
Reported by: | Michael Barr | Owned by: | nobody |
---|---|---|---|
Component: | Documentation | Version: | 1.8 |
Severity: | Normal | Keywords: | ValidationError |
Cc: | Loic Bistuer | Triage Stage: | Accepted |
Has patch: | yes | Needs documentation: | no |
Needs tests: | no | Patch needs improvement: | yes |
Easy pickings: | no | UI/UX: | no |
Description (last modified by )
Assuming the following model:
class DateRange(models.Model): start = models.DateField() end = models.DateField() def clean(self): super(DateRange, self).clean() if self.start and self.end: if self.start >= self.end: raise ValidationError( message={ 'start': _( '{start} must come before {end}.'.format( start=self._meta.get_field( 'start' ).verbose_name, end=self._meta.get_field( 'end' ).verbose_name, ) ), 'end': _( '{end} must come after {start}.'.format( end=self._meta.get_field( 'end' ).verbose_name, start=self._meta.get_field( 'start' ).verbose_name, ) ), }, code='invalid', )
After then validating the model with a ModelForm, the code
fails to be set to 'invalid'
but is instead an empty string. I discovered this when I was programming tests:
def test_start_before_end_validation(self): """Start date must come before end date.""" TestForm = modelform_factory( model=DateRange, fields=('start', 'end') ) form = TestForm( data=dict( start=date(2015, 1, 1), end=date(1900, 12, 31) # WHOOPS! ) ) self.assertEqual(first=form.is_valid(), second=False) # The below fails because the code is '' - we have to leave off the code self.assertTrue(form.has_error(field='start'), code='invalid') self.assertTrue(form.has_error(field='end'), code='invalid')
Upon inspection of the the ValidationError
code, I discovered that that any ValidationError
that is raised with a type of dict
or a list
as the message
will never set the code:
if isinstance(message, dict): self.error_dict = {} for field, messages in message.items(): if not isinstance(messages, ValidationError): messages = ValidationError(messages) self.error_dict[field] = messages.error_list elif isinstance(message, list): self.error_list = [] for message in message: # Normalize plain strings to instances of ValidationError. if not isinstance(message, ValidationError): message = ValidationError(message) if hasattr(message, 'error_dict'): self.error_list.extend(sum(message.error_dict.values(), [])) else: self.error_list.extend(message.error_list)
According to the documentation on raising ValidationError, it is suggested to "Provide a descriptive error code to the constructor." Is this a bug?
I believe the "fix" would be as simple as to pass code=code
following the message/messages, but I may be wrong. Thoughts?
Change History (2)
comment:1 by , 9 years ago
Description: | modified (diff) |
---|
comment:2 by , 9 years ago
Description: | modified (diff) |
---|