Django 表单集中每个表单的不同初始数据

Posted

技术标签:

【中文标题】Django 表单集中每个表单的不同初始数据【英文标题】:Different initial data for each form in a Django formset 【发布时间】:2010-12-26 05:56:03 【问题描述】:

是否可以为每行预填充不同数据的表单集?我想将一些信息放在以前视图的隐藏字段中。

根据文档,您只能全面设置初始值。

【问题讨论】:

【参考方案1】:
formset = BookFormset(request.GET or None,initial=['formfield1': x.modelfield_name1,'formfield2':x.modelfield_name2 for x in model])

formfield1,formfield2 是表单域的名称。

modelfield_name1,modelfield_name2 是模态字段名称。

model 是 models.py 文件中模态类的名称。

BookFormset 是您的 forms.py 文件中定义的表单或表单集名称

【讨论】:

【参考方案2】:

如果你和我一样犯了同样的错误,那你只是稍微弄错了文档。

当我第一次看到这个例子时......

formset = ArticleFormSet(initial=[
 'title': 'Django is now open source',
  'pub_date': datetime.date.today(),
])

我假设每个表单都根据字典获得相同的初始数据集。

但是,如果您仔细观察,您会发现表单集实际上是通过字典列表传递的。

为了在表单集中为每个表单设置不同的初始值,您只需要传递包含不同数据的字典列表。

Formset = formset_factory(SomeForm, extra=len(some_objects)
some_formset = FormSet(initial=['id': x.id for x in some_objects])

【讨论】:

这似乎是最简单的方法,也是默认的 Django 方法,并指出了 OP 的误解。应该是最佳答案。 请注意,这将使ArticleFormSet 成为unbound form,因为初始值将覆盖从文章查询集返回的值。 @Alistair,你在这里犯了一个小错误,是'id': x.id而不是'id': 'x.id' 好方法!谢谢! 惊人的解决方案!谢谢!重要的是,我已经在 formset_factory 中测试了您已经确定了额外表单的确切长度。【参考方案3】:

基于 Antony Vennard 的回答,我不确定他使用的是什么版本的 python/django,但我也无法让生成器在 curry 方法中工作。我目前在 python2.7.3 和 django1.5.1 上。我最终没有使用自定义生成器,而是在事物列表中使用内置 iter() 创建迭代器,并在 curry 方法中传递迭代器本身,并在 Form @987654324 中调用 next() @。这是我的解决方案:

# Build the Formset:
my_iterator = iter(my_list_of_things) # Each list item will correspond to a form.
Formset = formset_factory(MyForm, extra=len(my_list_of_things))
Formset.form = staticmethod(curry(MyForm, item_iterator=my_iterator))

形式如下:

# forms.py
class MyForm(forms.Form):
    def __init__(self, *args, **kwargs):
        # Calling next() on the iterator/generator here:
        list_item = kwargs.pop('item_iterator').next()

        # Now you can assign whatever you passed in to an attribute
        # on one of the form elements.
        self.fields['my_field'].initial = list_item

我发现的一些关键事情是您需要在 formset_factory 中指定一个“额外”值,或者在表单集上使用 initial kwarg 来指定一个与您传递给迭代器的列表相对应的列表(在上面的示例中,我将 my_list_of_things 列表的 len() 传递给“额外”kwarg 到 formset_factory)。这是在表单集中实际创建多个表单所必需的。

【讨论】:

【参考方案4】:

我遇到了这个问题,我制作了一个新的小部件:

from django.forms.widgets import Select
from django.utils.safestring import mark_safe
class PrepolutatedSelect(Select):
    def render(self, name, value, attrs=None, choices=()):
        if value is None: value = ''
        if value == '':
            value = int(name.split('-')[1])+1
        final_attrs = self.build_attrs(attrs, name=name)
        output = [u'<select%s>' % flatatt(final_attrs)]
        options = self.render_options(choices, [value])
        if options:
            output.append(options)
        output.append('</select>')
        return mark_safe(u'\n'.join(output))

也许这对你也有用。

【讨论】:

我遇到了与 OP 类似的问题。我正在尝试创建一个包含多个表单的表单集,每个表单都有自己独特的一组用于选择元素的选项(即“选择”)。我不太明白这个解决方案有什么帮助。我错过了什么吗?【参考方案5】:

您需要使用this post 中描述的技术才能将参数传入。感谢该作者的出色帖子。您可以通过几个部分来实现这一点:

知道它会获取额外参数的表单

来自链接问题的示例:

def __init__(self, *args, **kwargs):
    someeobject = kwargs.pop('someobject')
    super(ServiceForm, self).__init__(*args, **kwargs)
    self.fields["somefield"].queryset = ServiceOption.objects.filter(
                                                           somem2mrel=someobject)

或者您可以将后面的代码替换为

    self.fields["somefield"].initial = someobject

直接,它的工作原理。

柯里化表单初始化设置

formset = formset_factory(Someform, extra=3)
formset.form = staticmethod(curry(someform, somem2mrel=someobject))

这使您可以传递自定义表单参数。现在你需要的是:

获取不同初始参数的生成器

我正在使用这个:

def ItemGenerator(Item):
    i = 0
    while i < len(Item):
        yield Item[i]
        i += 1

现在,我可以这样做了:

iterdefs = ItemGenerator(ListofItems) # pass the different parameters 
                                      # as an object here
formset.form = staticmethod(curry(someform, somem2mrel=iterdefs.next()))

嘿,转眼间。 form 方法的每次评估都在传递迭代参数的部分中进行评估。我们可以迭代我们喜欢的东西,所以我使用这个事实来迭代一组对象并将每个对象的值作为不同的初始参数传递。

【讨论】:

嘿!我认为您的回答可能会解决我在这个问题***.com/questions/6123278/… 中解决的问题。但我实际上并不真正了解发生了什么 我尝试使用这种方法,但无法让迭代器在每次调用时进行迭代。我的代码:DecorationFileFormSet.form = staticmethod(curry(DecorationFileForm, filetype=counter.next())) 每次创建文件类型属性为 1 的表单。计数器是itertools.count(1) 的一个实例 有人已经找到解决方案了吗?生成器对我也不起作用(根本不迭代)。 这里也一样。生成器不会在 .next() 上进行迭代。这个答案对任何人有用吗?

以上是关于Django 表单集中每个表单的不同初始数据的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Django 中根据需要为 formset_factory 设置每个字段(如何验证表单集中的空白表单)

最初在 django 内联表单集中设置不同的外键值

Django formset 设置当前用户

Django - 禁用表单集中现有表单的编辑,但允许在新表单中编辑

如何将类设置为 django 模型表单集中的列

如何从表单集中删除表单