Fixed #4228 -- Removed hardcoding of `RadioFieldRenderer` in the `RadioSelect` Widget so that the display of `RadioSelect`s can be more easily customized. `BoundField.__unicode__` also no longer special cases `RadioSelect` since `RadioSelect.render()` now returns a string like every other Widget.
git-svn-id: http://code.djangoproject.com/svn/django/trunk@5782 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
parent
f27774ee0a
commit
cdbd5751d3
|
@ -232,16 +232,8 @@ class BoundField(StrAndUnicode):
|
||||||
self.help_text = field.help_text or ''
|
self.help_text = field.help_text or ''
|
||||||
|
|
||||||
def __unicode__(self):
|
def __unicode__(self):
|
||||||
"Renders this field as an HTML widget."
|
"""Renders this field as an HTML widget."""
|
||||||
# Use the 'widget' attribute on the field to determine which type
|
return self.as_widget()
|
||||||
# of HTML widget to use.
|
|
||||||
value = self.as_widget(self.field.widget)
|
|
||||||
if not isinstance(value, basestring):
|
|
||||||
# Some Widget render() methods -- notably RadioSelect -- return a
|
|
||||||
# "special" object rather than a string. Call __unicode__() on that
|
|
||||||
# object to get its rendered value.
|
|
||||||
value = unicode(value)
|
|
||||||
return value
|
|
||||||
|
|
||||||
def _errors(self):
|
def _errors(self):
|
||||||
"""
|
"""
|
||||||
|
@ -251,7 +243,14 @@ class BoundField(StrAndUnicode):
|
||||||
return self.form.errors.get(self.name, ErrorList())
|
return self.form.errors.get(self.name, ErrorList())
|
||||||
errors = property(_errors)
|
errors = property(_errors)
|
||||||
|
|
||||||
def as_widget(self, widget, attrs=None):
|
def as_widget(self, widget=None, attrs=None):
|
||||||
|
"""
|
||||||
|
Renders the field by rendering the passed widget, adding any HTML
|
||||||
|
attributes passed as attrs. If no widget is specified, then the
|
||||||
|
field's default widget will be used.
|
||||||
|
"""
|
||||||
|
if not widget:
|
||||||
|
widget = self.field.widget
|
||||||
attrs = attrs or {}
|
attrs = attrs or {}
|
||||||
auto_id = self.auto_id
|
auto_id = self.auto_id
|
||||||
if auto_id and 'id' not in attrs and 'id' not in widget.attrs:
|
if auto_id and 'id' not in attrs and 'id' not in widget.attrs:
|
||||||
|
|
|
@ -216,7 +216,11 @@ class SelectMultiple(Widget):
|
||||||
return data.get(name, None)
|
return data.get(name, None)
|
||||||
|
|
||||||
class RadioInput(StrAndUnicode):
|
class RadioInput(StrAndUnicode):
|
||||||
"An object used by RadioFieldRenderer that represents a single <input type='radio'>."
|
"""
|
||||||
|
An object used by RadioFieldRenderer that represents a single
|
||||||
|
<input type='radio'>.
|
||||||
|
"""
|
||||||
|
|
||||||
def __init__(self, name, value, attrs, choice, index):
|
def __init__(self, name, value, attrs, choice, index):
|
||||||
self.name, self.value = name, value
|
self.name, self.value = name, value
|
||||||
self.attrs = attrs
|
self.attrs = attrs
|
||||||
|
@ -239,7 +243,10 @@ class RadioInput(StrAndUnicode):
|
||||||
return u'<input%s />' % flatatt(final_attrs)
|
return u'<input%s />' % flatatt(final_attrs)
|
||||||
|
|
||||||
class RadioFieldRenderer(StrAndUnicode):
|
class RadioFieldRenderer(StrAndUnicode):
|
||||||
"An object used by RadioSelect to enable customization of radio widgets."
|
"""
|
||||||
|
An object used by RadioSelect to enable customization of radio widgets.
|
||||||
|
"""
|
||||||
|
|
||||||
def __init__(self, name, value, attrs, choices):
|
def __init__(self, name, value, attrs, choices):
|
||||||
self.name, self.value, self.attrs = name, value, attrs
|
self.name, self.value, self.attrs = name, value, attrs
|
||||||
self.choices = choices
|
self.choices = choices
|
||||||
|
@ -253,16 +260,30 @@ class RadioFieldRenderer(StrAndUnicode):
|
||||||
return RadioInput(self.name, self.value, self.attrs.copy(), choice, idx)
|
return RadioInput(self.name, self.value, self.attrs.copy(), choice, idx)
|
||||||
|
|
||||||
def __unicode__(self):
|
def __unicode__(self):
|
||||||
"Outputs a <ul> for this set of radio fields."
|
return self.render()
|
||||||
|
|
||||||
|
def render(self):
|
||||||
|
"""Outputs a <ul> for this set of radio fields."""
|
||||||
return u'<ul>\n%s\n</ul>' % u'\n'.join([u'<li>%s</li>' % force_unicode(w) for w in self])
|
return u'<ul>\n%s\n</ul>' % u'\n'.join([u'<li>%s</li>' % force_unicode(w) for w in self])
|
||||||
|
|
||||||
class RadioSelect(Select):
|
class RadioSelect(Select):
|
||||||
def render(self, name, value, attrs=None, choices=()):
|
|
||||||
"Returns a RadioFieldRenderer instance rather than a Unicode string."
|
def __init__(self, *args, **kwargs):
|
||||||
|
self.renderer = kwargs.pop('renderer', None)
|
||||||
|
if not self.renderer:
|
||||||
|
self.renderer = RadioFieldRenderer
|
||||||
|
super(RadioSelect, self).__init__(*args, **kwargs)
|
||||||
|
|
||||||
|
def get_renderer(self, name, value, attrs=None, choices=()):
|
||||||
|
"""Returns an instance of the renderer."""
|
||||||
if value is None: value = ''
|
if value is None: value = ''
|
||||||
str_value = force_unicode(value) # Normalize to string.
|
str_value = force_unicode(value) # Normalize to string.
|
||||||
final_attrs = self.build_attrs(attrs)
|
final_attrs = self.build_attrs(attrs)
|
||||||
return RadioFieldRenderer(name, str_value, final_attrs, list(chain(self.choices, choices)))
|
choices = list(chain(self.choices, choices))
|
||||||
|
return self.renderer(name, str_value, final_attrs, choices)
|
||||||
|
|
||||||
|
def render(self, name, value, attrs=None, choices=()):
|
||||||
|
return self.get_renderer(name, value, attrs, choices).render()
|
||||||
|
|
||||||
def id_for_label(self, id_):
|
def id_for_label(self, id_):
|
||||||
# RadioSelect is represented by multiple <input type="radio"> fields,
|
# RadioSelect is represented by multiple <input type="radio"> fields,
|
||||||
|
|
|
@ -4,6 +4,7 @@ from regressions import regression_tests
|
||||||
|
|
||||||
form_tests = r"""
|
form_tests = r"""
|
||||||
>>> from django.newforms import *
|
>>> from django.newforms import *
|
||||||
|
>>> from django.newforms.widgets import RadioFieldRenderer
|
||||||
>>> import datetime
|
>>> import datetime
|
||||||
>>> import time
|
>>> import time
|
||||||
>>> import re
|
>>> import re
|
||||||
|
@ -614,11 +615,11 @@ If 'choices' is passed to both the constructor and render(), then they'll both b
|
||||||
<li><label><input type="radio" name="num" value="5" /> 5</label></li>
|
<li><label><input type="radio" name="num" value="5" /> 5</label></li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
The render() method returns a RadioFieldRenderer object, whose str() is a <ul>.
|
RadioSelect uses a RadioFieldRenderer to render the individual radio inputs.
|
||||||
You can manipulate that object directly to customize the way the RadioSelect
|
You can manipulate that object directly to customize the way the RadioSelect
|
||||||
is rendered.
|
is rendered.
|
||||||
>>> w = RadioSelect()
|
>>> w = RadioSelect()
|
||||||
>>> r = w.render('beatle', 'J', choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo')))
|
>>> r = w.get_renderer('beatle', 'J', choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo')))
|
||||||
>>> for inp in r:
|
>>> for inp in r:
|
||||||
... print inp
|
... print inp
|
||||||
<label><input checked="checked" type="radio" name="beatle" value="J" /> John</label>
|
<label><input checked="checked" type="radio" name="beatle" value="J" /> John</label>
|
||||||
|
@ -644,10 +645,21 @@ beatle J P Paul False
|
||||||
beatle J G George False
|
beatle J G George False
|
||||||
beatle J R Ringo False
|
beatle J R Ringo False
|
||||||
|
|
||||||
|
You can create your own custom renderers for RadioSelect to use.
|
||||||
|
>>> class MyRenderer(RadioFieldRenderer):
|
||||||
|
... def render(self):
|
||||||
|
... return u'<br />\n'.join([unicode(choice) for choice in self])
|
||||||
|
>>> w = RadioSelect(renderer=MyRenderer)
|
||||||
|
>>> print w.render('beatle', 'G', choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo')))
|
||||||
|
<label><input type="radio" name="beatle" value="J" /> John</label><br />
|
||||||
|
<label><input type="radio" name="beatle" value="P" /> Paul</label><br />
|
||||||
|
<label><input checked="checked" type="radio" name="beatle" value="G" /> George</label><br />
|
||||||
|
<label><input type="radio" name="beatle" value="R" /> Ringo</label>
|
||||||
|
|
||||||
A RadioFieldRenderer object also allows index access to individual RadioInput
|
A RadioFieldRenderer object also allows index access to individual RadioInput
|
||||||
objects.
|
objects.
|
||||||
>>> w = RadioSelect()
|
>>> w = RadioSelect()
|
||||||
>>> r = w.render('beatle', 'J', choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo')))
|
>>> r = w.get_renderer('beatle', 'J', choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo')))
|
||||||
>>> print r[1]
|
>>> print r[1]
|
||||||
<label><input type="radio" name="beatle" value="P" /> Paul</label>
|
<label><input type="radio" name="beatle" value="P" /> Paul</label>
|
||||||
>>> print r[0]
|
>>> print r[0]
|
||||||
|
|
Loading…
Reference in New Issue