WTForm: FieldList with SelectField, how do I render?

I have this order form which allows my users to create an order. An order consists of multiple tuples of (producetype, quantity) . Producetype should be rendered in a <select> form while quantity can just be an input. The choices of producetype should be dynamically added because that could change. Currently, I've written this in bare html

在这里输入图像描述

I would like to use WTForm for this because WTForm really simplifies my code. 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:

  • How can I dynamically add choices to the order_entries field of the OrderForm?
  • 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?
  • My code is available here: https://gist.github.com/vicngtor/f8c8f0519dbd6b3b6110


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

    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. WTForms has a naming convention for addressing indices on form fields. Its just 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.

    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. You can assign choices any iterable of 2-tuples. 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?

    You can just bind objects directly to the form using the obj keyword argument. WTForms is smart enough to dynamically build the form from the object's attributes.

    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. On render this will generate the following(unstyled):

    在这里输入图像描述


    Add a SubmitField to your to OrderForm :

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

    and then call it from your view, and use the append_entry method of FieldList :

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

    Hope that helps !

    链接地址: http://www.djcxy.com/p/21172.html

    上一篇: 芹菜广播vs RabbitMQ粉丝

    下一篇: WTForm:带SelectField的FieldList,我该如何渲染?