﻿id	summary	reporter	owner	description	type	status	component	version	severity	resolution	keywords	cc	stage	has_patch	needs_docs	needs_tests	needs_better_patch	easy	ui_ux
24988	ValidationError fails to set code	Michael Barr	nobody	"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 [https://docs.djangoproject.com/en/1.8/ref/forms/validation/#raising-validationerror 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?"	Bug	new	Core (Other)	1.8	Normal		ValidationError		Unreviewed	0	0	0	0	0	0
