Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/356.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 创建具有动态字段数的Django表单类_Python_Django_Forms - Fatal编程技术网

Python 创建具有动态字段数的Django表单类

Python 创建具有动态字段数的Django表单类,python,django,forms,Python,Django,Forms,我在做一个网上商店。我正在制作一个表格,让客户购买一件物品,她可以选择她想购买的物品数量。但是,在她买的每件商品上,她都需要选择它的颜色。因此有一个非恒定数量的字段:如果客户购买3件商品,她应该得到3个选择颜色的框,如果她购买7件商品,她应该得到7个这样的框 我将使用JavaScript使HTML表单字段出现和消失。但是在我的Django表单类中如何处理这个问题呢?我看到表单字段是类属性,所以我不知道如何处理一些表单实例应该有3个颜色字段和7个颜色字段的事实 有什么线索吗?雅各布·卡普兰·莫斯(

我在做一个网上商店。我正在制作一个表格,让客户购买一件物品,她可以选择她想购买的物品数量。但是,在她买的每件商品上,她都需要选择它的颜色。因此有一个非恒定数量的字段:如果客户购买3件商品,她应该得到3个选择颜色的
框,如果她购买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