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
|
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 django.utils.html import escape
|
||||||
from itertools import chain
|
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.
|
# Converts a dictionary to a single string with key="value", XML-style.
|
||||||
# Assumes keys do not need to be XML-escaped.
|
# Assumes keys do not need to be XML-escaped.
|
||||||
flatatt = lambda attrs: ' '.join(['%s="%s"' % (k, escape(v)) for k, v in attrs.items()])
|
flatatt = lambda attrs: ' '.join(['%s="%s"' % (k, escape(v)) for k, v in attrs.items()])
|
||||||
|
|
||||||
class Widget(object):
|
class Widget(object):
|
||||||
|
requires_data_list = False # Determines whether render()'s 'value' argument should be a list.
|
||||||
def __init__(self, attrs=None):
|
def __init__(self, attrs=None):
|
||||||
self.attrs = attrs or {}
|
self.attrs = attrs or {}
|
||||||
|
|
||||||
|
@ -70,14 +80,31 @@ class Select(Widget):
|
||||||
final_attrs.update(attrs)
|
final_attrs.update(attrs)
|
||||||
output = [u'<select %s>' % flatatt(final_attrs)]
|
output = [u'<select %s>' % flatatt(final_attrs)]
|
||||||
str_value = str(value) # Normalize to string.
|
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 ''
|
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'<option value="%s"%s>%s</option>' % (escape(option_value), selected_html, escape(option_label)))
|
||||||
output.append(u'</select>')
|
output.append(u'</select>')
|
||||||
return u'\n'.join(output)
|
return u'\n'.join(output)
|
||||||
|
|
||||||
class SelectMultiple(Widget):
|
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):
|
class RadioSelect(Widget):
|
||||||
pass
|
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>
|
<option value="5">5</option>
|
||||||
</select>
|
</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 ###################################################################
|
# CharField ###################################################################
|
||||||
|
|
||||||
>>> f = CharField(required=False)
|
>>> f = CharField(required=False)
|
||||||
|
|
Loading…
Reference in New Issue