From b24c860fa21790bfe04f5afc7c8bcccb70902f83 Mon Sep 17 00:00:00 2001 From: Russell Keith-Magee Date: Thu, 26 Apr 2007 12:46:04 +0000 Subject: [PATCH] Fixed #3787, #3788 -- Corrected check for IndexError on MultiValueField, and fixed the value_from_datadict method for MultiWidgets to handle Multiwidgets containing Multiwidgets. Also added a testcase walking through the use of MultiWidget/MultiValueField. Thanks to Max Derkachev for reporting these issues and providing fixes. git-svn-id: http://code.djangoproject.com/svn/django/trunk@5088 bcc190cf-cafb-0310-a4f2-bffc1f526a37 --- django/newforms/fields.py | 2 +- django/newforms/widgets.py | 2 +- tests/regressiontests/forms/tests.py | 89 ++++++++++++++++++++++++++++ 3 files changed, 91 insertions(+), 2 deletions(-) diff --git a/django/newforms/fields.py b/django/newforms/fields.py index 7c542b9001..509c099e86 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 d50b1921ea..5f1a130459 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 8f8b3c828a..e0d05a2c89 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 # #################################