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 ''
|
||||
|
||||
def __unicode__(self):
|
||||
"Renders this field as an HTML widget."
|
||||
# Use the 'widget' attribute on the field to determine which type
|
||||
# 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
|
||||
"""Renders this field as an HTML widget."""
|
||||
return self.as_widget()
|
||||
|
||||
def _errors(self):
|
||||
"""
|
||||
|
@ -251,7 +243,14 @@ class BoundField(StrAndUnicode):
|
|||
return self.form.errors.get(self.name, ErrorList())
|
||||
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 {}
|
||||
auto_id = self.auto_id
|
||||
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)
|
||||
|
||||
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):
|
||||
self.name, self.value = name, value
|
||||
self.attrs = attrs
|
||||
|
@ -239,7 +243,10 @@ class RadioInput(StrAndUnicode):
|
|||
return u'<input%s />' % flatatt(final_attrs)
|
||||
|
||||
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):
|
||||
self.name, self.value, self.attrs = name, value, attrs
|
||||
self.choices = choices
|
||||
|
@ -253,16 +260,30 @@ class RadioFieldRenderer(StrAndUnicode):
|
|||
return RadioInput(self.name, self.value, self.attrs.copy(), choice, idx)
|
||||
|
||||
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])
|
||||
|
||||
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 = ''
|
||||
str_value = force_unicode(value) # Normalize to string.
|
||||
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_):
|
||||
# RadioSelect is represented by multiple <input type="radio"> fields,
|
||||
|
|
|
@ -4,6 +4,7 @@ from regressions import regression_tests
|
|||
|
||||
form_tests = r"""
|
||||
>>> from django.newforms import *
|
||||
>>> from django.newforms.widgets import RadioFieldRenderer
|
||||
>>> import datetime
|
||||
>>> import time
|
||||
>>> 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>
|
||||
</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
|
||||
is rendered.
|
||||
>>> 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:
|
||||
... print inp
|
||||
<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 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
|
||||
objects.
|
||||
>>> 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]
|
||||
<label><input type="radio" name="beatle" value="P" /> Paul</label>
|
||||
>>> print r[0]
|
||||
|
|
Loading…
Reference in New Issue