In the Python world there are three widely used Web frameworks: Flask, Pyramid and Django. Each of the frameworks has its own pros and cons. Flask is a "microframework" but in a sense that it provides the basic functionality of a Web framework, and it allows plugins to be added so the feature set can be extended. It is using Jinja2 template engine and the Werkzeug WSGI toolkit, and you can find more information about these in the Flask documentation, Jinja2 and Werkzeug homepages.
I created a Web application which uses Flask, pymongo/MongoDB (reused the concepts presented in my CRUD operations in MongoDB using Python article – I will not cover any pymongo/MongoDB related topic here) as data store and Foundation as HTML UI Framework (no details about Foundation will be explained here). The application is storing contact information about people.
It is a simple application, not having validation and perfect error handling, since the purpose was to create a Web application which can demonstrate how easy it is to create Web applications using Flask.
Flask Project Structure
Flask project structure is fairly simple if you compare it to Django's or Pyramid's default project layout. In Flask, there are (only) two important folders which need to be present -- templates and static -- and the rest of the files can be structured as you want it. The templates folder stores the Jinja2 templates (html pages with extra mark-up), while the static folder contains all the static files needed for the webpage: CSS files, JavaScript code files, images.
Besides the static and templates folder I have three Python code files:
- app.py – this contains the Flask app code
- contact.py – contains the class Contact used when loading data from MongoDB
- contacts_repository.py – contains the code for the CRUD operations of the contacts
Flask Basics
Creating and starting a Flask app
Creating a flask app is very easy. It takes only 7 lines of code, and this already has a routing setup:
from flask import Flask
# initialize a new Flask app
app = Flask(__name__)
# add one routing
@app.route("/")
def index():
return "Homepage routing works!"
# start the Flask app
if __name__ == "__main__":
app.run(debug=True)
The first thing is to import the Flask class, then initialize it by giving a name. After that, we setup the routing -- more details in the next section.
Starting the application is easy, invoking the run() method on the instance of the Flask class. If the debug=True value is specified, when running the application this will restart automatically each time we update or save one of the project files, in this way we do not have to manually start the application each time when we change something. Another useful feature when using debug mode is, if there are errors in the code or in the templates it gives a nice stacktrace and developer friendly error messages.
When starting the Flask application, this starts to listen on http://localhost:5000. Typing this in the browser will display “Homepage routing works!”.
Routing
Routing setup in Flask is easy and even in case of many routes, it can be easily reviewed. New routes can be specified using the @app.route(“actual route”) annotation.
@app.route("/contacts")
def contacts():
contacts_to_display = []
...
In this case @app.route(“/contacts”) defines, the Flask app will execute the contacts() function when the user navigates to http://localhost:5000/contacts.
Using templates
Templates are HTML5 pages, which contain extra mark-up which is interpreted by the Jinja2 template engine. This template engine is very similar to the one which is used in the Django framework. Templates serve to display data and content easily and you don’t have to create HTML manually using Python. Templates can be rendered using the render_template() method. The method can take multiple parameters -- these can be accessed in the template and will be displayed on the webpage after the template engine parses the template code and substitutes the parameters.
Templates can have: blocks, code and value accessing sections. Everything which is in {% %} gets interpreted and executed by the Jinja2 engine. Blocks can be defined using {% block BLOCK_NAME %}…{% endblock %}. Accessing variable values in templates can be done with the {{ VARIABLE }} syntax. In Jinja2 there are cycles, like for and methods like length, which help to generate HTML content. For example the code {{ contacts | length }} will return the number of items appearing in the contacts collection.
{% extends "index.html" %}
{% block title %}Contacts{% endblock %}
{% block content %}
<h2>Contacts</h2>
{% if contacts %}
<p>There are {{ contacts | length }} contacts in the database.</p>
{% if contacts|length > 0 %}
<table role="grid">
<tr>
...
</tr>
{% for contact in contacts %}
<tr>
<td>{{ contact['first_name'] }}</td>
<td>{{ contact['last_name'] }}</td>
...
</tr>
{% endfor %}
</table>
{% endif %}
{% else %}
<p>No contacts in the database.</p>
{% endif %}
{% endblock %}
This template creates a HTML table and displays the contact details if the contacts collection contains items, otherwise it displays No contacts in the database as a HTML paragraph.
The project is on GitHub at https://github.com/gergob/flask_web. The readme will help to install dependencies and start the application.