Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

Fixed #3787, #3788 -- Corrected check for IndexError on MultiValueFie…

…ld, 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
  • Loading branch information...
commit b24c860fa21790bfe04f5afc7c8bcccb70902f83 1 parent ed60b86
Russell Keith-Magee authored
2  django/newforms/fields.py
@@ -457,7 +457,7 @@ def clean(self, value):
457 457
         for i, field in enumerate(self.fields):
458 458
             try:
459 459
                 field_value = value[i]
460  
-            except KeyError:
  460
+            except IndexError:
461 461
                 field_value = None
462 462
             if self.required and field_value in EMPTY_VALUES:
463 463
                 raise ValidationError(gettext(u'This field is required.'))
2  django/newforms/widgets.py
@@ -347,7 +347,7 @@ def id_for_label(self, id_):
347 347
     id_for_label = classmethod(id_for_label)
348 348
 
349 349
     def value_from_datadict(self, data, name):
350  
-        return [data.get(name + '_%s' % i) for i in range(len(self.widgets))]
  350
+        return [widget.value_from_datadict(data, name + '_%s' % i) for i, widget in enumerate(self.widgets)]
351 351
 
352 352
     def format_output(self, rendered_widgets):
353 353
         return u''.join(rendered_widgets)
89  tests/regressiontests/forms/tests.py
@@ -5,6 +5,7 @@
5 5
 form_tests = r"""
6 6
 >>> from django.newforms import *
7 7
 >>> import datetime
  8
+>>> import time
8 9
 >>> import re
9 10
 
10 11
 ###########
@@ -3297,6 +3298,94 @@
3297 3298
 <option value="2016">2016</option>
3298 3299
 </select>
3299 3300
 
  3301
+# MultiWidget and MultiValueField #############################################
  3302
+# MultiWidgets are widgets composed of other widgets. They are usually 
  3303
+# combined with MultiValueFields - a field that is composed of other fields.
  3304
+# MulitWidgets can themselved be composed of other MultiWidgets.
  3305
+# SplitDateTimeWidget is one example of a MultiWidget.
  3306
+
  3307
+>>> class ComplexMultiWidget(MultiWidget):
  3308
+...     def __init__(self, attrs=None):
  3309
+...         widgets = (
  3310
+...             TextInput(), 
  3311
+...             SelectMultiple(choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo'))),
  3312
+...             SplitDateTimeWidget(),
  3313
+...         )
  3314
+...         super(ComplexMultiWidget, self).__init__(widgets, attrs)
  3315
+...
  3316
+...     def decompress(self, value):
  3317
+...         if value:
  3318
+...             data = value.split(',')
  3319
+...             return [data[0], data[1], datetime.datetime(*time.strptime(data[2], "%Y-%m-%d %H:%M:%S")[0:6])]
  3320
+...         return [None, None, None]
  3321
+...     def format_output(self, rendered_widgets):
  3322
+...         return u'\n'.join(rendered_widgets)
  3323
+>>> w = ComplexMultiWidget()
  3324
+>>> print w.render('name', 'some text,JP,2007-04-25 06:24:00')
  3325
+<input type="text" name="name_0" value="some text" />
  3326
+<select multiple="multiple" name="name_1">
  3327
+<option value="J" selected="selected">John</option>
  3328
+<option value="P" selected="selected">Paul</option>
  3329
+<option value="G">George</option>
  3330
+<option value="R">Ringo</option>
  3331
+</select>
  3332
+<input type="text" name="name_2_0" value="2007-04-25" /><input type="text" name="name_2_1" value="06:24:00" />
  3333
+
  3334
+>>> class ComplexField(MultiValueField):
  3335
+...     def __init__(self, required=True, widget=None, label=None, initial=None): 
  3336
+...         fields = (
  3337
+...             CharField(), 
  3338
+...             MultipleChoiceField(choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo'))),
  3339
+...             SplitDateTimeField()
  3340
+...         )
  3341
+...         super(ComplexField, self).__init__(fields, required, widget, label, initial) 
  3342
+...
  3343
+...     def compress(self, data_list):
  3344
+...         if data_list:
  3345
+...             return '%s,%s,%s' % (data_list[0],''.join(data_list[1]),data_list[2])
  3346
+...         return None
  3347
+
  3348
+>>> f = ComplexField(widget=w)
  3349
+>>> f.clean(['some text', ['J','P'], ['2007-04-25','6:24:00']])
  3350
+u'some text,JP,2007-04-25 06:24:00'
  3351
+>>> f.clean(['some text',['X'], ['2007-04-25','6:24:00']])
  3352
+Traceback (most recent call last):
  3353
+...
  3354
+ValidationError: [u'Select a valid choice. X is not one of the available choices.']
  3355
+
  3356
+# If insufficient data is provided, None is substituted
  3357
+>>> f.clean(['some text',['JP']])
  3358
+Traceback (most recent call last):
  3359
+...
  3360
+ValidationError: [u'This field is required.']
  3361
+
  3362
+>>> class ComplexFieldForm(Form):
  3363
+...     field1 = ComplexField(widget=w)
  3364
+>>> f = ComplexFieldForm()
  3365
+>>> print f
  3366
+<tr><th><label for="id_field1_0">Field1:</label></th><td><input type="text" name="field1_0" id="id_field1_0" />
  3367
+<select multiple="multiple" name="field1_1" id="id_field1_1">
  3368
+<option value="J">John</option>
  3369
+<option value="P">Paul</option>
  3370
+<option value="G">George</option>
  3371
+<option value="R">Ringo</option>
  3372
+</select>
  3373
+<input type="text" name="field1_2_0" id="id_field1_2_0" /><input type="text" name="field1_2_1" id="id_field1_2_1" /></td></tr>
  3374
+
  3375
+>>> f = ComplexFieldForm({'field1_0':'some text','field1_1':['J','P'], 'field1_2_0':'2007-04-25', 'field1_2_1':'06:24:00'})
  3376
+>>> print f
  3377
+<tr><th><label for="id_field1_0">Field1:</label></th><td><input type="text" name="field1_0" value="some text" id="id_field1_0" />
  3378
+<select multiple="multiple" name="field1_1" id="id_field1_1">
  3379
+<option value="J" selected="selected">John</option>
  3380
+<option value="P" selected="selected">Paul</option>
  3381
+<option value="G">George</option>
  3382
+<option value="R">Ringo</option>
  3383
+</select>
  3384
+<input type="text" name="field1_2_0" value="2007-04-25" id="id_field1_2_0" /><input type="text" name="field1_2_1" value="06:24:00" id="id_field1_2_1" /></td></tr>
  3385
+
  3386
+>>> f.clean_data
  3387
+{'field1': u'some text,JP,2007-04-25 06:24:00'}
  3388
+
3300 3389
 #################################
3301 3390
 # Tests of underlying functions #
3302 3391
 #################################

0 notes on commit b24c860

Please sign in to comment.
Something went wrong with that request. Please try again.