![Python Web Frameworks]()
Structures
(source: Eos Maia ).
Introduction
At the time of this writing, the web development landscape is dominated by javascript tools. Frameworks like ReactJS and AngularJS are very popular, and many things that were previously done on the server are handled on the client side by these frameworks. This is not limited to the client. Server-side JavaScript frameworks like NodeJS are also prominent.
Does that mean that languages like python should throw in the towel and forget about web applications? On the contrary. Python is a very powerful language that is easy to learn and provides a fast development pace. It has many mature libraries for web-related tasks, from object-relational mapping (ORM) to web scraping. Python is also a fabulous "glue" language for making disparate technologies work together. In this era where JSON APIs and communication with multiple systems are so important, Python is a great choice for server-side web development. And it's great for full-scale web applications, too!
There are many web frameworks for Python; some provide more facilities than others, some offer a greater degree of flexibility or more extensibility. Some try to provide everything you need for a web application and require the use of very specific components, whereas others focus on giving you the bare minimum so that you can pick only the components your application needs.
Among these frameworks, there are dozens that have a significant number of users. How do newcomers to the language choose the right one for their needs? The easiest criterion would probably be popularity, and there are two or three frameworks that will easily be found doing web searches or asking around. This is far from ideal, however, and leaves the possibility of overlooking a framework that is better suited to a developer's needs, tastes, or philosophy.
In this report, we will survey the Python web framework landscape, giving aspiring web developers a place to start their selection process for a web framework. We will look in some detail at a few of the available frameworks, as well as give pointers about how to pick one, and even how to go about creating your own.
Hopefully, this will make it easier for new developers to find what's available, and maybe give experienced Python developers an idea or two about how other web frameworks do things.
What Do Web Frameworks Do?
A web application is not a standalone program but part of the web "pipeline" that brings a website to a user's browser. There's much more to it than your application code working under the hood to make the web work, and having a good understanding of the other pieces of the puzzle is key to being a good web developer. In case you are new to web development or need a refresher, take a look atPython Web Development Fundamentalsto get your bearings.
When writing a web application, in addition to writing the code that does the "business logic" work, it's necessary to figure out things like which URL runs which code, plus take care of things like security, sessions, and sending back attractive and functional HTML pages. For a web service, perhaps we need a JSON rendering of the response instead of an HTML page. Or we might require both.
No matter what our application does, these are parts of it that very conceivably could be used in other, completely different applications. This is what a web framework is: a set of features that are common to a wide range of web applications.
Exactly which set of features a framework provides can vary a lot among frameworks. Some frameworks offer a lot of functionality, including URL routing, HTML templating systems, ORMs to interact with relational databases, security, sessions, form generation, and more. These are sometimes referred to as full-stack frameworks .
Other frameworks, known by many as micro frameworks , offer a much less varied set of features and focus on simplicity. They usually offer URL routing, templating, and not much else.
This emphasis on size (micro and full-stack) can sometimes be confusing. Are we referring to the framework's codebase? Are micro frameworks for small applications and full-stack frameworks for large applications? Also, not all frameworks easily fit into one of these categories. If a framework has lots of features but makes most of them optional, does that still count as full-stack?
From an experienced developer point of view, it could make sense to examine frameworks in terms of decisions made . Many features offered by frameworks, like which ORM it supports or which templating system it's bundled with, imply a decision to use that specific tool instead of other similar components.
Obviously, the more decisions made by the framework, the less decisions the developer needs to make. That means more reliance on the way the framework works, more knowledge of how its parts fit together, and more integrated behavior―all within the confines of what the web framework considers a web application. Conversely, if a developer needs to make more decisions, they'll have more work to do, but they will also have more control over their application, and can concentrate on the parts of a framework they specifically need.
Even if the framework makes these decisions, most of them are not set in stone. A developer can change these decisions, maybe by replacing certain components or libraries. The trade-off is losing some framework functionality in return for that freedom.
There are many Python web frameworks. Besides size and decisions made for the developer, many of them offer unique features or special twists on what a web appplication should do. Some developers will immediately feel attracted to some frameworks, or conclude after some analysis that one of them is better suited for the specific project they have in mind. Regardless of the chosen framework, it's always a good idea to be aware of the variety of other available frameworks so that a better choice can be made if necessary.
Python Web Framework Landscape
There are many options for building web applications with Python. Python's powerful yet flexible nature makes it perfect for this task. It's a good idea to know what's available before going in that direction, though. Perhaps one of the many existing options will suit your needs and save you a ton of work.
To make it easier to know at a glance what frameworks are out there, the following list shows 30 web frameworks that are active and have more than 1,000 monthly downloads at the time of this writing. For each framework, the list presents the following information:
Slogan
This is a short phrase that comes from the framework's site or documentation and attempts to convey the spirit of the framework according to its creators.
Description
In a nutshell, what this framework is and why you should use it.
Author
Main author, according to
Python Package Index .
Website
Official website of the framework, or code repository if no site is available.
Relative popularity
A very crude attempt at gauging a project's popularity, by normalizing the number of monthly downloads and generating a score. Its purpose is only to give the reader a general idea about how one framework compares to another in terms of number of users. For example, Django, which is the Python framework with the largest number of downloads, has 10 stars. At the other end of the spectrum, BlueBream, which is barely above 1,000 downloads, has one star. This popularity scale should not be taken too seriously.
Python versions
Shows the versions of Python that the framework runs on.
License
Shows the license under which the framework is distributed.
Documentation
This is a key part of any framework, because the more you know about how to use it, the quicker you can get started and take advantage of its features. Some people learn by example, so having tutorials and sample code can be very helpful too, both for beginners and more advanced users. For each framework, documentation is graded using a very simple scale: poor, adequate, extensive, or comprehensive. Again, this is very subjective and only meant as a simple guide to know what to expect.
Features
A short list of what the framework's authors consider its best features.
Other resources
This refers to resources other than web pages to get help and information for a framework, like mailing lists and IRC channels.
Persistence
Many web applications require a storage layer of some sort, usually a database. Because of this, most web frameworks are designed to use one or more specific data persistence options.
Templating
This is another very common feature of web frameworks. The HTML markup for an application page is usually written in a templating language.
Web Framework List
Appier
Joyful Python Web App development.
Appier is an object-oriented Python web framework built for super-fast app development. It’s as lightweight as possible, but not too lightweight. It gives you the power of bigger frameworks, without the complexity.
Author
Hive Solutions Lda.
Website
http://appier.hive.pt
Relative popularity
*****
Python versions
2.6 to 3.5
License
Apache
Documentation
Adequate
Other resources
None
Persistence
MongoDB
Templating
Jinja2
Features
REST dispatching
JSON response encoding
Admin interface
i18n
Aspen
A Python web framework that makes the most of the filesystem. Simplates are the main attraction.
Aspen maps your URLs directly to the filesystem. It’s way simpler than regular expression routing or object traversal.
Author
Gratipay, LLC
Website
http://aspen.io
Relative popularity
******
Python versions
2.6, 2.7
License
MIT
Documentation
Adequate
Other resources
IRC
Persistence
Any
Templating
Python, Jinja2, Pystache
Features
Simplates: code and template in same file, with structure
JSON helpers
Filesystem-based URL mapping
BlueBream
The Zope Web Framework.
BlueBream is an open source web application server, framework, and library created by the Zope community and formerly known as Zope 3. It is best suited for medium to large projects split into many interchangeable and reusable components.
Author
Zope Foundation and Contributors
Website
http://bluebream.zope.org
Relative popularity
*
Python versions
2.6, 2.7
License
ZPL
Documentation
Extensive
Other resources
Mailing list
Persistence
ZODB
Templating
ZPT
Features
Built on top of Zope 3
Full stack, but with distributed architecture
Mature, well-tested components
Object database
Bobo
Web application framework for the impatient.
Bobo is a lightweight framework for creating WSGI web applications. Its goal is to be easy to use and remember.
Author
Jim Fulton
Website
http://bobo.digicool.com
Relative popularity
*
Python versions
2.6 to 3.5
License
ZPL
Documentation
Extensive
Other resources
Mailing list
Persistence
Any
Templating
Any
Features
Subroutes for multiple-step URL matching
JSON request bodies
Automatic response generation, based on return value
Bottle
Fast and simple WSGI framework for small web applications.
Bottle is a fast, simple, and lightweight WSGI micro web framework for Python. It is distributed as a single-file module and has no dependencies other than the Python Standard Library.
Author
Marcel Hellkamp
Website
http://bottlepy.org
Relative popularity
******
Python versions
2.6 to 3.5
License
MIT
Documentation
Extensive
Other resources
Mailing list, IRC, Twitter
Persistence
Any
Templating
Simple templates, Jinja2, Mako, Cheetah
Features
HTTP utilities
Single file distribution
CherryPy
A Minimalist Python Web Framework.
CherryPy allows developers to build web applications in much the same way they would build any other object-oriented Python program.
Author
CherryPy Team
Website
http://www.cherrypy.org
Relative popularity
******
Python versions
2.6 to 3.5
License
BSD
Documentation
Comprehensive
Other resources
Mailing list, IRC
Persistence
Any
Templating
Any
Features
Authorization, sessions, static content, and more
Configuration system
Plugin system
Profiling and coverage support
Clastic
A functional Python web framework that streamlines explicit development practices while eliminating global state.
Clastic was created to fill the need for a minimalist web framework that does exactly what you tell it to, while eliminating common pitfalls and delays in error discovery.
Author
Mahmoud Hashemi
Website
https://github.com/mahmoud/clastic
Relative popularity
*
Python versions
2.6, 2.7
License
BSD
Documentation
Basic
Other resources
None
Persistence
Any
Templating
Any
Features
No global state
Proactive URL route checking
Improved middleware paradigm
Cyclone
Facebook's Tornado on top of Twisted.
Cyclone is a web server framework for Python that implements the Tornado API as a Twisted protocol.
Author
Alexandre Fiori
Website
https://cyclone.io
Relative popularity
***
Python versions
2.6, 2.7
License
Apache
Documentation
Adequate
Other resources
None
Persistence
Twisted adbapi, redis, sqlite, mongodb
Templating
Cyclone templates
Features
Asyncio stack
Command-line integration
Django
The web framework for perfectionists with deadlines.
Django is a high-level Python Web framework that encourages rapid development and clean, pragmatic design.
Author
Django Software Foundation
Website
https://djangoproject.com
Relative popularity
**********
Python versions
2.6 to 3.5
License
BSD
Documentation
Comprehensive
Other resources
Mailing lists, IRC
Persistence
Django ORM
Templating
Django templates, Jinja2
Features
Fully loaded: authentication, site maps, feeds, etc.
Superbly documented
Extensible admin interface
Security-minded
Falcon
An unladen web framework for building APIs and app backends.
Falcon is a minimalist, high-performance web framework for building RESTful services and app backends with Python.
Author
Kurt Griffiths
Website
http://falconframework.org
Relative popularity
****
Python versions
2.6 to 3.5
License
Apache
Documentation
Extensive
Other resources
Mailing list, IRC
Persistence
Any
Templating
Any
Features
Web service oriented
Focused on performance
Fantastico
Pluggable, developer-friendly content publishing framework for Python 3 developers.
Python 3 MVC web framework with built-in capabilities for developing web services and modular web applications.
Author
Radu Viorel Cosnita
Website
https://github.com/rcosnita/fantastico/
Relative popularity
*
Python versions
3.3, 3.4, 3.5
License
MIT
Documentation
Adequate
Other resources
None
Persistence
Fantastico ORM
Templating
Any
Features
Extensible routing engine
ORM
Dynamic content generation
Flask
Web development one drop at a time.
A micro framework based on Werkzeug, Jinja2, and good intentions.
Author
Armin Ronacher
Website
http://flask.pocoo.org
Relative popularity
*********
Python versions
2.6, 2.7, 3.3, 3.4, 3.5
License
BSD
Documentation
Comprehensive
Other resources
Mailing list, IRC
Persistence
Any
Templating
Jinja2
Features
Built-in debugger
RESTful request dispatching
Allows modular applications with plugins
Extensible
Giotto
Web development simplified. An MVC framework supporting Python 3.
Giotto is a Python web framework. It encourages a functional style where model, view, and controller code is strongly decoupled.
Author
Chris Priest
Website
http://giotto.readthedocs.org
Relative popularity
**
Python versions
2.7, 3.3, 3.4, 3.5
License
Own
Documentation
Adequate
Other resources
Google group
Persistence
SQLAlchemy
Templating
Jinja2
Features
Generic views and models
Functional CRUD patterns
Automatic RESTful interface
Automatic URL routing
Grok
A smashing web framework.
Grok uses the Zope Component Architecture and builds on Zope concepts like content objects (models), views, and adapters. Its simplicity lies in using convention over configuration and sensible defaults when wiring components together.
Author
Grok Team
Website
http://grok.zope.org
Relative popularity
***
Python versions
2.6, 2.7
License
ZPL
Documentation
Extensive
Other resources
Mailing list
Persistence
ZODB
Templating
Zope page templates
Features
Convention over configuration
Takes advantage of full Zope toolkit
Object-oriented database
kiss.py
MVC web framework in Python with Gevent, Jinja2, and Werkzeug.
Author
Stanislav Feldman
Website
http://stanislavfeldman.github.io/kiss.py
Relative popularity
*
Python versions
2.6, 2.7
License
Own
Documentation
Poor
Other resources
None
Persistence
Pewee
Templating
Jinja2
Features
Integration with Gevent
REST controllers
Minified templates
Klein
Werkzeug + twisted.web.
Klein is a micro framework for developing production-ready web services with Python. It’s built on widely used and well-tested components like Werkzeug and Twisted.
Author
Amber Brown
Website
http://klein.readthedocs.org
Relative popularity
*****
Python versions
2.6 to 3.5
License
MIT
Documentation
Adequate
Other resources
IRC
Persistence
Any
Templating
Twisted templates
Features
Focus on web services
Integrates Twisted concepts like deferreds
Morepath
A micro web framework with superpowers.
Morepath is a Python WSGI micro framework. It uses routing, but the routing is to models. Morepath is model-driven and flexible, which makes it expressive.
Author
Martijn Faassen
Website
http://morepath.readthedocs.org/
Relative popularity
**
Python versions
2.6 to 3.5
License
BSD
Documentation
Extensive
Other resources
Mailing list, IRC
Persistence
Any
Templating
Any
Features
Automatic hyperkinks that don't break
Generic UIs
Simple, flexible permissions
Easy to extend and override
Muffin
Web framework based on Asyncio stack.
Muffin is a fast, simple, and asyncronous web framework for Python 3 .
Author
Kirill Klenov
Website
https://github.com/klen/muffin
Relative popularity
*****
Python versions
2.6 to 3.5
License
MIT
Documentation
Poor
Other resources
None
Persistence
Any
Templating
Any
Features
Asyncio stack
Command-line integration
Pylons
A framework to make writing web applications in Python easy.
Pylons 1.0 is a lightweight web framework emphasizing flexibility and rapid development.
Author
Ben Bangert, Philip Jenvey, James Gardner
Website
http://www.pylonsproject.org/projects/pylons-framework/
Relative popularity
****
Python versions
2.6, 2.7
License
BSD
Documentation
Extensive
Other resources
Mailing lists, IRC
Persistence
SQLAlchemy
Templating
Mako, Genshi, Jinja2
Features
Uses existing and well-tested Python packages
Extensible application design
Minimalist, component-based philosophy
Pyramid
The start small, finish big, stay finished framework.
Pyramid is a general, open source, Python web application development framework. Its primary goal is to make it easier for a Python developer to create web applications.
Author
Chris McDonough, Agendaless Consulting
Website
https://trypyramid.com
Relative popularity
******
Python versions
2.6 to 3.5
License
BSD derived
Documentation
Comprehensive
Other resources
Mailing lists, IRC
Persistence
Any
Templating
Any
Features
Powerful configuration system
Overridable asset specifications
Extensible templating
Flexible view and rendering systems
Tornado
A Python web framework and asynchronous networking library, originally developed at FriendFeed.
A simple web framework with asynchronous features that allow it to scale to large numbers of open connections, making it ideal for long polling.
Author
Facebook
Website
http://www.tornadoweb.org
Relative popularity
*********
Python versions
2.6 to 3.5
License
Apache
Documentation
Adequate
Other resources
Mailing list, wiki
Persistence
Any
Templating
Tornado templates
Features
Ideal for long-polling and websockets
Can scale to tens of thousands of open connections
TurboGears
The web framework that scales with you.
TurboGears is a Python web framework based on the ObjectDispatch paradigm. It is meant to make it possible to write both small and concise applications in Minimal mode or complex applications in Full Stack mode.
Author
TurboGears Release Team
Website
http://www.turbogears.org
Relative popularity
***
Python versions
2.6, 2.7, 3.3, 3.4, 3.5
License
MIT
Documentation
Extensive
Other resources
Mailing list, IRC, Google+
Persistence
SQLAlchemy
Templating
Genshi
Features
From micro framework to full-stack applications
Pluggable applications
Widget system
Horizontal data partitioning
Twisted
Building the engine of your Internet.
An extensible framework for Python programming, with special focus on event-based network programming and multiprotocol integration. Twisted includes twisted.web, a web application server based on the concept of resources.
Author
Glyph Lefkowitz
Website
https://twistedmatrix.com
Relative popularity
*******
Python versions
2.6 to 3.5
License
MIT
Documentation
Adequate
Other resources
Mailing list, IRC
Persistence
Any
Templating
twisted.web.template
Features
Takes advantage of Twisted networking power
Allows "spreadable" web servers (multiple servers answer requests on same port)
Can use any WSGI application as a resource
Uliweb
Unlimited Python web framework.
Uliweb is a full-stacked Python-based web framework. It has three main design goals: reusability, configurability, and replaceability. Its functionality revolves around these goals.
Author
Limodou
Website
http://limodou.github.io/uliweb-doc/
Relative popularity
*
Python versions
2.6, 2.7
License
BSD
Documentation
Adequate
Other resources
Mailing list
Persistence
Uliorm
Templating
Uliweb
Features
Based on SQLAlchemy and Werkzeug
Extensible
Command-line tools
Watson
It's elementary, my dear Watson.
A framework designed to get out of your way and let you code your application rather than spend time wrangling with the framework. It follows the "convention over configuration" ideal.
Author
Simon Coulton
Website
http://watson-framework.readthedocs.org
Relative popularity
*
Python versions
3.3, 3.4, 3.5
License
Own
Documentation
Adequate
Other resources
Mailing list
Persistence
Any
Templating
Jinja2
Features
Event-based
Dependency injection
Form library
web.py
Think about the ideal way to write a web app. Write the code to make it happen.
web.py is a web framework for Python that is as simple as it is powerful.
Author
Anand Chitipothu
Website
http://webpy.org
Relative popularity
*****
Python versions
2.6, 2.7
License
Public Domain
Documentation
Adequate
Other resources
Mailing list
Persistence
web.database
Templating
Templetor
Features
Simple to use
Own database and template libraries
Form library
web2py
Everything in one package with no dependencies.
Free open source full-stack framework for rapid development of fast, scalable, secure, and portable database-driven web-based applications.
Author
Massimo Di Pierro
Website
http://web2py.com
Relative popularity
*
Python versions
2.6, 2.7
License
LGPL 3
Documentation
Extensive
Other resources
Mailing list
Persistence
DAL
Templating
web2py
Features
Requires no installation and no configuration
Web-based IDE
Everything included; no dependencies
Always backward-compatible
webapp2
Taking Google App Engine's webapp to the next level!
webapp2 is a lightweight Python web framework compatible with Google App Engine’s webapp.
Author
Rodrigo Moraes
Website
http://webapp-improved.appspot.com/
Relative popularity
****
Python versions
2.6, 2.7
License
Apache
Documentation
Extensive
Other resources
Mailing list
Persistence
Google datastore
Templating
Jinja2, Mako
Features
Compatible with webapp
Better URI routing and exception handling
Extras package with optional utilities
WebPages
A Python web framework.
This project was designed for web developers who want to do more in less time. To create a new project with Hello World and a database connection, you only need a few minutes.
Author
Anton Danilchenko
Website
https://github.com/webpages/webpages
Relative popularity
*
Python versions
3.3, 3.4, 3.5
License
MIT
Documentation
Poor
Other resources
Facebook
Persistence
WebPages ORM
Templating
WebPages templates
Features
Convention over configuration
Settings per component
User authentication out of the box
ORM with simplified syntax
wheezy.web
Python's fastest web framework.
A lightweight, high-performance, high-concurrency WSGI web framework with the key features to build modern, efficient web applications.
Author
Andriy Kornatskyy
Website
http://wheezyweb.readthedocs.org
Relative popularity
***
Python versions
2.6 to 3.5
License
MIT
Documentation
Adequate
Other resources
None
Persistence
Any
Templating
Jinja2, Mako, Tenjin, Wheezy
Features
High performance
Authentication/authorization
Model update/validation
Some Frameworks to Keep an Eye On
As we have seen, there are many Python web frameworks to choose from. In fact, there are too many to be able to cover every one in detail in this report. Instead, we will take a deeper look at six of the most popular. There is enough diversity here to give the reader some idea about how different frameworks work and what a web application's code looks like when using them.
For each framework, we are going to give a general description, discuss some key features, look at some sample code, and talk a bit about when it should be used. When possible, code for a simple single-file application will be shown. Quick start instructions assume Python and pip or easy_install are present on the system. It is also recommended that you use virtualenv (or pyvenv for Python 3.3+) to create an isolated environment for your application. For simplicity, the examples do not show the setup of pip and virtualenv . SeePython Web Development Fundamentalsfor help with any of these tools.
Django
Django is without a doubt the most popular web framework for Python at the time of this writing. Django is a high-level framework, designed to take care of most common web application needs.
Django makes a lot of decisions for you, from code layout to security. It's also very well documented, so it's very easy to get a project off the ground quickly. There are also many third-party applications that can complement its many features nicely.
Django is very well-suited for database-driven web applications. Not only does it include its own object-relational mapping (ORM), but it can do automatic form generation based on the schemas and even helps with migrations. Once your models are defined, a rich Python API can be used to access your data.
Django also offers a dynamic administrative interface that lets authenticated users add, change, and delete objects. This makes it possible to get a nice-looking admin site up very early in the development cycle, and start populating the data and testing the models while the user-facing parts of the application are taking shape.
In addition to all this, Django has a clean and simple way of mapping URLs to code (views), and deals with things like caching, user profiles, authentication, sessions, cookies, internationalization, and more. Its templating language is simple, but it's possible to create custom tags for more advanced needs. Also, Django now supports Jinja2, so there's that option if you require a bit more powerful templating.
Quick Start
To install Django:
$ pip install Django
Unlike the other frameworks discussed in this chapter, Django is a full-stack framework, so we won't show a code listing for a Hello World application. While it's possible to create a Django application in a single file, this goes against the way Django is designed, and would actually require more knowledge about the various framework pieces than a complete application.
Django organizes code inside a project. A project has a configuration, or settings, plus a set of URL declarations. Since Django is intended for working with relational databases, the settings usually include database configuration information. Inside the project, there is a command-line utility, named manage.py , for interacting with it in various ways. To create a project:
$ django-admin startproject mysite
A project can contain one or more applications. An application is an ordinary Python package where Django looks for some things. An application can contain the database models, views, and admin site registrations that will make your models be part of the automatic admin interface. The basic idea in Django is that an application performs one defined task.
Representative Code
Django's database integration is one of its strong suits, so let's take a look at a few examples of that.
Defining models
from django.db import models
class Author(models.Model):
first_name = models.CharField(max_length=70)
last_name = models.CharField(max_length=70)
def __str__(self):
return self.full_name
@property
def full_name(self):
return '{} {}'.format(self.first_name, self.last_name)
class Book(models.Model):
author = models.ForeignKey(Author)
title = models.CharField(max_length=200)
description = models.TextField()
pub_date = models.DateField()
def __str__(self):
return self.title
A model contains data about one single part of your application. It will usually map to a single database table. A model is defined in a class that subclasses django.db.models.Model . There are several types of fields, like CharField , TextField , DateField , etc. A model can have as many fields as needed, which are added simply by assigning them to attributes of the model. Relationships can be expressed easily, like in the author field in the Book model above, which uses a ForeignKey field to model a many-to-one relationship.
In addition to fields, a model can have behaviors, or "business logic." This is done using instance methods, like full_name in our sample code. All models also include automatic methods, which can be overriden if desired, like the __str__ method in the example, which gives a unicode representation for a model in Python 3.
Registering models with the admin interface
from django.contrib import admin
from mysite.myapp.models import Book
class BookAdmin(admin.ModelAdmin):
list_display = ['title', 'author', 'pub_date']
list_filter = ['pub_date']
search_fields = ['title', 'description']
admin.site.register(Book, BookAdmin)
To make your models appear in the Django admin site, you need to register them. This is done by inheriting from django.contrib.admin.ModelAdmin , customizing the display and behavior of the admin, and registering the class, like we do in the last line of the previous example. That's all the code needed to get a polished interface for adding, changing, and removing books from your site.
Django's admin is very flexible, and has many customization hooks. For example, the list_display attribute takes a list of fields and displays their values in columns for each row of books, rather than just showing the result of the __str__() method. The hooks are not just for display purposes. You can add custom validators, or define actions that operate on one or more selected instances and perform domain specific transformations on the data.
Views
from django.shortcuts import render
from .models import Book
def publication_by_year(request, year):
books = Book.objects.filter(pub_date__year=year)
context = {'year': year, 'book_list': books}
return render(request, 'books/by_year.html', context)
A view in Django can be a simple method that takes a request and zero or more URL parameters. The view is mapped to a URL using Django's URL patterns. For example, the view above might be associated with a pattern like this:
url(r'^books/([0-9]{4})/$, views.publication_by_year)
This is a simple regular expression pattern that will match any four-digit number after "books/" in the URL. Let's say it's a year. This number is passed to the view, where we use the model API to filter all existing books with this year in the publication date. Finally, the render method is used to generate an HTML page with the result, using a context object that contains any results that need to be passed to the template.
Automated Testing
Django recommends using the unittest module for writing tests, though any testing framework can be used. Django provides some tools to help write tests, like TestCase subclasses that add Django-specific assertions and testing mechanisms. It has a test client that simulates requests and lets you examine the responses.
Django's documentation has several sections dedicated to testing applications, giving detailed descriptions of the tools it provides and examples of how to test your applications.
When to Use Django
Django is very good for getting a database-driven application done really quickly. Its many parts are very well integrated and the admin site is a huge time saver for getting site administrators up and running right away.
If your data is not relational or you have fairly simple requirements, Django's features and parts can be left just sitting there, or even get in the way. In that case, a lighter framework might be better.
Flask
Flask is a micro framework. Micro refers to the small core of the framework, not the ability to create single-file applications. Flask basically provides routing and templating, wrapped around a few configuration conventions. Its objective is to be flexible and allow the user to pick the tools that are best for their project. It provides many hooks for customization and extensions.
Flask curiously started as an April Fool's joke, but it's in fact a very serious framework, heavily tested and extensively documented. It features integrated unit testing support and includes a development server with a powerful debugger that lets you examine values and step through the code using the browser.
Flask is unicode-based and supports the Jinja2 templating engine, which is one of the most popular for Python web applications. Though it can be used with other template systems, Flask takes advantage of Jinja2's unique features, so it's really not advisable to do so.
Flask's routing system is very well-suited for RESTful request dispatching, which is really a fancy name for allowing specific routes for specific HTTP verbs (methods). This is very useful for building APIs and web services.
Other Flask features include sessions with secure cookies, pluggable views, and signals (for notifications and subscriptions to them). Flask also uses the concept of blueprints for making application components.
Quick Start
To install Flask:
$ pip install Flask
Flask "Hello World"
from flask import Flask
app = Flask(__name__)
@app.route("/")
def hello():
return "Hello World!"
if __name__ == "__main__":
app.run()
The Flask class is used to create an instance of a WSGI application, passing in the name of the application's package or module. Once we have a WSGI application object, we can use Flask's specific methods and decorators.
The route decorator is used to connect a view function with a URL (in this case, the root of the site). This is a very simple view that just returns a string of text.
Finally, we use the common Python idiom for executing some code when a script is called directly by the interpreter, where we call app.run() to start the development server.
Representative Code
Let's look at a few examples of what Flask code looks like inside real applications.
Per request connections
@app.before_request
def before_request():
g.db = connect_db()
@app.teardown_request
def teardown_request(exception):
db = getattr(g, 'db', None)
if db is not None:
db.close()
It's common to need some resources present on a per request basis such as service connections to things like redis, Salesforce, or databases. Flask provides various decorators to set this up easily. In the example above, we assume that the connect_db method is defined somewhere else and takes care of connecting to an already initialized database. Any function decorated with before_request will be called before a request, and we use that call to store the database connection in the special g object provided by Flask.
To make sure that the connection is closed at the end of the request, we can use the teardown_request decorator. Functions decorated with this are guaranteed to be executed even if an exception occurs. In fact, if this happens, the exception is passed in. In this example, we don't care if there's an exception; we just try to get the connection from g , and if there is one, we close it.
There's also an after_request decorator, which gets called with the response as a parameter and must return that or another response object.
Sessions
from flask import Flask, session, redirect, url_for,
escape, request
app = Flask(__name__)
@app.route('/')
def index():
if 'username' in session:
return 'Logged in as %s' % escape(session['username'])
return 'You are not logged in'
@app.route('/login', methods=['GET', 'POST'])
def login():
if request.method == 'POST':
session['username'] = request.form['username']
return redirect(url_for('index'))
return render_template('login.html')
@app.route('/logout')
def logout():
session.pop('username', None)
return redirect(url_for('index'))
app.secret_key = 'A secret'
The session object allows you to store information specific to a user from one request to the next. Sessions are implemented using secure cookies, and thus need a key to be used.
The index view checks the session for the presence of a user name, and shows the logged-in state accordingly. The login view is a bit more interesting. It renders the login template if called with the GET method, and sets the session username variable if called with POST. The logout view simply removes the variable from the session, in effect logging out the user.
Views
@app.route('/')
def show_entries():
cur = g.db.execute(
'select title, text from entries order by id desc')
entries = [dict(title=row[0], text=row[1])
for row in cur.fetchall()]
return render_template('show_entries.html', entries=entries)
@app.route('/add', methods=['POST'])
def add_entry():
if not session.get('username'):
abort(401)
g.db.execute(
'insert into entries (title, text) values (?, ?)',
[request.form['title'], request.form['text']])
g.db.commit()
flash('New entry was successfully posted')
return redirect(url_for('show_entries'))
Here we show how to define views. The route decorator that we saw in the quickstart application is used to connect the add_entry method with the /add URL. Note the use of the methods parameter to restrict that view to POST requests.
We examine the session to see if the user is logged in, and if not, abort the request. We assume that the request comes from a form that includes the title and text parameters, which we extract from the request to use in an insert statement. The request object referenced here has to be imported from flask , as in the sessions example.
Finally, a flash message is set up to display the change to the user, and the browser is redirected to the main show_entries view. This last view is simple, but it shows how to render a template, calling it with the template name and the context data required for rendering.
Automated Testing
Flask exposes the Werkzeug test client to make testing applications easier. It also provides test helpers to let tests access the request context as if they were views.
The documentation has a long section about testing applications. The examples use unittest , but any other testing tool can be used. Since Werkzeug is fully documented itself, there is very good information available about the test client too.
When to Use Flask
Flask can be used to write all kinds of applications, but by design it's better for small- to medium-sized systems. It is also not ideal for composing multiple applications, because of its use of global variables. It's especially good for web APIs and services. Its small core allows it to be used as "glue" code for many data backends, and it's a very powerful companion for SQLAlchemy when dealing with database-driven web applications.
Tornado
Tornado is a combination of an asynchronous networking library and a web framework. It is intended for use in applications that require long-lived connections to their users.
Tornado has its own HTTP server based on its asynchronous library. While it's possible to use the web framework part of Tornado with WSGI, to take advantage of its asynchronous nature it's necessary to use it together with the web server.
In addition to typical web framework features, Tornado has libraries and utilities to make writing asynchronous code easier. Instead of depending on callbacks, Tornado's coroutines library allows a programming style more similar to synchronous code.
Tornado includes a simple templating language. Unlike other templating languages discussed here, in Tornado templates there are no restrictions on the kind of expressions that you can use. Tornado also has the concept of UI modules , which are special function calls to render UI widgets that can include their own CSS and JavaScript.
Tornado also offers support for authentication and security, including secure cookies and CSRF protection. Tornado authentication includes support for third-party login systems, like Google, Facebook, and Twitter.
Quick Start
To install Tornado:
$ pip install tornado
Tornado "Hello World"
import tornado.ioloop
import tornado.web
class MainHandler(tornado.web.RequestHandler):
def get(self):
self.write("Hello, world")
application = tornado.web.Application([
(r"/", MainHandler),
])
if __name__ == "__main__":
application.listen(8888)
tornado.ioloop.IOLoop.current().start()
First, we define a request handler, which will simply write our "Hello World" message in the response. A Tornado application usually consists of one or more handlers. The only prerequisite for defining a handler is to subclass from the tornado.web.RequestHandler class.
To route requests to the appropriate handlers and take care of global configuration options, Tornado uses an application object. In the example above, we can see how the application is passed the routing table, which in this case includes only one route. This route assigns the root URL of the site to the MainHandler created above.
Once we have an application object, we configure it to listen to port 8888 and start the asynchronous loop to serve our application. Note that there's no specific association of the application object we created and the ioloop , because the listen call actually creates an HTTP server behind the scenes.
Representative Code
Since Tornado's asynchronous nature is its main feature, let's see some examples of that.
Synchronous and asynchronous code
from tornado.httpclient import HTTPClient
def synchronous_fetch(url):
http_client = HTTPClient()
response = http_client.fetch(url)
return response.body
from tornado.httpclient import AsyncHTTPClient
def asynchronous_fetch(url, callback):
http_client = AsyncHTTPClient()
def handle_response(response):
callback(response.body)
http_client.fetch(url, callback=handle_response)
from tornado import gen
@gen.coroutine
def fetch_coroutine(url):
http_client = AsyncHTTPClient()
response = yield http_client.fetch(url)
raise gen.Return(response.body)
In these three short examples, we can see how Tornado uses asynchronous calls and how that compares with the normal, synchronous calls that we would use in a WSGI application.
In the first example, we use tornado.HTTPClient to fetch a URL from somewhere in the cloud. This is the regular case, and the synchronous_fetch call will not return until the client gets the response back.
The second example uses the AsyncHTTPClient . The call will return immediately after the fetch call, which is why Tornado can scale more. The fetch method is passed a callback, which is a function that will be executed when the client gets a response back. This works, but it can lead to situations where you have to chain callbacks together, which can quickly become confusing.
For this reason, coroutines are the recommended way to write asynchronous code in Tornado. Coroutines take advantage of Python generators to be able to return immediately with no callbacks. In the fetch_coroutine method above, the gen.coroutine decorator takes care of waiting without blocking for the client to finish fetching the URL, and then passes the result to the yield.
Request handlers
class BaseHandler(tornado.web.RequestHandler):
def get_current_user(self):
return self.get_secure_cookie("user")
class MainHandler(BaseHandler):
def get(self):
if not self.current_user:
self.redirect("/login")
return
name = tornado.escape.xhtml_escape(self.current_user)
self.render("hello.html", title="Welcome", name)
class LoginHandler(BaseHandler):
def get(self):
self.render("login.html", title="Login Form")
def post(self):
self.set_secure_cookie("user",
self.get_argument("name"))
self.redirect("/")
application = tornado.web.Application([
(r"/", MainHandler),
(r"/login", LoginHandler)],
cookie_secret="__TODO:_GENERATE_A_RANDOM_VALUE_HERE__")
Since request handlers are classes, you can use inheritance to define a base request handler that can have all the basic behavior needed for your application. In BaseHandler in the previous example, the get_current_user call will be available for both handlers defined in the next example.
A handler should have a method for every HTTP method that it can handle. In MainHandler , the GET method gets a look at the current user and redirects to the login handler if it is not set (remember that get_current_user is inherited from the base handler). If there's a user, its name is escaped before being passed to the template. The render method of a handler gets a template by name, optionally passes it some arguments, and renders it.
LoginHandler has both GET and POST methods. The first renders the login form, and the second sets a secure cookie with the name and redirects to the MainHandler . The Tornado handlers have several utility methods to help with requests. For example, the self.get_argument method gets a parameter from the request. The request itself can be accessed with self.request .
UI modules
class Entry(tornado.web.UIModule):
def embedded_css(self):
return ".entry { margin-bottom: 1em; }"
def render(self, entry, show_comments=False):
return self.render_string(
"module-entry.html", entry=entry,
show_comments=show_comments)
UI modules are reusable UI widgets that you can use across your application. They make it easy to design your page layouts using independent components. UI modules subclass from tornado.web.UIModule and must include a render method. In the example above, we define a UI module that represents a blog entry.
The render method can include arbitrary parameters, which usually will be passed on to the module template, like in the example above. A UI module can also include its own CSS and JavaScript. In our example, we use the embedded_css method to return some CSS to use for the entry class. There are also methods for embedding JavaScript and for pointing to CSS and JavaScript files.
Once the UI module is defined, we can call it within a template with:
{ % module Entry(entry, show_comments=True) % }
Automated Testing
Tornado offers support classes for automated testing that allow developers to test asynchronous code. It has a simple test runner, which wraps unittest.main . It also has a couple of test helper functions.
Tornado's test module is documented, but there is no specific tutorial or narrative section devoted to testing.
When to Use Tornado
Tornado is a bit different to the other web frameworks discussed here, in that it goes hand in hand with asynchronous networking. It's ideal to use when you need websockets, long polling, or any other kind of long-lived connections. It can also help you scale your application to tens of thousands of open connections, provided your code is written to be asynchronous and nonblocking.
For more "regular" applications, like database-driven sites, using a WSGI framework is probably a better choice. Some of those frameworks also include a lot of features that the Tornado web framework does not have.
Bottle
Bottle is a true Python micro framework, in that it's actually distributed as a single file and has no dependencies outside of the Python standard library. It's lightweight and fast.
Bottle focuses on providing clean and simple URL routing and templating. It includes utilities for many web development needs, like access to form data, cookies, headers, and file uploads.