Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Django 1.11 Horizontal choice field

Tags:

django

I've just updated from Django 1.10 to 1.11.1. In my template new_house_edit.html I have the following:

{{ form.rating }}

models.py contain the following:

class NewHouse(models.Model):
    rating = models.IntegerField(choices=(
                                    (1, "1"),
                                    (2, "2"),
                                    (3, "3"),
                                    (4, "4"),
                                    (5, "5"),
                                    ),
                                    default=3
                            )

In forms.py I used to have the following:

class HorizontalRadioRenderer(forms.RadioSelect.renderer):
    def render(self):
        return mark_safe(u'\n'.join([u'%s\n' % w for w in self]))

class NewHouseForm(forms.ModelForm):

    class Meta:
        model = NewHouse
        fields = (
                'rating',)
        widgets={
                "rating": forms.RadioSelect(renderer=HorizontalRadioRenderer),
                }

Which gave the following error AttributeError: type object 'RadioSelect' has no attribute 'renderer'. I tried to solve it by doing this which is not working:

class HorizontalRadioSelect(forms.RadioSelect):
    template_name = 'new_house_edit'


class NewHouseForm(forms.ModelForm):

    class Meta:
        model = NewHouse
        fields = (
                'rating',)
        widgets={
                "rating": "rating": forms.ChoiceField(widget=HorizontalRadioSelect, choices=(1, 2, 3, 4, 5)),
                }

I now get the error AttributeError: 'ChoiceField' object has no attribute 'use_required_attribute'. Can anyone help me fix this?

like image 231
Wessi Avatar asked May 25 '17 18:05

Wessi


3 Answers

In your second code snippet you pass form field object to widgets dict instead of widget object. So correct code look like:

class HorizontalRadioSelect(forms.RadioSelect):
    template_name = 'horizontal_select.html'


class NewHouseForm(forms.ModelForm):

    class Meta:
        model = NewHouse
        fields = (
                'rating',)
        widgets={
                "rating": HorizontalRadioSelect()
                }

In your app directory create templates folder and add horizontal_select.html with following html.

{% with id=widget.attrs.id %}
    <ul{% if id %} id="{{ id }}"{% endif %}{% if widget.attrs.class %} class="{{ widget.attrs.class }}"{% endif %}>
        {% for group, options, index in widget.optgroups %}
            {% if group %}
                <li>{{ group }}
                <ul{% if id %} id="{{ id }}_{{ index }}"{% endif %}>
            {% endif %}
            {% for option in options %}
                <li style="display: inline-block">{% include option.template_name with widget=option %}</li>
            {% endfor %}
            {% if group %}
                </ul>
                </li>
            {% endif %}
        {% endfor %}
    </ul>
{% endwith %}
like image 156
Dima Kudosh Avatar answered Sep 26 '22 21:09

Dima Kudosh


I know this is quite an old question but having spent some time today trying the different methods in various threads (after upgrading from 1.8 to 1.11) here is my solution.

For each radio group, define the following in the template (where "radio_list" is the name of the field):

{% for radio in radio_list %}
    {{ radio }}
{% endfor %} 

This is it at its simplest. Easy eh? You can basically apply any styling you want. It's all in the documentation in the RadioSelect section.

The moral of this little tale? Read the docs. Django is probably the best-documented app I have ever worked with. If I had done it earlier it would have saved me a lot of wasted time today when I could have been doing something more interesting.

Hope this helps someone.

like image 24
ElPedro Avatar answered Sep 22 '22 21:09

ElPedro


First, ChoiceField is not a widget - it is a Form Field.

So, change your form,

class NewHouseForm(forms.ModelForm):
    CHOICES = ((1, "1"),
               (2, "2"),
               (3, "3"),
               (4, "4"),
               (5, "5"))

    rating = forms.ChoiceField(choices=CHOICES,
       widget=forms.RadioSelect(attrs={'class': 'radio-inline'}),
       )

    class Meta:
        model = NewHouse
        fields = (
            'rating',)

Then in your customised radio-select template_name should be the path to the template which is you are using.
If the template resides under your app_level "templates" subdirectory or in your project-level "templates" sub-directory, you could just do like below.

class HorizontalRadioSelect(forms.RadioSelect):
    template_name = 'new_house_edit.html'

If its under another subdirectory under the "templates" sub-directory then you need to specify the path to the template.

Django as default check for templates in "templates" sub-directory in each apps of your project.

like image 43
zaidfazil Avatar answered Sep 23 '22 21:09

zaidfazil