diff options
| author | Gary Wilson Jr <gary.wilson@gmail.com> | 2007-08-01 05:41:32 +0000 |
|---|---|---|
| committer | Gary Wilson Jr <gary.wilson@gmail.com> | 2007-08-01 05:41:32 +0000 |
| commit | cdbd5751d3c9579bac7054b45edae11de27171ff (patch) | |
| tree | 3254da76e8356be5047748a40d6cbdb44f46babe | |
| parent | f27774ee0ab4b2537909d642c23ea6ae6ea8d166 (diff) | |
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
| -rw-r--r-- | django/newforms/forms.py | 21 | ||||
| -rw-r--r-- | django/newforms/widgets.py | 33 | ||||
| -rw-r--r-- | tests/regressiontests/forms/tests.py | 18 |
3 files changed, 52 insertions, 20 deletions
diff --git a/django/newforms/forms.py b/django/newforms/forms.py index 50e6f42108..5da85a69c4 100644 --- a/django/newforms/forms.py +++ b/django/newforms/forms.py @@ -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: diff --git a/django/newforms/widgets.py b/django/newforms/widgets.py index b90e6df9cd..e9b9b55470 100644 --- a/django/newforms/widgets.py +++ b/django/newforms/widgets.py @@ -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, diff --git a/tests/regressiontests/forms/tests.py b/tests/regressiontests/forms/tests.py index 28a5947eac..52cc9ccfa5 100644 --- a/tests/regressiontests/forms/tests.py +++ b/tests/regressiontests/forms/tests.py @@ -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] |
