Django:如何在表单集构造完成后向其添加额外的表单?

Django:如何在表单集构造完成后向其添加额外的表单?,django,django-forms,Django,Django Forms,这大概就是我要做的: def post(request): VehicleFormSet = formset_factory(StaffVehicleForm) if request.method == 'POST': vehicle_formset = VehicleFormSet(request.POST) if 'add_vehicle' in request.POST: if vehicle_formset.is_v

这大概就是我要做的:

def post(request):
    VehicleFormSet = formset_factory(StaffVehicleForm)
    if request.method == 'POST':
        vehicle_formset = VehicleFormSet(request.POST)
        if 'add_vehicle' in request.POST:
            if vehicle_formset.is_valid():
                form_count = vehicle_formset.total_form_count()
                vehicle_formset.forms.append(vehicle_formset._construct_form(form_count))
基本上,如果用户单击“添加”按钮并且他们的输入有效,我想向表单集中添加另一个空白表单,并隐藏上一个表单


上面代码的问题是我不知道如何增加
total\u form\u count()
。按照我现在的方式,它会工作一次,然后如果你再按一下,什么也不会发生,大概是因为
form\u count
是一样的。我也不喜欢调用
\u construct\u form
并依赖于内部结构。

我使用javascript来实现这一点。因为表单集呈现三个管理字段

<input type="hidden" id="id_TOTAL_FORMS" value="1" name="TOTAL_FORMS">
<input type="hidden" id="id_INITIAL_FORMS" value="1" name="INITIAL_FORMS">.
<input type="hidden" id="id_MAX_NUM_FORMS" name="MAX_NUM_FORMS">
棘手的事情是在javascript中创建额外的表单字段。我通常使用AJAX从自定义视图获取新行

class RequiredFormSet(BaseFormSet):
    def add_form(self, **kwargs):
        # add the form
        tfc = self.total_form_count()
        self.forms.append(self._construct_form(tfc, **kwargs))
        self.forms[tfc].is_bound = False

        # make data mutable
        self.data = self.data.copy()

        # increase hidden form counts
        total_count_name = '%s-%s' % (self.management_form.prefix, TOTAL_FORM_COUNT)
        initial_count_name = '%s-%s' % (self.management_form.prefix, INITIAL_FORM_COUNT)
        self.data[total_count_name] = self.management_form.cleaned_data[TOTAL_FORM_COUNT] + 1
        self.data[initial_count_name] = self.management_form.cleaned_data[INITIAL_FORM_COUNT] + 1

    def add_fields(self, form, index):
        super(RequiredFormSet, self).add_fields(form, index)
        form.empty_permitted = False

那就行了。只花了7个小时就搞定了。我仍然不知道为什么我需要
。is_bound=False
,以使初始值不会出错。

对于后代来说,这是另一种不需要JS(或与JS一起)的方法,并且不需要熟悉表单集方法。相反,您可以只检查POST数据并调整它,就像JS在客户端做了一些工作一样。以下内容确保表单集末尾始终(至少)有一个空表单:

def hsview( request):
    HS_formset = formset_factory( HSTestForm, extra=3 )
    prefix='XYZZY'
    testinpost, empty = 'key', ''  # field in the form and its default/empty value
    extra=3

# I prefer to do the short init of unbound forms first, so I invert the usual test ...   
    if request.method != 'POST':

        formset = HS_formset( prefix=prefix)
    else:
       # process POSTed forms data. 
       # pull all relevant things out of POST data, because POST itself is not mutable
        # (it doesn't matter if prefix allows in extraneous items)

        data = { k:v for k,v in request.POST.items() if k.startswith(prefix) } 

        #if there are no spare empty forms, tell it we want another form, in place of or extra to client-side JS
        #don't want to crash if unvalidated POST data is nbg so catch all ...
        try:
            n = int( data[ prefix + '-TOTAL_FORMS']) 
            test = '{}-{}-{}'.format(prefix, n-1, testinpost)
            #print(test)
            test = data.get( test, empty)
        except Exception:
            test = 'bleagh'
            # log the error if it matters enough ...
        if test != empty: 
            data[ prefix + '-TOTAL_FORMS'] = n + 1 

        # now the usual formset processing ...
        formset = HS_formset( data, prefix=prefix)
        # other_form = OtherForm( request.POST)
        if formset.is_valid(): 
            ...            

我在Vue.js方法中使用正则表达式:

addForm: function () {
    this.count++
    let form_count = this.count
    form_count++

    let formID = 'id_form-' + this.count
    incremented_form = this.vue_form.replace(/form-\d/g, 'form-' + this.count)
    this.formList.push(incremented_form)
    this.$nextTick(() => {
        let total_forms = document.getElementsByName('form-TOTAL_FORMS').forEach
        (function (ele, idx) {
            ele.value = form_count
        })
    })
},

delForm: function () {
    if (this.count != 0) {
        this.count--
        let form_count = this.count
        form_count++

        let formID = 'id_form-' + this.count
        this.formList.pop()
        this.$nextTick(() => {
            let total_forms = document.getElementsByName('form-TOTAL_FORMS').forEach
            (function (ele, idx) {
                ele.value = form_count
            })
        })
    }
    else return
},

BaseFormSet
上的
empty\u form
属性在这里可能有用。“返回一个前缀为
\uuuuu prefix\uuuuu
的表单实例,以便在动态表单中使用JavaScript”我认为您可以将其作为模板进行克隆。哦,好提示Reiner Gerecke!下一次我肯定会使用它:-)@Reiner:如果表单集被绑定,则空表单不尊重表单字段默认值。。。一个相当恼人的错误(表单将完全为空,而不是包含默认值)。我如何调用我的视图并要求它向我发送一个附加表单,因为我的表单包含两个下拉字段和许多数据库绑定选项?您能告诉我们如何使用AJAX从自定义视图中获取行吗?谢谢这对我很有帮助:除非您的表单绑定到提交的帖子(或获取)数据,否则is_bound应该始终为False。@Humphrey:是的。。。的确如此。整个表单集是。我不想要空白,但要添加的形式,但势必。@ MPEN我应该怎么称呼这个方法,我将从哪里得到总计,FuffyCo计数和其他变量。这是我6年前写的。对不起,谢谢你给我时间的提示,有时候我觉得几句话的时间太长了,这让我很担心!
addForm: function () {
    this.count++
    let form_count = this.count
    form_count++

    let formID = 'id_form-' + this.count
    incremented_form = this.vue_form.replace(/form-\d/g, 'form-' + this.count)
    this.formList.push(incremented_form)
    this.$nextTick(() => {
        let total_forms = document.getElementsByName('form-TOTAL_FORMS').forEach
        (function (ele, idx) {
            ele.value = form_count
        })
    })
},

delForm: function () {
    if (this.count != 0) {
        this.count--
        let form_count = this.count
        form_count++

        let formID = 'id_form-' + this.count
        this.formList.pop()
        this.$nextTick(() => {
            let total_forms = document.getElementsByName('form-TOTAL_FORMS').forEach
            (function (ele, idx) {
                ele.value = form_count
            })
        })
    }
    else return
},