Django:ModelMultipleChoiceField 不选择初始选择

问题描述 投票:0回答:5

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”用于测试,否则为变量
>>> form = Action_Form(initial={'from_company': [o.pk for o in contacts_from_company]}) # 按照修复中的建议
>>> 打印表格['from_company']
>>> 打印来自公司的联系人 [] >>> form2 = Action_Form(initial={'from_company':contacts_from_company}) >>> 打印 form2['from_company']
>>> form3 = Action_Form(initial={'from_company': Contact.objects.all()}) >>> 打印 form3['from_company']

我希望它能发挥作用的方式:
1.我的视图从 request.GET 中获取“company”
2. 然后过滤该“公司”的所有“联系人”
3. 最后,它创建一个表单并将这些“联系人”作为“initial={...}”传递

两个问题:
1. [尚未回答] 如何使 ModelMultipleChoiceField 采用这些“初始”值?
2. [已回答] 作为替代方案,我可以将变量传递给 Action_Form(ModelForm) 以便在我的 ModelForm 中我可以:

from_company = forms.ModelMultipleChoiceField(queryset=Contact.objects.filter(company__exact=some_id) # 其中 some_id 来自视图
python django django-models django-forms
5个回答
23
投票

我正在回复1)

1.如何使 ModelMultipleChoiceField 采用这些“初始”值?

这可以在您的

Action_Form
__init__
方法中使用 ModelMultipleChoiceField
initial
属性来完成。

正如 Django 源代码中所说(db/models/fields/lated.py) 在

def formfield(self, **kwargs)

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

所以你需要给它一个ID列表:

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

16
投票

您需要向

__init__
添加一个
Action_Form
方法来设置初始值,请记住通过
super
__init__
基类上调用 ModelForm

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 中的动态模型表单


13
投票

如果之前的答案不够直接,我会尝试再次回答1):

  1. 如何使 ModelMultipleChoiceField 采用这些“初始”值?

您可以保留原来问题中的

Action_Form
,然后使用它来准确渲染您想要的内容:

>>> form4 = Action_Form(initial={'from_company': Contact.objects.all().values_list('id',flat=True)})
>>> print form4['from_company']

12
投票

回答(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()]

0
投票

问题是因为

Contact.objects.all().values_list('id', flat=True)
如果是 QuerySet 对象,则 MultipleChoiceField 需要一个列表,请参阅文档中的

要解决此问题,只需将 QuerySet 转换为列表即可!

范例:

contacts = list(Contact.objects.values_list('id', flat=True))
form = Action_Form({'from_company': contacts})
© www.soinside.com 2019 - 2024. All rights reserved.