Django: ModelMultipleChoiceField ne sélectionne pas les choix initiaux

ModelMultipleChoiceField ne sélectionne pas les choix initiaux et je ne peux pas faire fonctionner le correctif suivant (lien ci-dessous) dans mon exemple:

Http://code.djangoproject.com/ticket/5247#comment:6

Mes modèles et forme:

class Company(models.Model):
    company_name = models.CharField(max_length=200)

class Contact(models.Model):
    company = models.ForeignKey(Company)
    first_name = models.CharField(max_length=100)
    last_name = models.CharField(max_length=100)

class Action(models.Model):
    company = models.ForeignKey(Company, blank=True, null=True)
    from_company = models.ManyToManyField(Contact, verbose_name='Participant(s) from "Company"', blank=True, null=True)

class Action_Form(ModelForm):
    from_company = forms.ModelMultipleChoiceField(queryset=Contact.objects.none(), widget=forms.CheckboxSelectMultiple())
    class Meta:
        model = Action

Ce que je fais et les résultats:

>>> contacts_from_company = Contact.objects.filter(company__exact=1) # "1" for test, otherwise a variable
>>> form = Action_Form(initial={'from_company': [o.pk for o in contacts_from_company]}) # as suggested in the fix
>>> print form['from_company']
<ul>
</ul>
>>> print contacts_from_company
[<Contact: test person>, <Contact: another person>]

>>> form2 = Action_Form(initial={'from_company': contacts_from_company})
>>> print form2['from_company']
<ul>
</ul>

>>> form3 = Action_Form(initial={'from_company': Contact.objects.all()})
>>> print form3['from_company']
<ul>
</ul>

La façon dont j'espérais que cela fonctionnerait:
1. Ma vue obtient "société" de la demande.Obtenir
2. Il filtre ensuite tous les "contacts" pour cette "entreprise"
3. Enfin, il crée une forme et passe ceux-ci "contacts "comme" initial={...}"

Deux questions:
1. [pas encore répondu] Comment puis-je faire en sorte que ModelMultipleChoiceField prenne ces valeurs "initiales"?
2. [répondu] comme alternative, puis-je passer une variable à Action_Form (ModelForm) afin que dans mon ModelForm je puisse avoir:

from_company = forms.ModelMultipleChoiceField(queryset=Contact.objects.filter(company__exact=some_id) # where some_id comes from a view
25
demandé sur dmi 2009-01-28 18:30:02

4 réponses

Vous devrez ajouter une méthode __init__ à Action_Form pour définir vos valeurs initiales, en vous rappelant d'appeler __init__ sur la classe de base ModelForm via super.

class Action_Form(forms.ModelForm):
    def __init__(self, *args, **kwargs):
        super(Action_Form, self).__init__(*args, **kwargs)
        self.fields['from_company'].queryset = Contact.object.filter(...

Si vous prévoyez de passer vos paramètres de filtre en tant qu'args de mots-clés à Action_Form, vous devrez les supprimer avant d'appeler super:

myfilter = kwargs['myfilter']
del kwargs['myfilter']

Ou, probablement mieux:

myfilter = kwargs.pop('myfilter')

Pour plus d'informations, voici un autre lien faisant référence à Dynamic ModelForms dans Django.

14
répondu Jeff Bauer 2012-11-08 12:41:08

Je réponds pour 1)

1. Comment puis-je faire en sorte que ModelMultipleChoiceField prenne ces valeurs "initiales"?

Cela pourrait être fait dans votre Action_Form __init__ Méthode utilisant l'attribut ModelMultipleChoiceField initial.

Comme il est dit dans le code source de Django ( db/models/fields/related.py ) dans def formfield(self, **kwargs):

        # If initial is passed in, it's a list of related objects, but the
        # MultipleChoiceField takes a list of IDs.

Vous devez donc lui donner une liste d'identifiants:

class Action_Form(forms.ModelForm):
    def __init__(self, *args, **kwargs):
        super(Action_Form, self).__init__(*args, **kwargs)
        self.fields['from_company'].initial = [c.pk for c in Contact.object.filter()]
21
répondu Andre Miras 2014-02-11 09:35:06

Si la réponse précédente n'était pas assez simple, j'essaie de répondre à nouveau à 1):

  1. Comment puis-je faire en sorte que ModelMultipleChoiceField prenne ces valeurs "initiales"?

Vous pouvez laisser Action_Form tel qu'il était dans la question originale, et utilisez simplement ceci pour rendre exactement ce que vous voulez:

>>> form4 = Action_Form(initial={'from_company': Contact.objects.all().values_list('id',flat=True)})
>>> print form4['from_company']
11
répondu ygneo 2013-03-29 12:30:34

Réponse à (1) question!

Cela ne fonctionnera pas:

self.fields['from_company'].initial = [c.pk for c in Contact.object.filter()]

Mais cela va vraiment fonctionner :

self.initial['from_company'] = [c.pk for c in Contact.object.filter()]
10
répondu Albert Tugushev 2015-01-26 17:00:19