Why I sort of dislike Django
Here is my opinion on Python web frameworks.
Pyramid is currently the best choice because:
- It is full-featured, with a very well-defined scope as a web framework and a really careful implementation of all the right choices, organized by this little genius called Chris McDonough over literally years of dedicated development.
- Routes are decoupled from request handlers, while offering both URL dispatch and tree traversal.
- Because template rendering is a separate step, view handlers can be easily unit tested. The test case can see the dictionary that a view handler returns. In other frameworks you have to inspect the returned HTML :(
- You can use whatever templating languages you want, including Genshi, Kajiki, Chameleon, Mako, Jinja2 etc.
- You can use whatever you want as a database, including SQLAlchemy, the most powerful Python ORM.
- It has a great authentication and authorization framework which is independent of your choices for data persistence.
- It makes your project an independent Python package, teaching you to use standard Python packaging tools for your benefit.
- It has the best scheme for reusing existing projects, since you can overload templates and views as you integrate another Pyramid site into yours. For an example, see horus, a Pyramid pluggable authentication app using SQLAlchemy.
- It avoids the global variables and threadlocal variables that other web frameworks, such as Flask, like to use, thinking they will be convenient, until they make some things impossible.
- It is thoroughly documented and has a great community with a great IRC channel and a great mailing list.
The only drawbacks of Pyramid might be:
- Because you can choose everything (templating language, ORM etc.), it might take longer to get a project started than if you pick, say, Django. (But the advantages of choosing your libraries, such as deform, compensate for this.)
- Pyramid takes time to learn properly. You have to read the documentation and practise for a while.
Let’s compare this to Django. The advantages of using Django today might be:
- It is old and well-established.
- It has by far the largest community of all web frameworks in Python.
- Very quick to get started because everything has been chosen for you, including templating language and an ORM (even if you don’t want or need an ORM).
- Therefore, there are many existing reusable applications developed in it. These apps tend to work well together because they use the same stack.
- Its web form stuff is really good. (Although not so powerful as deform.)
- Great documentation.
The disadvantages of Django are:
- It is old and needs to maintain backwards compatibility, so it evolves slowly.
- Its daft templating language is severely and deliberately handicapped. It goes to great lengths to prevent you, the developer, from putting logic in a template ― it even forbids you from calling a Python function from the template. Then, in order to remedy this, it allows you to implement a filter, which is nothing more than a way to call a function. What could be more retarded? The syntax of this templating language is also too verbose. On the plus side, many people use Jinja2 instead, which has the same bad syntax, but lets you call functions and works very well.
- People are impressed by the admin, but it really isn’t important at all for development. Other frameworks, being less tightly integrated, cannot offer an admin that would work for everybody. Again, this is of no consequence for real world development.
- Its ORM, created before SQLAlchemy existed, is now much inferior to SQLAlchemy. It is less flexible, its API is less well thought out, and it is based on the Active Record pattern which is worse than the Unit of Work pattern adopted by SQLAlchemy. This means, in Django, models can “save” themselves and transactions are off by default, they are an afterthought. In SQLAlchemy, one thinks in transactional terms from the start. This talk explains this better.
- Model relationships have ON DELETE CASCADE by default, which is a poor choice because it is not safe ― one might lose data because of this. The default should be safe, and the programmer would declare the cascade when applicable. To avoid cascading, one needs to write on_delete=models.PROTECT in each ForeignKey.
- Models can have no mixins ― only simple inheritance. Less powerful than SQLAlchemy.
- Many projects don’t access a database, but there is no way to turn off the ORM, you even have to configure it.
- Django enthusiasts sometimes boast that Django is a single package. Don’t they realize this is actually a bad thing? Django is a tangled monolithic piece of software. The fewer dependencies you have, the more code you have to write yourself. Django is in fact a bad case of Not Invented Here syndrome. Django by itself does not encourage anyone to learn and use standard Python packaging tools.
- Django solved the problem of route definition by using regular expressions; now they have 2 problems. This is jurassic next to the sophisticated dispatch in Pyramid...
- Class-based views. Oh, Django devs have really shot themselves in the foot here, soon they are going to be very sorry. Why? Well, please read Pylons creator Ben Bangert’s blog post titled Why Extending Through Subclassing (a framework’s classes) is a Bad Idea. Looks like Django devs weren’t paying attention to Pylons’ mistakes when they came up with their own class-based views! These are extended through inheritance, which will make everyone’s life complicated in subsequent versions. No separation between the framework’s API and implementation has been indicated. (This separation, by the way, is always in the mind of the Pyramid developers.)
- Class-based views, again, for a different reason. If you ever want to subclass one of them, to change their behaviour slightly, you will be in pain. This is because they themselves are a deep hierarchy of subclasses. Too deep. So you read about 10 classes trying to figure out where you should interfere. This is such a big problem for every Django user who likes class-based views, that an entire website was created to help understand them: http://ccbv.co.uk ― the very existence of which should be seen as a red flag.
Advantages of Flask:
- Gets you started quickly, if the job is simple.
Disadvantages of Flask:
- Suffers from thread local variables everywhere.
- Severely incomplete documentation that seems to only explain something to someone who already knows it.
- Blueprints are simple overengineering.
- Plugin greed: Flask enthusiasts may want everything in the system to be a Flask plugin, which is just plain bad software architecture.
What advantages do I see in Google App Engine?
- First off, the web framework of Google App Engine is very poorly organized. Some libraries are offered by default, you turn them on via configuration. Then you have to provide other libraries alongside your own project. There is no clean separation, no safe place to put them. You cannot use standand Python packaging tools. Let’s just say this: Guido, I expected more of you...
- The documentation is laughable. Very unhelpful.
- Google folks don’t seem to value an appengine-enabled Python interpreter for the developer to try things out. In order to obtain an ipython shell you have to resort to a tremendous hack that includes adding several directories to sys.path.
- Often, interesting subprojects appear, then their bugs are never ironed out and the projects are discontinued by Google because nobody uses them.
- Lock-in. Develop for the Google App Engine and you can only deploy there.
What advantages do I see in web2py?
- Its pypi description starts thus: “Everything in one package with no dependencies.” An even more extreme case of Not Invented Here than Django! At least Django was one of the very first web frameworks developed in Python. web2py is much newer. When it was created, SQLAlchemy already existed, along with many libraries that could have been reused...
- web2py does not offer an ORM (object-relational mapper), only a DAL (data access layer). It boasts this as a great advantage (it’s not a bug, it’s a feature?). By the way, SQLAlchemy has 2 layers: its ORM is based on its DAL, and you can use the one you prefer.
- I didn’t familiarize myself with web2py after seeing this, but I don’t suppose I am missing much.