Flask Python Web framework overview

Overview

Flask is one of the Python’s most popular web frameworks. This is an overview of its main concepts to get started quickly and understand how it works.

Flask is a microframework for Python based on Werkzeug, Jinja 2 and good intentions.

Flask script

Flask, like most modern frameworks, has its own command flask to perform tasks.


$ flask --help
Usage: flask [OPTIONS] COMMAND [ARGS]...

  This shell command acts as general utility script for Flask applications.

  It loads the application configured (through the FLASK_APP environment
  variable) and then provides commands either provided by the application or
  Flask itself.

  The most useful commands are the "run" and "shell" command.

  Example usage:

    $ export FLASK_APP=hello.py
    $ export FLASK_DEBUG=1
    $ flask run

Options:
  --version  Show the flask version
  --help     Show this message and exit.

Commands:
  run    Runs a development server.
  shell  Runs a shell in the app context.

Every Flask application you create is an instance of the flask.Flask class. The flask object implements a [WSGI] application and acts as the central object.

The flask.Flask class is responsible for handling all the view functions, URLs routing and templates setup, so in a simple app, you will end up having a single file.

To create a Flask app, we instantiate flask.Flask in our main module or in the __init__.py file of the package like:

from flask import Flask
app = Flask(__name__)

The first parameter tells Flask what belongs to this app, if you are using a single module, then __name__ is enough, but if not then you should specify the name of the package or module you are using to help Flask to find resources, improve debugging information, etc.

This is what a typical Flask app skeleton looks like:

# -*- coding: utf-8 -*-
from flask import Flask

# create application
app = Flask(__name__)

# Load default config and override config from an environment variable
app.config 

# db management

# routes and views
@app.route('/')
def show_a_url():
     return render_template('show_me.html', ..)

# local server running
if __name__ == '__main__':
	app.run()

Configuration

flask.Flask.config or likely app.config contains the configuration dictionary, it is an instance of config.Config from dict behaving like a common Python dictionary but supports additional methods to load a configurations from special dictionaries and files.

See also: How to configure Flask to have different configuration files in production and development environments

Populating the Configuration

The config.Config allows us to populate the configuration dictionary in several ways.

A common pattern for simple apps that don’t need to have configurations for multiple environments is to load the configuration from the yourapplication.default_settings module and then override the values with the contents of the file the YOURAPPLICATION_SETTINGS environment variable points to:

app = Flask(__name__)
app.config.from_object('yourapplication.default_settings')
app.config.from_envvar('YOURAPPLICATION_SETTINGS')

And then setup the environment variable with $ export YOURAPPLICATION_SETTINGS=/path/to/settings.cfg.

The available methods include:

dict keys

Defining or updating new configurations like a normal dicttionary

  app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
  # many keys at once
  app.config.update(
    DEBUG=True,
    SECRET_KEY='...'
  )

Files

Configuration can be stored in Python files with values in uppercase.

DEBUG = False
SECRET_KEY = '?\xbf,\xb4\x8d\xa3"<\x9c\xb0@\x0f5\xab,w\xee\x8d$0\x13\x8b83'

Python files

Creating a configuration in a Python file and loading it:

  app.config.from_pyfile('yourconfig.cfg')
  • load configuration from an environment variable pointing to a file

    
    $ export YOURAPPLICATION_SETTINGS='/path/to/config/file'
    
    

    Then in your code, load it using config.Config.from_envvar:

    app.config.from_envvar('YOURAPPLICATION_SETTINGS')
    

    This is the same of doing app.config.from_pyfile(os.environ['YOURAPPLICATION_SETTINGS']) with a nicer error message

Objects

Define configuration variables and add them with the from_object method, updating the vales of each variable:

  DEBUG = True
  SECRET_KEY = 'development key'
  app.config.from_object(__name__)

Others

  • From a json file with config.Config.from_json.
  • from mappings: config.Config.from_mapping

Development server

Flask comes with a development server to debug and test your app locally, it shouldn’t be used in a production environment mainly because two reasons:

  • it doesn’t scale well and
  • serves only one request at a time

The flask run command will end up calling flask.Flask.run(), this will always start a local [WSGI], so you need to make sure it is located in the block executed when running python scripts like if __name__ == '__main__': , to avoid executing it when serving your app in another web server.

The flask command depends on the FLASK_APP environment variable to know which app to work on, we start specifying this with the export command, then if we run the flask development server it knows which file to refer to:


$ export FLASK_APP=hello.py
$ flask run
 * Running on http://127.0.0.1:5000/

Reload server when code changes

There is a special debug mode handled by the FLASK_DEBUG environment variable that allows to:

  • reload the server automatically each time the code changes
  • output debugging information on errors

$ export FLASK_DEBUG=1
$ flask run
 * Forcing debug mode on
 * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
 * Restarting with stat
 * Debugger is active!
 * Debugger pin code: 292-824-230

Routing

Routing is done binding functions with URLs, using the route() decorator.

For example, the URL /hello-world would run the hello() function:

@app.route('/hello-world')
def hello():
    return 'Hello World'

Dynamic URLs

Flask URLs can also handle variables specifying them like <variable_name> or more precisely using converters <converter:variable_name> like '/post/<int:post_id>'.

@app.route('/user/<username>')
def show_user_profile(username):
    # show the user profile for that user
    return 'User %s' % username

Reverse URLs

Generating URLs knowing the function name is also possible with url_for like:


$ python
Python 3.5.2+ (default, Sep 22 2016, 12:18:14) 
[GCC 6.2.0 20160927] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>>  from flask import Flask, url_for
>>>  app = Flask(__name__)
>>>  @app.route('/login')
...  def login(): pass
...  
>>>  with app.test_request_context():
...      print(url_for('login', next='/'))
...  
/login?next=%2F
>>> 

test_request_context() method tells Flask to behave like handling a request, even though we are using a Python shell.

from flask import Flask, url_for
>>> app = Flask(__name__)
>>> @app.route('/login')
... def login(): pass
...
>>> with app.test_request_context():
...  print url_for('login', next='/')

Basic project structure

Flask applications are recommended to be installed and run as Python packages.

/myproject
    /myproject
		__init__.py  ## make the project a package
		myproject.py ## application module
		schema.sql   ## SQLite3 database
        /static      ## static files like js and css; var: `static_folder`
        /templates   ## jinja2 templates; var: `template_folder`
    /tests
        test_myproject.py
    setup.py     ## Setuptools packaging
    MANIFEST.in

References

Uruguay
Marcelo Canina
I'm Marcelo Canina, a developer from Uruguay. I build websites and web-based applications from the ground up and share what I learn here.