Index: django/newforms/widgets.py
===================================================================
--- django/newforms/widgets.py (revision 5582)
+++ django/newforms/widgets.py (working copy)
@@ -215,8 +215,10 @@
return data.getlist(name)
return data.get(name, None)
-class RadioInput(StrAndUnicode):
- "An object used by RadioFieldRenderer that represents a single ."
+class ChoiceInput(StrAndUnicode):
+ input_type = None # Subclasses must define this.
+
+ "An object used by ChoiceFieldRenderer that represents a single radio or checkbox input."
def __init__(self, name, value, attrs, choice, index):
self.name, self.value = name, value
self.attrs = attrs
@@ -233,36 +235,46 @@
def tag(self):
if 'id' in self.attrs:
self.attrs['id'] = '%s_%s' % (self.attrs['id'], self.index)
- final_attrs = dict(self.attrs, type='radio', name=self.name, value=self.choice_value)
+ final_attrs = dict(self.attrs, type=self.input_type, name=self.name, value=self.choice_value)
if self.is_checked():
final_attrs['checked'] = 'checked'
return u'' % flatatt(final_attrs)
-class RadioFieldRenderer(StrAndUnicode):
- "An object used by RadioSelect to enable customization of radio widgets."
- def __init__(self, name, value, attrs, choices):
+class RadioChoiceInput(ChoiceInput):
+ input_type = 'radio'
+
+class CheckboxChoiceInput(ChoiceInput):
+ input_type = 'checkbox'
+
+ def is_checked(self):
+ return self.choice_value in self.value
+
+class ChoiceFieldRenderer(StrAndUnicode):
+ "An object used to enable customization of radio and checkbox widgets."
+ def __init__(self, name, value, attrs, choices, choice_widget=ChoiceInput):
self.name, self.value, self.attrs = name, value, attrs
self.choices = choices
+ self.choice_widget = choice_widget
def __iter__(self):
for i, choice in enumerate(self.choices):
- yield RadioInput(self.name, self.value, self.attrs.copy(), choice, i)
+ yield self.choice_widget(self.name, self.value, self.attrs.copy(), choice, i)
def __getitem__(self, idx):
choice = self.choices[idx] # Let the IndexError propogate
- return RadioInput(self.name, self.value, self.attrs.copy(), choice, idx)
+ return self.choice_widget(self.name, self.value, self.attrs.copy(), choice, idx)
def __unicode__(self):
- "Outputs a
for this set of radio fields."
+ "Outputs a
for this set of choice fields."
return u'
\n%s\n
' % u'\n'.join([u'
%s
' % w for w in self])
class RadioSelect(Select):
def render(self, name, value, attrs=None, choices=()):
- "Returns a RadioFieldRenderer instance rather than a Unicode string."
+ "Returns a ChoiceFieldRenderer instance rather than a Unicode string."
if value is None: value = ''
str_value = smart_unicode(value) # Normalize to string.
final_attrs = self.build_attrs(attrs)
- return RadioFieldRenderer(name, str_value, final_attrs, list(chain(self.choices, choices)))
+ return ChoiceFieldRenderer(name, str_value, final_attrs, list(chain(self.choices, choices)), choice_widget=RadioChoiceInput)
def id_for_label(self, id_):
# RadioSelect is represented by multiple fields,
@@ -276,22 +288,11 @@
class CheckboxSelectMultiple(SelectMultiple):
def render(self, name, value, attrs=None, choices=()):
- if value is None: value = []
- has_id = attrs and 'id' in attrs
+ "Returns a ChoiceFieldRenderer instance rather than a Unicode string."
+ if value is None: value = ''
+ str_values = set([smart_unicode(v) for v in value]) # Normalize to strings.
final_attrs = self.build_attrs(attrs, name=name)
- output = [u'
']
- str_values = set([smart_unicode(v) for v in value]) # Normalize to strings.
- for i, (option_value, option_label) in enumerate(chain(self.choices, choices)):
- # If an ID attribute was given, add a numeric index as a suffix,
- # so that the checkboxes don't all have the same ID attribute.
- if has_id:
- final_attrs = dict(final_attrs, id='%s_%s' % (attrs['id'], i))
- cb = CheckboxInput(final_attrs, check_test=lambda value: value in str_values)
- option_value = smart_unicode(option_value)
- rendered_cb = cb.render(name, option_value)
- output.append(u'' % (rendered_cb, escape(smart_unicode(option_label))))
- output.append(u'
-The render() method returns a RadioFieldRenderer object, whose str() is a
.
+The render() method returns a ChoiceFieldRenderer object, whose str() is a
.
You can manipulate that object directly to customize the way the RadioSelect
is rendered.
>>> w = RadioSelect()
@@ -644,7 +644,7 @@
beatle J G George False
beatle J R Ringo False
-A RadioFieldRenderer object also allows index access to individual RadioInput
+A ChoiceFieldRenderer object also allows index access to individual RadioInput
objects.
>>> w = RadioSelect()
>>> r = w.render('beatle', 'J', choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo')))
@@ -792,7 +792,56 @@
->>> w.render('nums', ['ŠĐĆŽćžšđ'], choices=[('ŠĐĆŽćžšđ', 'ŠĐabcĆŽćžšđ'), ('ćžšđ', 'abcćžšđ')])
+The render() method returns a ChoiceFieldRenderer object, whose str() is a
.
+You can manipulate that object directly to customize the way the RadioSelect
+is rendered.
+>>> w2 = CheckboxSelectMultiple()
+>>> r = w2.render('beatle', ['J', 'G'], choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo')))
+>>> for inp in r:
+... print inp
+
+
+
+
+>>> for inp in r:
+... print '%s ' % inp
+
+
+
+
+>>> for inp in r:
+... print '
%s %s
' % (inp.tag(), inp.choice_label)
+
John
+
Paul
+
George
+
Ringo
+>>> for inp in r:
+... print '%s %s %s %s %s' % (inp.name, inp.value, inp.choice_value, inp.choice_label, inp.is_checked())
+beatle set([u'J', u'G']) J John True
+beatle set([u'J', u'G']) P Paul False
+beatle set([u'J', u'G']) G George True
+beatle set([u'J', u'G']) R Ringo False
+
+A ChoiceFieldRenderer object also allows index access to individual RadioInput
+objects.
+>>> w2 = CheckboxSelectMultiple()
+>>> r = w2.render('beatle', ['J'], choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo')))
+>>> print r[1]
+
+>>> print r[0]
+
+>>> r[0].is_checked()
+True
+>>> r[1].is_checked()
+False
+>>> r[1].name, r[1].value, r[1].choice_value, r[1].choice_label
+('beatle', set([u'J']), u'P', u'Paul')
+>>> r[10]
+Traceback (most recent call last):
+...
+IndexError: list index out of range
+
+>>> unicode(w.render('nums', ['ŠĐĆŽćžšđ'], choices=[('ŠĐĆŽćžšđ', 'ŠĐabcĆŽćžšđ'), ('ćžšđ', 'abcćžšđ')]))
u'