在 Flask 的 WTforms 中创建动态字段
create dynamic fields in WTform in Flask
我想使用 WTForms 和 Jinja2 在 Flask 中创建不同的表单。我调用了具有字段类型的 mysql。
所以 table 可能是:
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 循环中添加字段,但是如果表单被回发,如果我没有在 class?我在表单中确实有 form_id,因此我可以生成它然后进行验证。
动态添加字段
I think best would be to create an empty form and then add fields in a for-loop, however if a form is posted back how can I validate the form if I don't have it defined in a class?
在实例化表单之前使用 setattr
将字段添加到 表单 class:
def update_form(request):
table = query()
class MyForm(Form):
pass
for row in table:
setattr(MyForm, row.key, SomeField())
form = MyForm(request.form)
但是,我认为你的问题是我试图在下面解决的更大问题的一部分。
将 tables 映射到表单
您的 table 似乎很好地映射到表单本身。如果您想从 table 动态创建表单,您可以自己编写逻辑。但是,当支持的领域和选项范围扩大时,维护工作可能会非常繁重。如果您使用 SQLAlchemy, you might want to take a look at WTForms-Alchemy。来自它的介绍:
Many times when building modern web apps with SQLAlchemy you’ll have
forms that map closely to models. For example, you might have a
Article model, and you want to create a form that lets people post new
article. In this case, it would be time-consuming to define the field
types and basic validators in your form, because you’ve already
defined the fields in your model.
WTForms-Alchemy provides a helper class that let you create a Form
class from a SQLAlchemy model.
助手 class 是 ModelForm
,按照您的 table 的风格,下面是一个 Python 2/3 的 WTForms-Alchemy 示例。首先安装包 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 本质上是这样的:
class MyForm(Form):
title = StringField(validators=[InputRequired(), Length(max=5)])
gender = SelectField(choices=[('male', 'male'), ('female', 'female')])
text = TextField()
WTForms-Alchemy 的文档似乎非常全面。我自己没有用过,但如果我有类似的问题要解决,我一定会尝试一下。
我想使用 WTForms 和 Jinja2 在 Flask 中创建不同的表单。我调用了具有字段类型的 mysql。
所以 table 可能是:
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 循环中添加字段,但是如果表单被回发,如果我没有在 class?我在表单中确实有 form_id,因此我可以生成它然后进行验证。
动态添加字段
I think best would be to create an empty form and then add fields in a for-loop, however if a form is posted back how can I validate the form if I don't have it defined in a class?
在实例化表单之前使用 setattr
将字段添加到 表单 class:
def update_form(request):
table = query()
class MyForm(Form):
pass
for row in table:
setattr(MyForm, row.key, SomeField())
form = MyForm(request.form)
但是,我认为你的问题是我试图在下面解决的更大问题的一部分。
将 tables 映射到表单
您的 table 似乎很好地映射到表单本身。如果您想从 table 动态创建表单,您可以自己编写逻辑。但是,当支持的领域和选项范围扩大时,维护工作可能会非常繁重。如果您使用 SQLAlchemy, you might want to take a look at WTForms-Alchemy。来自它的介绍:
Many times when building modern web apps with SQLAlchemy you’ll have forms that map closely to models. For example, you might have a Article model, and you want to create a form that lets people post new article. In this case, it would be time-consuming to define the field types and basic validators in your form, because you’ve already defined the fields in your model.
WTForms-Alchemy provides a helper class that let you create a Form class from a SQLAlchemy model.
助手 class 是 ModelForm
,按照您的 table 的风格,下面是一个 Python 2/3 的 WTForms-Alchemy 示例。首先安装包 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 本质上是这样的:
class MyForm(Form):
title = StringField(validators=[InputRequired(), Length(max=5)])
gender = SelectField(choices=[('male', 'male'), ('female', 'female')])
text = TextField()
WTForms-Alchemy 的文档似乎非常全面。我自己没有用过,但如果我有类似的问题要解决,我一定会尝试一下。