Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

Fixed #7195 -- Fixed the validation of MultipleChoice fields so that …

…they can

be populated from request.REQUEST. Based on a patch from Daniel Roseman.


git-svn-id: http://code.djangoproject.com/svn/django/trunk@8525 bcc190cf-cafb-0310-a4f2-bffc1f526a37
  • Loading branch information...
commit 6d6fb392b4732fa4ff77e918c06ffcd92e753d9b 1 parent d6e5632
Malcolm Tredinnick authored
48  django/forms/widgets.py
@@ -10,7 +10,7 @@
10 10
 import copy
11 11
 from itertools import chain
12 12
 from django.conf import settings
13  
-from django.utils.datastructures import MultiValueDict
  13
+from django.utils.datastructures import MultiValueDict, MergeDict
14 14
 from django.utils.html import escape, conditional_escape
15 15
 from django.utils.translation import ugettext
16 16
 from django.utils.encoding import StrAndUnicode, force_unicode
@@ -35,36 +35,36 @@ def __init__(self, media=None, **kwargs):
35 35
             media_attrs = media.__dict__
36 36
         else:
37 37
             media_attrs = kwargs
38  
-            
  38
+
39 39
         self._css = {}
40 40
         self._js = []
41  
-        
  41
+
42 42
         for name in MEDIA_TYPES:
43 43
             getattr(self, 'add_' + name)(media_attrs.get(name, None))
44 44
 
45 45
         # Any leftover attributes must be invalid.
46 46
         # if media_attrs != {}:
47 47
         #     raise TypeError, "'class Media' has invalid attribute(s): %s" % ','.join(media_attrs.keys())
48  
-        
  48
+
49 49
     def __unicode__(self):
50 50
         return self.render()
51  
-        
  51
+
52 52
     def render(self):
53 53
         return mark_safe(u'\n'.join(chain(*[getattr(self, 'render_' + name)() for name in MEDIA_TYPES])))
54  
-        
  54
+
55 55
     def render_js(self):
56 56
         return [u'<script type="text/javascript" src="%s"></script>' % self.absolute_path(path) for path in self._js]
57  
-        
  57
+
58 58
     def render_css(self):
59 59
         # To keep rendering order consistent, we can't just iterate over items().
60 60
         # We need to sort the keys, and iterate over the sorted list.
61 61
         media = self._css.keys()
62 62
         media.sort()
63 63
         return chain(*[
64  
-            [u'<link href="%s" type="text/css" media="%s" rel="stylesheet" />' % (self.absolute_path(path), medium) 
65  
-                    for path in self._css[medium]] 
  64
+            [u'<link href="%s" type="text/css" media="%s" rel="stylesheet" />' % (self.absolute_path(path), medium)
  65
+                    for path in self._css[medium]]
66 66
                 for medium in media])
67  
-        
  67
+
68 68
     def absolute_path(self, path):
69 69
         if path.startswith(u'http://') or path.startswith(u'https://') or path.startswith(u'/'):
70 70
             return path
@@ -77,9 +77,9 @@ def __getitem__(self, name):
77 77
         raise KeyError('Unknown media type "%s"' % name)
78 78
 
79 79
     def add_js(self, data):
80  
-        if data:    
  80
+        if data:
81 81
             self._js.extend([path for path in data if path not in self._js])
82  
-            
  82
+
83 83
     def add_css(self, data):
84 84
         if data:
85 85
             for medium, paths in data.items():
@@ -99,8 +99,8 @@ def _media(self):
99 99
             base = super(cls, self).media
100 100
         else:
101 101
             base = Media()
102  
-        
103  
-        # Get the media definition for this class    
  102
+
  103
+        # Get the media definition for this class
104 104
         definition = getattr(cls, 'Media', None)
105 105
         if definition:
106 106
             extend = getattr(definition, 'extend', True)
@@ -117,16 +117,16 @@ def _media(self):
117 117
         else:
118 118
             return base
119 119
     return property(_media)
120  
-    
  120
+
121 121
 class MediaDefiningClass(type):
122 122
     "Metaclass for classes that can have media definitions"
123  
-    def __new__(cls, name, bases, attrs):            
  123
+    def __new__(cls, name, bases, attrs):
124 124
         new_class = super(MediaDefiningClass, cls).__new__(cls, name, bases,
125 125
                                                            attrs)
126 126
         if 'media' not in attrs:
127 127
             new_class.media = media_property(new_class)
128 128
         return new_class
129  
-        
  129
+
130 130
 class Widget(object):
131 131
     __metaclass__ = MediaDefiningClass
132 132
     is_hidden = False          # Determines whether this corresponds to an <input type="hidden">.
@@ -250,7 +250,7 @@ def render(self, name, value, attrs=None, choices=()):
250 250
             for v in value]))
251 251
 
252 252
     def value_from_datadict(self, data, files, name):
253  
-        if isinstance(data, MultiValueDict):
  253
+        if isinstance(data, (MultiValueDict, MergeDict)):
254 254
             return data.getlist(name)
255 255
         return data.get(name, None)
256 256
 
@@ -264,7 +264,7 @@ def render(self, name, value, attrs=None):
264 264
     def value_from_datadict(self, data, files, name):
265 265
         "File widgets take data from FILES, not POST"
266 266
         return files.get(name, None)
267  
-    
  267
+
268 268
     def _has_changed(self, initial, data):
269 269
         if data is None:
270 270
             return False
@@ -417,10 +417,10 @@ def render(self, name, value, attrs=None, choices=()):
417 417
         return mark_safe(u'\n'.join(output))
418 418
 
419 419
     def value_from_datadict(self, data, files, name):
420  
-        if isinstance(data, MultiValueDict):
  420
+        if isinstance(data, (MultiValueDict, MergeDict)):
421 421
             return data.getlist(name)
422 422
         return data.get(name, None)
423  
-    
  423
+
424 424
     def _has_changed(self, initial, data):
425 425
         if initial is None:
426 426
             initial = []
@@ -537,7 +537,7 @@ def render(self, name, value, attrs=None, choices=()):
537 537
                 label_for = u' for="%s"' % final_attrs['id']
538 538
             else:
539 539
                 label_for = ''
540  
-                
  540
+
541 541
             cb = CheckboxInput(final_attrs, check_test=lambda value: value in str_values)
542 542
             option_value = force_unicode(option_value)
543 543
             rendered_cb = cb.render(name, option_value)
@@ -611,7 +611,7 @@ def id_for_label(self, id_):
611 611
 
612 612
     def value_from_datadict(self, data, files, name):
613 613
         return [widget.value_from_datadict(data, files, name + '_%s' % i) for i, widget in enumerate(self.widgets)]
614  
-    
  614
+
615 615
     def _has_changed(self, initial, data):
616 616
         if initial is None:
617 617
             initial = [u'' for x in range(0, len(data))]
@@ -647,7 +647,7 @@ def _get_media(self):
647 647
             media = media + w.media
648 648
         return media
649 649
     media = property(_get_media)
650  
-    
  650
+
651 651
 class SplitDateTimeWidget(MultiWidget):
652 652
     """
653 653
     A Widget that splits datetime input into two <input type="text"> boxes.
10  tests/regressiontests/forms/forms.py
@@ -540,8 +540,9 @@
540 540
 <li><label for="composers_id_1"><input type="checkbox" name="composers" value="P" id="composers_id_1" /> Paul McCartney</label></li>
541 541
 </ul>
542 542
 
543  
-Data for a MultipleChoiceField should be a list. QueryDict and MultiValueDict
544  
-conveniently work with this.
  543
+Data for a MultipleChoiceField should be a list. QueryDict, MultiValueDict and
  544
+MergeDict (when created as a merge of MultiValueDicts) conveniently work with
  545
+this.
545 546
 >>> data = {'name': 'Yesterday', 'composers': ['J', 'P']}
546 547
 >>> f = SongForm(data)
547 548
 >>> f.errors
@@ -556,6 +557,11 @@
556 557
 >>> f = SongForm(data)
557 558
 >>> f.errors
558 559
 {}
  560
+>>> from django.utils.datastructures import MergeDict
  561
+>>> data = MergeDict(MultiValueDict(dict(name=['Yesterday'], composers=['J', 'P'])))
  562
+>>> f = SongForm(data)
  563
+>>> f.errors
  564
+{}
559 565
 
560 566
 The MultipleHiddenInput widget renders multiple values as hidden fields.
561 567
 >>> class SongFormHidden(Form):

0 notes on commit 6d6fb39

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