Django: How can I create a multiple select form?
I think CheckboxSelectMultiple
should work according to your problem.
In your forms.py
, write the below code:
from django import formsclass 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>
I did it in this way :
forms.py
class ChoiceForm(ModelForm): class Meta: model = YourModel 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 CreateViewfrom django.core.urlresolvers import reverseurlpatterns = 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 formsfrom django.utils.encoding import force_unicodefrom itertools import chainfrom django.utils.html import escape, conditional_escapeclass 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): pass
Example:
OPTIONS = [ ["AUT", "Australia", {'selected':'selected', 'data-index':'1'}], ["DEU", "Germany", {'selected':'selected'}], ["NLD", "Neitherlands", {'selected':'selected'}], ["USA", "United States", {}] ]