简体   繁体   English

WTForm:带有 SelectField 的 FieldList,我该如何渲染?

[英]WTForm: FieldList with SelectField, how do I render?

I have this order form that allows my users to create an order.我有这个订单表,允许我的用户创建订单。 An order consists of multiple tuples of (producetype, quantity) .一个订单由多个(producetype, quantity)元组组成。 Producetype should be rendered in a <select> form while quantity can just be an input. Producetype 应该以<select>形式呈现,而数量可以只是一个输入。 The choices of producetype should be dynamically added because that could change.应该动态添加生产类型的选择,因为这可能会改变。 Currently, I've written this in bare html目前,我已经用裸 html 写了这个

在此处输入图片说明

I would like to use WTForm for this because WTForm really simplifies my code.我想为此使用 WTForm,因为 WTForm 确实简化了我的代码。 However, I am unable to do so:但是,我无法这样做:

Code:代码:

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))

I have the following questions:我有以下问题:

  1. How can I dynamically add choices to the order_entries field of the OrderForm?如何将选项动态添加到order_entries字段?
  2. If I have an order, order = { name:hello, due_date:2014-06-18, order_entries:[ {producetype_id: 1, quantity: 2}, {producetype_id: 3, quantity: 4}] } , how can populate my OrderForm with the right OrderEntryForm values?如果我有订单, order = { name:hello, due_date:2014-06-18, order_entries:[ {producetype_id: 1, quantity: 2}, {producetype_id: 3, quantity: 4}] } ,如何填充我的具有正确OrderEntryForm值的OrderForm

How can I dynamically add choices to the order_entries field of the OrderForm如何将选项动态添加到 OrderForm 的 order_entries 字段

This depends on what you mean这取决于你的意思

If you mean you want to add lines items to the form after render.如果您的意思是要在渲染后向表单添加行项目。 You have to use DOM manipulation to add these on the client side.您必须使用 DOM 操作在客户端添加这些。 WTForms has a naming convention for addressing indices on form fields. WTForms有一个命名约定来处理表单字段上的索引。 Its just name="<form-field)name>-<index>" .它只是name="<form-field)name>-<index>" If you add a name using javascript that follows this convention WTForms will know how to handle it on the backend.如果您使用遵循此约定的 javascript 添加名称, WTForms将知道如何在后端处理它。

If you mean you want to have a dynamic choice list then you can just iterate over the FieldList in the form after its instantiated.如果你的意思是你想要一个动态的选择列表,那么你可以在实例化后迭代表单中的FieldList You can assign choices any iterable of 2-tuples.您可以分配choices任何可迭代的 2 元组。 In the example below I am assigning them directly but they could just as easily have been retrieved from storage.在下面的示例中,我直接分配了它们,但它们也可以很容易地从存储中检索。

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?如何使用正确的 OrderEntryForm 值填充我的 OrderForm?

You can just bind objects directly to the form using the obj keyword argument.您可以使用obj关键字参数将对象直接绑定到表单。 WTForms is smart enough to dynamically build the form from the object's attributes. 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

The above example creates a sample Order and supplies it to the obj keyword.上面的示例创建了一个示例Order并将其提供给obj关键字。 On render this will generate the following(unstyled):在渲染时,这将生成以下内容(无样式):

在此处输入图片说明

For anyone else stumped by SelectField s + FieldList s, this is how I implemented a FieldList with SelectField s (inspired by nsfyn55's answer ).对于其他被SelectField s + FieldList s 难倒的人,这就是我使用SelectField s 实现FieldList的方式(受nsfyn55 的回答启发)。 This approach dynamically renders an arbitrary number of SelectFields to the /home route based on JSON data.这种方法基于 JSON 数据将任意数量的 SelectField 动态呈现到/home路由。

The route (routes.py):路线(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)

The forms (forms.py):表格(forms.py):

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


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

The template ( home.html ):模板home.html ):

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

Helper methods (app.py):辅助方法(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

The 'data' (custom_metadata.json): “数据” (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"]
    }
  ]
}

The result :结果

在此处输入图片说明

Add a SubmitField to your to OrderForm :SubmitField添加到您的 to OrderForm

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

and then call it from your view, and use the append_entry method of FieldList :然后从您的视图调用它,并使用append_entry的方法FieldList

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

Hope that helps !希望有帮助!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM