Hacker News new | comments | show | ask | jobs | submit login
Choosing a Web Framework: Django, Flask, or Pyramid (airpair.com)
81 points by ryan_sb on Oct 7, 2014 | hide | past | web | favorite | 63 comments

I've built things with each, so I'm pretty opinionated on the subject.

My verdict: Start with Django; use Flask once you hit 10M+ users.

• Django -- Sensible defaults. A plugin for most things you may need. Fairly high learning curve, but worth it. I've heard people at big startups say that they've spent weeks building things with Flask that were either built-in, or came as a pluggable app for Django. Pinterest still uses Django for their middleware, but switched over to Flask for their API [1].

• Flask -- Low learning curve. Very lightweight. The go-to ORM is SQLAlchemy, which is more fully featured, but has a higher learning curve, and is generally less-liked than the Django ORM. Great for hackathons.

• Pyramid -- Extremely configurable. You get to (have to) make a lot of low-level decisions. Serious lack of sensible defaults. Strong community. The IRC channel is helpful, yet time is spent discussing why Pyramid isn't more popular (lack of sensible defaults).

[1] http://www.quora.com/Pinterest/Would-Pinterest-consider-Flas...

"Fairly high learning curve, but worth it"

Exactly. Apart from the tutorial there's not much of "a way" of progressing forward (like "learn this now"). Except South/Migration. Learn this.

There are a lot of resources but it follows the Pareto rule, depending on what you need you may need to go learn Localization/Middleware/Advanced ORM queries/Advanced template tags and filters/Details of Requests and Responses/Advanced forms or models (yeah, Django really doesn't help with CSSing your forms)/etc

I'd hold off on South now that Django has its own migrations. They're going to be the method of choice moving forward as far as I know.

Yes, that's why I said South (for older versions) or Migration (for newer versions)

They're very similar, so learning South won't be detrimental (and it is useful from the moment you learn it)

Has someone created a hackathon starter app for flask?

It's not targeted specifically for hackathons, but cookiecutter-flask[1] is a skeleton project for the cookiecutter[2] project creator.

[1]: https://github.com/sloria/cookiecutter-flask

[2]: https://github.com/audreyr/cookiecutter

On the cookiecutter project page ([2]) there are links to cookiecutters for a bunch of other frameworks/toolsets.

What I really want in a web framework is for it to stay out of my way. In that regard I have been happy with Flask. All of the functionality lives in external modules (many of which are reused in back end tools) with the relatively simple task of HTTP interactions living in a Flask powered facade.

What I really want in a web framework is for a web framework to solve the common problems so I can write less code unless I'm doing something unusual. In that regard I have been happy with Django. All of the functionality does what you'd expect and nearly everything is overridable in a consistent way when you need to get closer to the 'metal'.

This is just my personal experience, but once you try to do certain things with Django, you start to butt heads with it. Django relies far too much on convention, and it shoehorns you into their tooling patterns.

I think the most exciting and flexible way to do things these days is with a collection of microservices. You can do feature work independently, test small isolable units of functionality, and achieve scale.That said, we could use cross-cutting libraries to make microservice implementation easier...

Ever since the beginning of the rise of microservice "architecture" we all know that a complete web-framework like Rails/Django does not fit the toolbox so I would suggest not to discuss the excess baggage/shortcoming of software X that is 90% designed to do Y to be applied to a different problem domain.

Developers tend to get excited building microservices because let's be honest, most of us aren't Ops that have to watch those services 24/7.

During the development of Microservices, everything looks rosy, as things evolved, if the organization does not have the skill-sets and the discipline to maintain these microservices, things fall down pretty quickly.

Take logging as an example, I'm betting that many microservices implementation would find it a wee bit challenging to trace a user transaction end-to-end.

We've been pretty happy with it at Pathwright. 1.7 was a great release. The conventions aren't too restrictive, and it has been incredibly easy to get contractors plugged in and productive in minimal time. We follow many best practices, so our codebase is going to be "familiar" (to some extent) to anyone with some experience. We love Django for the productivity level our team achieves with it.

The ecosystem is great, too. django-rest-framework in particular makes us oh-so-happy.

Not to knock flask/Pyramid/everything else. Pick what your team can be most productive wit. I just think there are less reasons than ever to get too caught up in choice of framework. There are so many great options now.

> Pick what your team can be most productive with

Absolutely. If you already know one and like it, go forth and hack. If you're not sure, or don't like the one you have, there are tons of great options. Not just Flask/Django/Pyramid either. Tornado, Bottle, CherryPy, Falcon, and more all have dedicated users (some more than others).

Have concrete examples where Django gets in the way?

Re: microservices, I think it's much healthier to frame that debate as a matter of tradeoffs rather than one approach being universally better suited than the other.

> Have concrete examples where Django gets in the way?

Add support for multiple-column primary keys https://code.djangoproject.com/ticket/373 Opened 9 years ago

NULL fields and Unique keys https://code.djangoproject.com/ticket/4136 Opened 7 years ago

So you're saying things nobody cared enough about to get them implemented in 7+ years? You'll find bugs old like this in any open source project.

Eh, they all solve the same problems.

Django has the additional requirement that you think exactly like the designers of the monolithic framework or you will spend a lot of time swimming upstream. Ever tried to integrate Django or Celery into a project whose configuration comes from .ini files or some other method? You end up writing your own configuration layer to get something that Django approves of. Don't even get me started on the ORM -- why does it even exist when we have SQLAlchemy?

In the end, convention over configuration (just put your files in the magic locations, for example) is just another term for developer arrogance: of course my way is natural and everyone will want to think like me! With something like Pyramid I never find myself following a debugger down into the guts to understand why it is or isn't doing something -- I have to do this all the time with Django because some piece of magic isn't working as advertised.

Ultimately, something like Django is concerned with "how can I make it work?" What professional engineers should be concerned with are questions like "what happens when it doesn't work?" and "will someone else be able to understand this?" With Django, what happens when it doesn't work is you find yourself about 13 levels deep in the stack looking at some wrapper class in this giant framework. If you do have to get into a Pyramid component, most of them are actually just individual projects, a single developer can understand the whole thing.

The entire work of engineering is to make it work, without also making it comprehensible to others and easily serviceable -- and do it fast. Picking Django because it makes it easy to start a new project is just satisfying one of those, unless you really understand deeply the bowels of the framework or expect to hire someone who does.

I think that Django actually has very little "magic", given the functionality that it provides. With respect to the ORM - For standard CRUD stuff, I think the ORM just works.

With respect to "Will someone else understand the code" - Having trained few engineers to use Django, the main issue always has been correct decomposition of the entire webapp into different submodules or Django "apps" - If the project has been properly modularized, then it is easy to find problems or add functionality.

In short, imho writing good serviceable code does not depend upon the framework - it depends upon the team :)

> Eh, they all solve the same problems.

This is really the best summary. It comes down to what your individual team can be more productive with. If it's Django, use Django. If it's Flask, use Flask.

> Don't even get me started on the ORM -- why does it even exist when we have SQLAlchemy?

There was a time when I thought much the same. But now I am glad for Django's more simple ORM. I've ended up liking ORMs less and less in general. If I'm going to use one, it's only going to be for the more simple queries. For this kind of case, Django's ORM really shines. Even our less technical staffers can get a copy of the DB and run some business analytics queries themselves.

For anything else, I'd much rather write the SQL myself. It's not difficult, and you are going to do better than the ORM could. Additionally, no ORM is going to have 100% support for every feature Postgres or MySQL offers. For example, we've made great use of Common Table Expressions.

> With Django, what happens when it doesn't work is you find yourself about 13 levels deep in the stack looking at some wrapper class in this giant framework. If you do have to get into a Pyramid component, most of them are actually just individual projects, a single developer can understand the whole thing.

Conversely, having a bunch of projects to track and update means breakages can occur in many different places for any given combination of versions.

In practice, we haven't found Django to be difficult to run. Quite the opposite, really. It's a cohesive unit. If you run into an issue, you are going to find lots of mailing list/bug tracker posts walking you through the solution in most cases.

> Ever tried to integrate Django or Celery into a project whose configuration comes from .ini files or some other method? You end up writing your own configuration layer to get something that Django approves of.

I'm doing exactly that in my current project. It wasn't so bad, just a couple lines in settings.py. ConfigParser FTW!

> In the end, convention over configuration (just put your files in the magic locations, for example) is just another term for developer arrogance: of course my way is natural and everyone will want to think like me!

I'd argue that Flask or Pyramid encourage a form of that too, just in a different place. Yes the Django devs have decided where you should put many of the things, but if someone new comes to your project already knowing Django they'll know where to look for things, whereas a Flask or Pyramid project may have its own idiosyncratic layout.

Django is not known about it's 'overridability'. The only part which is easy to switch/leave is the template engine. Otherwise it makes not much sense to use Django if you want to 'override' any other component.

Django makes it nearly trivial to switch:

* Email backend: https://docs.djangoproject.com/en/dev/topics/email/#defining...

* User model: https://docs.djangoproject.com/en/1.7/topics/auth/customizin...

* Authentication backend: https://docs.djangoproject.com/en/1.7/topics/auth/customizin...

* Databases

Django makes is very easy to write

* Views which extend from generic CBV and only need you to customize your CBV

* Custom template tags

* Wonderful admin pages: Its amazing what you can do with just Inline, list_display, list_search, list_filter etc. If you are willing to read through a bit of ModelAdmin class, then you will see it has nearly all hook points over ridable, though some it could do with a bit of documentation around ModelAdmin hook points.

When people say that `Django is not known about it's 'overridability'.`, they need to back it up with more data, because that not true at all, at least in 1.7

To be fair they were mostly recent additions.

What parts would you like to override that are difficult to do so?

Some people want to replace the ORM, but I find myself dropping into SQL in places where I need more advanced features. Django is sometimes chided for its simplistic ORM, but I've actually started thinking that if you are going to use an ORM at all, it probably should only be used for the more simple cases. Fortunately, the vast majority of queries in our codebase at Pathwright are pretty simple.

You need not be afraid to use SQL when you need to do something more advanced. You don't need to feel dirty about it. Postgres in particular can do many more things than any ORM is going to be able to cover 100%. Sometimes you can flat out do something much more efficiently than the ORM can with a simple SQL statement.

If you follow this line of thinking, I'm not sure there's a great reason to bother wedging SQLAlchemy into Django, if I'm just going to end up dropping down into SQL for the more advanced queries.

The ORM lets you write raw SQL with .extra: https://docs.djangoproject.com/en/dev/ref/models/querysets/#... and still get ORM objects back in return, or with .raw: https://docs.djangoproject.com/en/dev/topics/db/sql/ or just by manipulating cursors directly. Nothing in Django makes it harder to use raw SQL...

I agree, sure, you lose portability (or you can have a generic slower ORM case if it's that important) but dropping down to the SQL in corner cases is perfectly valid (and helpful)

For many cases, portability is a complete non-issue. For example, at Pathwright we chose Postgres for a bunch of reasons. We don't care about MySQL or Oracle or SQL Server. If there ever came a point where we had to make a switch for some reason, it wouldn't be horrible to make the necessary changes to the smaller number of places that we use SQL.

Of course, portability could be more of a concern if you are writing something that you are going to let customers run on their own hardware/environment. Though even then, I'm not sure I'd want to have to deal with supporting customers using every DB server that Django supports...

Staying out of way is relative to developer to developer. I'm not experienced web developer.

For me it was very quick to get started with Django and get things done. Documentation and community support is great, and so for Django related libraries. However I found its templating system getting in my way as compared to Jinja.

Flask again damn easy to start with. However I had to spend time looking for auth frameworks, making it work, and found documentation for flask related libraries not very complete. Some modules seemed to be inactive.

I had a similar experience with setting up Django for the first time. The community is actually quite vibrant and I found an expert on AirPair that guided me through my use case.

I choose Pyramid for the same reasons. Additionally, through paster I've been able to create custom empty project templates to easily get started on projects.

Yeah, paster is awesome, esp since there's so many great skeletons on PyPi already.

I feel just the same. It feels much more modular than Django's module system.

I'm a big fan of Pyramid because (among many other reasons) I think ORMs are a poor abstraction and therefore do not want to be forced into using one (a la Django). I didn't find the learning curve terrible either--it's just MVC (er, "MVT") with some configuration/logging/routing capabilities built in.

Being able to do dynamic routing (via Traversal) is also cool. I really like being able to attach custom objects/attributes to the request object--that lets me write my own datalayer (without an ORM) and have it shared as a singleton across the lifetime of the request. It's also cool that you can write "views" (aka "controllers") either as flat functions or classes.

I personally don't write much server-side HTML munging anymore so I don't have much to say about Chameleon templates. Last time I used them I found the documentation a little lacking but otherwise it worked well. I still prefer Jade.

What do you use to query a relational database, if not an ORM? Do you build your SQL with string concatenation? In my experience that gets messy very quickly for complicated queries, so you end up needing some sort of SQL builder abstraction.

For Mongo I write a data layer that has methods like GetFoo() or UpdateFoo() where the methods have implicit knowledge of key structure (and query model objects for validation, etc)

For SQL I would do something similar but use (for example) SQLAlchemy Core (not ORM) to do DB-agnostic SQL generation. That would essentially give me a SQL API somewhat similar to pymongo.

For some things ORM's get in the way, but avoiding them by your own data layer sounds like a pretty big time-suck.

Being able to write a single line of SQLAlchemy to build relationships into your models seems way simpler than implementing relationships in a custom data layer.

I don't deny that it's more work. The question is whether it's worth the investment. I think for large, complex codebases (not little one-off apps) the gains in performance and long-term maintainability are worth it. Having the ability to know the exact performance implications of a query (and not having to waste brain cycles on questions about lazy vs eager loading, etc) is more desirable.

Yeah, I think the sweet spot is using SQLAlchemy's ORM for simple queries and dropping down to core for more advanced usage. Best of both worlds.

Even for advanced queries (ok, not super advanced) SQLAlchemy can hold its own, especially if you're willing to dip into the sqlalchemy.core modules.

I'm surprised nobody shows interest in CherryPy? I prefer it to Flask, I got more done coding with CherryPy, than I did with Flask, in less time. It just doesn't get in my way. I guess it's a matter of preference though.

I haven't done any Python web application stuff for a while, but most of what I have done was with CherryPy. I liked it a lot.

Mostly, I prefer to have things already done for me so the micro-frameworks quickly build into added work later.

One of the secret weapons of the Django world is Django REST framework. The built-in API browser alone is pretty amazing.

South is also a pretty darn good migrations system, and is well up there too.

I think I could take or leave the Django admin panel for an established app, but for small apps or just getting started, it's a nice thing to have too.

We don't use Django's templating system.

DRF is great, but it's pretty heavy weight. I've used both DRF and Flask for building API's. I was far more productive with DRF at first, but once I developed my own system for flask, I much preferred bare-bones flask coding. It's really nice to have all the code that could be causing bugs, directly in front of you.

> DRF is great, but it's pretty heavy weight.

What does this even mean? It can do a lot for me, therefore it's bad?

We use DRF extensively, but we don't come close to using everything that it can do. We don't tend to use ViewSets or the auto-routing features, but the fact that it can do those things doesn't hurt us.

DRF gets so much attention from such a large community. It's constantly improving to the point where we don't have to worry about it. If you fall victim to NIH Syndrome and roll your own, you have to be proactive about finding and addressing your own issues, as well as keeping up with advancements around the ecosystem.

I'd just rather let the people who focus on DRF handle that, and we'll throw a pull request over the wall if we run into anything that hasn't been addressed.

An example of where this excess bloat would be bad is in a microservice architecture. Django has a footprint so big that using it for microservices doesn't make sense, because at that point you may as well roll all the services into a single application. In that case, I think DRF is great. But if I'm building a microservice architecture, I want the API code for each service to be 100-200 lines, not 100-200 lines + Django.

So yeah, there are efficiency gains from DRF, I agree. But (in my opinion), the gains are far less in architectures with separate applications all using DRF. In that case, something like Flask makes more sense to me, purely for the benefit of debugging, logic clarity, and independence.

I recommend a great talk by Kenneth Reitz on exactly this topic. [1] (He's given a variation on it multiple times -- just search youtube.)

[1] https://m.youtube.com/watch?v=U2frH932U1g

> An example of where this excess bloat would be bad is in a microservice architecture.

Django is pretty easy to slim down. Yank the middleware you don't need, stick to what you do. No need for stuff like context processors if you are using DRF. You don't have to use models or the ORM at all if you don't want.

I think the line count would be very similar for many cases. For example, if your flask app needed DB access, you'd end up pulling in and boilerplating an ORM anyway. Ditto for sessions/authentication/etc.

That sounds dangerously close to "not invented here syndrome."

You can get pretty bare-bones with DRF. I enjoyed working with it because it has magic for when you need it, and low-level functionality for when you need more control.

South is deprecated now - Django 1.7 has migrations built in.

It's too bad whenever these articles come up that Tornado (http://www.tornadoweb.org) seldom gets a mention. It's minimalist and stays out of your way; pair it up with SqlAlchemy and you've got a complete solution. And you don't have to fool around with wsgi.

Has anyone tried deploying Flask apps with Tornado? I'm curious what the performance and tradeoffs would be, since it might be a convenient migration path from Nginx+uWSGI should a compelling reason to do so ever arise.

- http://flask.pocoo.org/docs/0.10/deploying/wsgi-standalone/#...

FWIW it's 4th the list of frameworks in the article, Flask/Django/Pyramid being the top 3.

We had a panel discussion at PyCon India (a little over a week back) on Flask vs Django vs web.py with considerations for other frameworks as well.

Video: http://www.youtube.com/watch?v=jM-SgJTi8g0&t=6h00m00s

If I were at the crossroads of choosing between Django, Flask & Pyramid, this post doesn't tell me enough to make a choice that I won't regret later. It doesn't go into the depths of the shortcomings that you will start noticing when you are months into the project. Unfortunately, there's no easy way to choose the right framework. Or put it differently, the right framework does not exist. Although, I feel that flask has the potential to get there.

From a purely technical perspective, you probably can't go wrong with any of the three unless you have super specific needs. In cases like that, you may not even want to use Python at all.

The best way to decide which to use is to take your team and hammer out some quick project using your 2-3 leading framework candidates. Whichever your team is more subjectively happy with is where you should go.

There are other considerations, but so many projects fail to gain traction after taking longer than planned to launch. Team productivity is priority #1 for us, though subjectively we've found it to be very easy to find contractors who can be plugged into a Django project with minimal ramp-up.

While not really a framework, i've getting used to using webapp and appengine's ndb datastore (yes its an appengine application). The application doesn't serve html, only json (its basically an api).

The our app is build as an ios, android and webapp on top of this api.

It depends on what you're building. And sometimes this approach is not nice. But it works for our usecase.

In conclusion: sometimes your architecture doesn't need a full-fledged webapp framework.

Even for building a mobile backend, having a framework can help. Tools like Cornice (Pyramid), Django REST framework, and Flask-REST can make building API's much easier.

Here's my quick take on the subject:

- Django: a big framework for simple projects. Batteries included (most). Even better if it's a CMS. ORM is fine if you don't do anything complicated.

- Pyramid: much more flexible, more "pick and choose". Also try http://jinja.pocoo.org/

- Flask: if you need to get web requests and do whatever you want with it.

If you do like jinja, it's Flask's 'native' template engine.

Python + Flask is nice but has serious performance constraints. I guess I found a bug in Flask or Werkzeug that restricts requests per second to a value below 600 req/s. See here for more details: https://medium.com/@tschundeee/express-vs-flask-vs-go-acc087...

Many times when I’d like to use Django, I have to eliminate it because of one thing: I’d like to access the database from non-web programs, and Django certainly does not make it easy to use its ORM in a non-web context.

Sometimes I’d even like to access the database from external, possibly non-Python tools, and then Django is out of the question, since it does not define a stable API to its database layer, only its ORM.

Therefore, I go with Flask + SQLAlchemy in these cases.

(One time, for a short-lived project, I chose to ignore that Django does not provide a stable database, and simply let Django create the database and then simply assumed that the database table definitions would not change during the lifetime of the project and accessed it externally via SQL. But this was for a short-lived project which would only run for a few days.)

I've been using Flask, I love it for the most part. I use PeeWee but prefer to use just raw SQlite. It's supposedly faster with the new 3.8 sqlite version, so I think I'm gonna stay with it.

My gripe with Flask is not itself but the other plugins like flask-security which lacks a lot of documentation.

Flask itself is a delight to use but the only trouble is organizing the code in separate files. I still haven't mastered it, I just import the same file which imports all the modules in all of my flask scripts.

Applications are open for YC Summer 2018

Guidelines | FAQ | Support | API | Security | Lists | Bookmarklet | Legal | Apply to YC | Contact