Implemented SelectMultiple in django.newforms.widgets
git-svn-id: http://code.djangoproject.com/svn/django/trunk@3958 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
parent
964ccd1023
commit
36786d28f5
|
@ -2,16 +2,26 @@
|
|||
HTML Widget classes
|
||||
"""
|
||||
|
||||
__all__ = ('Widget', 'TextInput', 'PasswordInput', 'HiddenInput', 'FileInput', 'Textarea', 'CheckboxInput', 'Select')
|
||||
__all__ = (
|
||||
'Widget', 'TextInput', 'PasswordInput', 'HiddenInput', 'FileInput',
|
||||
'Textarea', 'CheckboxInput',
|
||||
'Select', 'SelectMultiple',
|
||||
)
|
||||
|
||||
from django.utils.html import escape
|
||||
from itertools import chain
|
||||
|
||||
try:
|
||||
set # Only available in Python 2.4+
|
||||
except NameError:
|
||||
from sets import Set as set # Python 2.3 fallback
|
||||
|
||||
# Converts a dictionary to a single string with key="value", XML-style.
|
||||
# Assumes keys do not need to be XML-escaped.
|
||||
flatatt = lambda attrs: ' '.join(['%s="%s"' % (k, escape(v)) for k, v in attrs.items()])
|
||||
|
||||
class Widget(object):
|
||||
requires_data_list = False # Determines whether render()'s 'value' argument should be a list.
|
||||
def __init__(self, attrs=None):
|
||||
self.attrs = attrs or {}
|
||||
|
||||
|
@ -70,14 +80,31 @@ class Select(Widget):
|
|||
final_attrs.update(attrs)
|
||||
output = [u'<select %s>' % flatatt(final_attrs)]
|
||||
str_value = str(value) # Normalize to string.
|
||||
for option_value, option_label, in chain(self.choices, choices):
|
||||
for option_value, option_label in chain(self.choices, choices):
|
||||
selected_html = (str(option_value) == str_value) and ' selected="selected"' or ''
|
||||
output.append(u'<option value="%s"%s>%s</option>' % (escape(option_value), selected_html, escape(option_label)))
|
||||
output.append(u'</select>')
|
||||
return u'\n'.join(output)
|
||||
|
||||
class SelectMultiple(Widget):
|
||||
pass
|
||||
requires_data_list = True
|
||||
def __init__(self, attrs=None, choices=()):
|
||||
# choices can be any iterable
|
||||
self.attrs = attrs or {}
|
||||
self.choices = choices
|
||||
|
||||
def render(self, name, value, attrs=None, choices=()):
|
||||
if value is None: value = []
|
||||
final_attrs = dict(self.attrs, name=name)
|
||||
if attrs:
|
||||
final_attrs.update(attrs)
|
||||
output = [u'<select multiple="multiple" %s>' % flatatt(final_attrs)]
|
||||
str_values = set([str(v) for v in value]) # Normalize to strings.
|
||||
for option_value, option_label in chain(self.choices, choices):
|
||||
selected_html = (str(option_value) in str_values) and ' selected="selected"' or ''
|
||||
output.append(u'<option value="%s"%s>%s</option>' % (escape(option_value), selected_html, escape(option_label)))
|
||||
output.append(u'</select>')
|
||||
return u'\n'.join(output)
|
||||
|
||||
class RadioSelect(Widget):
|
||||
pass
|
||||
|
|
|
@ -236,6 +236,110 @@ If 'choices' is passed to both the constructor and render(), then they'll both b
|
|||
<option value="5">5</option>
|
||||
</select>
|
||||
|
||||
# SelectMultiple Widget #######################################################
|
||||
|
||||
>>> w = SelectMultiple()
|
||||
>>> print w.render('beatles', ['J'], choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo')))
|
||||
<select multiple="multiple" name="beatles">
|
||||
<option value="J" selected="selected">John</option>
|
||||
<option value="P">Paul</option>
|
||||
<option value="G">George</option>
|
||||
<option value="R">Ringo</option>
|
||||
</select>
|
||||
>>> print w.render('beatles', ['J', 'P'], choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo')))
|
||||
<select multiple="multiple" name="beatles">
|
||||
<option value="J" selected="selected">John</option>
|
||||
<option value="P" selected="selected">Paul</option>
|
||||
<option value="G">George</option>
|
||||
<option value="R">Ringo</option>
|
||||
</select>
|
||||
>>> print w.render('beatles', ['J', 'P', 'R'], choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo')))
|
||||
<select multiple="multiple" name="beatles">
|
||||
<option value="J" selected="selected">John</option>
|
||||
<option value="P" selected="selected">Paul</option>
|
||||
<option value="G">George</option>
|
||||
<option value="R" selected="selected">Ringo</option>
|
||||
</select>
|
||||
|
||||
If the value is None, none of the options are selected:
|
||||
>>> print w.render('beatles', None, choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo')))
|
||||
<select multiple="multiple" name="beatles">
|
||||
<option value="J">John</option>
|
||||
<option value="P">Paul</option>
|
||||
<option value="G">George</option>
|
||||
<option value="R">Ringo</option>
|
||||
</select>
|
||||
|
||||
If the value corresponds to a label (but not to an option value), none of the options are selected:
|
||||
>>> print w.render('beatles', ['John'], choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo')))
|
||||
<select multiple="multiple" name="beatles">
|
||||
<option value="J">John</option>
|
||||
<option value="P">Paul</option>
|
||||
<option value="G">George</option>
|
||||
<option value="R">Ringo</option>
|
||||
</select>
|
||||
|
||||
If multiple values are given, but some of them are not valid, the valid ones are selected:
|
||||
>>> print 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>
|
||||
<option value="P">Paul</option>
|
||||
<option value="G" selected="selected">George</option>
|
||||
<option value="R">Ringo</option>
|
||||
</select>
|
||||
|
||||
The value is compared to its str():
|
||||
>>> print w.render('nums', [2], choices=[('1', '1'), ('2', '2'), ('3', '3')])
|
||||
<select multiple="multiple" name="nums">
|
||||
<option value="1">1</option>
|
||||
<option value="2" selected="selected">2</option>
|
||||
<option value="3">3</option>
|
||||
</select>
|
||||
>>> print w.render('nums', ['2'], choices=[(1, 1), (2, 2), (3, 3)])
|
||||
<select multiple="multiple" name="nums">
|
||||
<option value="1">1</option>
|
||||
<option value="2" selected="selected">2</option>
|
||||
<option value="3">3</option>
|
||||
</select>
|
||||
>>> print w.render('nums', [2], choices=[(1, 1), (2, 2), (3, 3)])
|
||||
<select multiple="multiple" name="nums">
|
||||
<option value="1">1</option>
|
||||
<option value="2" selected="selected">2</option>
|
||||
<option value="3">3</option>
|
||||
</select>
|
||||
|
||||
The 'choices' argument can be any iterable:
|
||||
>>> def get_choices():
|
||||
... for i in range(5):
|
||||
... yield (i, i)
|
||||
>>> print w.render('nums', [2], choices=get_choices())
|
||||
<select multiple="multiple" name="nums">
|
||||
<option value="0">0</option>
|
||||
<option value="1">1</option>
|
||||
<option value="2" selected="selected">2</option>
|
||||
<option value="3">3</option>
|
||||
<option value="4">4</option>
|
||||
</select>
|
||||
|
||||
You can also pass 'choices' to the constructor:
|
||||
>>> w = SelectMultiple(choices=[(1, 1), (2, 2), (3, 3)])
|
||||
>>> print w.render('nums', [2])
|
||||
<select multiple="multiple" name="nums">
|
||||
<option value="1">1</option>
|
||||
<option value="2" selected="selected">2</option>
|
||||
<option value="3">3</option>
|
||||
</select>
|
||||
|
||||
If 'choices' is passed to both the constructor and render(), then they'll both be in the output:
|
||||
>>> print w.render('nums', [2], choices=[(4, 4), (5, 5)])
|
||||
<select multiple="multiple" name="nums">
|
||||
<option value="1">1</option>
|
||||
<option value="2" selected="selected">2</option>
|
||||
<option value="3">3</option>
|
||||
<option value="4">4</option>
|
||||
<option value="5">5</option>
|
||||
</select>
|
||||
|
||||
# CharField ###################################################################
|
||||
|
||||
>>> f = CharField(required=False)
|
||||
|
|
Loading…
Reference in New Issue