web-dev-qa-db-fra.com

Django Champ à choix multiples / Case à cocher Sélectionner plusieurs

J'ai une application Django et je souhaite afficher plusieurs cases à cocher dans le profil d'un utilisateur. Il pourra alors sélectionner plusieurs éléments.

Ceci est une version simplifiée de mes models.py:

from profiles.choices import SAMPLE_CHOICES

class Profile(models.Model):
    user = models.ForeignKey(User, unique=True, verbose_name_('user'))
    choice_field = models.CharField(_('Some choices...'), choices=SAMPLE_CHOICES, max_length=50)

Et ma classe de forme:

class ProfileForm(forms.ModelForm):
    choice_field = forms.MultipleChoiceField(choices=SAMPLE_CHOICES, widget=forms.CheckboxSelectMultiple)

    class Meta:
        model = Profile

Et mon views.py:

if request.method == "POST":
    profile_form = form_class(request.POST, instance=profile)
    if profile_form.is_valid():
        ...
        profile.save()
return render_to_response(template_name, {"profile_form": profile_form,}, context_instance=RequestContext(request))

Je peux voir que le POST n'envoie qu'une seule valeur:

choice_field u'choice_three' 

Et les paramètres locaux de vars envoient une liste:

[u'choice_one', u'choice_two', u'choice_three']

Tous les champs du formulaire s'affichent correctement, mais lorsque je soumets un POST, j'obtiens une erreur

Erreur de liaison du paramètre 7 - type probablement non pris en charge.

Dois-je traiter le champ à choix multiple plus loin dans la vue? Le type de champ de modèle est-il correct? Toute aide ou référence serait grandement appréciée.

35
twampss

Les choix de profil doivent être configurés en tant que ManyToManyField pour que cela fonctionne correctement.

Donc ... votre modèle devrait ressembler à ceci:

class Choices(models.Model):
  description = models.CharField(max_length=300)

class Profile(models.Model):
  user = models.ForeignKey(User, blank=True, unique=True, verbose_name='user')
  choices = models.ManyToManyField(Choices)

Ensuite, synchronisez la base de données et chargez Choices avec les différentes options que vous souhaitez disponibles.

Maintenant, le ModelForm va se construire ...

class ProfileForm(forms.ModelForm):
  Meta:
    model = Profile
    exclude = ['user']

Et enfin, la vue:

if request.method=='POST':
  form = ProfileForm(request.POST)
  if form.is_valid():
    profile = form.save(commit=False)
    profile.user = request.user
    profile.save()
else:
  form = ProfileForm()

return render_to_response(template_name, {"profile_form": form}, context_instance=RequestContext(request))

Il convient de mentionner que vous pouvez configurer un profil de différentes manières, y compris l'héritage. Cela dit, cela devrait également fonctionner pour vous.

Bonne chance.

34
Brant

La solution de Brant est absolument correcte, mais je devais la modifier pour qu'elle fonctionne avec plusieurs cases à cocher et commit=false. Voici ma solution:

models.py

class Choices(models.Model):
    description = models.CharField(max_length=300)

class Profile(models.Model):
   user = models.ForeignKey(User, blank=True, unique=True, verbose_name_('user'))
   the_choices = models.ManyToManyField(Choices)

forms.py

class ProfileForm(forms.ModelForm):
    the_choices = forms.ModelMultipleChoiceField(queryset=Choices.objects.all(), required=False, widget=forms.CheckboxSelectMultiple)

    class Meta:
        model = Profile
        exclude = ['user']

views.py

if request.method=='POST':
    form = ProfileForm(request.POST)
    if form.is_valid():
        profile = form.save(commit=False)
        profile.user = request.user
        profile.save()
        form.save_m2m() # needed since using commit=False
    else:
        form = ProfileForm()

return render_to_response(template_name, {"profile_form": form}, context_instance=RequestContext(request))
15
twampss

Les modèles.CharField est une représentation CharField de l'un des choix. Ce que vous voulez, c'est un ensemble de choix. Cela ne semble pas être implémenté dans Django (encore).

Vous pourriez utiliser un champ plusieurs à plusieurs pour cela, mais cela a l'inconvénient que les choix doivent être placés dans une base de données. Si vous souhaitez utiliser des choix codés en dur, ce n'est probablement pas ce que vous voulez.

Il y a un Django extrait de code à http://djangosnippets.org/snippets/1200/ que fait semble résoudre votre problème, en implémentant un ModelField MultipleChoiceField .

13
Webthusiast

ManyToManyField n'est pas un bon choix. Vous pouvez utiliser des extraits de code pour implémenter MultipleChoiceField .Vous pouvez vous inspirer de MultiSelectField avec des valeurs séparées par des virgules (Field + FormField) Mais il contient des bogues et vous pouvez installer Django-multiselectfield . C'est plus préfet.

2
wyx