Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ChoiceFieldRenderer removed. What is the solution?

Tags:

python

django

It seems very few people used it, but... I did. Here you can read:

Some undocumented classes in django.forms.widgets are removed: SubWidget RendererMixin, ChoiceFieldRenderer, RadioFieldRenderer, CheckboxFieldRenderer ChoiceInput, RadioChoiceInput, CheckboxChoiceInput

My source code is:

from django.forms.widgets import ChoiceFieldRenderer, RadioChoiceInput, \
    RendererMixin, Select


class BootstrapRadioFieldRenderer(ChoiceFieldRenderer):
    outer_html = '<span {id_attr}>{content}</span>'
    inner_html = '<div class="radio">{choice_value}{sub_widgets}</div>'
    choice_input_class = RadioChoiceInput


class BootstrapRadioSelect(RendererMixin, Select):
    renderer = BootstrapRadioFieldRenderer
    _empty_value = ''

I really dont know how to convert this to make it work with 1.11 and later: they say:

Use a custom widget template instead.

Well. How?

like image 834
Olivier Pons Avatar asked Oct 30 '22 01:10

Olivier Pons


1 Answers

We used RadioFieldRenderer to add a description to each option. Your usecase may be far from it, but I hope it helps you to make the migration too.

This was the legacy code for Django <=1.10

class MyRadioFieldRenderer(forms.widgets.RadioFieldRenderer):

    def render(self):
        radios = []
        for w in self:
            radios.append(u"""<li class="%s">%s <span>%s</span></li>"""
                          % (w.choice_value, force_unicode(w), get_description(w)))
        return mark_safe(u'<ul>\n%s\n</ul>' % u'\n'.join(radios))

class MyRadioSelect(forms.RadioSelect):
    renderer = MyRadioFieldRenderer

And I replaced it with this for Django 1.11 utilizing custom template snippets and only adding the description to the template context.

from django.forms.widgets import RadioSelect

class MyRadioSelect(RadioSelect):

    template_name = 'myapp/multiple_input.html'
    option_template_name = 'myapp/input_option.html'

    def get_context(self, name, value, attrs):
        context = super(MyRadioSelect, self).get_context(name, value, attrs)

        for i in range(len(context['widget']['optgroups'][0][1])):
            value = context['widget']['optgroups'][0][1][i]['value']
            context['widget']['optgroups'][0][1][i]['attrs']['description'] = \
                get_description(value)
        return context

The for loop in this deep list is not pretty. Need to look at that again.

In the template snippet I can then render the description behind the options with <span>{{widget.attrs.description | safe}}</span>

The form remained the same:

class MyForm(forms.Form):

    order_method = ChoiceField(
        widget=MyRadioSelect,
        required=True)

Important: For Django to find your custom template snippets in the regular template folder add this to your settings:

FORM_RENDERER = 'django.forms.renderers.TemplatesSetting'

and django.forms to your INSTALLED_APPS

like image 161
djangonaut Avatar answered Nov 13 '22 03:11

djangonaut