Flask web forms

Flask wtforms
Flask web form

In this tutorial you will learn how to do form validation with Flask. Forms play an important role in all web applications.

We use WTForms, a module for validation of forms. We will start with a simple form containing one field asking for a name.

Related course:
Python Flask: Make Web Apps with Python

from flask import Flask, render_template, flash, request
from wtforms import Form, TextField, TextAreaField, validators, StringField, SubmitField
 
# App config.
DEBUG = True
app = Flask(__name__)
app.config.from_object(__name__)
app.config['SECRET_KEY'] = '7d441f27d441f27567d441f2b6176a'
 
class ReusableForm(Form):
name = TextField('Name:', validators=[validators.required()])
 
@app.route("/", methods=['GET', 'POST'])
def hello():
form = ReusableForm(request.form)
 
print form.errors
if request.method == 'POST':
name=request.form['name']
print name
 
if form.validate():
# Save the comment here.
flash('Hello ' + name)
else:
flash('All the form fields are required. ')
 
return render_template('hello.html', form=form)
 
if __name__ == "__main__":
app.run()

We then create the template hello.html in the /templates/ directory:

 
<title>Reusable Form Demo</title>
 
{% with messages = get_flashed_messages(with_categories=true) %}
{% if messages %}
<ul>
                    {% for message in messages %}
 	<li>{{ message[1] }}</li>
{% endfor %}</ul>
{% endif %}
{% endwith %}
<form action="" method="post">
            {{ form.csrf }}
<div class="input text">
                {{ form.name.label }} {{ form.name }}</div>
<div class="input submit">
                <input type="submit" value="Submit"></div>
</form>

Start the application and open it in your webbrowser at http://127.0.0.1:5000.

python miniapp.py
* Running on http://127.0.0.1:5000/
* Restarting with reloader

If you will submit an empty form, you will get an error. But if you enter your name, it will greet you. Form validation is handled by the wtforms module, but because we gave the argument

name = TextField('Name:', validators=[validators.required()])

the field cannot be empty. Other parameters can be given here.

python wtforms
Python wtforms, text field validation. The app returns the name if entered

css with Flask

We use bootstrap to style the form.Bootstrap is a popular HTML, CSS, and JS framework for developing responsive, mobile first projects on the web. It makes front-end web development faster and easier. The output will be:

Flask wtforms
Flask wtforms

You can get the bootstrap files from http://getbootstrap.com/getting-started/#download and extract them in a new directory /static/. The code remains almost the same, but the template is changed. Code:

from flask import Flask, render_template, flash, request
from wtforms import Form, TextField, TextAreaField, validators, StringField, SubmitField
 
# App config.
DEBUG = True
app = Flask(__name__)
app.config.from_object(__name__)
app.config['SECRET_KEY'] = '7d441f27d441f27567d441f2b6176a'
 
class ReusableForm(Form):
name = TextField('Name:', validators=[validators.required()])
 
@app.route("/", methods=['GET', 'POST'])
def hello():
form = ReusableForm(request.form)
 
print form.errors
if request.method == 'POST':
name=request.form['name']
print name
 
if form.validate():
# Save the comment here.
flash('Hello ' + name)
else:
flash('Error: All the form fields are required. ')
 
return render_template('hello.html', form=form)
 
if __name__ == "__main__":
app.run()

We added bootstrap to the template hello.html:

 
<title>Reusable Form Demo</title>
        	 	<link rel="stylesheet" media="screen" href="static/bootstrap.min.css">
        	 	<link rel="stylesheet" href="static/bootstrap-theme.min.css">
       <meta name="viewport" content="width=device-width, initial-scale=1.0">
<div class="container">
<h2>Flask Web Form</h2>
<form action="" method="post" role="form">
    {{ form.csrf }}
<div class="form-group">
      <label for="name">Name:</label>
<input type="text" class="form-control" id="name" name="name" placeholder="What's your name?"></div>
<button type="submit" class="btn btn-success">Submit</button>
</form>{% with messages = get_flashed_messages(with_categories=true) %}
{% if messages %}
 
{% for message in messages %}
{% if "Error" not in message[1]: %}
<div class="alert alert-info">
                <strong>Success! </strong> {{ message[1] }}</div>
{% endif %}
 
{% if "Error" in message[1]: %}
<div class="alert alert-warning">
                {{ message[1] }}</div>
{% endif %}
{% endfor %}
{% endif %}
{% endwith %}
 
</div>

Flask registration form

We use the same principle to create a registration form asking for name, email and password. We update the Form class:

class ReusableForm(Form):
name = TextField('Name:', validators=[validators.required()])
email = TextField('Email:', validators=[validators.required(), validators.Length(min=6, max=35)])
password = TextField('Password:', validators=[validators.required(), validators.Length(min=3, max=35)])
 
def reset(self):
blankData = MultiDict([ ('csrf', self.reset_csrf() ) ])
self.process(blankData)

And we can get the variables passed using:

        name=request.form['name']
password=request.form['password']
email=request.form['email']

Full code:

from flask import Flask, render_template, flash, request
from wtforms import Form, TextField, TextAreaField, validators, StringField, SubmitField
 
# App config.
DEBUG = True
app = Flask(__name__)
app.config.from_object(__name__)
app.config['SECRET_KEY'] = '7d441f27d441f27567d441f2b6176a'
 
class ReusableForm(Form):
name = TextField('Name:', validators=[validators.required()])
email = TextField('Email:', validators=[validators.required(), validators.Length(min=6, max=35)])
password = TextField('Password:', validators=[validators.required(), validators.Length(min=3, max=35)])
 
@app.route("/", methods=['GET', 'POST'])
def hello():
form = ReusableForm(request.form)
 
print form.errors
if request.method == 'POST':
name=request.form['name']
password=request.form['password']
email=request.form['email']
print name, " ", email, " ", password
 
if form.validate():
# Save the comment here.
flash('Thanks for registration ' + name)
else:
flash('Error: All the form fields are required. ')
 
return render_template('hello.html', form=form)
 
if __name__ == "__main__":
app.run()

Update the template hello.html with this code:

 
<title>Reusable Form Demo</title>
        	 	<link rel="stylesheet" media="screen" href="static/bootstrap.min.css">
        	 	<link rel="stylesheet" href="static/bootstrap-theme.min.css">
       <meta name="viewport" content="width=device-width, initial-scale=1.0">
<div class="container">
<h2>Flask Web Form</h2>
<form action="" method="post" role="form">
    {{ form.csrf }}
<div class="form-group">
      <label for="name">Name:</label>
<input type="text" class="form-control" id="name" name="name" placeholder="What's your name?">
 
<label for="email">Email:</label>
<input type="text" class="form-control" id="email" name="email" placeholder="Your email will be used to contact you.">
 
<label for="password">Password:</label>
<input type="password" class="form-control" id="password" name="password" placeholder="Enter a password.">
 
</div>
<button type="submit" class="btn btn-success">Sign Up</button>
</form>{% with messages = get_flashed_messages(with_categories=true) %}
{% if messages %}
 
{% for message in messages %}
{% if "Error" not in message[1]: %}
<div class="alert alert-info">
                <strong>Success! </strong> {{ message[1] }}</div>
{% endif %}
 
{% if "Error" in message[1]: %}
<div class="alert alert-warning">
                {{ message[1] }}</div>
{% endif %}
{% endfor %}
{% endif %}
{% endwith %}
 
</div>

Output:

flask form bootstrap
flask form bootstrap

Download Flask Examples

WTForms can validate email, password, numbers and many more. For a list of validators see: http://wtforms.readthedocs.org/latest/validators.html

JSON encoding and decoding with Python

Introduction
JSON (JavaScript Object Notation) is frequently used between a server and a web application. An example of JSON data:

{
    "persons": [
        {
            "city": "Seattle", 
            "name": "Brian"
        }, 
        {
            "city": "Amsterdam", 
            "name": "David"
        }
    ]
}

The json module enables you to convert between JSON and Python Objects.

JSON conversion examples

Convert JSON to Python Object (Dict)
To convert JSON to a Python dict use this:

import json
 
json_data = '{"name": "Brian", "city": "Seattle"}'
python_obj = json.loads(json_data)
print python_obj["name"]
print python_obj["city"]

Convert JSON to Python Object (List)
JSON data can be directly mapped to a Python list.

import json
 
array = '{"drinks": ["coffee", "tea", "water"]}'
data = json.loads(array)
 
for element in data['drinks']:
    print element

Convert JSON to Python Object (float)
Floating points can be mapped using the decimal library.

import json
from decimal import Decimal
 
jsondata = '{"number": 1.573937639}'
 
x = json.loads(jsondata, parse_float=Decimal)
print x['number']

Convert JSON to Python Object (Example)
JSON data often holds multiple objects, an example of how to use that below:

import json
 
json_input = '{"persons": [{"name": "Brian", "city": "Seattle"}, {"name": "David", "city": "Amsterdam"} ] }'
 
try:
    decoded = json.loads(json_input)
 
    # Access data
    for x in decoded['persons']:
        print x['name']
 
except (ValueError, KeyError, TypeError):
    print "JSON format error"

Convert Python Object (Dict) to JSON
If you want to convert a Python Object to JSON use the json.dumps() method.

import json
from decimal import Decimal
 
d = {}
d["Name"] = "Luke"
d["Country"] = "Canada"
 
print json.dumps(d, ensure_ascii=False)
# result {"Country": "Canada", "Name": "Luke"}

Converting JSON data to Python objects 
JSON data can be converted (deserialized) to Pyhon objects using the json.loads() function.  A table of the mapping:

JSON Python
object dict
array list
string str
number (int) int
number (real) float
true True
false False
null None

Pretty printing

If you want to display JSON data you can use the json.dumps() function.

import json
 
json_data = '{"name": "Brian", "city": "Seattle"}'
python_obj = json.loads(json_data)
print json.dumps(python_obj, sort_keys=True, indent=4)

More
Google Charts with JSON data

Flask, JSON and the Google Charts API

This tutorial will teach you how to build a Flask app that combined with JSON and the Google Charts API. If you have no experience with Flask before I recommend reading my previous tutorials, they are great fun!

Related course
Python Flask: Make Web Apps with Python

$ pip install Flask

Create a file called hello.py

from flask import Flask
app = Flask(__name__)
 
@app.route("/")
def hello():
return "Hello World!"
 
if __name__ == "__main__":
app.run()

Finally run the web app using this command:

$ python hello.py
* Running on http://localhost:5000/

Open http://localhost:5000/ in your webbrowser, and “Hello World!” should appear.

Download Flask Examples

Get JSON data

To display awesome charts we first need some data. There are two common ways to get data in web apps: data from servers using an API (usually JSON) and data from databases. I use the Fixer.io JSON API to get some financial data, but any JSON API should do. If you are unfamiliar with JSON, see this article.

We wrote this script to get the exchange rates:

import json
import urllib2
 
def getExchangeRates():
rates = []
response = urllib2.urlopen('http://api.fixer.io/latest')
data = response.read()
rdata = json.loads(data, parse_float=float)
 
rates.append( rdata['rates']['USD'] )
rates.append( rdata['rates']['GBP'] )
rates.append( rdata['rates']['JPY'] )
rates.append( rdata['rates']['AUD'] )
return rates
 
rates = getExchangeRates()
print rates

Google Charts API with Flask

With the Google Charts API you can display live data on your site. There are a lot of great charts there that are easy to add to your Flask app. We simply give the data that we got from the server through JSON and parsed, to the Google Charts API.

Create a flask app with the directory /templates/ for your templates. This is the main Flask code:

from flask import Flask, flash, redirect, render_template, request, session, abort
import os
import json
import urllib2
 
tmpl_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'templates')
app = Flask(__name__, template_folder=tmpl_dir)
 
def getExchangeRates():
rates = []
response = urllib2.urlopen('http://api.fixer.io/latest')
data = response.read()
rdata = json.loads(data, parse_float=float)
 
rates.append( rdata['rates']['USD'] )
rates.append( rdata['rates']['GBP'] )
rates.append( rdata['rates']['HKD'] )
rates.append( rdata['rates']['AUD'] )
return rates
 
@app.route("/")
def index():
rates = getExchangeRates()
return render_template('test.html',**locals())
 
@app.route("/hello")
def hello():
return "Hello World!"
 
if __name__ == "__main__":
app.run()

And we have this template:

{% block body %}
 
<script type="text/javascript" src="https://www.google.com/jsapi"></script>
<div id="chart_div" style="width: 900px; height: 300px;">
<div>
 
<script type="text/javascript">//<![CDATA[ 
 
google.load('visualization', '1', {packages: ['corechart', 'bar']});<br />
google.setOnLoadCallback(drawBasic);</p>
<p>function drawBasic() {</p>
<p>      var data = google.visualization.arrayToDataTable([<br />
        ['Currency', 'Rate', { role: 'style' }],<br />
        ['USD', {{rates[0]}}, 'gold'],<br />
        ['GBP', {{rates[1]}}, 'silver'],<br />
        ['HKD', {{rates[2]}}, 'brown'],<br />
        ['AUD', {{rates[3]}}, 'blue']<br />
      ]);</p>
<p>      var options = {<br />
        title: 'Exchange rate overview',<br />
        chartArea: {width: '50%'},<br />
        hAxis: {<br />
          title: '',<br />
          minValue: 0<br />
        },<br />
        vAxis: {<br />
          title: ''<br />
        }<br />
      };</p>
<p>      var chart = new google.visualization.BarChart(document.getElementById('chart_div'));</p>
<p>      chart.draw(data, options);<br />
    }<br />
//]]>  </p>
<p></script>
 
{% endblock %}

Result:

Flask App
Flask App