diff --git a/django/newforms/fields.py b/django/newforms/fields.py index 7c542b90014..509c099e860 100644 --- a/django/newforms/fields.py +++ b/django/newforms/fields.py @@ -457,7 +457,7 @@ class MultiValueField(Field): for i, field in enumerate(self.fields): try: field_value = value[i] - except KeyError: + except IndexError: field_value = None if self.required and field_value in EMPTY_VALUES: raise ValidationError(gettext(u'This field is required.')) diff --git a/django/newforms/widgets.py b/django/newforms/widgets.py index d50b1921ea3..5f1a130459e 100644 --- a/django/newforms/widgets.py +++ b/django/newforms/widgets.py @@ -347,7 +347,7 @@ class MultiWidget(Widget): id_for_label = classmethod(id_for_label) def value_from_datadict(self, data, name): - return [data.get(name + '_%s' % i) for i in range(len(self.widgets))] + return [widget.value_from_datadict(data, name + '_%s' % i) for i, widget in enumerate(self.widgets)] def format_output(self, rendered_widgets): return u''.join(rendered_widgets) diff --git a/tests/regressiontests/forms/tests.py b/tests/regressiontests/forms/tests.py index 8f8b3c828ad..e0d05a2c89d 100644 --- a/tests/regressiontests/forms/tests.py +++ b/tests/regressiontests/forms/tests.py @@ -5,6 +5,7 @@ from regressions import regression_tests form_tests = r""" >>> from django.newforms import * >>> import datetime +>>> import time >>> import re ########### @@ -3297,6 +3298,94 @@ True +# MultiWidget and MultiValueField ############################################# +# MultiWidgets are widgets composed of other widgets. They are usually +# combined with MultiValueFields - a field that is composed of other fields. +# MulitWidgets can themselved be composed of other MultiWidgets. +# SplitDateTimeWidget is one example of a MultiWidget. + +>>> class ComplexMultiWidget(MultiWidget): +... def __init__(self, attrs=None): +... widgets = ( +... TextInput(), +... SelectMultiple(choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo'))), +... SplitDateTimeWidget(), +... ) +... super(ComplexMultiWidget, self).__init__(widgets, attrs) +... +... def decompress(self, value): +... if value: +... data = value.split(',') +... return [data[0], data[1], datetime.datetime(*time.strptime(data[2], "%Y-%m-%d %H:%M:%S")[0:6])] +... return [None, None, None] +... def format_output(self, rendered_widgets): +... return u'\n'.join(rendered_widgets) +>>> w = ComplexMultiWidget() +>>> print w.render('name', 'some text,JP,2007-04-25 06:24:00') + + + + +>>> class ComplexField(MultiValueField): +... def __init__(self, required=True, widget=None, label=None, initial=None): +... fields = ( +... CharField(), +... MultipleChoiceField(choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo'))), +... SplitDateTimeField() +... ) +... super(ComplexField, self).__init__(fields, required, widget, label, initial) +... +... def compress(self, data_list): +... if data_list: +... return '%s,%s,%s' % (data_list[0],''.join(data_list[1]),data_list[2]) +... return None + +>>> f = ComplexField(widget=w) +>>> f.clean(['some text', ['J','P'], ['2007-04-25','6:24:00']]) +u'some text,JP,2007-04-25 06:24:00' +>>> f.clean(['some text',['X'], ['2007-04-25','6:24:00']]) +Traceback (most recent call last): +... +ValidationError: [u'Select a valid choice. X is not one of the available choices.'] + +# If insufficient data is provided, None is substituted +>>> f.clean(['some text',['JP']]) +Traceback (most recent call last): +... +ValidationError: [u'This field is required.'] + +>>> class ComplexFieldForm(Form): +... field1 = ComplexField(widget=w) +>>> f = ComplexFieldForm() +>>> print f + + + + +>>> f = ComplexFieldForm({'field1_0':'some text','field1_1':['J','P'], 'field1_2_0':'2007-04-25', 'field1_2_1':'06:24:00'}) +>>> print f + + + + +>>> f.clean_data +{'field1': u'some text,JP,2007-04-25 06:24:00'} + ################################# # Tests of underlying functions # #################################