I’ve recently made the transition from full-time Rails development to a mix of technologies including, in large part, Django. Since I was a Python guy before I ever started using Ruby, the transition has mostly been an easy one, but there are some fairly significant differences in design and philosophy between the two frameworks that are worth thinking about if you’re picking a platform for a new project. Given that most of the comparisons out there on the Intertubes seem to be woefully out of date — the first page of Google results is mostly populated by articles that are 3-4 years old — I thought I might toss out some of my own highly-subjective observations out there anyone else trying to evaluate both stacks.
Similarities
Generally, the two projects are more alike than they are different, at least from the POV of a working web developer. Either one will give you a nice boost in productivity when building non-trivial applications where time-to-market trumps hard performance, runtime platform, or office politics. Much as Ruby and Python offer similar competitive advantage to the teams using them, neither Rails and Django will leave you struggling to keep up with other agile web development teams (or conversely, easily coasting past them).
Both Django and Rails have fairly powerful object-relational layers baked-in, and have good support for popular open source databases, including MySQL, PostgreSQL, and SQLite3. They both offer flexible URL mapping/routing tools, fairly easy-to-learn standard template formats, and (at least for Rails >= 2.3) the ability to insert middleware into the fast path of your request/response cycle, either to manipulate the request data, or to short-circuit loading in cases where you don’t need the whole framework for a particular client request.
In addition, both frameworks benefit from an active, supportive community that will help you get up to speed and answer questions. The online documentation for each project is fairly extensive, although I personally feel that the Django folks have done a better job of pulling the 80% of the docs that most developers need when they’re getting started into one place, with a consistent style and voice.
Django wins
There are a couple of big ones: form classes and idiomatic use of Python modules.
Form classes
This is, without a doubt, my favorite feature of Django that simply has no real equivalent in Rails. Basically, a Django form lets you de-couple the HTML editing UI for a model from its storage and business logic. The big win here is due to the fact that form validation != domain model validation. Depending on your application, you want to allow users to populate forms with more or less information than would be stored in a single model class instance, and validate those forms using their own internal validation logic, rather than delegating all validation decisions to the model class.
As a case in point, consider a simple comment form. If you add a CAPTCHA to the form, you could make your Django form class perform checking of that field, and display errors in CAPTCHA solving alongside those affecting the other comment fields, without forcing the comment model to even be aware that its views relied on such protections. Furthermore, once that form class was implemented, you could re-use it in any number of views without duplicating the display or validation logic. This is simply a better way to build views than the Rails model of helpers and shared controller methods, and I would encourage the Rails community to find some way to provide more support for structured views, especially in the areas of form handling.
Python modules
Ruby and Python both support modules as a namespace construct. However, much as Ruby classes default to having private instance variables and public methods, the Ruby module type is largely opaque except when used as a mixin to a class implementation. Few Ruby libraries would be written to use instances of the Module type directly; rather, they would expect either an instance of some class, or a hash mapping symbols to objects. In Python, however, modules are “open” by default, with any defined names visible both inside and outside the module — just as Python objects default to being public bags of attributes.
This leads to one very natural means to connecting applications and components in a Django project: passing modules (or module names) as first-class constructs. Want to “mount” all the URLs in a pluggable Django app into your project? Use include('myapp.urls'). Want to override the content model classes used in a CMS workflow app? Parameterize the application with an optional model namespace module, and look up the needed model classes in that module at runtime. Dependency injection, “duck typed” polymorphism, etc., can all happen at the module level, and the entire Django framework (and well-written reusable applications that use it) capitalize quite effectively on this capability.
Rails wins
There are two major areas where Rails stomps Django: testing tools and database schema migrations.
Testing tools
This one should be obvious to anyone who compares recent conference talk or blog post titles from the Rails and Django worlds. For those who don’t want to click through: RailsConf had 3-4x as many testing-focused sessions, and it was mentioned in many if not most other talks. The highly-scientific Google Fight also shows a much higher amount of online discussion of Rails testing, adding further anecdotal evidence to support the argument that the Rails community is at least
Rails developers, as a community, have been thoroughly bitten by the testing bug, and are always on the lookup for better ways to write more copious and useful collections of tests for their applications. This has led to the development of great tools like RSpec, Shoulda, WebRat, and Cucumber for authoring tests, along with a huge supporting cast of libraries, reporting tools, and howto guides to make testing as easy as possible for Rails developers. Django has TestCase and TestClient, with a smattering of support from other Python tools like Windmill and python-nose to speed things along.
I recognize that most of the Ruby modules I linked to above are not part of the Rails core, and than there are lots of similarities in the features available for testing in either Ruby or Python. The difference is that most Rails developers I’ve talked to use the full breadth of testing tools available to them, and extol their use to others, while the Django community takes a much more lackadaisical attitude about testing outside of the Django core. (Even the bundled “contrib” apps in Django often have weak test coverage — as an example, there are zero included unit or doctests for the django.contrib.admin in my local django trunk checkout at r11578).
Schema migrations
ActiveRecord migrations are not the solution for all possible database changes in real-world applications, but they cover most cases in a consistent, easy-to-learn way. Once they learn a handful of migration library methods, Rails developers can happily write clear, lightweight database manipulation routines that allow their application database to evolve as requirements change without having to resort to non-portable low-level SQL queries. This is a Good Thing ™, and worth emulating in other frameworks.
South is an entirely-reasonable implementation of a very similar model. The Django core team should adopt it as part of the platform, or implement their own simplified version. This is an obvious case where the perfect is the enemy of the good.
Conclusions
Generally, I’m pretty happy about working with Django instead of Rails these days. Whereas I spent days struggling with obscure classloading issues trying to trivially extend the Rails framework, I’ve been able to make use of the module-driven pluggability of Django to swap out cache backends, template libraries, and entire domain model namespaces in my Django apps without much more than a brief foray into the source for an external library or two. Modulo the testing issues I raised above, and the lack of a really good equivalent to ActiveMerchant, I would call myself a fairly satisfied Django user, at least until the next big thing comes along.
There are some less technical reasons to consider Django over Rails, as well. First, who doesn’t love any typically male-dominated developer community which adopts such a ridiculous mascot? Also, I attended both RailsConf and DjangoCon this year, and have to say that I enjoyed the latter quite a bit more. The difference in location for the two conferences may have altered my perceptions a bit, but I personally had more fun at DjangoCon. I also didn’t overhear anyone describe themselves as a “rockstar” at there, which was just fine with me.
FTW Django!
We use Form classes extensively with Rails at Songkick. As you say, they are very helpful.
Thanks for a nice comparison. Speaking of ActiveMerchant, are you aware of this effort of separating the payment system out of the Satchmo project?
Very good article! This proves once for all that these two frameworks are not the equivalents in their different languages.
I completly agree the forms library is one of djangos best parts.
I usally say rails is better when you need to develop APIs and services and django when you want to develop websites.
The python equivalent of rails would be the smisk framework http://python-smisk.org/
You pretty much hit the nail on the head there, I feel the same way on nearly every point. Django sits better with me ultimately and feels less like a fad or statement
Great comparison of the two frameworks. I’ve been using Django for 3+ years, and about 6 months ago started working with Rails full-time (while still using Django a lot for side-projects).
You’ve definitely identified the biggest differences. I totally agree with Django’s forms frameworks being one of it’s advantages — that’s probably the only piece I find myself *really* wishing for when working in Rails.
Has anyone heard of or started on a plugin to emulate Django form classes in Rails? I would love something like this, as dealing with conditional validations depending on state can get very hairy.
Regarding tests for django.contrib.admin: you must have been looking in the wrong place, there are actually quite a lot – see http://code.djangoproject.com/browser/django/trunk/tests/regressiontests?rev=11578
I’d say another difference between Django & Rails is performance and resource consumption.
Django is significantly faster than Rails. It also uses significantly fewer memory. A Rails process typically can be around 100MB, while a Django process is more like 20MB. Django can be run in multithreaded mode, so you can have 5 threads in a 30MB Django process vs. 500MB for 5 Rails processes.
This means that with Django you get a bigger bang for your buck spent on hardware. If you have a $20 256MB VPS that needs to run Linux, Apache, Django or Rails, and MySQL – with Rails youwon’t be able to serve more than 1 concurrent user while with Django you can serve 5 or 10. Same if you have a 8G dedicated server – you can serve far more concurrent users with Django than with Rails.
Andy:
Django is faster than rails, but please check your informations before writing
http://guides.rubyonrails.org/2_2_release_notes.html#thread-safety – it has been released about a year ago.
Excellent, level-headed analysis. Thanks for the post.
+1 for Django
Andy: I have no idea how you’re running Rails (if you are actually running rails), but with Passenger + REE our per-process footprint is closer to 30 megs. Rails also is multithreaded, as Piotr notes.
As for the post, very nice writeup! I largely agree with everything here, even thought I’m a Rails guy. I’d add a couple more wins for Django: The admin is a very slick feature, and I absolutely prefer the templatting language vs. erb, which invites all sorts of problems. Of course you can emulate both with various Rails plugins, but that’s not the point here.
On the Rails side, I think ActiveRecord is a far, far, far better ORM in general, and Rails 3 promises to vastly improve things further by allowing the ORM to be completely swappable.
Just the two cents from a relatively inexperienced web developer: on my shared hosting, rails app (30-40 Mb) always uses more memory than django app (quite similar apps). However, I can’t compare their performance.
Django has twill. http://djangosnippets.org/snippets/665/