Django: ModelMultipleChoiceField не выбирает начальный выбор - PullRequest
25 голосов
/ 28 января 2009

ModelMultipleChoiceField не выбирает начальные варианты, и я не могу заставить работать следующее исправление (ссылка ниже) в моем примере:

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

Мои модели и форма:

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

Что я делаю и результаты:

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

То, как я надеялся, это сработает:
1. Мой взгляд получает "компанию" из запроса. GET
2. Затем он фильтрует все «контакты» для этой «компании»
3. Наконец, он создает форму и передает эти «контакты» как «initial = {...}»

Два вопроса:
1. [пока не ответил] Как я могу заставить ModelMultipleChoiceField принимать эти "начальные" значения?
2. [ответил] В качестве альтернативы я могу передать переменную в Action_Form (ModelForm), чтобы в моей ModelForm я мог иметь:

from_company = forms.ModelMultipleChoiceField(queryset=Contact.objects.filter(company__exact=some_id) # where some_id comes from a view

Ответы [ 4 ]

21 голосов
/ 07 октября 2009

Я отвечаю за 1)

1. Как я могу заставить ModelMultipleChoiceField принимать эти «начальные» значения?

Это можно сделать в вашем методе Action_Form __init__ с использованием атрибута ModelMultipleChoiceField initial.

Как говорится в исходном коде Django ( db / models / fields / related.py ) в def formfield(self, **kwargs):

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

Так что вам нужно дать ему список идентификаторов:

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()]
14 голосов
/ 28 января 2009

Вам нужно будет добавить метод __init__ к Action_Form, чтобы установить начальные значения, не забывая вызывать __init__ для базового ModelForm класса через 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(...

Если вы планируете передавать параметры фильтра в качестве аргументов ключевых слов на Action_Form, вам нужно удалить их перед вызовом super:

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

или, возможно, лучше:

myfilter = kwargs.pop('myfilter')

Для получения дополнительной информации, вот еще одна ссылка, относящаяся к Динамические модели моделей в Django .

11 голосов
/ 12 октября 2010

Если предыдущий ответ не был достаточно простым, я пытаюсь ответить 1) еще раз:

  1. Как я могу заставить ModelMultipleChoiceField принимать эти "начальные" значения?

Вы можете оставить Action_Form, как это было в исходном вопросе, и просто использовать это, чтобы сделать именно то, что вы хотите:

>>> form4 = Action_Form(initial={'from_company': Contact.objects.all().values_list('id',flat=True)})
>>> print form4['from_company']
10 голосов
/ 18 декабря 2013

Ответ на (1) вопрос!

Это не будет работать:

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

Но это будет действительно работать :

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