简体   繁体   English

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

[英]Set instance of each form in Django model formset

When working with Django model forms, I often do something like this: 使用Django模型表单时,我经常这样做:

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

I want to do something similar with a modelformset. 我想用modelformset做类似的事情。 Something like this would be ideal: 这样的事情是理想的:

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

Since the items are not stored in the database yet, I can't set the instances using a queryset. 由于项目尚未存储在数据库中,因此无法使用查询集设置实例。 If I want to use initial I have to declare the fields in the form, which is not ideal and seems a bit hacky. 如果我想使用初始我必须声明表单中的字段,这是不理想的,似乎有点hacky。

Any suggestions how I can set the instances of each modelform in a modelformset? 有关如何在modelformset中设置每个模型的实例的任何建议吗?

Ok, I think I've found a solution. 好的,我想我找到了解决方案。

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

Be careful when using this modelformsets or inlinemodelformsets, as the queryset will override the instance you set. 使用此modelformsets或inlinemodelformsets时要小心,因为查询集将覆盖您设置的实例。

An alternative approach: 另一种方法:

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

Then, when creating instances of FormSetWithInstances , you pass in a list of instances as a form kwarg: 然后,在创建FormSetWithInstances实例时,您将实例列表作为表单kwarg传入:

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

I personally prefer this method because it takes advantage of existing class infrastructure instead of defining custom class members in an overridden __init__() . 我个人更喜欢这种方法,因为它利用了现有的类基础结构,而不是在重写的__init__()中定义自定义类成员。 Also, it's in the docs . 此外,它在文档中

I'm not aware of an easy way to pass a list of instances as you are trying to do. 我不知道一种简单的方法来传递实例列表,就像你想要的那样。 Here's a couple of options that might work depending on your use case. 根据您的使用案例,这里有两个可能有效的选项。

You can provide initial data for the model formset. 您可以提供模型表单集的初始数据 This should be a list of dictionaries, not model instances: 这应该是字典列表,而不是模型实例:

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

Note that I have set the queryset to an empty queryset. 请注意,我已将查询集设置为空查询集。 If you didn't do this, then the formset would display existing instances, and the initial data would be used for new instances. 如果您不这样做,那么formset将显示现有实例,初始数据将用于新实例。

If you have initial values for fields that you do not wish to include in the form, then you could be able to set those values when you [save the formset]. 如果您不希望在表单中包含字段的初始值,则可以在[保存表单集]时设置这些值。

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM