Django formset:从 formset 中保存多个表单
Django formset : Save multiple forms from formset
为了 add dynamically forms to formset
我花了几天时间,我找到了一种方法来做到这一点。但是我对 forms saving
有一个小问题,因为它只保存第一个表单而不是 formset 中的所有表单。
这是我的表格集:
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>
这是我的 JS 部分:
$('#add_more').click(function () {
var form_idx = $('#id_form-TOTAL_FORMS').val();
$('#form_set').append($('#empty_form').html().replace(/__prefix__/g, form_idx));
$('#id_form-TOTAL_FORMS').val(parseInt(form_idx) + 1);
});
这是我的 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_documents-0-title
但是当我添加更多表单时,标题字段总是得到 id_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': ['']}>
这是我的 console.log
:
Element kt.fn.init {}
幸运的是,我最近刚刚使用 FormSet,所以我可以看到相关代码的问题。
(由 Ducky 编辑。谢谢!)
您必须在 views.py 文件和 app.js 文件之间设置相同的 prefix
。因为在您的视图文件中您使用的是 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)
为了 add dynamically forms to formset
我花了几天时间,我找到了一种方法来做到这一点。但是我对 forms saving
有一个小问题,因为它只保存第一个表单而不是 formset 中的所有表单。
这是我的表格集:
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>
这是我的 JS 部分:
$('#add_more').click(function () {
var form_idx = $('#id_form-TOTAL_FORMS').val();
$('#form_set').append($('#empty_form').html().replace(/__prefix__/g, form_idx));
$('#id_form-TOTAL_FORMS').val(parseInt(form_idx) + 1);
});
这是我的 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_documents-0-title
但是当我添加更多表单时,标题字段总是得到 id_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': ['']}>
这是我的 console.log
:
Element kt.fn.init {}
幸运的是,我最近刚刚使用 FormSet,所以我可以看到相关代码的问题。
(由 Ducky 编辑。谢谢!)
您必须在 views.py 文件和 app.js 文件之间设置相同的 prefix
。因为在您的视图文件中您使用的是 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)