I want to create different forms in Flask using WTForms and Jinja2. I make a call to mysql, which has the type of field.
So i.e. the table could be:
form_id | type | key | options | default_value
1 | TextField | title | | test1
1 | SelectField | gender |{'male','female'}|
2 | TextAreaField| text | | Hello, World!
Then I query on form_id. then I want to create a form with WTforms having the fields of the rows which are returned.
For a normal form I do:
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)
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? I do have the form_id in the form so I can generate it and then validate.
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?
Add the fields to the form class using setattr
before the form is instantiated:
def update_form(request):
table = query()
class MyForm(Form):
pass
for row in table:
setattr(MyForm, row.key, SomeField())
form = MyForm(request.form)
However, I think your question is part of a bigger problem, which I have tried to address below.
Your table seem to map very nicely to the form itself. If you want to create forms dynamically from your tables, you could write the logic yourself. But when the range of fields and options to support grows, it can be a lot of work to maintain. If you are using SQLAlchemy, you might want to take a look at WTForms-Alchemy. From its introduction:
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.
The helper class is ModelForm
, and in the style of your table, below is a Python 2/3 sample with WTForms-Alchemy. Install the package wtforms-alchemy
first, which will pull in SQLAlchemy and WTForms as well.
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)
Running the above code prints:
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>
As you can see, WTForms-Alchemy did a whole lot with MyForm
. The class is essentially this:
class MyForm(Form):
title = StringField(validators=[InputRequired(), Length(max=5)])
gender = SelectField(choices=[('male', 'male'), ('female', 'female')])
text = TextField()
The documentation for WTForms-Alchemy seems to be very comprehensive. I have not used it myself, but if I had a similar problem to solve I would definitely try it out.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With