2013-08-07

After writing Python FR for the Web , I've mostly been coding in the high-level frameworks. Recently, thanks to an awesome gig, I re-introduced myself to Flask , which is "a microframework for Python". Flask is a tool and a platform. Like any other tools there are right and wrong ways to use it. Unlike some other tools, however, it can be a little unclear how to get started and correctly use it.

Forward

Before we get started on how to use Flask, let's talk a little about the best practices and where some of the design ideas come from.

I've been developing web applications with Django for about a year and a half now. Django adheres to the " Don't Repeat Yourself " policy. One of the many reasons people use Django as their web-framework of choice is because it comes with equipped with a number of tools out of the box. Because so much is built in and because of the way Django is designed there is a "django" way of doing things. If you look at enough Django apps you'll start to see the patterns emerge and get a feeling for how to use it.

Most of the design patterns that I've seen emerge in Django projects are in line with some of Python's core principles. Python is itself a tool. In order for Django to be an effective tool it must use the tools it is constructed from correctly. If you didn't already know, Python has some coding "guidelines" that can help you figure out how to best use it.

They're called the Zen of Python .

To give them a read, simply open a python interpreter and type-

>>> import this

-and then you'll see

The Zen of Python, by Tim Peters

Beautiful is better than ugly.
Explicit is better than implicit.
Simple is better than complex.
Complex is better than complicated.
Flat is better than nested.
Sparse is better than dense.
Readability counts.
Special cases aren't special enough to break the rules.
Although practicality beats purity.
Errors should never pass silently.
Unless explicitly silenced.
In the face of ambiguity, refuse the temptation to guess.
There should be one-- and preferably only one --obvious way to do it.
Although that way may not be obvious at first unless you're Dutch.
Now is better than never.
Although never is often better than *right* now.
If the implementation is hard to explain, it's a bad idea.
If the implementation is easy to explain, it may be a good idea.
Namespaces are one honking great idea -- let's do more of those!

These are words to code live by. Read here for a more detailed explanation.

The Zen of Python not only applies to raw Python code but to Python projects as well. Like anything else it will take you a fair amount of practice to really 'get' these.

Why did I bother bringing these ideas up? Because they'll make you a better coder, make your life as a coder easier and make you easier to work/code with. It's also the 'right' way to use Python.

How does all of that relate to Flask? Well, when you use Flask as a tool to solve your problems, these guidelines can help you avoid trouble and unnecessary work.

Flask is a Microframework

Before using any tool you should read the instructions. In this case that's the documentation for the project. This will give you a good idea "about the purpose and goals of Flask, and when you should or should not be using it".

To start, the term 'microframework' might be a bit misleading :

“Micro” does not mean that your whole web application has to fit into a single Python file, although it certainly can. Nor does it mean that Flask is lacking in functionality. The “micro” in microframework means Flask aims to keep the core simple but extensible. Flask won’t make many decisions for you, such as what database to use. Those decisions that it does make, such as what templating engine to use, are easy to change. Everything else is up to you, so that Flask can be everything you need and nothing you don’t.

There are a lot of good ideas there. While Django is/can be a full solution without any add-ons, forcing you to do things the 'Django' way, Flask is a much simpler platform that gives you a good enough starting point but lets you finish in your own way.

Measure Twice Cut Once

Before you start writing any code plan out how your project is going to work. Break your project down into groups that share common functionality, define your models, views, routes, etc. The more planning you do the easier the coding should be.

When designing your application you should think of your end goals:

  • How big is this application going to be?
  • How many people are going to use it?
  • What are my performance requirements?
  • How many people are going to be contributing code?

Think about how your application is going to work. Do some research, look at how other people have solved the same problem or a similar problem.

Next think about how your project is going to work. This is different than how your application will work. How are you going to structure your work environment? How are you going to make it easy to expand your project? How are you going to keep your workspace clean? How are you going to track bugs down and fix them?

After meditating on those questions, documentaing your answers, and altering your plans accordingly, you can move on to setting up your project.

Starting a Project

If you haven't gone through the Flask Quickstart Tutorial , I suggest you do that first.

You could use something like Flask-Boilerplate to start off. However, I'm going to start with a blank directory and work towards something we can use as a boilerplate setup.

  1. First create a directory for your project:

    $ mkdir flaskapp && cd flaskapp 
    

    (replace flaskapp with the name of your application)

  2. Then inside of flaskapp create the following files:

    $ touch config.py run.py shell.py app.db requirements.txt
    

    Initial structure:

    flaskapp
    ├── app.db
    ├── config.py
    ├── requirements.txt
    ├── run.py
    └── shell.py
    

    The top level of our project houses the scripts we'll use to run and manage our application.

  3. Then create a directory called app

    $ mkdir app
    

    And inside of it put:

    $ touch app/__init__.py app/constants.py
    

    Structure:

    flaskapp
    ├── app
    │   ├── __init__.py
    │   └── constants.py
    ├── app.db
    ├── config.py
    ├── requirements.txt
    ├── run.py
    └── shell.py
    
  4. And then create a directory for our static assets and one for our templates:

    $ mkdir app/static app/templates
    

    Structure:

    flaskapp
    ├── app
    │   ├── __init__.py
    │   ├── constants.py
    │   ├── static
    │   └── templates
    ├── app.db
    ├── config.py
    ├── requirements.txt
    ├── run.py
    └── shell.py
    

Everything inside of the app directory is what our application will run off of.

Project Environment/Work Flow

There are a couple of things that your project environment needs before you can start working on your app.

  1. First thing you need to do is set up virtualenv to manage your python workspace and setup a requirements.txt file, which are both vital to any project. If someone else clones your codebase they can use virtualenv and requirements.txt to get up and running with the correct version of all of the necessary dependencies for your project.

    $ virtualenv venv --distribute
    

    and then

    $ source venv/bin/activate
    

    to activate it.

  2. I'm a fan of git for source control - but you can really use whatever you want .

    To set up a git repository for your project do the following:

    Make a .gitignore file so git knows what to ignore

    $ touch .gitignore
    

    And then put this inside of it

    venv
    *.pyc
    
  3. Next you need to instantiate the git repo:

    $ git init
    $ git add .
    $ git commit -m "first commit"
    

    If you have a Github account you can make a repo there and then push there.

  4. Finally we want to set up some documentation standards for our project. This can range from just leaving comments in your code to having something read all of your code and then create .html files from it so your documentation is traversable and readable.

    Personally I like docco . It outputs beautifully formatted documentation and lets you use markdown in your comments. However, docco is a documentation generator for javascript/coffeescript. Fortunately for us there is a python port called pycco .

    We can add pycco to our requirements.txt and whenever someone goes to get set up to work on our project it'll be already installed in their virtualenv.

    Our requirements.txt so far will read:

    Flask==0.10.1
    pycco
    

    To install everything from here to our virtualenv run

    $ pip install -r requirements.txt
    

    To run pycco and document all of your code run

    $ pycco ./*.py
    

    Pycco will traverse your project and store all of your documentation in a docs directory. Check it out.

Adding Applets and Modules

All of the project modules/appletts for our app go inside of their own directory inside of the app directory:

flaskapp
├── app
├── __init__.py
├── constants.py
└── module
    ├── constants.py
    ├── decorators.py
    ├── forms.py
    ├── models.py
    └── views.py

Let's use a forum app as an example. One module would be the users of the forum. Inside of app/users you'd put all of the code that manages your application's users: logging in, registration, account management. Then you'd also have a forum module that would have all of the code related to forum posts: posting, commenting, editing.

Now, say for some reason you needed to have search functionality for both forums and users. Instead of writing separate search code in both the users and forum modules, you could just make a search module that can be re-used in both user and forum .

Any further functionality related to users would obviously go in users , etc.

Modules vs. Extensions

Remember all that extra stuff that Django had built in that Flask purposely left out? Well, you can add those features using Flask Extensions .

"Flask Extensions extend the functionality of Flask in various different ways. For instance they add support for databases and other common tasks"

If we need to add support for a database connection (usually you do) we can either write our own (bad idea) or use an extension.

Take a look around the Flask Extensions page and see what's available.

Instead of reinventing the wheel and writing your own solution, you can use code that someone else wrote and that other people are currently using. If you run into a bug or don't know how to use it, other people may have a solution.

However, do keep in mind that depending on other people's solutions has its own share of problems. For starters you are dependent on that person to not only write quality code but that s/he continues to maintain the code. Also, in production environments much time is spent solving the "why doesn't this thing that someone else built work they way I expected" problem - which can be difficult to debug if you are not aware of all the intricacies invoked in the other person's code.

Wrapping Up

That's it for this post.

In Part II, I'll use the concepts developed in Part I to create an application and use some Flask Extensions. We'll explore some more best practices for writing views, templates, models, integrating and managing a database, static files, and forms.

In Part III, we'll explore writing tests for your application and debugging errors.

And to finish everything off, Part IV will focus on Flask Blueprints, writing a REST JSON API, Accepting Payments, Deployment on Heroku with Fabric and basic A/B Feature Testing

Thanks for reading and tune in next time! Oh, and here's the final structure of our basic app:

flaskapp
├── app
│   ├── __init__.py
│   ├── constants.py
│   ├── module
│   │   ├── constants.py
│   │   ├── decorators.py
│   │   ├── forms.py
│   │   ├── models.py
│   │   └── views.py
│   ├── static
│   └── templates
├── app.db
├── config.py
├── docs
│   ├── config.html
│   ├── pycco.css
│   ├── run.html
│   └── shell.html
├── requirements.txt
├── run.py
└── shell.py


Want to learn more? Download PythonFR.

Download Now » $35

Or, click here to learn more about the course



blog comments powered by Disqus