动态向表单添加字段

79 投票
5 回答
105680 浏览
提问于 2025-04-16 18:24

我在表单里有三个字段。

我有一个提交按钮,还有一个“添加额外字段”的按钮。

我知道可以通过表单类里的 __init__ 方法来添加字段。

我刚开始学Python和Django,现在遇到了一个初学者的问题;我的问题是:

当我点击“添加额外字段”按钮时,添加这个额外字段的过程是什么?

表单需要重新渲染吗?

我应该怎么调用 __init__ 方法,或者我根本就不需要调用它吗?

我该如何给 __init__ 传递参数?

5 个回答

4

这里有一种方法,不需要用到JavaScript,而且字段类型在JavaScript中没有描述:

PYTHON

 def __init__(self, *args, **kwargs):
        super(Form, self).__init__(*args, **kwargs)

        ##ajouts des champs pour chaque chien
        for index in range(int(nb_dogs)):
            self.fields.update({
                'dog_%s_name' % index: forms.CharField(label=_('Name'), required=False, max_length=512),
            })

 def fields_dogs(self):
        fields = []
        for index in range(int(nb_dogs)):
            fields.append({
                'name': self['dog_%s_name' % index],
            })
        return fields

模板

{% for field_dog in f.fields_dogs %}
        <thead>
            <tr>
                <th style="background-color: #fff; border-width: 0px;"></th>
                <th>{% trans 'Dog' %} #{{forloop.counter}}</th>
                <th>{% trans 'Name' %}</th>
            </tr>
        </thead>
        <tbody>
            <tr>
                <td style="background-color: #fff; border-width: 0px;"></td>
                <td style="background-color: #fff; border-width: 0px;"></td>
                <td>{{field_dog.name.errors}}{{field_dog.name}}</td>
            </tr>
            <tr>
                <td style="padding: 10px; border-width: 0px;"></td>
            </tr>
        </tbody>
{% endfor %}
16

我遇到过一个情况,需要动态创建表单,并且表单里的字段也是动态的。我是通过这个小技巧来实现的:

from django import forms

...

dyn_form = type('DynForm',  # form name is irrelevant
                (forms.BaseForm,),
                {'base_fields': fields})

想了解更多信息,可以参考这个链接: 动态表单

除此之外,我还需要在表单创建后,动态地添加字段,也就是说要在表单类里注入字段。

dyn_form.base_fields['field1'] = forms.IntegerField(widget=forms.HiddenInput(), initial=field1_val)
dyn_form.base_fields['field2'] = forms.CharField(widget=forms.HiddenInput(), initial=field2_val)

这样做是成功的。

77

你的表单需要根据从POST请求中传递过来的变量来构建(或者直接检查属性)。每次视图重新加载时,表单都会被构建,无论有没有错误,所以HTML里需要包含关于有多少个字段的信息,以便正确地构建这些字段进行验证。

我会把这个问题看作是FormSet的工作方式:有一个隐藏字段,里面包含当前活动表单的数量,每个表单的名字前面会加上表单的索引。

实际上,你可以创建一个只有一个字段的FormSet

https://docs.djangoproject.com/en/dev/topics/forms/formsets/#formsets

如果你不想使用FormSet,你也可以自己实现这个功能。

这里有一个从头开始制作的例子——它应该能给你一些灵感。它也回答了你关于如何将参数传递给__init__的问题:你只需将参数传递给对象的构造函数:MyForm('arg1', 'arg2', kwarg1='keyword arg')

表单

class MyForm(forms.Form):
    original_field = forms.CharField()
    extra_field_count = forms.CharField(widget=forms.HiddenInput())

    def __init__(self, *args, **kwargs):
        extra_fields = kwargs.pop('extra', 0)

        super(MyForm, self).__init__(*args, **kwargs)
        self.fields['extra_field_count'].initial = extra_fields

        for index in range(int(extra_fields)):
            # generate extra fields in the number specified via extra_fields
            self.fields['extra_field_{index}'.format(index=index)] = \
                forms.CharField()

视图

def myview(request):
    if request.method == 'POST':
        form = MyForm(request.POST, extra=request.POST.get('extra_field_count'))
        if form.is_valid():
            print "valid!"
    else:
        form = MyForm()
    return render(request, "template", { 'form': form })

HTML

<form>
    <div id="forms">
        {{ form.as_p }}
    </div>
    <button id="add-another">add another</button>
    <input type="submit" />
</form>

JS

<script>
let form_count = Number($("[name=extra_field_count]").val());
// get extra form count so we know what index to use for the next item.

$("#add-another").click(function() {
    form_count ++;

    let element = $('<input type="text"/>');
    element.attr('name', 'extra_field_' + form_count);
    $("#forms").append(element);
    // build element and append it to our forms container

    $("[name=extra_field_count]").val(form_count);
    // increment form count so our view knows to populate 
    // that many fields for validation
})
</script>

撰写回答