diff options
| author | Tai Lee <tai.lee@3030.com.au> | 2013-05-07 19:06:03 +1000 |
|---|---|---|
| committer | Tim Graham <timograham@gmail.com> | 2013-08-06 08:50:47 -0400 |
| commit | 12806758347dfd63a3cd1bfc0d925c09fdbd9cff (patch) | |
| tree | 5adcb1291326bb822f1ccb6e94526e57037261be /django | |
| parent | c33d1ca1d98003de29cdecb6080b52c5c52139bd (diff) | |
Fixed #15511 -- Allow optional fields on ``MultiValueField` subclasses.
The `MultiValueField` class gets a new ``require_all_fields`` argument that
defaults to ``True``. If set to ``False``, individual fields can be made
optional, and a new ``incomplete`` validation error will be raised if any
required fields have empty values.
The ``incomplete`` error message can be defined on a `MultiValueField`
subclass or on each individual field. Skip duplicate errors.
Diffstat (limited to 'django')
| -rw-r--r-- | django/forms/fields.py | 32 |
1 files changed, 24 insertions, 8 deletions
diff --git a/django/forms/fields.py b/django/forms/fields.py index b07ebe84ee..e995187682 100644 --- a/django/forms/fields.py +++ b/django/forms/fields.py @@ -955,15 +955,20 @@ class MultiValueField(Field): """ default_error_messages = { 'invalid': _('Enter a list of values.'), + 'incomplete': _('Enter a complete value.'), } def __init__(self, fields=(), *args, **kwargs): + self.require_all_fields = kwargs.pop('require_all_fields', True) super(MultiValueField, self).__init__(*args, **kwargs) - # Set 'required' to False on the individual fields, because the - # required validation will be handled by MultiValueField, not by those - # individual fields. for f in fields: - f.required = False + f.error_messages.setdefault('incomplete', + self.error_messages['incomplete']) + if self.require_all_fields: + # Set 'required' to False on the individual fields, because the + # required validation will be handled by MultiValueField, not + # by those individual fields. + f.required = False self.fields = fields def validate(self, value): @@ -993,15 +998,26 @@ class MultiValueField(Field): field_value = value[i] except IndexError: field_value = None - if self.required and field_value in self.empty_values: - raise ValidationError(self.error_messages['required'], code='required') + if field_value in self.empty_values: + if self.require_all_fields: + # Raise a 'required' error if the MultiValueField is + # required and any field is empty. + if self.required: + raise ValidationError(self.error_messages['required'], code='required') + elif field.required: + # Otherwise, add an 'incomplete' error to the list of + # collected errors and skip field cleaning, if a required + # field is empty. + if field.error_messages['incomplete'] not in errors: + errors.append(field.error_messages['incomplete']) + continue try: clean_data.append(field.clean(field_value)) except ValidationError as e: # Collect all validation errors in a single list, which we'll # raise at the end of clean(), rather than raising a single - # exception for the first error we encounter. - errors.extend(e.error_list) + # exception for the first error we encounter. Skip duplicates. + errors.extend(m for m in e.error_list if m not in errors) if errors: raise ValidationError(errors) |
