django radioselect render to table

2019-04-12 14:18发布

I want to render the django form widget radioselect into a table rather than a ul list. With labels in the first row and the radio buttons below in the second row. One cell for each button. e.g.

-------------------------------
| label 1 | label 2 | label 3 |
-------------------------------
|   O     |    O    |    O    |
-------------------------------

I've looked at the default selectradio widget but the render function seems so complicated, calling many different classes to do each part of the render.

Does anyone have any examples of how to do this or could provide a simple solution?

4条回答
The star\"
2楼-- · 2019-04-12 14:27

Just to fill in a bit more of Béres Botond's answer

class MyForm(forms.ModelForm):
    my_field = forms.TypedChoiceField(choices=some_choices,
                                      label=u"bla",
                                      widget=forms.RadioSelect(renderer=MyCustomRenderer))

The custom renderer would look like:

from django import forms
from django.forms.widgets import RadioFieldRenderer
from django.utils.encoding import force_unicode
from django.utils.safestring import mark_safe

class MyCustomRenderer( RadioFieldRenderer ):
    def render( self ):
        """Outputs a series of <td></td> fields for this set of radio fields."""
        return( mark_safe( u''.join( [ u'<td>%s</td>' % force_unicode(w.tag()) for w in self ] )))

In this case I didn't want the name of the radio box next to it, so I am using "force_unicode(w.tag())" If you wanted the name next to it, just render the object directly like "force_unicode(w)"

I hope that helps!

查看更多
做个烂人
3楼-- · 2019-04-12 14:29

If you need to customize the input elements further, overwrite the choice_input_class attribute on the custom renderer.

from django.forms.widgets import RadioChoiceInput, RadioFieldRenderer   
from django.utils.safestring import mark_safe
from django.utils.html import format_html

class MyCustomRenderer( RadioFieldRenderer ):
    choice_input_class = MyCustomInputClass

class MyCustomInputClass(RadioChoiceInput):
    def render(self, name=None, value=None, attrs=None, choices=()):
        # Generate outer label, insert a custom div
        output = format_html('''
            <div id="{}"></div>
        ''', self.choice_label)
        if self.id_for_label:
            label_for = format_html(' for="{}"', self.id_for_label)
        else:
            label_for = ''
        attrs = dict(self.attrs, **attrs) if attrs else self.attrs
        return format_html('<label{}>{} {}</label>',
                           label_for, self.tag(attrs), output)

    def tag(self, attrs=None):
        # Generate the customized input element.
        attrs = attrs or self.attrs
        final_attrs = dict(attrs, type=self.input_type, name=self.name, value=self.choice_value)
        if self.is_checked():
            final_attrs['checked'] = 'checked'
        return format_html('<input{} class="my_custom_class" />', flatatt(final_attrs))

These render() and tag() methods are from the 1.9 source code, modified only slightly to show the application of a simple customization in each.

查看更多
霸刀☆藐视天下
4楼-- · 2019-04-12 14:31

You need to subclass django.forms.widgets.RadioFieldRenderer and override it's render method. Then in your form, when declaring your field specify the custom renderer for the widget

class MyForm(forms.ModelForm):
    my_field = forms.TypedChoiceField(choices=some_choices,
                                      label=u"bla",
                                      widget=forms.RadioSelect(renderer=MyCustomRenderer))
查看更多
成全新的幸福
5楼-- · 2019-04-12 14:31

You could also use django-uni-form and use divs instead of tables.

查看更多
登录 后发表回答