将initial传递给Django的ModelFormSet

时间:2009-08-21 21:39:38

标签: django

我有一个模型formset,我需要传递关键字initial in(在formset中有一些初始值,例如设置为今天的日期)。据我所知,queryset参数(默认为YourModel.objects.all())会覆盖此功能,以便创建初始空表单。我将查询集指定为:YourModel.objects.none(),它阻止它使用数据库中的条目填充formset,但我仍然无法弄清楚如何有效地传递initial。我是否需要从ModelForm子类化方法?

10 个答案:

答案 0 :(得分:9)

您正在将空的查询集传递给ModelFormset。

ExampleModelFormSet = modelformset_factory(ExampleModel, extra=2)
formset = ExampleModelFormSet(queryset=ExampleModel.objects.none(),
                          initial=[{'name': 'Some Name'},
                                   {'name': 'Another Name'}])

这确实是实现你想要的方式。传递空的查询集是有意义的,否则初始值将覆盖模型的数据库值。

如果我想,你传递的是一个非空的查询集,但是希望你的额外表格填充初始值,你可以覆盖Formset

from django.forms.models import modelformset_factory  
ExampleFormset = modelformset_factory(OpenIDProfile, extra=3)

class myFormset(ExampleFormset):

    def _construct_form(self, i, **kwargs):
        """
        Instantiates and returns the i-th form instance in a formset.
        """
        if self.is_bound and i < self.initial_form_count():
            pk_key = "%s-%s" % (self.add_prefix(i), self.model._meta.pk.name)
            pk = self.data[pk_key]
            pk_field = self.model._meta.pk
            pk = pk_field.get_db_prep_lookup('exact', pk)
            if isinstance(pk, list):
                pk = pk[0]
            kwargs['instance'] = self._existing_object(pk)
        if i < self.initial_form_count() and not kwargs.get('instance'):
            kwargs['instance'] = self.get_queryset()[i]

        defaults = {'auto_id': self.auto_id, 'prefix': self.add_prefix(i)}
        if self.data or self.files:
            defaults['data'] = self.data
            defaults['files'] = self.files
        # Check to confirm we are not overwriting the database value.
        if not i in range(self.initial_form_count()) and self.initial:
            try:
                defaults['initial'] = self.initial[i - self.initial_form_count()]
            except IndexError:
                pass
        # Allow extra forms to be empty.
        if i >= self.initial_form_count():
            defaults['empty_permitted'] = True
        defaults.update(kwargs)
        form = self.form(**defaults)
        self.add_fields(form, i)        
        return form

注意:initial是dicts列表。它希望列表中的项目与额外的数量完全相同。

答案 1 :(得分:9)

Django 1.4中的新功能...如果你在modelformset上设置了初始值,它现在只适用于'额外'表单,而不是那些绑定到查询集实例的表单:

https://docs.djangoproject.com/en/dev/topics/forms/modelforms/#providing-initial-values

所以不再需要上面的各种黑客,使用initial就是答案。

答案 2 :(得分:4)

我发现这样做的最好方法是在初始化后手动调整formset对象的“extra”属性。这已经过测试,可以在Django 1.9中使用。

ExampleModelFormSet = modelformset_factory(ExampleModel, extra=1)
formset = ExampleModelFormSet(initial=[{'name': 'Some Name'},
                                       {'name': 'Another Name'}])
formset.extra = 3

这将吐出3种形式(2个预先填充和1个空白)。

如果你想要更动态的东西(例如initial是在其他地方计算的var),你可以这样做:

ExampleModelFormSet = modelformset_factory(ExampleModel, extra=1)
formset = ExampleModelFormSet(initial=initial)
formset.extra += len(initial)

希望有所帮助。

答案 3 :(得分:2)

仍然可以将initial传递给ModelFormSet。

from django.forms.models import modelformset_factory
from example.models import ExampleModel

ExampleModelFormSet = modelformset_factory(ExampleModel)
formset = ExampleModelFormSet(initial=[{'name': 'Some Name'},
                                       {'name': 'Another Name'}])

如果这不是您的追求,可以更多地解释您的问题。

编辑:

ExampleModelFormSet = modelformset_factory(ExampleModel, extra=2)
formset = ExampleModelFormSet(queryset=ExampleModel.objects.none(),
                              initial=[{'name': 'Some Name'},
                                       {'name': 'Another Name'}])

答案 4 :(得分:1)

您可以在之后更改初始数据。

例如:

# Construct the FormSet class
ExampleFormSet = modelformset_factory(ParentModel, ChildModel)

# Set the initial data
initial_data = {'field1': 1}
for form in ExampleFormSet.extra_forms:
    for field in form.fields:
        field.initial = initial_data[field.name]

答案 5 :(得分:1)

在Django 1.4中,规则发生了变化:要显示的首字母数量对应于“额外”参数。 https://docs.djangoproject.com/en/dev/topics/forms/modelforms/#providing-initial-values

在我的情况下,初始参数的计数会动态变化,因此 我发现了以下方式:

initial=[{'name': 'Some Name'},{'name': 'Another Name'}]
formset = ExampleModelFormSet(queryset=ExampleModel.objects.none(),
                      initial=initial, extra=len(initial))


class MyBaseFormSet(BaseModelFormSet):
    def __init__(self, *args, **kwargs):
        self.extra = kwargs.pop('extra', self.extra)
        super(MyBaseFormSet, self).__init__(*args, **kwargs)

提供,ExampleModelFormSet基于MyBaseFormSet

答案 6 :(得分:0)

一个简单的解决方案可能是您传递一个将modelform()扩展为formset(而不是modelformset)的表单。

这样你就可以在表格中设置初始值。

答案 7 :(得分:0)

我认为您可以使用初始参数,就像使用常规表单集一样 http://docs.djangoproject.com/en/dev/topics/forms/formsets/#using-initial-data-with-a-formset

答案 8 :(得分:0)

如何使用相同数量的额外表单传递初始数据的简单方法:

MyModelFormSet = lambda *a, **kw: modelformset_factory(MyModel, extra=kw.pop('extra', 1))(*a, **kw)

视图中的用法:

initial=[{'name': 'Some Name'},{'name': 'Another Name'}
formset = MyModelFormSet(queryset=MyModel.objects.none(), initial, extra=len(initial))})

答案 9 :(得分:0)

Affter两天发现了这个:http://streamhacker.com/2010/03/01/django-model-formsets/

def custom_field_callback(field):
    return field.formfield(required=False)

FormSet = modelformset_factory(model, formfield_callback=custom_field_callback)

def custom_field_callback(field):
    if field.name == 'optional':
        return field.formfield(required=False)
    elif field.name == 'text':
        return field.formfield(widget=Textarea)
    elif field.name == 'integer':
        return IntegerField()
    else:
        return field.formfield()