© Photographer, 133RF.com

© Photographer, 133RF.com

Web applications with Flask

A Tasty Drop

Article from ADMIN 13/2013
By
Django is often used for creating Python web applications, but a lesser known option called Flask can offer more flexibility. In this article, we will take a closer look at Flask.

If you are considering writing a web application with Python, one obvious choice is Django, which enjoys popularity within the Python world that is similar to Rails in the Ruby community. An alternative to Django is Flask [1], which has become increasingly popular since its inception in 2010.

The advantage of Django is that it comes with more or less everything you need for many web applications: templates, a database connection, user authentication, and so on. However, it is difficult to leave out or replace components. If you prefer a more flexible approach, you should take a look at Flask. Out of the box, Flask relies on underpinnings provided by a WSGI library by the name of Werkzeug [2], which was written by Flask programmer Armin Ronacher. The same applies to the Jinja2 template library, which Flask uses by default.

WSGI [3] is a specification that defines how a web server software and a web application written in Python communicate. This could be the Apache or Nginx web server with their WSGI modules or special WSGI web servers, such as Gunicorn or uWSGI. The Flask library also contains a separate web server for development.

The latest version of Flask, 0.9, was released in July 2012, and it is uncertain when version 0.10 will be released. Flask requires at least Python 2.5; Python 3 is not currently supported. The easiest approach is to install Flask with Virtualenv [4], which maintains a local version of Python and its modules in a local directory, thus avoiding conflicts with the other projects on a server. Virtualenv itself is available with most Linux distributions. Alternatively, you can install it with the Python package management tools pip and easy_install.

The following commands create a new project directory; change to this directory and parse the shell variables that define the virtual Python environment (Figure 1):

Figure 1: Virtualenv installs a Python environment in a directory. Newly installed extension modules are stored in a subdirectory below it.
virtualenv webproject
cd webproject
source bin/activate

You can return to your normal Python environment at system level by typing deactivate. As long as you are in Virtualenv, which is shown by the (webproject) prompt prefix, you can install Python modules for the local directory structure only. If you issue the pip install Flask command to install the library, you will find it in webproject/lib/python2.7/site-packages/flask. Tools and Jinja2 are then installed by Pip.

Routing

Flask itself is little more than the glue that keeps the WSGI layer and the template library together. In particular, it handles routing that maps URLs to functions. The blueprint for this comes from the Sinatra Ruby framework [5], which has been copied in many variants for many different programming languages. Besides Flask, another option is Bottle, which is covered by Admin Story in this issue.

With a Flask application, you basically assign functions to individual URLs using Python decorators; the URLs then rely on templates to render individual websites. A simple example looks like this:

@app.route('/')
def homepage():
    return "This is the homepage"

For this approach to work, you obviously need to import the Flask module at the start of the script. The function name is not important at this point. The only important thing is that the URL specified in the @app.route decorator, /, is linked to a function. The complete minimalist web application is given in Listing 1. The typical Python idiom ensures that app.run() only runs if the script is called by the interpreter and not imported by another module.

Listing 1

Simple Flask App

01 from flask import Flask
02 app = Flask("My app")
03
04 @app.route('/')
05 def homepage():
06     return 'This is the homepage'
07
08 if __name__ == '__main__':
09     app.run()

Note the final slash in pathnames in the listing. If you type a slash, as in @app.route("/article/"), the URL will work either with or without it. But if you just write "/article", trying to access http://Server/article/ will result in a 404 error message. If you want to differentiate by the HTTP verb in the call to the URL, which is typical of REST applications, you can use the methods keyword parameter to do so. The following URL can only be called by a POST:

@app.route('/login', methods=['POST'])

By default, the built-in web server with local host IP 127.0.0.1 runs on port 5000. To change this, pass in the keyword parameters host=<IP address> and port=<port number> to the run() method. Make sure that your own application is not available via an address that is reachable from the Internet while it is still running in debug mode. In this case, you can run your own Python instructions on the server from your browser!

Templates

The bad old days in which websites were still output using Print statements should be a thing of the past. This legacy approach not only led to unmanageable code, but typically also to security holes.

The alternative is the use of templates, which isolate the code from the presentation. If you have Flask and the Jinja2 library, you can do this in a single line:

render_template("homepage.html")

Because this approach would only let you serve up a static page, render_template naturally also lets you pass in variables, which the template outputs using {{ Variable }}. Additionally, you can use control structures, such as for loops, that iterate over sequences (Listing 2). They lie between {% and %}, but you can change the syntax if needed.

Listing 2

Templates

01 <!doctype html>
02 <head>
03     {% block head %}
04     <link rel="stylesheet" href="style.css" />
05     {% endblock %}
06 </head>
07 <body>
08 <ul>
09 {% for item in seq %}
10     <li>{{ item }}</li>
11 {% endfor %}
12 </ul>
13 </body>
14 </html>

If a variable contains HTML code, Jinja2 automatically masks it before output – again this is protection against undesirable injection of exploit code. If you can rely on the content of a variable, you can prevent this behavior manually.

What is particularly interesting here is that templates also support inheritance. Thus, you can outsource elements of all of your websites into a basic template, from which you can then derive all other templates. The basic template can define default blocks that the derivate templates "overwrite" with their own content. Alternatively, templates can integrate other templates, thus allowing programmers to create a modular structure for a website, if needed.

Variables

To make web applications from static HTML pages, they need to respond dynamically to user input that the web browser sends in the form of GET or POST requests. For example, if the directory for the blog entries is followed by an ID, Flask can process it with the following code block:

@app.route('/blog/<blog_id>')
def show_blog(blog_id):
    render_template("blog.html", blog_id)

Also, you can convert the variable directly from a string to another type (e.g., integer: <int:blog_id>). To access variables transferred by POSTing an HTML form, Flask accesses the HTTP Request object, which imports the instruction from flask import request into the script. The Python form dictionary for the request object contains the form variables:

login = request.form['login']

If the variable is not found, the method creates a type KeyError exception. If you don't handle this exception yourself, the web application outputs an HTTP 400 "Bad Request" error.

To store variables between requests, Flask uses a session object, which also works like a Python dictionary. For security reasons, it is important to use a robust (i.e., random) key to sign the sessions.

Buy ADMIN Magazine

SINGLE ISSUES
 
SUBSCRIPTIONS
 
TABLET & SMARTPHONE APPS
Get it on Google Play

US / Canada

Get it on Google Play

UK / Australia

Related content

comments powered by Disqus