Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Fixes #8103 -- Select widget should only allow for one selected option

git-svn-id: http://code.djangoproject.com/svn/django/trunk@16848 bcc190cf-cafb-0310-a4f2-bffc1f526a37
  • Loading branch information...
commit e63fa0ff832e4a6c18aa9f427b643b3445c5abb0 1 parent 1ec25c4
@SmileyChris SmileyChris authored
View
14 django/forms/widgets.py
@@ -499,6 +499,8 @@ def _has_changed(self, initial, data):
return bool(initial) != bool(data)
class Select(Widget):
+ allow_multiple_selected = False
+
def __init__(self, attrs=None, choices=()):
super(Select, self).__init__(attrs)
# choices can be any iterable, but we may need to render this widget
@@ -518,14 +520,20 @@ def render(self, name, value, attrs=None, choices=()):
def render_option(self, selected_choices, option_value, option_label):
option_value = force_unicode(option_value)
- selected_html = (option_value in selected_choices) and u' selected="selected"' or ''
+ if option_value in selected_choices:
+ selected_html = u' selected="selected"'
+ if not self.allow_multiple_selected:
+ # Only allow for a single selection.
+ selected_choices.remove(option_value)
+ else:
+ selected_html = ''
return u'<option value="%s"%s>%s</option>' % (
escape(option_value), selected_html,
conditional_escape(force_unicode(option_label)))
def render_options(self, choices, selected_choices):
# Normalize to strings.
- selected_choices = set([force_unicode(v) for v in selected_choices])
+ selected_choices = set(force_unicode(v) for v in selected_choices)
output = []
for option_value, option_label in chain(self.choices, choices):
if isinstance(option_label, (list, tuple)):
@@ -571,6 +579,8 @@ def _has_changed(self, initial, data):
return initial != data
class SelectMultiple(Select):
+ allow_multiple_selected = True
+
def render(self, name, value, attrs=None, choices=()):
if value is None: value = []
final_attrs = self.build_attrs(attrs, name=name)
View
19 tests/regressiontests/forms/tests/widgets.py
@@ -12,7 +12,6 @@
from django.utils.unittest import TestCase
-
class FormsWidgetTestCase(TestCase):
# Each Widget class corresponds to an HTML form widget. A Widget knows how to
# render itself, given a field name and some data. Widgets don't perform
@@ -257,6 +256,15 @@ def test_select(self):
<option value="R">Ringo</option>
</select>""")
+ # Only one option can be selected, see #8103:
+ self.assertEqual(w.render('choices', '0', choices=(('0', '0'), ('1', '1'), ('2', '2'), ('3', '3'), ('0', 'extra'))), """<select name="choices">
+<option value="0" selected="selected">0</option>
+<option value="1">1</option>
+<option value="2">2</option>
+<option value="3">3</option>
+<option value="0">extra</option>
+</select>""")
+
# The value is compared to its str():
self.assertEqual(w.render('num', 2, choices=[('1', '1'), ('2', '2'), ('3', '3')]), """<select name="num">
<option value="1">1</option>
@@ -440,6 +448,15 @@ def test_selectmultiple(self):
<option value="R">Ringo</option>
</select>""")
+ # Multiple options (with the same value) can be selected, see #8103:
+ self.assertEqual(w.render('choices', ['0'], choices=(('0', '0'), ('1', '1'), ('2', '2'), ('3', '3'), ('0', 'extra'))), """<select multiple="multiple" name="choices">
+<option value="0" selected="selected">0</option>
+<option value="1">1</option>
+<option value="2">2</option>
+<option value="3">3</option>
+<option value="0" selected="selected">extra</option>
+</select>""")
+
# If multiple values are given, but some of them are not valid, the valid ones are selected:
self.assertEqual(w.render('beatles', ['J', 'G', 'foo'], choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo'))), """<select multiple="multiple" name="beatles">
<option value="J" selected="selected">John</option>
Please sign in to comment.
Something went wrong with that request. Please try again.