xxx WIP xxx
for now this is the raw Flask text, to be updated for FastAPI
xxx WIP xxx
A recurring thing in web development is forms:
Authentication
Messaging
User interface
...
A need
Specify the fields (name and nature/type); aggregate data entered by the user; send this data to the backend; process this data and emit a response
A ready-made Python module WTForm and its interface for Flask FlaskWTF
pip install flask-wtfPrinciples¶
Using Flask-WTF is done by defining your own form by creating a class inheriting from the FlaskForm class.
from flask_wtf import FlaskFormFor example, a login form could be written as follows:
from wtforms import StringField, PasswordField, BooleanField, SubmitField
from wtforms.validators import DataRequired
class LoginForm(FlaskForm):
username = StringField('Username', validators=[DataRequired()])
password = PasswordField('Password', validators=[DataRequired()])
submit = SubmitField('Sign In')Input types¶
The different predefined types in WTForm are as follows:
BooleanField: represents a booleanIntegerFieldFloatFieldDecimalFieldSelectField: choice from a list of optionsDateField: represents a dateFileField: for file selectionMultipleFileField: for multiple selectionPasswordField: field for password (displays stars)TextAreaField: free text input fieldSubmitField: the form submission button
Possibility to add “validators”
DataRequired: required fieldEmail: the field is an email addressEqualTo: equality testNumberRange: numeric value in a rangeOptional: optional field
Using with templates¶
<html>
<head>
<title>Flask WTF</title>
</head>
<body>
<hr />
<h1>Sign In</h1>
<form action="" method="post" novalidate>
{{ form.hidden_tag() }}
<p>
{{ form.username.label }}<br />
{{ form.username(size=32) }}
</p>
<p>
{{ form.password.label }}<br />
{{ form.password(size=32) }}
</p>
<p>{{ form.submit() }}</p>
</form>
</body>
</html>The form.hidden_tag method will generate a line like:
<input
id="csrf_token"
name="csrf_token"
type="hidden"
value="ImI0ODg5NjE3NzdiYjM5NWJlZWRiYzE3MDlmZjBhNjFkMDhlMjE4M2Ii.Xq_IiQ.GG9q2vWBhqbZGuGGJue2MwDIQwI"
/>No functional interest. However useful for security 🚨 and to protect against attacks like
Cross Site Request Forgery
And this requires defining a secret key
app.config['SECRET_KEY'] = os.urandom(32))
Form data in the handlers¶
We can directly reuse the LoginForm class in our handler functions, for example:
@app.route("/", methods=['GET', 'POST'])
def login():
form = LoginForm()
if form.validate_on_submit():
print(f"Log in requested for {form.username.data} with password {form.password.data}")
## Add function here to check password
return redirect("/home")
return render_template("login.html", form=form)Notes
login.htmlmust be in a/templatesdirectoryits extension must be
.html,.htm,.xml,.xhtml, or.svg
A little bonus: Cookies 🍪¶
@app.route('/route/install/cookie')
def handler():
resp = make_response(render_template('mapage.html'))
resp.set_cookie('cookie', "eat me")
return resp@app.route('/route/read/cookie')
def handler():
name = request.cookies.get('cookieName')
# ...For example, number of times we visit a page!
A word on the Session concept¶
Very often need the concept of a user session
Store user-specific information between two requests
Possible to do this manually 🖖🏻 using cookies 🍪 ...
but Flask can do it all for you
from Flask import sessionNeed a bit of config though
app.config["SECRET_KEY"] = "a secret"@app.route("/une/url/<string:username>")
def handler( username ):
session["name"] = username
return "Ok I saved it"
@app.route("/")
def index():
name = session.get("name")
if name:
return f"Hello {name}"
else:
return ("Please first make a request"
" to /une/url/<username>")
