在Flask中的WTform中创建动态字段

时间:2016-09-22 13:09:59

标签: python flask wtforms

我想使用WTForms和Jinja2在Flask中创建不同的表单。我调用mysql,它具有字段类型。

因此表格可以是:

 form_id   |  type         |   key    |    options      | default_value
    1      |  TextField    |   title  |                 |      test1
    1      |  SelectField  |   gender |{'male','female'}|      
    2      |  TextAreaField|   text   |                 |   Hello, World!

然后我在form_id上查询。然后我想创建一个带有WTforms的表单,其中包含返回的行的字段。

对于普通表格,我这样做:

class MyForm(Form):

    title = TextField('test1', [validators.Length(min=4, max=25)])
    gender = SelectField('', choices=['male','female'])


def update_form(request):

     form = MyForm(request.form)

     if request.method == 'POST' and form.validate():
          title = form.title.data
          gender = form.gender.data

          #do some updates with data
          return .....
     else:
          return render_template('template.html',form)
          #here should be something like:
          #dict = query_mysql()
          #new_form = MyForm(dict);
          #render_template('template.html',new_form)

我认为最好是创建一个空表单,然后在for循环中添加字段,但是如果表单被回发,如果我没有在类中定义它,我如何验证表单?我在表单中有form_id,因此我可以生成它然后验证。

1 个答案:

答案 0 :(得分:6)

动态添加字段

  

我认为最好是创建一个空表单然后在for循环中添加字段,但是如果表单被回发,如果我没有在类中定义它,我如何验证表单?

在实例化表单之前,使用setattr将字段添加到表单类

def update_form(request):
    table = query()

    class MyForm(Form):
        pass

    for row in table:
        setattr(MyForm, row.key, SomeField())

    form = MyForm(request.form)

但是,我认为你的问题是一个更大问题的一部分,我试图在下面解决。

将表映射到表单

你的表似乎很好地映射到表单本身。如果要从表中动态创建表单,可以自己编写逻辑。但是当支持的字段和选项范围增加时,维护可能需要做很多工作。如果您使用的是SQLAlchemy,则可能需要查看WTForms-Alchemy。从其介绍:

  

很多时候,使用SQLAlchemy构建现代Web应用程序时,您将拥有   与模型紧密贴图的表格。例如,你可能有一个   文章模型,您想要创建一个允许人们发布新内容的表单   文章。在这种情况下,定义字段将是耗时的   您的表单中的类型和基本验证器,因为您已经   定义了模型中的字段。

     

WTForms-Alchemy提供了一个帮助程序类,可以让您创建一个表单   来自SQLAlchemy模型的类。

帮助程序类是ModelForm,在表的样式中,下面是使用WTForms-Alchemy的Python 2/3示例。首先安装包wtforms-alchemy,这也将引入SQLAlchemy和WTForms。

from __future__ import print_function
from __future__ import unicode_literals

import sqlalchemy as sa
from sqlalchemy import create_engine
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker
from wtforms_alchemy import ModelForm

engine = create_engine('sqlite:///:memory:')
Base = declarative_base(engine)
Session = sessionmaker(bind=engine)
session = Session()


class MyClass(Base):
    __tablename__ = 'mytable'

    id = sa.Column(sa.BigInteger, autoincrement=True, primary_key=True)
    title = sa.Column(sa.Unicode(5), nullable=False)
    gender = sa.Column(sa.Enum('male', 'female', name='gender'))
    text = sa.Column(sa.Text)


class MyForm(ModelForm):
    class Meta:
        model = MyClass


form = MyForm()

print('HTML\n====')
for field in form:
    print(field)

运行上面的代码打印:

HTML
====
<input id="title" name="title" required type="text" value="">
<select id="gender" name="gender"><option value="male">male</option><option value="female">female</option></select>
<textarea id="text" name="text"></textarea>

正如你所看到的,WTForms-Alchemy用MyForm做了很多。该课程基本上是这样的:

class MyForm(Form):
    title = StringField(validators=[InputRequired(), Length(max=5)])
    gender = SelectField(choices=[('male', 'male'), ('female', 'female')])
    text = TextField()

WTForms-Alchemy的文档似乎非常全面。我自己没有用过它,但是如果我有类似的问题需要解决,我肯定会尝试一下。