Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

Fixed #4228 -- Removed hardcoding of `RadioFieldRenderer` in the `Rad…

…ioSelect` 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
  • Loading branch information...
commit cdbd5751d3c9579bac7054b45edae11de27171ff 1 parent f27774e
Gary Wilson Jr. authored August 01, 2007
21  django/newforms/forms.py
@@ -232,16 +232,8 @@ def __init__(self, form, field, name):
232 232
         self.help_text = field.help_text or ''
233 233
 
234 234
     def __unicode__(self):
235  
-        "Renders this field as an HTML widget."
236  
-        # Use the 'widget' attribute on the field to determine which type
237  
-        # of HTML widget to use.
238  
-        value = self.as_widget(self.field.widget)
239  
-        if not isinstance(value, basestring):
240  
-            # Some Widget render() methods -- notably RadioSelect -- return a
241  
-            # "special" object rather than a string. Call __unicode__() on that
242  
-            # object to get its rendered value.
243  
-            value = unicode(value)
244  
-        return value
  235
+        """Renders this field as an HTML widget."""
  236
+        return self.as_widget()
245 237
 
246 238
     def _errors(self):
247 239
         """
@@ -251,7 +243,14 @@ def _errors(self):
251 243
         return self.form.errors.get(self.name, ErrorList())
252 244
     errors = property(_errors)
253 245
 
254  
-    def as_widget(self, widget, attrs=None):
  246
+    def as_widget(self, widget=None, attrs=None):
  247
+        """
  248
+        Renders the field by rendering the passed widget, adding any HTML
  249
+        attributes passed as attrs.  If no widget is specified, then the
  250
+        field's default widget will be used.
  251
+        """
  252
+        if not widget:
  253
+            widget = self.field.widget
255 254
         attrs = attrs or {}
256 255
         auto_id = self.auto_id
257 256
         if auto_id and 'id' not in attrs and 'id' not in widget.attrs:
33  django/newforms/widgets.py
@@ -216,7 +216,11 @@ def value_from_datadict(self, data, name):
216 216
         return data.get(name, None)
217 217
 
218 218
 class RadioInput(StrAndUnicode):
219  
-    "An object used by RadioFieldRenderer that represents a single <input type='radio'>."
  219
+    """
  220
+    An object used by RadioFieldRenderer that represents a single
  221
+    <input type='radio'>.
  222
+    """
  223
+
220 224
     def __init__(self, name, value, attrs, choice, index):
221 225
         self.name, self.value = name, value
222 226
         self.attrs = attrs
@@ -239,7 +243,10 @@ def tag(self):
239 243
         return u'<input%s />' % flatatt(final_attrs)
240 244
 
241 245
 class RadioFieldRenderer(StrAndUnicode):
242  
-    "An object used by RadioSelect to enable customization of radio widgets."
  246
+    """
  247
+    An object used by RadioSelect to enable customization of radio widgets.
  248
+    """
  249
+
243 250
     def __init__(self, name, value, attrs, choices):
244 251
         self.name, self.value, self.attrs = name, value, attrs
245 252
         self.choices = choices
@@ -253,16 +260,30 @@ def __getitem__(self, idx):
253 260
         return RadioInput(self.name, self.value, self.attrs.copy(), choice, idx)
254 261
 
255 262
     def __unicode__(self):
256  
-        "Outputs a <ul> for this set of radio fields."
  263
+        return self.render()
  264
+
  265
+    def render(self):
  266
+        """Outputs a <ul> for this set of radio fields."""
257 267
         return u'<ul>\n%s\n</ul>' % u'\n'.join([u'<li>%s</li>' % force_unicode(w) for w in self])
258 268
 
259 269
 class RadioSelect(Select):
260  
-    def render(self, name, value, attrs=None, choices=()):
261  
-        "Returns a RadioFieldRenderer instance rather than a Unicode string."
  270
+
  271
+    def __init__(self, *args, **kwargs):
  272
+        self.renderer = kwargs.pop('renderer', None)
  273
+        if not self.renderer:
  274
+            self.renderer = RadioFieldRenderer
  275
+        super(RadioSelect, self).__init__(*args, **kwargs)
  276
+
  277
+    def get_renderer(self, name, value, attrs=None, choices=()):
  278
+        """Returns an instance of the renderer."""
262 279
         if value is None: value = ''
263 280
         str_value = force_unicode(value) # Normalize to string.
264 281
         final_attrs = self.build_attrs(attrs)
265  
-        return RadioFieldRenderer(name, str_value, final_attrs, list(chain(self.choices, choices)))
  282
+        choices = list(chain(self.choices, choices))
  283
+        return self.renderer(name, str_value, final_attrs, choices)
  284
+
  285
+    def render(self, name, value, attrs=None, choices=()):
  286
+        return self.get_renderer(name, value, attrs, choices).render()
266 287
 
267 288
     def id_for_label(self, id_):
268 289
         # RadioSelect is represented by multiple <input type="radio"> fields,
18  tests/regressiontests/forms/tests.py
@@ -4,6 +4,7 @@
4 4
 
5 5
 form_tests = r"""
6 6
 >>> from django.newforms import *
  7
+>>> from django.newforms.widgets import RadioFieldRenderer
7 8
 >>> import datetime
8 9
 >>> import time
9 10
 >>> import re
@@ -614,11 +615,11 @@
614 615
 <li><label><input type="radio" name="num" value="5" /> 5</label></li>
615 616
 </ul>
616 617
 
617  
-The render() method returns a RadioFieldRenderer object, whose str() is a <ul>.
  618
+RadioSelect uses a RadioFieldRenderer to render the individual radio inputs.
618 619
 You can manipulate that object directly to customize the way the RadioSelect
619 620
 is rendered.
620 621
 >>> w = RadioSelect()
621  
->>> r = w.render('beatle', 'J', choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo')))
  622
+>>> r = w.get_renderer('beatle', 'J', choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo')))
622 623
 >>> for inp in r:
623 624
 ...     print inp
624 625
 <label><input checked="checked" type="radio" name="beatle" value="J" /> John</label>
@@ -644,10 +645,21 @@
644 645
 beatle J G George False
645 646
 beatle J R Ringo False
646 647
 
  648
+You can create your own custom renderers for RadioSelect to use.
  649
+>>> class MyRenderer(RadioFieldRenderer):
  650
+...    def render(self):
  651
+...        return u'<br />\n'.join([unicode(choice) for choice in self])
  652
+>>> w = RadioSelect(renderer=MyRenderer)
  653
+>>> print w.render('beatle', 'G', choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo')))
  654
+<label><input type="radio" name="beatle" value="J" /> John</label><br />
  655
+<label><input type="radio" name="beatle" value="P" /> Paul</label><br />
  656
+<label><input checked="checked" type="radio" name="beatle" value="G" /> George</label><br />
  657
+<label><input type="radio" name="beatle" value="R" /> Ringo</label>
  658
+
647 659
 A RadioFieldRenderer object also allows index access to individual RadioInput
648 660
 objects.
649 661
 >>> w = RadioSelect()
650  
->>> r = w.render('beatle', 'J', choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo')))
  662
+>>> r = w.get_renderer('beatle', 'J', choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo')))
651 663
 >>> print r[1]
652 664
 <label><input type="radio" name="beatle" value="P" /> Paul</label>
653 665
 >>> print r[0]

0 notes on commit cdbd575

Please sign in to comment.
Something went wrong with that request. Please try again.