带SelectField的FieldList,如何呈现?

2024-05-29 10:26:19 发布

您现在位置:Python中文网/ 问答频道 /正文

我有一个订单,允许我的用户创建一个订单。一个顺序由多个(producetype, quantity)元组组成。Producetype应该以<select>形式呈现,而quantity可以只是一个输入。应该动态添加producetype的选项,因为这可能会更改。目前,我已经用纯html编写了这个

enter image description here

我想使用WTForm来实现这一点,因为WTForm确实简化了我的代码。但是,我不能这样做:

代码:

class OrderEntryForm(Form):
  quantity = IntegerField('Quantity',
                          [validators.Required(), validators.NumberRange(min=1)])
  # we will be dynamically adding choices
  producetype = SelectField('Produce',
                            [validators.Required()],
                            choices=[])

class OrderForm(Form):
  name = TextField('Crop', [validators.Length(min=3, max=60)])
  due_date = DateField('Due Date', [validators.required()])
  order_entries = FieldList(FormField(OrderEntryForm))

我有以下问题:

  1. 如何向OrderForm的order_entries字段动态添加选项?
  2. 如果我有一个命令order = { name:hello, due_date:2014-06-18, order_entries:[ {producetype_id: 1, quantity: 2}, {producetype_id: 3, quantity: 4}] },如何用正确的OrderEntryForm值填充我的OrderForm

我的代码在这里可用:https://gist.github.com/vicngtor/f8c8f0519dbd6b3b6110


Tags: 代码订单form选项required动态orderquantity
3条回答

SubmitField添加到您的收件人OrderForm

submit_something = SubmitField((u'Add something'))

然后从您的视图调用它,并使用FieldListappend_entry方法:

if form.submit_something.data:
         form.order_entries.append_entry()
         return render_template('yourtemplate.html', form=form)

希望能有帮助!

对于其他被SelectFields+fieldlist困扰的人- 这就是我用SelectFields(inspire dbynsfyn55's answer)实现FieldList的方法。这种方法基于JSON日期动态地向/home路由呈现任意数量的SelectFields。

路线(routes.py):

@app.route('/home', methods=['POST', 'GET'])
def home():
    custom_metadata = data

    select_metadata_form_list = SelectFormList()
    select_metadata_form_list.select_entries = get_select_entries()

    context = {
        "select_metadata_form_list": select_metadata_form_list,
    }

    return render_template('home.html', **context)

表单(forms.py):

class SelectForm(FlaskForm):
    select = SelectField("Placeholder", choices=[])


class SelectFormList(FlaskForm):
    select_entries = FieldList(FormField(SelectForm))

模板home.html):

{% for select_form in select_metadata_form_list.select_entries %}
    {{select_form.select.label}}: {{ select_form.select}}
{% endfor %}

帮助程序方法(app.py):

def get_select_entries():
    """
    Converts custom metadata to a forms.SelectForm(), which can then be
    used by SelectFormlist() to dynamically render select items.

    :return: <forms.SelectForm object>
    """
    select_data = get_select_data_from_custom_metadata()

    select_data_labeled = get_labled_select_data(select_data=select_data)

    all_select_items = []
    for select_dict in select_data_labeled:
        for k, v in select_dict.items():
            select_id = uuid.uuid1()   # allows for multiple selects
            select_entry = SelectForm()
            select_entry.select.label = k
            select_entry.id = select_id
            select_entry.select.choices = v
            all_select_items.append(select_entry)

    return all_select_items
def get_select_data_from_custom_metadata():
    """
    [
    {"Seniority": ["Intern", "Associate", "Senior"]}
    ]
    :return: List of dictionaries containing key and list of select values
    """
    type = "select"
    select_data = []
    custom_metadata = get_custom_metadata()

    for field in custom_metadata["fields"]:
        if field["type"] == type:
            select_data.append({field["key"]: field["data_list"]})

    return select_data

数据(custom_metadata.json):

{
  "fields": [
    {
      "type": "text",
      "key": "Position"
    },

    {
      "type": "select",
      "key": "Seniority",
      "data_list": ["Intern", "Associate", "Senior", "Executive"]
    },
    {
      "type": "select",
      "key": "Company",
      "data_list": ["Ford", "Chevy", "Toyota"]
    },
    {
      "type": "select",
      "key": "Team",
      "data_list": ["Bucks", "Raptors", "Thunder"]
    }
  ]
}

结果

enter image description here

How can I dynamically add choices to the order_entries field of the OrderForm

这取决于你的意思

如果您的意思是希望在渲染后将行项目添加到表单中。您必须使用DOM操作在客户端添加这些内容。WTForms有一个命名约定,用于处理表单字段上的索引。只是name="<form-field)name>-<index>"。如果您使用遵循此约定的javascript添加名称,WTForms将知道如何在后端处理它。

如果您的意思是希望有一个动态选择列表,那么您可以在表单中的FieldList被实例化之后对其进行迭代。您可以分配choices任何2元组的iterable。在下面的例子中,我直接分配它们,但它们也可以很容易地从存储器中检索出来。

order_form = OrderForm()
for sub_form in order_form.order_entries:
    sub_form.producetype.choices = [('2', 'apples'), ('2', 'oranges')]

how can populate my OrderForm with the right OrderEntryForm values?

只需使用obj关键字参数将对象直接绑定到表单。WTForms足够聪明,可以根据对象的属性动态构建表单。

from wtforms import Form, IntegerField, SelectField, TextField, FieldList, FormField
from wtforms import validators
from collections import namedtuple

OrderEntry = namedtuple('OrderEntry', ['quantity', 'producetype'])
Order = namedtuple('Order', ['name', 'order_entries'])

class OrderEntryForm(Form):
  quantity = IntegerField('Quantity',
                          [validators.Required(), validators.NumberRange(min=1)])
  # we will be dynamically adding choices
  producetype = SelectField('Produce',
                            [validators.Required()],
                            choices=[
                                (1, 'carrots'),
                                (2, 'turnips'),
                            ])

class OrderForm(Form):
  name = TextField('Crop', [validators.Length(min=3, max=60)])
  order_entries = FieldList(FormField(OrderEntryForm))

# Test Print of just the OrderEntryForm
o_form = OrderEntryForm()
print o_form.producetype()

# Create a test order
order_entry_1 = OrderEntry(4, 1)
order_entry_2 = OrderEntry(2, 2)

order = Order('My First Order', [order_entry_1, order_entry_2])

order_form = OrderForm(obj=order)

print order_form.name
print order_form.order_entries

上面的示例创建一个样本Order,并将其提供给obj关键字。渲染时,将生成以下内容(未设置样式):

enter image description here

相关问题 更多 >

    热门问题