2012-05-07T06:05:40Z

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

(Great news! There is a new version of this tutorial!)

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

NOTE: This article was revised in September 2014 to be in sync with current versions of Python and Flask.

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 have written a book titled "Flask Web Development", published in 2014 by O'Reilly Media. The book and the tutorial complement each other, the book presents a more updated usage of Flask and is, in general, more advanced than the tutorial, but some topics are only covered in the tutorial. Visit http://flaskbook.com for more information.

The application

The application 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 this project:

  • 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 application, when finished, will serve as a sort of template for writing other web applications.

Requirements

If you have a computer that runs Python then you are probably good to go. The tutorial application should run just fine on Windows, OS X and Linux. Unless noted, the code presented in these articles has been tested against Python 2.7 and 3.4, though it will likely be okay if you use a newer 3.x release.

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.

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.

If you are using Python 3, then cd into the microblog folder and then create a virtual environment with the following command:

$ python -m venv flask

Note that in some operating systems you may need to use python3 instead of python. The above command creates a private version of your Python interpreter inside a folder named flask.

If you are using any other version of Python older than 3.4, then you need to download and install virtualenv.py before you can create a virtual environment. If you are on Mac OS X, then you can install it with the following command:

$ sudo easy_install virtualenv

On Linux you likely have a package for your distribution. For example, if you use Ubuntu:

$ sudo apt-get install python-virtualenv

Windows users have the most difficulty in installing virtualenv, so if you want to avoid the trouble then install Python 3. If you want to install virtualenv on Windows then the easiest way is by installing pip first, as explaned in this page. Once pip is installed, the following command installsvirtualenv`:

$ pip install virtualenv

We've seen above how to create a virtual environment in Python 3. For older versions of Python that have been expanded with virtualenv, the command that creates a virtual environment is the following:

$ virtualenv flask

Regardless of the method you use to create the virtual environment, you will end up with a folder named flask that contains a complete Python environment ready to be used for this project.

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. But activating a virtual environment is not necessary, it is equally effective to invoke the interpreter by specifying 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
$ flask/bin/pip install flask-login
$ flask/bin/pip install flask-openid
$ flask/bin/pip install flask-mail
$ flask/bin/pip install flask-sqlalchemy
$ flask/bin/pip install sqlalchemy-migrate
$ flask/bin/pip install flask-whooshalchemy
$ flask/bin/pip install flask-wtf
$ flask/bin/pip install flask-babel
$ flask/bin/pip install guess_language
$ flask/bin/pip install flipflop
$ flask/bin/pip install coverage

If you are on Windows the commands are slightly different:

$ flask\Scripts\pip install flask
$ flask\Scripts\pip install flask-login
$ flask\Scripts\pip install flask-openid
$ flask\Scripts\pip install flask-mail
$ flask\Scripts\pip install flask-sqlalchemy
$ flask\Scripts\pip install sqlalchemy-migrate
$ flask\Scripts\pip install flask-whooshalchemy
$ flask\Scripts\pip install flask-wtf
$ flask\Scripts\pip install flask-babel
$ flask\Scripts\pip install guess_language
$ flask\Scripts\pip install flipflop
$ flask\Scripts\pip install coverage

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

"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 application:

$ 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 cascading 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. Do not confuse app the variable (which gets assigned the Flask instance) with app the package (from which we import the views module).

If you are wondering why the import statement is at the end and not at the beginning of the script as it is always done, the reason is to avoid circular references, because you are going to see that the views module needs to import the app variable defined in this script. Putting the import at the end avoids the circular import error.

The views are the handlers that respond to requests from web browsers or other clients. In Flask handlers 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 application 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 that 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 from the virtual environment:

$ 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 with our view function, so they produce the same result. If you enter any other URL you will get an error, since only these two have been defined.

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

350 comments

  • #151 Peter said 2013-11-27T00:11:42Z

    Hello Miguel, I am sorry this is so late but I was just linked to your article and am having the following issue when installing the flask libs

    "bash: flask/bin/pip: "/home/user/Documents/Python: bad interpreter: No such file or directory""

    If it makes any difference I am runnig Ubuntuo 12.0.4 on a Chromebook so on ARM architecture.

  • #152 Miguel Grinberg said 2013-11-27T05:08:42Z

    @Peter: ARM should not be a problem, near the end of the series I show how to install the application on a Raspberry Pi, which is also ARM. Take a look at this question on stack overflow: http://stackoverflow.com/questions/7911003/cant-install-via-pip-with-virtualenv. If you have spaces in the folder you are using then that's the problem.

  • #153 Peter said 2013-11-27T13:56:34Z

    Thank you so much Michael! I must admit I am very much a beginner in Python, have completed CodeAcademy path and 2/3rds of Learn Python the Hard Way so far and am interested in setting up this blog for my significant other. I hope the rest of the post is as helpful as you are! (but I don't doubt it since you wrote it)

  • #154 Anonymous Coward said 2013-12-03T15:54:07Z

    is there perhaps a more recent version of this tutorial? setting up, i get to:

    me@comp:/var/www/pvnp/microblog$ ./run.py * Running on http://127.0.0.1:5000/ * Restarting with reloader

    looks good ... but nothing ever appears on that site, and nothing in apache logs.

  • #155 Anonymous Coward said 2013-12-03T16:50:25Z

    n/m, got it working by changing app.run(debug = True) to app.run(host='0.0.0.0')

    might be useful for remote devs who are trying to follow this tut.

  • #156 Cory said 2013-12-05T01:02:05Z

    Thank you for the tutorial. I am having an issue with init.py. It says ImportError: No module named flask. I am running Ubuntu and followed the steps as you specified. I initially started learning flask from the offical flask quick start guide. From there I installed flask and had a local webserver running correctly. I do not see what the issue is here. Thank you for any help!

  • #157 Miguel Grinberg said 2013-12-05T05:50:12Z

    @Cory: my guess is that you are not running the Python interpreter installed in the virtual environment. That's the one that has flask installed, the system installed Python does not know about it.

  • #158 Cory said 2013-12-06T01:05:29Z

    @Miguel: I ran source bin/activate and it set my PATH to use the python virtual env installed. Is there anything I can do to fix this?

    I took another short tutorial and ran virtualenv flaskapp. In that directory I was able to start the webserver.

  • #159 Miguel Grinberg said 2013-12-06T15:14:56Z

    @Cory: did you install Flask in the virtualenv? Maybe you installed it on a different environment, like the global one?

  • #160 Cory said 2013-12-06T22:44:47Z

    @Miguel: I didn't install it correctly. I reran your steps to install flask and it is working prefectly now. Thank you for your help! I look foward to the rest off the tutorial and book to come!

  • #161 jctt said 2013-12-11T03:14:06Z

    Thanks!!

    BTW, I'm looking forward for your new Book.

    cheers

  • #162 jneighbs said 2013-12-17T19:15:35Z

    Wow. This is awesome. I really appreciate all the detail you put into this. It makes picking up Flask much easier! Thanks!

  • #163 Samuel said 2013-12-30T00:38:48Z

    Hi Miguel. I am very new to programming and am trying to learn some Flask starting with this tutorial. I believe I've followed all instructions to a T, and when I run the following command into the terminal './run.py' and/or 'flask/bin/python run.py' I get the following error :

    File "/Users/user/Desktop/flasktut/microblog/flask/lib/python2.7/site-packages/jinja2/utils.py", line 520, in from markupsafe import Markup, escape, soft_unicode ImportError: No module named markupsafe

    I have run.py in the microblog folder and have checked my virtualenv python libraries to see that I have downloaded them and I have. Markupsafe has been such a pain to try and figure out. Can you please help? Thanks!

  • #164 Miguel Grinberg said 2013-12-30T01:15:46Z

    @Samuel: for some reason markupsafe (a dependency of Jinja2) did not get installed in your virtual environment. A quick way to fix it is to run "pip install markupsafe" to install it explicitly. Recreating the virtual environment from scratch will likely address the issue as well.

  • #165 robin said 2013-12-30T10:49:49Z

    having this error . please help New python executable in flask/bin/python Installing setuptools............ Complete output from command /home/naman/Desktop/...log/flask/bin/python -c "#!python \"\"\"Bootstra...sys.argv[1:])

    " --always-copy -U setuptools: Downloading http://pypi.python.org/packages/2.7/s/setuptools/setuptools-0.6c11-py2.7.egg Searching for setuptools Reading http://pypi.python.org/simple/setuptools/ Reading http://peak.telecommunity.com/snapshots/ Download error: [Errno -2] Name or service not known -- Some packages may not be found! Reading https://pypi.python.org/pypi/setuptools Best match: setuptools 2.0.2 Downloading https://pypi.python.org/packages/source/s/setuptools/setuptools-2.0.2.tar.gz#md5=101b0829eca064fe47708039d66fc135 error: Download error for https://pypi.python.org/packages/source/s/setuptools/setuptools-2.0.2.tar.gz: [Errno -2] Name or service not known

    ...Installing setuptools...done. Traceback (most recent call last): File "virtualenv.py", line 2577, in main() File "virtualenv.py", line 979, in main no_pip=options.no_pip) File "virtualenv.py", line 1091, in create_environment search_dirs=search_dirs, never_download=never_download) File "virtualenv.py", line 611, in install_setuptools search_dirs=search_dirs, never_download=never_download) File "virtualenv.py", line 583, in _install_req cwd=cwd) File "virtualenv.py", line 1057, in call_subprocess % (cmd_desc, proc.returncode)) OSError: Command /home/robin/Desktop/...log/flask/bin/python -c "#!python \"\"\"Bootstra...sys.argv[1:])

    " --always-copy -U setuptools failed with error code 1

  • #166 Miguel Grinberg said 2013-12-30T17:33:21Z

    @robin: it's probably a internet connectivity issue, it appears a package could not be downloaded.

  • #167 robin said 2014-01-04T19:47:42Z

    No the internet is working just fine. I also tried using sudo also. But result is still the same.

  • #168 A. Reader said 2014-01-05T05:44:39Z

    it seems now you have to:

    pip install setuptools --no-use-wheel --upgrade

    between the

    python virtualenv.py flask

    and the

    pip install flask==0.9

    ( I also

    export PATH="$(pwd)/flask/bin:$PATH"

    )

  • #169 Andris said 2014-01-11T18:46:33Z

    What happened with extension installation? it shows : "Wheel installs require setuptools >= 0.8 for dist-info support. pip's wheel support requires setuptools >= 0.8 for dist-info support."and does not install extensions. A.Reader's solution "pip install setuptools --no-use-wheel --upgrade" seems to work but I kinda dont understand what happened :) does it affect anything?

  • #170 Miguel Grinberg said 2014-01-11T19:49:08Z

    @Andris: there was a new release of virtualenv that is causing these problems. I recommend that you install version 0.10.1 instead for now.

  • #171 Ravindra said 2014-01-12T01:39:29Z

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

    In the above piece of code, you are writing def index() as a function. What is the intuition behind it? Is this called by the application during execution? You wrote

    @app.route('/index') and def index(): so does the url extension index and the function name index() need to be same?

  • #172 Miguel Grinberg said 2014-01-12T01:52:15Z

    @Ravindra: The index() function is called by Flask when a client requests the "/" or "/index" URLs in the browser. The route() decorator basically associates URLs to functions. The name of the function does not need to match the URL.

  • #173 Sean Patterson said 2014-01-15T08:54:22Z

    Hi Miguel,

    Having a couple of setup issues.

    I have created a virtual environment as per your instructions and have been trying to install the extensions you asked for.

    When I run them I get the following error message for each one:

    Wheel installs require setuptools >= 0.8 for dist-info support. pip's wheel support requires setuptools >= 0.8 for dist-info support. Storing debug log for failure in /Users/seanpatterson/.pip/pip.log

    From reading my thoughts are I'm running an old version of setup tools, but I'm not sure how to upgrade this, or what setup file it would be. Any thoughts?

  • #174 Miguel Grinberg said 2014-01-15T16:37:34Z

    @Sean: This problem started with virtualenv 0.11, released a few days ago. You can either upgrade your setuptools, or downgrade your virtualenv to 0.10.1.

  • #175 Ann said 2014-01-21T14:50:03Z

    Hi, I followed all your steps but I keep getting this error when I try to use ./run.py or python run.py. I am using Ubuntu 13.10. I get this error: File "run.py", line 2, in from app import app File "/....../microblog/app/init.py", line 1, in from flask import Flask ImportError: No module named flask

    Would you know what is causing this error? Nothing shows up at http://localhost:5000 In the flask dir there is no file called Flask, correct? Thank you very much.