The Flask Mega-Tutorial, Part I: Hello, World!

This is the first article in a series where I will be documenting my experience writing web applications in Python using the Flask microframework.

Here is an index of all the articles in the series that have been published to date:

My background

I'm a software engineer with double digit years of experience developing complex applications in several languages. I first learned Python as part of an effort to create bindings for a C++ library at work.

In addition to Python, I've written web apps in PHP, Ruby, Smalltalk and believe it or not, also in C++. Of all these, the Python/Flask combination is the one that I've found to be the most flexible.

UPDATE: I'm currently writing a book titled "Web Development With Flask", to be published in 2014 by O'Reilly. Visit http://flaskbook.com for more information and to sign up to receive news.

The application

The app I'm going to develop as part of this tutorial is a decently featured microblogging server that I decided to call microblog. Pretty creative, I know.

These are some of the topics I will cover as we make progress with the app:

  • User management, including managing logins, sessions, user roles, profiles and user avatars.
  • Database management, including migration handling.
  • Web form support, including field validation.
  • Pagination of long lists of items.
  • Full text search.
  • Email notifications to users.
  • HTML templates.
  • Support for multiple languages.
  • Caching and other performance optimizations.
  • Debugging techniques for development and production servers.
  • Installation on a production server.

So as you see, I'm going pretty much for the whole thing. I hope this app, when finished, will serve as a sort of template for writing other web applications.

Requirements

If you have a computer that runs Python 2.6 or 2.7 then you are probably good to go. The tutorial application should run just fine on Windows, OS X and Linux. (If you intend to follow this tutorial on Python 3 you will need to make some small changes, I wrote this tutorial before Flask had support for Python 3).

The tutorial assumes that you are familiar with the terminal window (command prompt for Windows users) and know the basic command line file management functions of your operating system. If you don't, then I recommend that you learn how to create directories, copy files, etc. using the command line before continuing.

Finally, you should be somewhat comfortable writing Python code. Familiarity with Python modules and packages is also recommended.

Installing Flask

Okay, let's get started!

If you haven't yet, go ahead and install Python 2.7.

Now we have to install Flask and several extensions that we will be using. My preferred way to do this is to create a virtual environment where everything gets installed, so that your main Python installation is not affected. As an added benefit, you won't need root access to do the installation in this way.

So, open up a terminal window, choose a location where you want your application to live and create a new folder there to contain it. Let's call the application folder microblog.

Next, download virtualenv.py and put it inside the new folder.

To create the virtual environment enter the following command:

python virtualenv.py flask

The above command creates a complete Python environment inside the flask folder.

Virtual environments can be activated and deactivated, if desired. An activated environment adds the location of its bin folder to the system path, so that for example, when you type python you get the environment's version and not the system's one. I personally do not like this feature, so I never activate any of my environments and instead just invoke the interpreter I want by typing its pathname.

If you are on Linux, OS X or Cygwin, install flask and extensions by entering the following commands, one after another:

flask/bin/pip install flask==0.9
flask/bin/pip install flask-login
flask/bin/pip install flask-openid
flask/bin/pip install flask-mail==0.7.6
flask/bin/pip install sqlalchemy==0.7.9
flask/bin/pip install flask-sqlalchemy==0.16
flask/bin/pip install sqlalchemy-migrate==0.7.2
flask/bin/pip install flask-whooshalchemy==0.55a
flask/bin/pip install flask-wtf==0.8.4
flask/bin/pip install pytz==2013b
flask/bin/pip install flask-babel==0.8
flask/bin/pip install flup

If you are on Windows the commands are slightly different:

flask\Scripts\pip install flask==0.9
flask\Scripts\pip install flask-login
flask\Scripts\pip install flask-openid
flask\Scripts\pip install sqlalchemy==0.7.9
flask\Scripts\pip install flask-sqlalchemy==0.16
flask\Scripts\pip install sqlalchemy-migrate==0.7.2
flask\Scripts\pip install flask-whooshalchemy==0.55a
flask\Scripts\pip install flask-wtf==0.8.4
flask\Scripts\pip install pytz==2013b
flask\Scripts\pip install flask-babel==0.8
flask\Scripts\pip install flup

These commands will download and install all the packages that we will use for our application.

Note that we are going to use Flask 0.9, which is not the latest version. Flask 0.10 hasn't been out for long and some extensions haven't been updated to work well with it. Also there are some incompatibilities between packages and the latest version of pip that are sorted out by giving specific versions to install.

Windows users have one more step. If you have good observation skills you may have noticed that flask-mail was not included in the Windows installation command list. This extension does not install cleanly on Windows, so we have to get it installed via a workaround:

flask\Scripts\pip install --no-deps lamson chardet flask-mail==0.7.6

I won't go into details regarding this, if you want more information please refer to the flask-mail documentation.

If the installation of all the packages was successful you can delete virtualenv.py, since we won't need it anymore.

"Hello, World" in Flask

You now have a flask sub-folder inside your microblog folder that is populated with a Python interpreter and the Flask framework and extensions that we will use for this application. Now it's time to write our first web application!

After you cd to the microblog folder, let's create the basic folder structure for our app:

mkdir app
mkdir app/static
mkdir app/templates
mkdir tmp

The app folder will be where we will put our application package. The static sub-folder is where we will store static files like images, javascripts, and style sheets. The templates sub-folder is obviously where our templates will go.

Let's start by creating a simple init script for our app package (file app/__init__.py):

from flask import Flask

app = Flask(__name__)
from app import views

The script above simply creates the application object (of class Flask) and then imports the views module, which we haven't written yet.

The views are the handlers that respond to requests from web browsers. In Flask views are written as Python functions. Each view function is mapped to one or more request URLs.

Let's write our first view function (file app/views.py):

from app import app

@app.route('/')
@app.route('/index')
def index():
    return "Hello, World!"

This view is actually pretty simple, it just returns a string, to be displayed on the client's web browser. The two route decorators above the function create the mappings from urls / and /index to this function.

The final step to have a fully working web app is to create a script that starts up the development web server with our application. Let's call this script run.py, and put it in the root folder:

#!flask/bin/python
from app import app
app.run(debug = True)

The script simply imports the app variable from our app package and invokes its run method to start the server. Remember that the app variable holds the Flask instance, we created it above.

To start the app you just run this script. On OS X, Linux and Cygwin you have to indicate that this is an executable file before you can run it:

chmod a+x run.py

Then the script can simply be executed as follows:

./run.py

On Windows the process is a bit different. There is no need to indicate the file is executable. Instead you have to run the script as an argument to the Python interpreter:

flask\Scripts\python run.py

After the server initializes it will listen on port 5000 waiting for connections. Now open up your web browser and enter the following URL in the address field:

http://localhost:5000

Alternatively you can use the following URL:

http://localhost:5000/index

Do you see the route mappings in action? The first URL maps to /, while the second maps to /index. Both routes are associated to our view function, so they produce the same result. If you enter any other route you will get an error, since only these two have been mapped to a view function.

When you are done playing with the server you can just hit Ctrl-C to stop it.

And with this I conclude this first installment of this tutorial.

For those of you that are lazy typists, you can download the code from this tutorial below:

Download microblog-0.1.zip.

Note that you still need to install Flask as indicated above before you can run the application.

What's next

In the next part of the series we will modify our little application to use HTML templates.

I hope to see you in the next chapter.

Miguel

228 comments

  • #1 Alexander Manenko said :

    Hello, thank you for your article. It is definitely a good starting point for beginner like I am. However, I found one misprint here: >> from Flask import Flask This should be from flask import Flask

  • #2 Miguel Grinberg said :

    Alexander, thanks for letting me know, I have corrected the error now.

  • #3 twrivera said :

    Good Job!!! Me likes and thx for doing this

  • #4 drew said :

    Wounderful, thanks for sharing this.

  • #5 drew said :

    You said :"Virtual environments can be activated and deactivated, if desired. An activated environment adds the location of its bin folder to the system path, so that for example, when you type python you get the environment's version and not the system's one. I personally do not like this feature.." Can you explain why?

  • #6 Miguel Grinberg said :

    @drew: There is nothing wrong with activating virtualenvs, it's just that the feature does not work for me. I typically need to switch between two or more environments, so I've found that if I get used to having an "active" virtualenv I end up forgetting to activate another one when I need to switch and end up mixing up virtual environments. Once I got used to explicitly invoke the python interpreter I want I stopped making these kinds of mistakes. On Linux/OS X/Cygwin it is really not much different, since the interpreter is in the shebang line of the scripts. Since all my virtualenvs have the same relative path to my scripts I can even copy scripts between projects and the scripts always find the project specific virtualenv.

  • #7 Alex said :

    Wonderful tutorial. I keep running into an issue though, Python isn't looking for the modules in the right place. For example, when run.py calls __init__.py, I get "ImportError: No module named flask". I can force it to find flask with sys.path.append(flask_path) but that seems like a crude hack. Is there a better way of managing the environment this module operates in? Maybe some virtualenv setting? I'm working on a Windows XP machine. My folder structure matches my understanding of your structure: \microblog run.py \flask \Include \Scripts \Lib \app \__init__.py \etc.

  • #8 Miguel Grinberg said :

    @Alex: I think you must be running the regular Python interpreter instead of the one from the virtual environment. On WinXP you run the run.py script as follows: "flask/Scripts/python run.py" as this ensures that the Flask modules are in the Python module path.

  • #9 Alex said :

    You are right! Thank you, I'm new to virtualenv.

  • #10 Catherine Penfold said :

    Hi Miguel, so I am starting afresh to try to get things working with the flask-WTF. I have followed your instructions incl 'flask\Scripts\pip install flask-wtf' should this now be visible somewhere. Also ./run.py does not work from the microblog directory, but python run.py does. Should this file be put elsewhere? Thanks, Catherine

Leave a Comment

Note: all comments are screened before they are published. Thank you for your patience!