Django:如何在表单集构建后添加额外的表单?
Posted
技术标签:
【中文标题】Django:如何在表单集构建后添加额外的表单?【英文标题】:Django: How to add an extra form to a formset after it has been constructed? 【发布时间】:2011-06-24 10:50:06 【问题描述】:这大致就是我想要做的:
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_form_count()
。我现在的方式,它会工作一次,然后如果你再次按下它,什么都不会发生,大概是因为form_count
是一样的。我也不喜欢打电话给_construct_form
依赖内部。
【问题讨论】:
【参考方案1】: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
来使初始值不会搞砸。
【讨论】:
is_bound 应该始终为 False,除非您的表单绑定到提交的 POST(或获取)数据。 @Humphrey:是的……确实如此。整个表单集是。不过,我不希望绑定尚未添加的空白表单。 @mpen 我应该如何调用这个方法以及从哪里得到 TOTAL_FORM_COUNT 和其他变量。 @CrazyGeek 不知道。这是我 6 年前写的。对不起 感谢您提供时间提示,有时我觉得几行字就没有时间了,这让我很担心!【参考方案2】:我使用 javascript 执行此操作。由于formset渲染了三个管理字段
<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 来增加 id_TOTAL_FORMS 值,然后添加额外的字段。所以我会像这样创建我的字段集:
VehicleFormSet = modelformset_factory(StaffVehicleForm, extra = 0, max_num = None)
棘手的是在 javascript 中创建额外的表单字段。我通常使用 AJAX 从自定义视图中获取新行。
【讨论】:
BaseFormSet
上的 empty_form
属性可能在这里有用。 docs.djangoproject.com/en/1.2/topics/forms/formsets/#empty-form “返回一个前缀为 __prefix__
的表单实例,以便更轻松地在带有 JavaScript 的动态表单中使用”我认为您可以将其作为模板进行克隆。
哦,好的提示 Reiner Gerecke!下次我肯定会使用它:-)
@Reiner:如果绑定了表单集,则 empty_form 不尊重表单字段的默认值......一个相当烦人的错误(表单将完全空白,而不是包含默认值)。跨度>
我如何调用我的视图并要求它向我发送一个额外的表单,因为我的表单包含几个下拉字段和很多数据库绑定选项?您能告诉我们您是如何使用 AJAX 从自定义视图中获取一行的吗?谢谢!
这对我有帮助:***.com/questions/501719/…【参考方案3】:
对于后代来说,这是另一种在没有 JS(或与 JS 一起)的情况下工作的方式,它不需要深入了解 formset 方法。相反,您可以只检查 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():
...
【讨论】:
【参考方案4】:我在 Vue.js 方法中使用 RegEx:
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
,
【讨论】:
以上是关于Django:如何在表单集构建后添加额外的表单?的主要内容,如果未能解决你的问题,请参考以下文章