Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

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 malcolmt authored
Showing with 32 additions and 26 deletions.
  1. +24 −24 django/forms/widgets.py
  2. +8 −2 tests/regressiontests/forms/forms.py
48 django/forms/widgets.py
View
@@ -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 @@ def __init__(self, media=None, **kwargs):
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 @@ def __getitem__(self, name):
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 @@ def _media(self):
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 @@ def _media(self):
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 @@ def render(self, name, value, attrs=None, choices=()):
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 render(self, name, value, attrs=None):
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 @@ def render(self, name, value, attrs=None, choices=()):
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 @@ def render(self, name, value, attrs=None, choices=()):
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 id_for_label(self, id_):
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 @@ def _get_media(self):
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.
10 tests/regressiontests/forms/forms.py
View
@@ -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):
Please sign in to comment.
Something went wrong with that request. Please try again.