Ask HN: Best Python web framework
I know this question gets asked every now and again, but the most recent informed thread I found was two years old and, as we all know, things move on.
Last time, the answer could be summarized as "Django but ...", with Pylons and Flask getting a good mention. Have these now "overtaken" the incumbent? What about Web2Py?
109 comments
[ 4.4 ms ] story [ 188 ms ] threadFlask is nicer (and lets you seamlessly use SQLAlchemy, which is so much better than Django's crappy ORM), but also tiny. It's basically just a bit of glue between werkzeug, SQLAlchemy and Jinja2.
Pyramid has more things in it than Flask and also uses SQLAlchemy.
web2py appears both bad and unpopular to me.
It is less popular than django, sure. But it is reasonably popular - with books about it coming out and selling well, and a lot of users, see http://web2py.com/poweredby including pycon registration websites.
Regarding popularity, for some time now the web2py Google Group has had more postings than the Django group, and the web2py group membership has been growing at a much faster rate than Django. Overall, Django is still more widely used, but web2py is certainly popular and growing rapidly.
Regarding whether web2py is "bad", that's obviously your opinion, but it is notable that you did not provide any argument or evidence whatsoever to support it.
We have found Django to be great for throwing up a site quickly. We primarily use Pyramid now for our more serious development as it fits more with what we're trying to achieve. My feeling is the beauty of Python is that there are more than one ways of doing something. Define what you want out of your framework, try some and then see how you feel
However I have a longer term concern, which is that I don't want to be learning a new framework for every project or have legacies with the "wrong" framework knocking around. This is why I framed the question in general terms.
Django is great for learning very fast. It has all the documentation in one place. There's generally one way to do any one thing with Django.
Pyramid is super flexible because it's not much of a framework to begin with. Think of it as glue to stick together a bunch of components to handle specific parts of your app (like database ORM, cache, sessions etc) and you can use any components that you like. Pyramid is harder to pick up than Django though because of this reason.
Pyramid is faster than django on benchmarks I've seen on the web (but this will hardly matter in the real world in my opinion)
Both have some big projects executed using them(Disqus is written in Django and Reddit is written in pylons for examples)
There are a bunch of other python frameworks that I haven't used yet so I can't tell you anything about them.
I'm currently working on something using Pyramid so if you have something specific you want to know, I'll try and answer (I'm new to this too)
I'd recommend learning django first though. It's what you should look at if you want a quick inroad into python web frameworks without much time spent learning.
A small photo sharing app that deals with occasional intense traffic spikes sits bang in the middle of Django's sweet spot (I'd suggest investigating the Django cache_page decorator, or maybe looking at integrating with Varnish).
"There should be one-- and preferably only one --obvious way to do it."
You'd have to define the "it" being done to make that meaningful...
I prefer pylons above Django. Simply because it feels less like a framework.
All of the controllers stuff was replaced with the code formerly known as repoze.bfg
It offers a good balance between Django (which i find a little big and unwieldy), and Flask (which I think suffers from the opposite problem).
Flask is designed under the assumption that you will most likely use third party frameworks for stuff like database abstraction and input validation.
It's kinda neat in that regard, and if you prefer to work that way then more power to you.
But I believe Web2py gets the balance between 'batteries included' and 'find your own damn batteries' right.
I picked web2py about 3 years ago, and it has worked well for me. I'm developing CRUD apps to solve business problems with the minimum of fuss and effort, but with the confidence that I can roll my sleeves up and exercise more control if I need to - web2py has been a good fit for that.
[1] http://bottlepy.org/docs/stable/
An example from their website:
Most of these other frameworks/languages (barring CFM and old ASP) expect you to adhere to some sort of MVC.
Saying PHP smells by default is a little less than fair. :-)
Generally you won't see PHP/JSP levels of code, but the more popular engines do allow quite a bit of logic, i.e. don't adhere to StringTemplate-level purity[1].
[1]: http://www.cs.usfca.edu/~parrt/papers/mvc.templates.pdf
Built-in async operations.
Not standing in your way.
Rapid developments.
Huge community.
Simply works.
Simple, yet rich.
That said, you can't go too far wrong picking Python web frameworks. They each have their strengths and weaknesses, but on the whole they're all fairly competitive offerings with helpful communities. If you don't find something you like then it's pretty trivial to roll-your-own from existing components like Werkzeug, WTForms, SQLAlchemy, Jinja, beaker, Mako, etc.
Use gevent. Huge community. Simply works and simply scales. And it makes all your blocking calls nonblocking automatically. Tornado just blocks.
There's no single "best" for every application. One-size-fits-none. One of Django's strengths is in the fact that parts of the framework come off easily when they no longer serve your needs. If the ORM is no longer working for you, you can use SQLAlchemy or write raw SQL. Authentication no longer working for you? Write your own or use a 3rd party one.
Et cetera. The key aspect is that you don't need to sacrifice the entire framework when only one part of it no longer addresses your needs. Keep in mind that 99% of sites never even reach this point.
The other major strength of django is the rich ecosystem of 3rd party apps. That's a lot of code you don't need to write yourself.
That being said, Flask is popular for a reason. Django offers a lot of power, which means adding some complexity to even the simplest projects (something we're working to address with features like project templates in Django 1.4). Flask fills a niche for a framework that is easy to get up and running and addresses 90% of the things which 90% of people need for many projects.
I've heard good things about pyramid, but haven't had a chance to play yet.
I haven't had the "pleasure" of working with web2py, and I'm not knocking the effort which Massimo puts into it, but the choices made there often elicit a raised eyebrow. Ignoring my opinion for a moment, the smartest web hackers I know universally regard web2py as a fundamentally incorrect way to approach web development—but usually say so in far more colorful terms.
TL;DR
* Flask for simpler stuff
* Django for anything larger, or simple stuff that leverages a 3rd-party app you need.
* What matters is the app you ship, not the framework it was built with.
* Django developers are in super-high demand. I get cold-called frequently.
Yes and no (disclaimer: I mostly use Django for my development), while parts come off easily the tools provided by the framework are "standard" and taking them off usually means not being able to take advantages of many Django features, e.g. if you replace django's ORM with SQLAlchemy, you'll have to say goodbye to the admin or to ModelForms, if you don't use Django's auth then extensions to it (django-registration &al) will have to be torn-out and/or reimplemented, ...
So while theoretically you can remove things, it's not a straightforward process and it'll likely be a lonesome road.
can you explain what i've been doing wrong, please?
https://groups.google.com/d/topic/web2py/dmN54cpMuXo/discuss...
https://groups.google.com/d/topic/web2py/GQWCsNzwP28/discuss...
Armin Ronacher's take: http://lucumr.pocoo.org/2011/2/1/exec-in-python/
If I found myself talking to someone who had used web2py, I'd be very interested in their critique, but sadly in every case so far, it's been second hand.
Going back to the original discussions about this, and discounting the unnecessarily intemperate language used, it seems to boil down to web2py's conscious design decisions being discounted as "Pythonic heresy" - fair enough if that is your PoV, but that's a long way from "a fundamentally incorrect way to approach web development".
In two years of active mailing list participation, I've never seen any actual users complain about these problems. They are hypothetical concerns that simply do not arise in real world usage.
Are you building an API? If yes, use Flask.
Are you building a website? If yes, use Django.
Are you building an API and a website? If yes, use Flask for the API and consume it from a Django site.
I wouldn't advocate using Django but ditching the ORM for SQLAlchemy, nor replacing the Auth, as noted (above or below my comment) it gets messy and becomes a lonely road fast.
I would advocate moving a lot (all?) of the model into a REST API, implemented in Flask, using SQLAlchemy. But perhaps my experience isn't as wide or deep as others.
I'd also argue in favour of ditching Django's auth. It's fine if your project has very simple auth requirements, but these days very few interesting projects have simple auth requirements - plus it's much easier to extend the functionality of your own Account models than to try and hook extra stuff on to Django's.
Separation of concerns, loose coupling.
I tended to find (in the few Django projects I worked on), that models were frequently accessed outside the app that created and owned the model. The subsequent dependency diagram would be spaghetti.
We had apps for each significant feature area, and when we wanted to drop a feature it was my desire to just remove an app.
It may well have been our implementation that was the problem (poorly separated concerns across apps), but we made great strides at solving these problems by using APIs to both force the de-coupling and to increase our confidence that our mobile clients (using the API) had the same capabilities available to them as the website (because no Django dev could cheat and make a call without the API existing).
Why Flask and not just Django again? That came down to personal preference over how clean it is to handle headers correctly (Accept headers, CORS and other things were fun), layout of the code and project, simplicity of testing, etc.
Mostly it was just subjective and personal preference, once we saw that the Django projects we had tended not to follow loose coupling, we used APIs as a way to increase our own discipline. Preferring that the architecture helped ensure the way we wanted to work on (and maintain) the code.
Auth we had already externalised (into the edge of the network, implemented within Varnish, similar to Flickr's GodAuth).
You either choose high-chatter and low complexity, or low-chatter and high complexity. As high-chatter is also a decrease in performance (mostly due to JSON serialisation/deserialisation and HTTP requests), we opted for low-chatter.
Resources that were a composite of other resources had their own knowledge of how they were composed, and generated their own IDs to save that knowledge. Each new composition resource got it's own Accept header identifier as a result.
Within that composition resource, there wasn't just knowledge of "I'm composed of x:17 and y:3", but also knowledge of how to search across the underlying services. This could be to call search on the underlying service if one side of the composition was dominant in applying the filter to the dataset.
Where it was trivial, a search index belonging to the composed service was used. And because this duplicates data from the underlying resources, messaging was put into the underlying service to notify the composed service of changes that affect searches.
For simplicity you can just imagine that we had some kind of table in the composed service, with ID on each row that because the ID of the composed resource, and that we could search that table, and that messaging magic kept that table in sync.
We could do all of this because we owned all of the services. If we didn't, then I imagine we would have followed a similar path to http://ql.io/
Implementation-wise they both hook into the model framework and the form framework, although you can swap out those parts if your data lives elsewhere.
But I disagree that:
Database = Model = Resource
Flask is great if you're going to do a complex app. All the interface will be custom designed (so the Django admin is of no use). You have a database heavy app, SQLAlchemy is more flexible than Django ORM and allows greater SQL expression, Unit of Work etc. Jinja2 is more flexible then Django templates (and faster). Flatland is more flexible than Django forms (supports nested forms for example).
That being said, Django is also great for some large apps and just for example it's great for news sites where new types of content is added each day and the admin interface saves a ton of time. For simple apps it's also brilliant because everything that's in Django works well together and you don't need the extra features of the aforementioned libraries.
So to sum up, both great frameworks and I use both every day :)
I don't even want to sum up the amount of time that Django would have solved my problem instantly, but instead I had to pull my hair out dealing with Flask's global variables, circular dependency issues, and general lack of cohesion or standards. I think it's a great micro-framework if you're writing a one-python-file personal site or blog. Anything larger than that and you're going to regret it.
One of my pet peeve with Django is the reliance on settings.py. This makes it a PITA to use Django's components in apps that aren't necessarily Django apps (or web apps for that matter).
For instance Ruby on Rails got separated in components and you can now import ActiveRecord in any project, without it being a Rails project or having a Rails project structure. Ditto for their database migrations ... you don't even need to use ActiveRecord to have the migrations DSL in a project. Doing this with Django's ORM is really, really ugly, mostly because of the reliance on a Django project structure. Why can't it be configured like any other Python library, in a pythonic way? Why does it need a global "settings" module?
Another pet peeve I've got is with the definition of an app. I hate what Django means by "app". It's totally un-pythonic. First of all the definition is unclear ... is it a module declared in settings.py? Not so fast, as some functionalities (e.g. manage.py test) expect those modules to have a "models" sub-module, even if it is empty.
Why does Django need apps anyway? It only needs apps for auto-discovery of model definitions. This goes back to Django's admin, which is a cool piece of software that I love, but how about declaring somewhere the modules that represent models, instead of building an unpythonic project structure?
I'm happy to hear that along with Django 1.4 you guys are working on project templates (really, that's awesome). But please strive to make it more pythonic / decoupled.
I've just gone over the public discussions. They could basically be summarized in two points:
jacobian&ronacher dislike web2py's inclusion of a few new "builtins" (that is, they are builtins for a web2py applications). They used extremely colorful terms ("divisive! harmful!"), but that's essentially what it boils down to: It's fine that "len", "dict", and "list" are builtins, but it's horrible that web2py introduces a few more for web2py apps ("request", "response", "session", and a few others). Well, that's not much more than a difference of opinion. They feel very strongly about it, for some reason.
ronacher also dislikes web2py's use of "exec" for some reason. Almost all of his criticism is meritless (web2py precompiles for production, and the namespaces are used as he thinks they should be). The part that isn't, about classes with destructors leaking is valid, but it's a general Python "bug" that web2py potentially amplifies if you use it -- but it is not idiomatic in either Python or Web2py.
It's rather telling that every single strong criticism of web2py you can find on the web comes from someone who has never used it, and more often than not has some vested interest in a competing framework.
Web2py is not perfect, far from it -- but it is extremely well built, very robust, has a lively and helpful community, and gets things done quickly and well. Give it a try when you have the time and feeling curious.
With great power comes great responsibility.
People like you who have never actually used web2py routinely express concern that this will somehow set up false expectations and confuse people about how Python modules and imports work, but in practice this is simply not the case. Note, web2py also includes a number of modules that require explicit importing, and applications can include their own modules as well as import standard library and third-party modules. As a result, web2py developers are perfectly comfortable with normal Python imports and do not have any false expectations.
Web2py is indeed using its "great power" responsibly.
Anthony already addressed the details in his reply below, but let me just add: IPython and sage essentially redo the python command line, and get nothing but praise. web2py, in some limited contexts (models and controllers) introduces a few useful names into the global namespace, and gets a ton of criticism.
Django (and just about every other framework) introduces a whole new language for templates, and no one squeaks, wheresa web2py uses plain Python as its template language with the smallest modification possible to provide that (you need to add "pass" at the end of a block, because you don't have indentation to guide you properly inside an html template; other template languages add an "endif" one way or another), and no one cares.
It is telling that all this criticism is coming from people who never use web2py, much like criticism of significant whitespace comes from people who do not use Python.
It is bigotry, disguised as a technical argument. In both cases.
Would you care to elaborate on that? Have any of these smart web hackers used web2py for real web development? I ask because web2py has had thousands of happy users building and maintaining web applications for several years now, and in practice, no one seems to be having the kinds of problems one might expect from a "fundamentally incorrect" approach. What exactly is fundamentally incorrect?
Also, getting started on a Flask application is a lot more work than Django, setting up logins, permissions, database stuff and so on takes longer compare to Django. I would pick Django for something that just needs to be up and running quickly and with an okay admin interface.
If you start picking of core bit of Django, I personally think it starts to lose part of what makes it a handy framework.
But in the end your right, the framework isn't important, it's the product. I try out frameworks every now and then and pick the one I feel comfortable and happy working with. Currently that's Flask, but previously I normally went for web.py.
Are these the same web hackers that believe, say, using PHP is a fundamentally incorrect way to approach web development?
I started on Pylons. I then used Django. So far I've been very happy with Django. I wish the ORM layer was more pluggable as well as the templating system. (I believe this is changing rapidly). But for the most part it works and it is great.
Obviously, as idan mentioned already, there is no single "best" framework, so it really depends on the type of application you want to build whether you should choose something like bottle/flask, django/mezzanine/pinax or brubeck/tornado, or even twisted.
http://en.wikipedia.org/wiki/Pyramid_%28web_framework%29
* faster.
* better quality (100% statement coverage via unit tests)
* supports latest python.
* great documentation (including free up to date book). There's also a separate pyramid cookbook.
* simplicity. If you just see a pyramid app, you can dive right in fairly easily without learning lots of alien stuff.
* sensible defaults, and you can choose to swap out parts easily if you want (templates, ORM, etc).
* works well with other python software, doesn't bundle everything in, with NIH syndrome.
* great tools. like the web console that drops straight into a debugger when an exception happens on the page you're looking at.
The framework that starts with D is a legacy framework (doesn't even support python3 yet).
* It's complicated
* It doesn't really do much for you (have to spend lots of effort/time/learning plumbing in all the 3rd party libs)
* Lacks sensible defaults for many things
* Documentation is rather lacking. Oh, there's tons of it, but it's rather maze-like and hard to use if you don't actually understand the system. High-level overview/cookbook type stuff is severely lacking.
Pyramid will:
* get you laid.
* help you take over the world.
* bring about world peace.
* 100% compatible with emacs, vim, textmate, and even eclipse.
* enterprise mumble mumble certified.
* tool of choice for the coolest startups in the world.
* Compatible with multiple currencies, $ £ and €. So you can make three times as much money.
* venture capitalists prefer it. 'I will chose companies that use pyramid, over those that use Django.' -- pg
My previous company has a huge SQLAlchemy-based codebase with literally hundreds of defined classes, many with hugely complex relationships (as it was built on top of a legacy database that had accreted over many years). Switching to a non-Alchemy backend simply wasn't an option. They also have a large, complex web application built in Zope with hundreds of tested, working page templates. Django is the easy first choice when starting a new Python web app. However, if we'd replaced the Django ORM with SQLAlchemy and Django's templates with something like ZPT so that we could incorporate our large pre-existing code, there wouldn't have been a lot of Django we could still use. In particular, the admin would have been virtually unusable without a large amount of reimplementation to adapt it to our internal code.
Pyramid was a big win for us in that it used our preferred backend choices by default. More importantly, though, was that it's comparatively very easy to change those defaults without losing the rest of Pyramid's features. After a couple of hours of experimenting with integrating our legacy codebase, I had new pages up and running.
I have nothing bad to say about Django and I've used it successfully in other projects. It's a neat framework with a lot of talented people behind it. But Pyramid has its own charms, especially for those who absolutely need to do things their own way.
Diesel (http://diesel.io/) has piqued my interest as of late -- it's a high-concurrency, coroutine-based framework with Flask under the hood, by the guys at Bump.
The next-gen Python Web frameworks will probably be non-WSGI because WSGI doesn't support WebSockets.
One approach would be a ZeroMQ-based framework like Brubeck (http://brubeck.io/) behind Mongrel2 (http://mongrel2.org/). But AFAIK, WebSocket support is not yet fully baked into Mongrel2. The handshake still needs to happen on the handler side.
It converts your blocking calls to nonblocking, has no spaghetti code filled with callback shenanigans, and can even generate a full REST API for you.
https://github.com/j2labs/brubeck
>Availability: 99.98 %
>Failed transactions: 2
I am guessing Brubeck runs solid now. But that benchmark was done 5 months ago and it's still advertised on this page. http://brubeck.io/readme.html
I have since switched over to Gevent and the performance is significantly better than Tornado now. I will update this test very soon to demonstrate.
https://groups.google.com/forum/?fromgroups#!topic/brubeck-d...
web2py is super complete, but doesn't get in your way, and doesn't require you to learn everything up front. It's DAL is much simpler (and in my opinion, much more effective) than an ORM -- but you don't have to use it.
Its templating system is just plain python inside {{}}, where you need to add "pass:" to dedent if it cannot be inferred from the code, but that's it. No need to learn a new templating system.
The community is super awesome. Starter applications like issue trackers, minimal facebooks or twitters etc. are often posted on the mailing list inside one short message (not as an attachment -- the whole thing is posted inside the message text, and takes no more than two screenfuls)
Really, give web2py a try if you haven't.
Quite unlikely, they'd probably have far more praises for it if they did confuse them.
- well designed components: DAL, SQLFORM, views, etc
- commitment to backwards compatibility
- works on GAE
- helpful community (groups.google.com/group/web2py)
- thorough documentation (web2py.com/book)
The main criticism of web2py is that its design is not 'pythonic', which is irrelevant to me.
Here's my answer on stackoverflow early last year when someone asked for a CherryPy vs Flask comparison. I believe all the points still stand and still represent CherryPy's strengths.
1. Simplicity. Controller object trees more or less equal to how you would define your URLs. 2. Flexibility. In case you don't like how the URLs are defined by default, you can use routes or methods to expose your URL handlers, which are just as easy. 3. Tools. CherryPy isn't religious about WSGI, though it's 100% compatible with the WSGI spec, the recommended approach is to use Tools. They are simple to make and use, and the way they are wired to the request is a lot more efficient than WSGI, which typically a request has to pass through whether or not that particular WSGI middleware is relevant. (Unless you use a framework where each URL handler is a WSGI application, but wiring up WSGI apps are still annoying). There are LOTS of them supplied by default that cover most of the use cases you can think of. 4. Plugins. For cross-cutting concerns, engine plugins are a much more granular, well-defined, and suitable way to deal with them as opposed to a WSGI app, which is typically the hammer people use to hammer in every screw these days. 5. Easy chunked responses. You just yield a string in the controller and that's it. Very useful for returning large documents in pieces. 6. Full-featured request and response objects. WebOb and CherryPy are about the only 2 frameworks that have comparably complete implementations of them, but I'd still choose CherryPy for the last reason: 7. Zero dependency on other packages. You won't bring in a dozen other libraries just to run a server. You just easy_install or pip install cherrypy and that's it.
Its WSGI server is also the canonical choice if you need a fast and stable pure Python WSGI server implementation. It's actually really really fast and stable:
Now, I've been using CherryPy for about 5 years now and am still absolutely in love with it. I love it so much that I've decided last month to open source the micro-framework I've built on top of CherryPy called BlueberryPy: It's basically a set of additional tools and plugins for CherryPy which give you an easier integration with SQLAlchemy, logging, Redis and Jinja2, webassets and various other goodies. It also comes with a project skeleton generator akin to many other frameworks out there but doesn't get in your way with the generated source files. All that BlueberryPy asks for is a configuration directory with a few correct YAML config files with a few keys pointing to a few classes in your package. Documentation is a little light but more will come soon enough as I find time to finish them up. Stay tuned :PThe slides are at http://www.slideshare.net/r1chardj0n3s/web-microframework-ba... -- they don't seem to be loading inline now but the PDF download still works. Video of the talk is at http://www.youtube.com/watch?v=AYjPIMe0BhA .
Spoiler alert: the winner was bottle.py, by a nose.
The project is a web interface for our library's digital archives (mostly audio and video assets, but also images and print documents). Version 1 of the project used php and mysql for the front end with python scripts handling the transcoding and metadata handling on the back end. For a variety of reasons the project got bloated to the point of being unmanageable. I decided I wanted a fresh start with a python framework and considered all the ones mentioned here.
I went with Flask because I wanted to leave the existing database structure in place and I wanted to err on the side of the framework doing too little instead of too much.
As a non-programmer (my job title says "audio engineer"), Flask was simple enough to understand, but did enough to make my life considerably easier. My one gripe is I think Flask-Login still has room for improvement, at least in terms of documentation. I've gotten it working good enough, but I still don't understand how credentials are passed around my application.
I'm sure other frameworks would have also gotten me to where I needed to be, but after working with Flask for a month or so, I'm not immediately reaching for something else.