在Django模型formset中设置每个表单的实例

时间:2016-04-28 13:11:26

标签: python django

使用Django模型表单时,我经常这样做:

def my_view(request):
    new_entry = MyModel(name='a')
    form = MyModelForm(instance=new_entry)
    ...

我想用modelformset做类似的事情。这样的事情是理想的:

def my_view(request):
    MyFormSet = modelformset_factory(MyModel, form=MyModelForm)
    new_entries = [MyModel(name='a'), MyModel(name='b')]
    formset = MyFormSet(instances=new_entries) # off course this does not work
    ...

由于项目尚未存储在数据库中,因此我无法使用查询集设置实例。如果我想使用初始,我必须声明表单中的字段,这是不理想的,似乎有点hacky。

有关如何在modelformset中设置每个模型的实例的任何建议吗?

3 个答案:

答案 0 :(得分:4)

好的,我认为我找到了解决方案。

class FormSetWithInstances(BaseFormSet):
    def __init__(self, *args, **kwargs):
        self.instances = kwargs.pop('instances')
        super(FormSetWithInstances, self).__init__(*args, **kwargs)

    def get_form_kwargs(self, index):
        form_kwargs = super(FormSetWithInstances, self).get_form_kwargs(index)
        if index < len(self.instances):
            form_kwargs['instance'] = self.instances[index]
        return form_kwargs

使用此modelformsets或inlinemodelformsets时要小心,因为查询集将覆盖您设置的实例。

答案 1 :(得分:2)

另一种方法:

class FormSetWithInstances(BaseFormSet):

    def get_form_kwargs(self, index):
        kwargs = super(FormSetWithInstances, self).get_form_kwargs(index)
        instances = kwargs.pop('instances')
        try:
            kwargs.update({'instance': instances[index])
        except IndexError:
            pass
        return kwargs

然后,在创建FormSetWithInstances的实例时,您将实例列表作为表单kwarg传递:

form_set = FormSetWithInstances(form_kwargs={'instances': [...]})

我个人更喜欢这种方法,因为它利用了现有的类基础结构,而不是在被覆盖的__init__()中定义自定义类成员。此外,它位于docs

答案 2 :(得分:1)

我不知道在您尝试传递实例列表时有一种简单的方法。根据您的使用情况,这里有两个选项可供使用。

您可以provide initial data获取模型表单集。这应该是字典列表,而不是模型实例:

initial = [{'name': 'a'}, {'name': 'b'}]
formset = MyFormSet(
    queryset=MyModel.objects.none(),
    initial=initial,
)

请注意,我已将查询集设置为空查询集。如果您没有这样做,那么formset将显示现有实例,初始数据将用于新实例。

如果您希望在表单中包含不希望包含的字段的初始值,则可以在[保存表单集]时设置这些值。

instances = formset.save(commit=False)
names = ['a', 'b']
for instance, name in zip(instances, names):
    instance.name = name
    instance.save()