[Django]-How do I iterate over the options of a SelectField in a template?

94👍

✅

I’ve been struggling with this problem today and found the solution. Yes, you can iterate over options of the select tag directly in template. Here’s how to do it in template:

<select id="id_customer" name="customer">
{% for x, y in form.fields.customer.choices %}
    <option value="{{ x }}"{% if form.fields.customer.value == x %} selected{% endif %}>{{ y }}</option>
{% endfor %}
</select>

In this case I have a customer field in the form which has choices set up as follows:

class SomeForm(forms.Form):
    customer = forms.ChoiceField(label=u'Customer')

    def __init__(self, *args, **kwargs):
        super(SomeForm, self).__init__(*args, **kwargs)
        self.fields['customer'].choices = [(e.id, e.customer) for e in Customers.objects.all()]

30👍

Got it to work with:

    <select name="myselect" class="i-can-add-my-own-attrs-now" id="id_myselect">
        {% for id, name in form.myselect.field.choices %}
        <option value="{{ id }}">{{ name }}</option>
        {% endfor %}
    </select>

BUT REALLY, a better way to do this is with django-widget-tweaks:

    {% load widget_tweaks %}
    {{ form.myselect|add_class:"i-can-haz-custom-classes-easily" }}

Doing it with django-widget-tweaks will also set the default ‘selected=”selected”‘ for you, which is super nice!

9👍

I do this way:

<select id="id_construction_type" name="construction_type" class="form-control input-md">
{% for value, key in form_urban.fields.construction_type.choices %}
    <option value="{{ value }}"{% if form_urban.initial.construction_type == value %} selected {% endif %}>
        {{ key }}
    </option>
{% endfor %}
</select>

4👍

This is a cleaner solution, you can set the attributes using a custom Widget. This way you don’t have to render the field manually:

class CustomSelectWidget(forms.Select):
    def create_option(self, name, value, *args, **kwargs):
        option = super().create_option(name, value, *args, **kwargs)
        if value:
            instance = self.choices.queryset.get(pk=value)  # get instance
            option['attrs']['custom_attr'] = instance.field_name  # set option attribute
        return option

class SomeForm(forms.ModelForm):
    some_field = forms.ModelChoiceField(
        queryset=SomeModel.objects.all(),
        widget=CustomSelectWidget
    )

1👍

I’ve run into this issue several times and wanted to add an additional situation where you are using Django filters and setting choices that are related to a FieldFilter you’ve defined inside the FilterSet class.

class CustomFilter(django_filters.FilterSet):
    your_field = django_filters.CharFilter(
        field_name='your_field',
        lookup_expr='iexact',
        widget=forms.Select(
            choices=[(x, x) for x in some_list_of_choices]
        )
    )

The other solutions, rely on a .choices attribute on the field class but they did not work for me. Instead I iterated through the your_field attr on the Form associated with the FilterSet.

This allows you to easily set your own default and assign any desired classes to the select element.

<select name="your_field">
    <option value="" selected>Your Field</option>
    {% for option in filter.form.your_field %}
        {{ option }}
    {% endfor %}

</select>

0👍

With radio buttons in your template use.

    <table>
        {% for x,y in form.fields.Customer.choices %}
        <tr>
            <td><input id="id_Customer_{{x}}" {% if form.fields.Customer.value == x %}checked="checked"{% endif %} name="Customer" type="radio" value="{{x}}" /></td>
            <td>{{ y }}</td>
        </tr>
        {% endfor %}
    </table>

Leave a comment