After writing Real Python 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.
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.
- First create a directory for your project:
(replace flaskapp with the name of your application)
$ mkdir flaskapp && cd flaskapp
- Then inside of
flaskappcreate the following files:
$ touch config.py run.py shell.py app.db requirements.txt
The top level of our project houses the scripts we'll use to run and manage our application.
flaskapp ├── app.db ├── config.py ├── requirements.txt ├── run.py └── shell.py
- Then create a directory called app
And inside of it put:
$ mkdir app
$ touch app/__init__.py app/constants.py
flaskapp ├── app │ ├── __init__.py │ └── constants.py ├── app.db ├── config.py ├── requirements.txt ├── run.py └── shell.py
- And then create a directory for our static assets and one for our templates:
$ mkdir app/static app/templates
flaskapp ├── app │ ├── __init__.py │ ├── constants.py │ ├── static │ └── templates ├── app.db ├── config.py ├── requirements.txt ├── run.py └── shell.py
Everything inside of the
appdirectory 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.
- First thing you need to do is set up virtualenv to manage your python workspace and setup a
requirements.txtfile, 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
to activate it.
$ source venv/bin/activate
- 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:
.gitignorefile so git knows what to ignore
And then put this inside of it
$ touch .gitignore
- Next you need to instantiate the git repo:
If you have a Github account you can make a repo there and then push there.
$ git init $ git add . $ git commit -m "first commit"
- 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
.htmlfiles from it so your documentation is traversable and readable.
We can add pycco to our
requirements.txtand 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:
To install everything from here to our virtualenv run
To run pycco and document all of your code run
$ pip install -r requirements.txt
Pycco will traverse your project and store all of your documentation in a
$ pycco ./*.py
docsdirectory. 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
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
usersof the forum. Inside of
app/usersyou'd put all of the code that manages your application's users: logging in, registration, account management. Then you'd also have a
forummodule 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
forummodules, you could just make a
searchmodule that can be re-used in both
Any further functionality related to users would obviously go in
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.
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