Django表单集:从表单集中保存多个表单

Django表单集:从表单集中保存多个表单,django,django-forms,formset,Django,Django Forms,Formset,我花了几天的时间在表单集中动态添加表单,我找到了一种方法。但是我对表单保存有一个小问题,因为它只保存第一个表单,而不是表单集中的所有表单 这是我的表格集: DocumentFormSets = inlineformset_factory(Publication, Document, form=DocumentForm, extra=1, max_num=4) 这是我的模板: <fieldset> <legend class="title"><span cl

我花了几天的时间在表单集中动态添加表单,我找到了一种方法。但是我对
表单保存有一个小问题,因为它只保存第一个表单,而不是表单集中的所有表单

这是我的表格集:

DocumentFormSets = inlineformset_factory(Publication, Document, form=DocumentForm, extra=1, max_num=4)
这是我的模板:

<fieldset>
    <legend class="title"><span class="name">{% trans 'Document form' %}</span></legend>
    {{ DocumentFormSet.management_form }}
    <div id="form_set">
      {% for form in DocumentFormSet.forms %}
        <div class='formset-document'>
          <table class='no_error'>
            <div class="row">
              <div class="col-xs-3">
                {{ form.title|as_crispy_field }}
              </div>
              <div class="col-xs-3">
                {{ form.language|as_crispy_field }}
              </div>
              <div class="col-xs-3">
                {{ form.format|as_crispy_field }}
              </div>
              <div class="col-xs-3">
                {{ form.upload|as_crispy_field }}
              </div>
            </div>
          </table>
        </div>
      {% endfor %}
    </div>
    <br>
    <input type="button" class="btn btn-default" value="Add More" id="add_more">
    <div id="empty_form" style="display:none">
      <table class='no_error'>
        <div class="row">
          <div class="col-xs-3">
            {{ DocumentFormSet.empty_form.title|as_crispy_field }}
          </div>
          <div class="col-xs-3">
            {{ DocumentFormSet.empty_form.language|as_crispy_field }}
          </div>
          <div class="col-xs-3">
            {{ DocumentFormSet.empty_form.format|as_crispy_field }}
          </div>
          <div class="col-xs-3">
            {{ DocumentFormSet.empty_form.upload|as_crispy_field }}
          </div>
        </div>
      </table>
    </div>
</fieldset>
这是我的views.py文件:

class PublicationCreateView(EdqmCreateView):
    """ Create publication with document form through formset """
    model = Publication
    template_name = 'freepub/publication/publication_form.html'

    def get_context_data(self, **kwargs):
        context = super(PublicationCreateView, self).get_context_data(**kwargs)
        context['DocumentFormSets'] = DocumentFormSets(self.request.POST or None, self.request.FILES or None)
        return context

    def form_valid(self, form):
        context = self.get_context_data()
        formsets = context['DocumentFormSets']
        if form.is_valid() and formsets.is_valid():
            self.object = form.save()
            formsets.instance = self.object
            formsets.save()
        return super(PublicationCreateView, self).form_valid(form)
但使用此功能,它仅保存我的表单集中的第一个文档表单:

我查看了id文档表单字段,得到以下信息:

第一个标题字段获取
id\u documents-0-title
,但当我添加更多表单时,标题字段始终获取
id\u documents-undefined-title

如何从表单集中保存文档表单

谢谢大家!

编辑:

这是@HaiLang问题的编辑:

这是我的
self.request.POST

<QueryDict: {'csrfmiddlewaretoken': ['0LHaaEG1dkyZmOnP3X7037tZI45QrQOIRrQQAMhiOoTyeohDwQdcdTt08yuqH86Z'], 'category': ['23'], 'pub_id': ['PUBSDDD-55'], 'title': ['TESTPUBLIE'], 'description': [''], 'doc-TOTAL_FORMS': ['1'], 'doc-INITIAL_FORMS': ['0'], 'doc-MIN_NUM_FORMS': ['0'], 'doc-MAX_NUM_FORMS': ['4'], 'doc-0-title': ['doc1'], 'doc-0-language': ['FR'], 'doc-0-format': ['pdf'], 'doc-undefined-title': ['doc2'], 'doc-undefined-language': ['FR'], 'doc-undefined-format': ['pdf'], 'doc-__prefix__-title': [''], 'doc-__prefix__-language': [''], 'doc-__prefix__-format': [''], 'doc-__prefix__-upload': ['']}>

幸运的是,我最近刚刚使用FormSet,所以我可以看到问题代码的问题

(由Ducky编辑,谢谢!)

您必须在views.py文件和app.js文件之间设置相同的
前缀。因为在视图文件中使用的是
prefix='doc'
,在javascript函数中使用的是
form
前缀

因此,在JQuery文件中,您必须编写:

(function ($) {
$('#add_more').click(function () {
    var form_idx = $('#id_doc-TOTAL_FORMS').val();
    // For debugging the issue
    // console.log('Element', $('#id_doc-TOTAL_FORMS'), 'Num of forms', form_idx);
    $('#form_set').append($('#empty_form').html().replace(/__prefix__/g, form_idx));
    $('#id_doc-TOTAL_FORMS').val(parseInt(form_idx) + 1);
    console.log('Element', $('#id_doc-TOTAL_FORMS'));
});
})(jQuery)
您可以这样覆盖视图:

class PublicationCreateView(CreateView):
    """ Create publication with document form through formset """
    model = Publication
    template_name = 'publication_form.html'

    def get_context_data(self, **kwargs):
        context = super(PublicationCreateView, self).get_context_data(**kwargs)
        document_queryset = Document.objects.all()
        context['DocumentFormSets'] = DocumentFormSet(self.request.POST or None, self.request.FILES or None, prefix='doc', queryset=document_queryset)
        return context

    def form_valid(self, form):
        context = self.get_context_data()
        formsets = context['DocumentFormSets']
        // For debugging
        // print(self.request.POST)
        if form.is_valid() and formsets.is_valid():
            self.object = form.save()
            formsets.instance = self.object
            formsets.save()
        return super(PublicationCreateView, self).form_valid(form)

为了便于阅读,您应该在表单集中使用复数形式。但是,如果表单集是
document
,为什么要给
document
分配一些内容并将
document
保存在for循环中?还有,在哪一行您会得到错误?并向我们展示如何构建表单集(您的get_context_data)@dirkgroten这是我第一次使用表单集,所以有些事情还不太清楚。我在问题中添加了
get\u context\u data
。问题是在线的:
self.object=form.save()
是使用
inlineformset\u工厂创建的
DocumentFormset
吗?是的!我编辑我的代码是为了向您显示缺少的元素。谢谢您的回答。但是我有一些黑点:第一点,控制台中的打印是:
numofformsindefined
每次我在表单集中添加一个新表单时。我必须明白为什么它被定义为
未定义的
。然后根据视图部分,如果我一次保存所有表单,它只保存表单集中的第一个表单。如果我尝试逐个保存,它不会保存任何文档。因此控制台中的
numofformsindefined
确认错误在form_idx。现在可以将脚本更新为
console.log('Element',$('id#form-TOTAL_FORMS')即确认可以检索管理表单中的输入。$符号是jQuery的签名。您是否在HTML标题中包含jQuery脚本?关于保存表单,请将
print(self.request.POST)
放在
formsets=
之前并提供输出?这是为了确认已发布的数据是否有足够的表格。我相信语句
$('#id_form-TOTAL_FORMS').val(parseInt(form_idx)+1)没有完成更新表单总数的工作。下面是生成的HTML文件中的我的管理表单。它具有javascript所需的
id\u form-TOTAL\u FORMS
。能否在生成的HTML文件中提供相同的内容
请将javascript中的
id\u表单-TOTAL\u表单
更新为
id\u doc-TOTAL\u表单
?这是因为在管理表单中,它使用
doc
而不是
form
(function ($) {
$('#add_more').click(function () {
    var form_idx = $('#id_doc-TOTAL_FORMS').val();
    // For debugging the issue
    // console.log('Element', $('#id_doc-TOTAL_FORMS'), 'Num of forms', form_idx);
    $('#form_set').append($('#empty_form').html().replace(/__prefix__/g, form_idx));
    $('#id_doc-TOTAL_FORMS').val(parseInt(form_idx) + 1);
    console.log('Element', $('#id_doc-TOTAL_FORMS'));
});
})(jQuery)
class PublicationCreateView(CreateView):
    """ Create publication with document form through formset """
    model = Publication
    template_name = 'publication_form.html'

    def get_context_data(self, **kwargs):
        context = super(PublicationCreateView, self).get_context_data(**kwargs)
        document_queryset = Document.objects.all()
        context['DocumentFormSets'] = DocumentFormSet(self.request.POST or None, self.request.FILES or None, prefix='doc', queryset=document_queryset)
        return context

    def form_valid(self, form):
        context = self.get_context_data()
        formsets = context['DocumentFormSets']
        // For debugging
        // print(self.request.POST)
        if form.is_valid() and formsets.is_valid():
            self.object = form.save()
            formsets.instance = self.object
            formsets.save()
        return super(PublicationCreateView, self).form_valid(form)