Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

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
Chris Beaven authored September 18, 2011
14  django/forms/widgets.py
@@ -499,6 +499,8 @@ def _has_changed(self, initial, data):
499 499
         return bool(initial) != bool(data)
500 500
 
501 501
 class Select(Widget):
  502
+    allow_multiple_selected = False
  503
+
502 504
     def __init__(self, attrs=None, choices=()):
503 505
         super(Select, self).__init__(attrs)
504 506
         # 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=()):
518 520
 
519 521
     def render_option(self, selected_choices, option_value, option_label):
520 522
         option_value = force_unicode(option_value)
521  
-        selected_html = (option_value in selected_choices) and u' selected="selected"' or ''
  523
+        if option_value in selected_choices:
  524
+            selected_html = u' selected="selected"'
  525
+            if not self.allow_multiple_selected:
  526
+                # Only allow for a single selection.
  527
+                selected_choices.remove(option_value)
  528
+        else:
  529
+            selected_html = ''
522 530
         return u'<option value="%s"%s>%s</option>' % (
523 531
             escape(option_value), selected_html,
524 532
             conditional_escape(force_unicode(option_label)))
525 533
 
526 534
     def render_options(self, choices, selected_choices):
527 535
         # Normalize to strings.
528  
-        selected_choices = set([force_unicode(v) for v in selected_choices])
  536
+        selected_choices = set(force_unicode(v) for v in selected_choices)
529 537
         output = []
530 538
         for option_value, option_label in chain(self.choices, choices):
531 539
             if isinstance(option_label, (list, tuple)):
@@ -571,6 +579,8 @@ def _has_changed(self, initial, data):
571 579
         return initial != data
572 580
 
573 581
 class SelectMultiple(Select):
  582
+    allow_multiple_selected = True
  583
+
574 584
     def render(self, name, value, attrs=None, choices=()):
575 585
         if value is None: value = []
576 586
         final_attrs = self.build_attrs(attrs, name=name)
19  tests/regressiontests/forms/tests/widgets.py
@@ -12,7 +12,6 @@
12 12
 from django.utils.unittest import TestCase
13 13
 
14 14
 
15  
-
16 15
 class FormsWidgetTestCase(TestCase):
17 16
     # Each Widget class corresponds to an HTML form widget. A Widget knows how to
18 17
     # render itself, given a field name and some data. Widgets don't perform
@@ -257,6 +256,15 @@ def test_select(self):
257 256
 <option value="R">Ringo</option>
258 257
 </select>""")
259 258
 
  259
+        # Only one option can be selected, see #8103:
  260
+        self.assertEqual(w.render('choices', '0', choices=(('0', '0'), ('1', '1'), ('2', '2'), ('3', '3'), ('0', 'extra'))), """<select name="choices">
  261
+<option value="0" selected="selected">0</option>
  262
+<option value="1">1</option>
  263
+<option value="2">2</option>
  264
+<option value="3">3</option>
  265
+<option value="0">extra</option>
  266
+</select>""")
  267
+
260 268
         # The value is compared to its str():
261 269
         self.assertEqual(w.render('num', 2, choices=[('1', '1'), ('2', '2'), ('3', '3')]), """<select name="num">
262 270
 <option value="1">1</option>
@@ -440,6 +448,15 @@ def test_selectmultiple(self):
440 448
 <option value="R">Ringo</option>
441 449
 </select>""")
442 450
 
  451
+        # Multiple options (with the same value) can be selected, see #8103:
  452
+        self.assertEqual(w.render('choices', ['0'], choices=(('0', '0'), ('1', '1'), ('2', '2'), ('3', '3'), ('0', 'extra'))), """<select multiple="multiple" name="choices">
  453
+<option value="0" selected="selected">0</option>
  454
+<option value="1">1</option>
  455
+<option value="2">2</option>
  456
+<option value="3">3</option>
  457
+<option value="0" selected="selected">extra</option>
  458
+</select>""")
  459
+
443 460
         # If multiple values are given, but some of them are not valid, the valid ones are selected:
444 461
         self.assertEqual(w.render('beatles', ['J', 'G', 'foo'], choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo'))), """<select multiple="multiple" name="beatles">
445 462
 <option value="J" selected="selected">John</option>

0 notes on commit e63fa0f

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