Friday, August 5, 2016

Django vs Flask vs Pyramid: Choosing a Python Web Framework_part1


TL;DR: Pyramid, Django, and Flask are all excellent frameworks, and choosing just one for a project is hard. We'll see working apps with identical functionality in all three frameworks to make comparing the three easier. Skip to Frameworks in Action[1]
1 Introduction

The world of Python web frameworks is full of choices. Django, Flask, Pyramid, Tornado, Bottle, Diesel, Pecan, Falcon, and many more are competing for developer mindshare. As a developer you want to cut the legions of options down to the one that will help you finish your project and get on to the Next Big Thing (tm). We'll focus on Flask, Pyramid, and Django. Their ideal cases span from micro-project to enterprise-size web service.
To help make the choice between the three easier (or at least more informed), we'll build the same application in each framework and compare the code, highlighting the strengths and weaknesses of each approach. If you just want the code, skip straight to Frameworks in Action or view the code on Github.
Flask is a "microframework" primarily aimed at small applications with simpler requirements. Pyramid and Django are both aimed at larger applications, but take different approaches to extensibility and flexibility. Pyramid targets flexibility and lets the developer use the right tools for their project. This means the developer can choose the database, URL structure, templating style, and more. Django aims to include all the batteries a web application will need so developers need only open the box and start working, pulling in Django's many modules as they go.
Django includes an ORM out of the box, while Pyramid and Flask leave it to the developer to choose how (or if) they want their data stored. The most popular ORM for non-Django web applications is SQLAlchemy by far, but there are plenty of other options from DynamoDB and MongoDB to simple local persistence like LevelDB or plain SQLite. Pyramid is designed to use any persistence layer, even yet-to-be-invented ones.

2 About the Frameworks

Django's "batteries included" approach makes it easy for developers who know Python already to dive in to web applications quickly without needing to make a lot of decisions about their application's infrastructure ahead of time. Django has for templating, forms, routing, authentication, basic database administration, and more built in. In contrast, Pyramid includes routing and authentication, but templating and database administration require external libraries.
The extra work up front to choose components for Flask and Pyramid apps yields more flexibility for developers whose use case doesn't fit a standard ORM, or who need to interoperate with different workflows or templating systems.
Flask, the youngest of the three frameworks, started in mid-2010. The Pyramid framework began life in the Pylons project and got the name Pyramid in late 2010, though the first release was in 2005. Django had its first release in 2006, shortly after the Pylons (eventually Pyramid) project began. Pyramid and Django are extremely mature frameworks, and have accumulated plugins and extensions to meet an incredibly large range of needs.
Though Flask has a shorter history, it has been able to learn from frameworks that have come before and has set its sights firmly on small projects. It is clearly used most often in smaller projects with just one or two functions. One such project is httpbin, a simple (but extremely powerful) helper for debugging and testing HTTP libraries.

3 Community

The prize for most active community goes to Django with 80,000 StackOverflow questions and a healthy set of blogs from developers and power users. The Flask and Pyramid communities aren't as large, but their communities are quite active on their mailing lists and on IRC. With only 5,000 StackOverflow questions tagged, Flask is 15x smaller than Django. On Github, they have a nearly identical number of stars with 11,300 for Django, and 10,900 for Flask.
All three frameworks are available under BSD-derived permissive licenses. Both Flask's and Django's licenses are 3-clause BSD, while Pyramid's Repoze Public License RPL is a derivative of the 4-clause BSD license.

4 Bootstrapping

Django and Pyramid both come with bootstrapping tools built in. Flask includes nothing of the sort because Flask's target audience isn't trying to build large MVC applications.

4.1 Flask

Flask's Hello World app has to be the simplest out there, clocking in at a puny 7 lines of code in a single Python file.
  1. # from http://flask.pocoo.org/ tutorial
  2. from flask import Flask
  3. app = Flask(__name__)
  4. @app.route("/") # take note of this decorator syntax, it's a common pattern
  5. def hello():
  6.     return "Hello World!"
  7. if __name__ == "__main__":
  8.     app.run()
This is why there aren't bootstrapping tools for Flask: there isn't a demand for them. From the above Hello World featured on Flask's homepage, a developer with no experience building Python web applications can get hacking immediately.

For projects that need more separation between components, Flask has blueprints. For example, you could structure your Flask app with all user-related functions in users.py and your sales-related functions in ecommerce.py, then import them and add them to your app in site.py. We won't go over this functionality, as it's beyond the needs of our demo app.

4.2 Pyramid

Pyramid's bootstrapping tool is called pcreate which is part of Pyramid. Previously the Paste suite of tools provided bootstrapping for but has since been replaced with a Pyramid-specific toolchain.
  1. $ pcreate -s starter hello_pyramid # Just make a Pyramid project
Pyramid is intended for bigger and more complex applications than Flask. Because of this, its bootstrapping tool creates a bigger skeleton project. It also throws in basic configuration files, an example template, and the files to package your application for uploading to the Python Package Index.
  1. hello_pyramid
  2. ├── CHANGES.txt
  3. ├── development.ini
  4. ├── MANIFEST.in
  5. ├── production.ini
  6. ├── hello_pyramid
  7. │   ├── __init__.py
  8. │   ├── static
  9. │   │   ├── pyramid-16x16.png
  10. │   │   ├── pyramid.png
  11. │   │   ├── theme.css
  12. │   │   └── theme.min.css
  13. │   ├── templates
  14. │   │   └── mytemplate.pt
  15. │   ├── tests.py
  16. │   └── views.py
  17. ├── README.txt
  18. └── setup.py
As in the rest of the framework, Pyramid's bootstrapper is incredibly flexible. It's not limited to one default application; pcreate can use any number of project templates. Included in pcreate there is the "starter" template we used above, along with SQLAlchemy- and ZODB-backed scaffold projects. On PyPi it's possible to find ready-made scaffolds for Google App Engine, jQuery Mobile, Jinja2 templating, modern frontend frameworks, and many more.

4.3 Django

Django also has its own bootstrapping tool built in as a part of django-admin.
  1. django-admin startproject hello_django
  2. django-admin startapp howdy # make an application within our project
We can already see one of the ways Django differs from Pyramid. Django separates a project into individual applications, where Pyramid and Flask expect a project to be a single "application" with several views or models. It's possible to replicate the project/app distinction in Flask and Pyramid, but the notion does not exist by default.
  1. hello_django
  2. ├── hello_django
  3. │   ├── __init__.py
  4. │   ├── settings.py
  5. │   ├── urls.py
  6. │   └── wsgi.py
  7. ├── howdy
  8. │   ├── admin.py
  9. │   ├── __init__.py
  10. │   ├── migrations
  11. │   │   └── __init__.py
  12. │   ├── models.py
  13. │   ├── tests.py
  14. │   └── views.py
  15. └── manage.py
By default Django only includes empty model and template files, so a new user sees a bit less example code to start out. It also (unfortunately) leaves the choice of how to distribute their application to the developer.
The downside of the bootstrap tool not guiding users to package their apps is that novice users won't. If a developer hasn't packaged an app before, they'll find themselves rudely surprised upon their first deploy. Projects with a large community like django-oscar are packaged and available on PyPi, but smaller projects on Github often to lack uniform packaging.

5 Templating

Just having a Python application that can respond to HTTP requests is a great start, but it's a good bet that most of your users won't be interested in using curl to interact with your web app. Fortunately, all three contenders provide an easy way to fill in HTML with custom info, and let folks enjoy your swanky Bootstrap frontend.
Templating lets you inject dynamic information directly into your page without using making AJAX requests. This is nice from a user experience perspective since you only need to make one round-trip to get the full page and all its dynamic data. This is especially important on mobile sites where round trips can take multiple seconds.
All the templating options we'll see rely on a "context" that provides the dynamic information for the template to render into HTML. The simplest use case for a template would be to populate a logged-in user's name to greet them properly. It would be possible to use AJAX to get this sort of dynamic information, but requiring a whole call just to fill in a user's name would be a bit excessive when templates are this easy.

5.1 Django

Our example use case is about as easy as it gets, assuming that we have a user object that has a fullname property containing a user's name. In Python we'd pass the current user to the template like so:
  1. def a_view(request):
  2.     # get the logged in user
  3.     # ... do more things
  4.     return render_to_response(
  5.         "view.html",
  6.         {"user": cur_user}
  7.     )
Populating the template context is as simple as passing a dictionary of the Python objects and data structures the template should use. Now we need to render their name to the page, just in case they forget who they are.
  1. <!-- view.html -->
  2. <div class="top-bar row">
  3.   <div class="col-md-10">
  4.   <!-- more top bar things go here -->
  5.   </div>
  6.   {% if user %}
  7.   <div class="col-md-2 whoami">
  8.     You are logged in as {{ user.fullname }}
  9.   </div>
  10.   {% endif %}
  11. </div>
First, you'll notice the {% if user %} construct. In Django templates {% is used for control statements like loops and conditionals. The if user statement is there to guard against cases where there is not a user. Anonymous users shouldn't see "you are logged in as" in the site header.
Inside the if block, you can see that including the name is as simple as wrapping the property we want to insert in {{ }}. The {{ is used to insert actual values into the template, such as {{ user.fullname }}.
Another common use for templates is displaying groups of things, like the inventory page for an ecommerce site.
  1. def browse_shop(request):
  2.     # get items
  3.     return render_to_response(
  4.         "browse.html",
  5.         {"inventory": all_items}
  6.     )
In the template we can use the same {% to loop over all the items in the inventory, and to fill in the URL to their individual page.
  1. {% for widget in inventory %}
  2.     <li><a href="/widget/{{ widget.slug }}/">{{ widget.displayname }}</a></li>
  3. {% endfor %}
To do most common templating tasks, Django can accomplish the goal with just a few constructs, making it easy to get started.
Written by Ryan Brown (continue)

If you found this post interesting, follow and support us.
Suggest for you:

No comments:

Post a Comment