Flask-WTF
extension, which is a wrapper WTForms
and integrates perfectly with Flask applications.
CSRF_ENABLED = True SECRET_KEY = 'you-will-never-guess'
Flask-WTF
extension needs. CSRF_ENABLED
activates the prevention of fake cross-site requests. In most cases, you will want to enable this option, which will make your application more secure.
SECRET_KEY
needed only when CSRF
enabled. It is used to create a cryptographic token that is used during form validation. When you write your application, make sure that your secret key is difficult to find.
from flask import Flask app = Flask(__name__) app.config.from_object('config') from app import views
Flask-WTF
forms are represented as subclass objects of the Form
class. The subclass of forms simply defines the form fields as variables in a class.
from flask.ext.wtf import Form from wtforms import TextField, BooleanField from wtforms.validators import Required class LoginForm(Form): openid = TextField('openid', validators = [Required()]) remember_me = BooleanField('remember_me', default = False)
Form
class and two field classes that we need, TextField
and BooleanField
.
Required
is a validator, a function that can be attached to a field, to validate the data sent by the user. The Required
validator simply checks that the field was not sent empty. Flask-WTF
has a lot of validators, we will use some new ones in the future.
LoginForm
class that we just created knows how to render form fields in HTML, so we just need to concentrate on the layout. Here is our login template: (app / templates / login.html file):
<!-- extend from base layout --> {% extends "base.html" %} {% block content %} <h1>Sign In</h1> <form action="" method="post" name="login"> {{form.hidden_tag()}} <p> Please enter your OpenID:<br> {{form.openid(size=80)}}<br> </p> <p>{{form.remember_me}} Remember Me</p> <p><input type="submit" value="Sign In"></p> </form> {% endblock %}
base.html
template through the inheritance operator, extending it. We will do this with all of our templates, ensuring that the layout is consistent across all pages.
form
template argument. We will take care of sending this template argument in the future when we write the view function that returns this template.
form.hidden_tag()
will be replaced with a hidden field to prevent CSRF, included in our settings file. This field must be in all of your forms if CSRF is enabled.
{{form.field_name}}
argument in the place of the template where the field is to be inserted. Some fields can take arguments. In our case, we ask the form to create our openid field with a width of 80 characters.
from flask import render_template, flash, redirect from app import app from forms import LoginForm # index @app.route('/login', methods = ['GET', 'POST']) def login(): form = LoginForm() return render_template('login.html', title = 'Sign In', form = form)
LoginForm
class, created an instance of it and sent it to a template. This is all you need to draw the form fields.
flash
and redirect
. We use them a little later.
route
decorator. Here we tell Flask that the view function accepts a GET
and POST
request. Without this, the view will only accept GET
requests. We want to receive POST
requests which will give the form with the data entered by the user.
Flask-WTF
facilitates our work is the processing of submitted data. This is a new version of our login
view function, which validates and saves form data (app / views.py file):
@app.route('/login', methods = ['GET', 'POST']) def login(): form = LoginForm() if form.validate_on_submit(): flash('Login requested for OpenID="' + form.openid.data + '", remember_me=' + str(form.remember_me.data)) return redirect('/index') return render_template('login.html', title = 'Sign In', form = form)
validate_on_submit
method does all the processing. If you call the method when the form is submitted to the user (that is, before the user has the opportunity to enter data there), then he will return False
, in which case you know that you must draw the template.
validate_on_submit
is called together as part of the form validate_on_submit
request, it will collect all the data, run any validators attached to the fields, and if everything is OK, it returns True
, which indicates the data is valid. This means that the data is safe to be included in the application.
False
and this will again cause the form to be drawn to the user, thereby making it possible to correct the errors. Later we will learn to show error messages when validation fails.
validate_on_submit
returns True
, our view function calls two new functions imported from Flask. The Flash
feature is a quick way to display a message on the next page presented to the user. In this case, we will use this for debugging as long as we do not have the infrastructure necessary for logging, instead, we will simply display a message that will show the sent data. Also, flash
extremely useful on the production server to provide user feedback.
<html> <head> {% if title %} <title>{{title}} - microblog</title> {% else %} <title>microblog</title> {% endif %} </head> <body> <div>Microblog: <a href="/index">Home</a></div> <hr> {% with messages = get_flashed_messages() %} {% if messages %} <ul> {% for message in messages %} <li>{{ message }} </li> {% endfor %} </ul> {% endif %} {% endwith %} {% block content %}{% endblock %} </body> </html>
redirect
. This function redirects the client web browser to another page, instead of the requested one. In our presentation function, we used a redirect to the main page developed in the previous sections. Keep in mind that flash messages will be displayed even if the function ends with redirection.
Required
validator stops the transfer process.
Flask-WTF
also facilitates this task.
Flask-WTF
adds a visual error message to the form object. These messages are available in the template, so we just need to add some logic to display them.
<!-- extend base layout --> {% extends "base.html" %} {% block content %} <h1>Sign In</h1> <form action="" method="post" name="login"> {{form.hidden_tag()}} <p> Please enter your OpenID:<br> {{form.openid(size=80)}}<br> {% for error in form.errors.openid %} <span style="color: red;">[{{error}}]</span> {% endfor %}<br> </p> <p>{{form.remember_me}} Remember Me</p> <p><input type="submit" value="Sign In"></p> </form> {% endblock %}
form.errors._
. In our case, we use form.errors.openid
. We display these messages in red to draw the user's attention to them.
OPENID_PROVIDERS = [ { 'name': 'Google', 'url': 'https://www.google.com/accounts/o8/id' }, { 'name': 'Yahoo', 'url': 'https://me.yahoo.com' }, { 'name': 'AOL', 'url': 'http://openid.aol.com/<username>' }, { 'name': 'Flickr', 'url': 'http://www.flickr.com/<username>' }, { 'name': 'MyOpenID', 'url': 'https://www.myopenid.com' }]
@app.route('/login', methods = ['GET', 'POST']) def login(): form = LoginForm() if form.validate_on_submit(): flash('Login requested for OpenID="' + form.openid.data + '", remember_me=' + str(form.remember_me.data)) return redirect('/index') return render_template('login.html', title = 'Sign In', form = form, providers = app.config['OPENID_PROVIDERS'])
app.config
. Next, the list is added to the render_template
call as a template argument.
<!-- extend base layout --> {% extends "base.html" %} {% block content %} <script type="text/javascript"> function set_openid(openid, pr) { u = openid.search('<username>') if (u != -1) { // openid requires username user = prompt('Enter your ' + pr + ' username:') openid = openid.substr(0, u) + user } form = document.forms['login']; form.elements['openid'].value = openid } </script> <h1>Sign In</h1> <form action="" method="post" name="login"> {{form.hidden_tag()}} <p> Please enter your OpenID, or select one of the providers below:<br> {{form.openid(size=80)}} {% for error in form.errors.openid %} <span style="color: red;">[{{error}}]</span> {% endfor %}<br> |{% for pr in providers %} <a href="javascript:set_openid('{{pr.url}}', '{{pr.name}}');">{{pr.name}}</a> | {% endfor %} </p> <p>{{form.remember_me}} Remember Me</p> <p><input type="submit" value="Sign In"></p> </form> {% endblock %}
Source: https://habr.com/ru/post/194062/