Python 创建具有动态字段数的Django表单类
我在做一个网上商店。我正在制作一个表格,让客户购买一件物品,她可以选择她想购买的物品数量。但是,在她买的每件商品上,她都需要选择它的颜色。因此有一个非恒定数量的字段:如果客户购买3件商品,她应该得到3个选择颜色的Python 创建具有动态字段数的Django表单类,python,django,forms,Python,Django,Forms,我在做一个网上商店。我正在制作一个表格,让客户购买一件物品,她可以选择她想购买的物品数量。但是,在她买的每件商品上,她都需要选择它的颜色。因此有一个非恒定数量的字段:如果客户购买3件商品,她应该得到3个选择颜色的框,如果她购买7件商品,她应该得到7个这样的框 我将使用JavaScript使HTML表单字段出现和消失。但是在我的Django表单类中如何处理这个问题呢?我看到表单字段是类属性,所以我不知道如何处理一些表单实例应该有3个颜色字段和7个颜色字段的事实 有什么线索吗?雅各布·卡普兰·莫斯(
框,如果她购买7件商品,她应该得到7个这样的
框
我将使用JavaScript使HTML表单字段出现和消失。但是在我的Django表单类中如何处理这个问题呢?我看到表单字段是类属性,所以我不知道如何处理一些表单实例应该有3个颜色字段和7个颜色字段的事实
有什么线索吗?雅各布·卡普兰·莫斯(Jacob Kaplan Moss)对动态表单字段有着广泛的研究: 本质上,您可以在实例化过程中向表单的
self.fields
字典添加更多项。您可以像这样做
def __init__(self, n, *args, **kwargs):
super(your_form, self).__init__(*args, **kwargs)
for i in range(0, n):
self.fields["field_name %d" % i] = forms.CharField()
当您创建表单实例时,只需执行以下操作
forms = your_form(n)
这只是一个基本概念,您可以根据自己的需要更改代码D这里还有另一个选择:a怎么样? 由于您的字段都是相同的,这正是Formset的用途 django管理员使用
FormSet
s+一点javascript来添加任意长度的内联线
class ColorForm(forms.Form):
color = forms.ChoiceField(choices=(('blue', 'Blue'), ('red', 'Red')))
ColorFormSet = formset_factory(ColorForm, extra=0)
# we'll dynamically create the elements, no need for any forms
def myview(request):
if request.method == "POST":
formset = ColorFormSet(request.POST)
for form in formset.forms:
print "You've picked {0}".format(form.cleaned_data['color'])
else:
formset = ColorFormSet()
return render(request, 'template', {'formset': formset}))
JavaScript
$(函数(){
//这是一个点击事件,只是为了演示。
//您可能会在页面加载或数量更改时运行此操作。
$(“#生成表格”)。单击(函数(){
//更新表格总数
数量=$(“[名称=数量]”).val();
$(“[name=form-TOTAL_FORMS]”)val(数量);
//复制模板并用正确的索引替换前缀
对于(i=0;i而言,我的方法如下:
创建一个从froms.Form
继承的“空”类,如下所示:
class ItemsForm(forms.Form):
pass
构建实际表单的表单对象字典,其组成取决于上下文(例如,您可以从外部模块导入它们)。例如:
new_fields = {
'milk' : forms.IntegerField(),
'butter': forms.IntegerField(),
'honey' : forms.IntegerField(),
'eggs' : forms.IntegerField()}
在视图中,可以使用python本机“type”函数动态生成具有可变字段数的表单类
DynamicItemsForm = type('DynamicItemsForm', (ItemsForm,), new_fields)
将内容传递到表单并在模板中呈现:
Form = DynamicItemsForm(content)
context['my_form'] = Form
return render(request, "demo/dynamic.html", context)
“内容”是字段值的字典(例如,甚至request.POST也可以)。
您可以看到我的整个示例得到了解释。另一种方法:我们可以使用mixin覆盖字段,在generate_dynamic_字段中返回动态字段的OrderedDict,而不是破坏正常的字段初始化流,只要设置它,就会添加这些字段
from collections import OrderedDict
class DynamicFormMixin:
_fields: OrderedDict = None
@property
def fields(self):
return self._fields
@fields.setter
def fields(self, value):
self._fields = value
self._fields.update(self.generate_dynamic_fields())
def generate_dynamic_fields(self):
return OrderedDict()
一个简单的例子:
class ExampleForm(DynamicFormMixin, forms.Form):
instance = None
def __init__(self, instance = None, data=None, files=None, auto_id='id_%s', prefix=None, initial=None,
error_class=ErrorList, label_suffix=None, empty_permitted=False, field_order=None,
use_required_attribute=None, renderer=None):
self.instance = instance
super().__init__(data, files, auto_id, prefix, initial, error_class, label_suffix, empty_permitted, field_order,
use_required_attribute, renderer)
def generate_dynamic_fields(self):
dynamic_fields = OrderedDict()
instance = self.instance
dynamic_fields["dynamic_choices"] = forms.ChoiceField(label=_("Number of choices"),
choices=[(str(x), str(x)) for x in range(1, instance.number_of_choices + 1)],
initial=instance.initial_choice)
return dynamic_fields
非常感谢这个“额外”的普通链接,非常聪明的方法在这种情况下你如何传递初始数据?很好的链接,但这个用例正是表单集的用途。链接不再存在如果你的模型中有更多的字段,/\uuu prefix\uuu/g而不是“prefix”可能非常有用;)一些小的输入错误(1)在最后一行视图中:在模板中返回render(请求'template',{'formset':formset})(一个括号太多)(2),忘记删除'in-line:html=$(“#form#template”).clone().html().replace(/#form#prefix_u/g',i);必须是:$(“#form##template”).clone().html().replace(/#form prefix_u/g,i);很好的例子,通过它学到了很多,只是修复了一些发生的错误,第三个例子(3):在视图中,您还必须调用函数form.is_valid()为表单提供已清理的数据属性这应该是正式答案。那么表单是如何提交的呢?我似乎无法在视图中获取表单字段的值。我甚至在表单中添加了一个提交按钮。我的已清理的表单
和视图
中的数据都是空的。我如何发送帖子代码>请求?这很有效。如果你传递一个表单字段列表而不是仅仅传递“n”,你可以稍微修改循环以动态生成任意表单!(我就是这么做的)-上面的示例来自所选答案中的链接。
from collections import OrderedDict
class DynamicFormMixin:
_fields: OrderedDict = None
@property
def fields(self):
return self._fields
@fields.setter
def fields(self, value):
self._fields = value
self._fields.update(self.generate_dynamic_fields())
def generate_dynamic_fields(self):
return OrderedDict()
class ExampleForm(DynamicFormMixin, forms.Form):
instance = None
def __init__(self, instance = None, data=None, files=None, auto_id='id_%s', prefix=None, initial=None,
error_class=ErrorList, label_suffix=None, empty_permitted=False, field_order=None,
use_required_attribute=None, renderer=None):
self.instance = instance
super().__init__(data, files, auto_id, prefix, initial, error_class, label_suffix, empty_permitted, field_order,
use_required_attribute, renderer)
def generate_dynamic_fields(self):
dynamic_fields = OrderedDict()
instance = self.instance
dynamic_fields["dynamic_choices"] = forms.ChoiceField(label=_("Number of choices"),
choices=[(str(x), str(x)) for x in range(1, instance.number_of_choices + 1)],
initial=instance.initial_choice)
return dynamic_fields