web-dev-qa-db-fra.com

Django: Comment créer un formulaire de sélection multiple?

Je suis débutant dans Django/Python et je dois créer un formulaire de sélection multiple. Je sais que c'est facile mais je ne trouve aucun exemple. Je sais comment créer un CharField avec un widget mais je me perds dans toutes les options de fields.py .

Par exemple, je ne sais pas lequel des éléments suivants convient le mieux à un formulaire à sélection multiple.

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

Et voici la forme que je dois créer.

        <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>

MODIFIER:

Encore une petite question. Si je veux ajouter à chaque option un attribut supplémentaire comme data:

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

Comment puis-je le faire?

Merci pour toute aide!

11
CodeArtist

Je pense que CheckboxSelectMultiple devrait fonctionner. Selon votre problème, dans votre formulaire, votre code ci-dessous

from Django import forms

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

EDIT: J'ai pensé écrire un flux de code complet pour que vous puissiez mieux le comprendre. Parce que vous pourriez vous embrouiller

Dans votre Views.py, définissez la fonction suivante

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))

Dans votre render_country.html

<form method='post'>
    {% csrf_token %}
    {{ form.as_p }}
    <input type='submit' value='submit'>
</form>

J'espère que cela vous aidera. Faites-moi savoir si c'est ce à quoi vous vous attendiez.

27
vibhor

Je l'ai fait de cette façon:

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 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> 

Cela fonctionne bien dans mon exemple. Si vous avez besoin de quelque chose de plus, demandez-le moi !! 

4
prog.Dusan

En ce qui concerne ma deuxième question, c'est la solution. Une classe en extension:

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):
    pass

Exemple:

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

ModelMultipleChoiceField est votre ami. Un CharField est capable de stocker une sélection, mais pas plusieurs, sans un travail supplémentaire, ce que je déconseillerais.

Doc de l'API pour ModelMultipleChoiceField

1
Brandon

Vous pouvez également définir le champ pays dans votre classe de formulaire en tant que 

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

Je ne sais pas lequel est le meilleur dans SelectMultiple et CheckboxSelectMultiple mais cela fonctionne aussi.

Pour plus de détails, vous pouvez utiliser la documentation de Django sur widgets .

1
Navjot Gwal