Collectives™ on Stack Overflow

Find centralized, trusted content and collaborate around the technologies you use most.

Learn more about Collectives

Teams

Q&A for work

Connect and share knowledge within a single location that is structured and easy to search.

Learn more about Teams

I'm beginner in Django/Python and I need to create a multiple select form. I know it's easy but I can't find any example. I know how to create a CharField with a widget but I get confused of all the options inside fields.py .

For example I don't know which one of the followings is best for a multiple select form.

'ChoiceField', 'MultipleChoiceField',
'ComboField', 'MultiValueField',
'TypedChoiceField', 'TypedMultipleChoiceField'

And here is the form I need to create.

        <form action="" method="post" accept-charset="utf-8">
        <select name="countries" id="countries" class="multiselect" multiple="multiple">
            <option value="AUT" selected="selected">Austria</option>
            <option value="DEU" selected="selected">Germany</option>
            <option value="NLD" selected="selected">Netherlands</option>
            <option value="USA">United States</option>
        </select>
        <p><input type="submit" value="Continue &rarr;"></p>
    </form>

EDIT:

One more small question. If I want to add to each option one more attribute like data:

 <option value="AUT" selected="selected" data-index=1>Austria</option>

How can I do it?

Thanks for any help!

I think CheckboxSelectMultiple should work according to your problem.

In your forms.py, write the below code:

from django import forms
class CountryForm(forms.Form):
    OPTIONS = (
        ("AUT", "Austria"),
        ("DEU", "Germany"),
        ("NLD", "Neitherlands"),
    Countries = forms.MultipleChoiceField(widget=forms.CheckboxSelectMultiple,
                                          choices=OPTIONS)

In your views.py, define the following function:

def countries_view(request):
    if request.method == 'POST':
        form = CountryForm(request.POST)
        if form.is_valid():
            countries = form.cleaned_data.get('countries')
            # do something with your results
    else:
        form = CountryForm
    return render_to_response('render_country.html', {'form': form},
                              context_instance=RequestContext(request))

In your render_country.html:

<form method='post'>
    {% csrf_token %}
    {{ form.as_p }}
    <input type='submit' value='submit'>
</form>
                Yes this is but one more thing small... If i want to add to each option a data property like this <option value="DEU" selected="selected" data-index=1>Germany</option> how i can do it? Also missing the last option which is not selected. Thanks anyway
– CodeArtist
                Mar 13, 2013 at 19:51
                Not sure!! make the form as model form. I believe then atleast in backend a primary key will be associated. Need to check it out.
– vibhor
                Mar 14, 2013 at 5:54
                Good answer @vibhor but "AUT" != "Australia" as stated in your code, it's Austria. Sorry to be a pedant, we Australians get that a lot and we're a bit sensitive about it :-)
– Nexus
                Sep 28, 2015 at 5:16
    def __init__(self, *args, **kwargs):
        super(ChoiceForm, self).__init__(*args, **kwargs)
        self.fields['countries'] =  ModelChoiceField(queryset=YourModel.objects.all()),
                                             empty_label="Choose a countries",)

urls.py

from django.conf.urls.defaults import * 
from django.views.generic import CreateView
from django.core.urlresolvers import reverse
urlpatterns = patterns('',
    url(r'^$',CreateView.as_view(model=YourModel, get_success_url=lambda: reverse('model_countries'),
        template_name='your_countries.html'), form_class=ChoiceForm, name='model_countries'),)

your_countries.html

<form action="" method="post">
    {% csrf_token %}
    {{ form.as_table }}
    <input type="submit" value="Submit" />
</form> 

It is works fine in my example, If you need something more, just ask me!!

Regarding to my second question this is the solution. An extending class:

from django import forms
from django.utils.encoding import force_unicode
from itertools import chain
from django.utils.html import escape, conditional_escape
class Select(forms.Select):
    A subclass of Select that adds the possibility to define additional 
    properties on options.
    It works as Select, except that the ``choices`` parameter takes a list of
    3 elements tuples containing ``(value, label, attrs)``, where ``attrs``
    is a dict containing the additional attributes of the option.
    def render_options(self, choices, selected_choices):
        def render_option(option_value, option_label, attrs):
            option_value = force_unicode(option_value)
            selected_html = (option_value in selected_choices) and u' selected="selected"' or ''
            attrs_html = []
            for k, v in attrs.items():
                attrs_html.append('%s="%s"' % (k, escape(v)))
            if attrs_html:
                attrs_html = " " + " ".join(attrs_html)
            else:
                attrs_html = ""
            return u'<option value="{0}"{1}{2}>{3}</option>'.format(
                escape(option_value), selected_html, attrs_html, 
                conditional_escape(force_unicode(option_label))
            return u'<option value="%s"%s%s>%s</option>' % (
                escape(option_value), selected_html, attrs_html,
                conditional_escape(force_unicode(option_label)))
        # Normalize to strings.
        selected_choices = set([force_unicode(v) for v in selected_choices])
        output = []
        for option_value, option_label, option_attrs in chain(self.choices, choices):
            if isinstance(option_label, (list, tuple)):
                output.append(u'<optgroup label="%s">' % escape(force_unicode(option_value)))
                for option in option_label:
                    output.append(render_option(*option))
                output.append(u'</optgroup>')
            else:
                output.append(render_option(option_value, option_label,
                    option_attrs))
        return u'\n'.join(output)
class SelectMultiple(forms.SelectMultiple, Select):

Example:

OPTIONS = [
        ["AUT", "Australia", {'selected':'selected', 'data-index':'1'}],
        ["DEU", "Germany", {'selected':'selected'}],
        ["NLD", "Neitherlands", {'selected':'selected'}],
        ["USA", "United States", {}]

ModelMultipleChoiceField is your friend. A CharField is capable of storing one selection, but not multiple, without some extra work, which I would recommend against.

API doc for ModelMultipleChoiceField

You can also define countries field in your form class as

Countries = forms.MultipleChoiceField(widget=forms.SelectMultiple,
                                             choices=OPTIONS_TUPPLE)

I don't know which one is better in SelectMultiple and CheckboxSelectMultiple but it also works.

For more details you can use django documentation about widgets.

Working with widget=forms CheckboxSelectMultiple is quite difficult when you want to select multiple values. (Remember Multiple select is for ManytoMany key Field)

In this condition SelectMultiple is better as you can select multiple items with ctrl or select all items with ctrl+a.

class MyModalForm(forms.ModelForm):
    class Meta:
    model = MyModel
        widgets = {            
            'products': forms.SelectMultiple(attrs={'required': True})

if you wants dynamic values for multiple select you can do this with init

class MyModalForm(forms.ModelForm):
    class Meta:
    model = MyModel
        widgets = {            
            'products': forms.SelectMultiple(attrs={'required': True})
    def __init__(self, *args, **kwargs):
        selected_products = kwargs.pop('selected_products', None)   ##queryset returned from function
        self.fields['products'].queryset = selected_products
        self.fields['orders'].queryset = OrderModal.objects.filter(pk=2)

I know your problem has been solved but from my research on Django Multiple Checkbox I discovered that the best way or practice is to use django-multiselectfield package. You first need to install it using pip: pip install django-multiselectfield then add it to installed apps in settings.py; 'multiselectfield'. Import the package in your models.py file: from multiselectfield import MultiSelectField then below is how you go about your models and form: Models code:

class Country(models.Model):
    COUNTRY_CHOICES = (
    ('Nigeria', 'Nigeria'),
    ('USA', 'USA'),
    ('UK', 'UK'),
    ('Ghana', 'Ghana'),
    favourates = MultiSelectField(choices = COUNTRY_CHOICES)

form.py code:

class CountriesForm(models.Model):
    class Meta:
        model = Country

views.py code: Import the form in the views then do the following in function view for the template to display the checkboxes.

def UserCountryLikes(request):
    if request.method == "POST":
        form = CountriesForm(request.POST)
        if form.is_valid():
            country.form = CountriesForm(commit=False)
            country.save()
    else:
        form = CountryForm()
    context = {
    'form':form,
    return render(request, 'app_name_folder_template/form_template.html', context)

In the Template (form_template.html in the views.py) to display the form do the following:

  <form method="POST" enctype="multipart/form-data">
    {% csrf_token %}
    {{ form }}
    <input class="btn btn-info mt-3" type="submit" value="Add Drinks">
    </form>

Remember to run migrations and migrate

Thanks for contributing an answer to Stack Overflow!

  • Please be sure to answer the question. Provide details and share your research!

But avoid

  • Asking for help, clarification, or responding to other answers.
  • Making statements based on opinion; back them up with references or personal experience.

To learn more, see our tips on writing great answers.