Author: mtredinnick
Date: 2008-08-24 19:32:32 -0500 (Sun, 24 Aug 2008)
New Revision: 8525

Modified:
   django/trunk/django/forms/widgets.py
   django/trunk/tests/regressiontests/forms/forms.py
Log:
Fixed #7195 -- Fixed the validation of MultipleChoice fields so that they can
be populated from request.REQUEST. Based on a patch from Daniel Roseman.


Modified: django/trunk/django/forms/widgets.py
===================================================================
--- django/trunk/django/forms/widgets.py        2008-08-25 00:11:23 UTC (rev 
8524)
+++ django/trunk/django/forms/widgets.py        2008-08-25 00:32:32 UTC (rev 
8525)
@@ -10,7 +10,7 @@
 import copy
 from itertools import chain
 from django.conf import settings
-from django.utils.datastructures import MultiValueDict
+from django.utils.datastructures import MultiValueDict, MergeDict
 from django.utils.html import escape, conditional_escape
 from django.utils.translation import ugettext
 from django.utils.encoding import StrAndUnicode, force_unicode
@@ -35,36 +35,36 @@
             media_attrs = media.__dict__
         else:
             media_attrs = kwargs
-            
+
         self._css = {}
         self._js = []
-        
+
         for name in MEDIA_TYPES:
             getattr(self, 'add_' + name)(media_attrs.get(name, None))
 
         # Any leftover attributes must be invalid.
         # if media_attrs != {}:
         #     raise TypeError, "'class Media' has invalid attribute(s): %s" % 
','.join(media_attrs.keys())
-        
+
     def __unicode__(self):
         return self.render()
-        
+
     def render(self):
         return mark_safe(u'\n'.join(chain(*[getattr(self, 'render_' + name)() 
for name in MEDIA_TYPES])))
-        
+
     def render_js(self):
         return [u'<script type="text/javascript" src="%s"></script>' % 
self.absolute_path(path) for path in self._js]
-        
+
     def render_css(self):
         # To keep rendering order consistent, we can't just iterate over 
items().
         # We need to sort the keys, and iterate over the sorted list.
         media = self._css.keys()
         media.sort()
         return chain(*[
-            [u'<link href="%s" type="text/css" media="%s" rel="stylesheet" />' 
% (self.absolute_path(path), medium) 
-                    for path in self._css[medium]] 
+            [u'<link href="%s" type="text/css" media="%s" rel="stylesheet" />' 
% (self.absolute_path(path), medium)
+                    for path in self._css[medium]]
                 for medium in media])
-        
+
     def absolute_path(self, path):
         if path.startswith(u'http://') or path.startswith(u'https://') or 
path.startswith(u'/'):
             return path
@@ -77,9 +77,9 @@
         raise KeyError('Unknown media type "%s"' % name)
 
     def add_js(self, data):
-        if data:    
+        if data:
             self._js.extend([path for path in data if path not in self._js])
-            
+
     def add_css(self, data):
         if data:
             for medium, paths in data.items():
@@ -99,8 +99,8 @@
             base = super(cls, self).media
         else:
             base = Media()
-        
-        # Get the media definition for this class    
+
+        # Get the media definition for this class
         definition = getattr(cls, 'Media', None)
         if definition:
             extend = getattr(definition, 'extend', True)
@@ -117,16 +117,16 @@
         else:
             return base
     return property(_media)
-    
+
 class MediaDefiningClass(type):
     "Metaclass for classes that can have media definitions"
-    def __new__(cls, name, bases, attrs):            
+    def __new__(cls, name, bases, attrs):
         new_class = super(MediaDefiningClass, cls).__new__(cls, name, bases,
                                                            attrs)
         if 'media' not in attrs:
             new_class.media = media_property(new_class)
         return new_class
-        
+
 class Widget(object):
     __metaclass__ = MediaDefiningClass
     is_hidden = False          # Determines whether this corresponds to an 
<input type="hidden">.
@@ -250,7 +250,7 @@
             for v in value]))
 
     def value_from_datadict(self, data, files, name):
-        if isinstance(data, MultiValueDict):
+        if isinstance(data, (MultiValueDict, MergeDict)):
             return data.getlist(name)
         return data.get(name, None)
 
@@ -264,7 +264,7 @@
     def value_from_datadict(self, data, files, name):
         "File widgets take data from FILES, not POST"
         return files.get(name, None)
-    
+
     def _has_changed(self, initial, data):
         if data is None:
             return False
@@ -417,10 +417,10 @@
         return mark_safe(u'\n'.join(output))
 
     def value_from_datadict(self, data, files, name):
-        if isinstance(data, MultiValueDict):
+        if isinstance(data, (MultiValueDict, MergeDict)):
             return data.getlist(name)
         return data.get(name, None)
-    
+
     def _has_changed(self, initial, data):
         if initial is None:
             initial = []
@@ -537,7 +537,7 @@
                 label_for = u' for="%s"' % final_attrs['id']
             else:
                 label_for = ''
-                
+
             cb = CheckboxInput(final_attrs, check_test=lambda value: value in 
str_values)
             option_value = force_unicode(option_value)
             rendered_cb = cb.render(name, option_value)
@@ -611,7 +611,7 @@
 
     def value_from_datadict(self, data, files, name):
         return [widget.value_from_datadict(data, files, name + '_%s' % i) for 
i, widget in enumerate(self.widgets)]
-    
+
     def _has_changed(self, initial, data):
         if initial is None:
             initial = [u'' for x in range(0, len(data))]
@@ -647,7 +647,7 @@
             media = media + w.media
         return media
     media = property(_get_media)
-    
+
 class SplitDateTimeWidget(MultiWidget):
     """
     A Widget that splits datetime input into two <input type="text"> boxes.

Modified: django/trunk/tests/regressiontests/forms/forms.py
===================================================================
--- django/trunk/tests/regressiontests/forms/forms.py   2008-08-25 00:11:23 UTC 
(rev 8524)
+++ django/trunk/tests/regressiontests/forms/forms.py   2008-08-25 00:32:32 UTC 
(rev 8525)
@@ -540,8 +540,9 @@
 <li><label for="composers_id_1"><input type="checkbox" name="composers" 
value="P" id="composers_id_1" /> Paul McCartney</label></li>
 </ul>
 
-Data for a MultipleChoiceField should be a list. QueryDict and MultiValueDict
-conveniently work with this.
+Data for a MultipleChoiceField should be a list. QueryDict, MultiValueDict and
+MergeDict (when created as a merge of MultiValueDicts) conveniently work with
+this.
 >>> data = {'name': 'Yesterday', 'composers': ['J', 'P']}
 >>> f = SongForm(data)
 >>> f.errors
@@ -556,6 +557,11 @@
 >>> f = SongForm(data)
 >>> f.errors
 {}
+>>> from django.utils.datastructures import MergeDict
+>>> data = MergeDict(MultiValueDict(dict(name=['Yesterday'], composers=['J', 
'P'])))
+>>> f = SongForm(data)
+>>> f.errors
+{}
 
 The MultipleHiddenInput widget renders multiple values as hidden fields.
 >>> class SongFormHidden(Form):


--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups 
"Django updates" group.
To post to this group, send email to [email protected]
To unsubscribe from this group, send email to [EMAIL PROTECTED]
For more options, visit this group at 
http://groups.google.com/group/django-updates?hl=en
-~----------~----~----~----~------~----~------~--~---

Reply via email to