【问题标题】:How do I bind an flask-wtform UnboundField?如何绑定烧瓶wtform UnboundField?
【发布时间】:2018-07-31 14:42:19
【问题描述】:

我正在创建一个将产品发布到市场的应用。这个市场上的每个产品类别都有不同的产品属性形式,例如,如果它是电子产品,则有电压、型号等字段。 我通过市场服务器通过 json 获取此信息。 首先,用户必须写下产品的名称及其主要类别,市场服务器预测他们自己的类别并将其属性返回给我。 以下是响应示例:

{
"id": "MODEL",
"name": "Modelo",
"tags": {
  "hidden": true
},
{
"id": "PACKAGE_LENGTH",
"name": "Comprimento da embalagem",
"tags": {
  "hidden": true,
  "read_only": true,
  "variation_attribute": true
},
"hierarchy": "ITEM",
"relevance": 2,
"value_type": "number_unit",
"value_max_length": 255,
"allowed_units": [
  {
    "id": "km",
    "name": "km"
  },
  {
    "id": "polegadas",
    "name": "polegadas"
  },
  {
    "id": "ft",
    "name": "ft"
  },
  {
    "id": "mm",
    "name": "mm"
  },
  {
    "id": "m",
    "name": "m"
  },
  {
    "id": "\"",
    "name": "\""
  },
  {
    "id": "in",
    "name": "in"
  },
  {
    "id": "cm",
    "name": "cm"
  }
],
"default_unit": "cm",
"attribute_group_id": "OTHERS",
"attribute_group_name": "Outros"
}

到目前为止一切顺利。

现在我需要创建一个动态表单来添加/编辑这些字段,因为每个类别都有不同类型的属性和不同的数量。 每个字段都需要有一个 ID、一个类型(可以是字符串,也可以是数字) 一个标签,一个最大长度,如果它的 value_type number_unit 需要一个具有给定单位的 SelectField。

我在视图中获取此信息,并在同一视图中创建 FlaskForm 的子类,在其中我根据属性的类型创建字段列表。

   class DynamicForm(PostProductForm):
        loaded_attr = json.loads(meli.get(f"/categories/{category}/attributes").content.decode('utf-8'))
        attribute_fields = []
        for attribute in loaded_attr:
            tags = attribute.get('tags')
            if not tags.get('read_only'):
                if attribute.get('value_type') == 'number_unit':
                    attribute_fields.append(IntegerField(
                        attribute['name'], validators=[Length(min=0, max=attribute['value_max_length'])]))
                    allowed_units = [(unit['id'], unit['name']) for unit in attribute['allowed_units']]
                    attribute_fields.append(SelectField('Unidade', choices=allowed_units))

                elif attribute['value_type'] == 'string':
                    attribute_fields.append(StringField(
                        attribute['name'], validators=[Length(min=0, max=attribute['value_max_length'])]))

                elif attribute['value_type'] == 'number':
                    attribute_fields.append(IntegerField(
                        attribute['name'],
                        validators=[Length(min=0, max=attribute['value_max_length'])]))
                elif attribute['value_type'] == 'boolean':
                    attribute_fields.append(BooleanField(attribute['name']))

但这会创建一堆 UnboundFields。如果我尝试仅渲染每个字段 repr,它会向我显示:

<UnboundField(StringField, ('SKU ',), {'validators': [<wtforms.validators.Length object at 0x04DFBEF0>]})>

如果我尝试渲染该字段,它会给我一个异常:

TypeError: 'UnboundField' object is not callable

我正在遍历模板内的列表。

    {% for attribute in form.attribute_fields %}
    <div class="form-group blocked">
        {{ attribute() }}
    </div>
    {% endfor %}

如何绑定 UnboundField?

【问题讨论】:

  • 我读过这个问题,但我的问题是我在创建时只有字段ID。在这个线程中,OP 创建了另一个具有定义字段(书名)的类。就我而言,有些类别只有一两个字段,但其他类别则更多。每个类别都有不同类型的字段。我想知道是否可以使用 json 文件提供的信息来创建这些字段,如果这有意义的话。
  • 是的,这是可能的,但我建议你使用 javascript 来做到这一点
  • 是否可以混合使用 wtforms 和 javascript?我可以使用相同的语法访问表单数据吗?例如:form.attribute.data
  • 您可能需要使用一个小技巧,您需要添加一个隐藏字段(不是 HiddenField 类),然后将所有 javascript 字段以 json 之类的格式放入其中,然后您可以访问该隐藏字段现场数据和流程,我不确定它是否是最好的选择,但它比你现在做的更好

标签: python flask jinja2 flask-wtforms dynamicform


【解决方案1】:

要使用 wtforms 创建动态表单,请使用以下模板

def DynamicForm(*args, **kwargs):
    class StaticForm(FlaskForm):
        pass

    if args[0] == True:
        StaticForm.class_attrib1 = StringField(...)
    else:
        StaticForm.class_attrib2 = StringField(...)

    return StaticForm()

这会在函数的本地范围内建立一个 StaticForm,根据函数参数中的编程逻辑附加所有相关项,并返回一个实例化的表单:

form = DynamicForm(True)
# form has attribute: class_attrib1

这在某处的文档中有解释,但我现在找不到链接

【讨论】:

    猜你喜欢
    • 2016-12-26
    • 2019-07-19
    • 1970-01-01
    • 2015-02-02
    • 1970-01-01
    • 2018-10-27
    • 2023-04-03
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多