summaryrefslogtreecommitdiff
path: root/django/forms
diff options
context:
space:
mode:
authorTai Lee <tai.lee@3030.com.au>2013-05-07 19:06:03 +1000
committerTim Graham <timograham@gmail.com>2013-08-06 08:50:47 -0400
commit12806758347dfd63a3cd1bfc0d925c09fdbd9cff (patch)
tree5adcb1291326bb822f1ccb6e94526e57037261be /django/forms
parentc33d1ca1d98003de29cdecb6080b52c5c52139bd (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/forms')
-rw-r--r--django/forms/fields.py32
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)