As written here some weeks ago, we’re in the process of selecting a web framework for our future developments. To clarify the subject, I did some test in both technologies (basically rewriting a prototype from one to the another), taking some notes along. Looking at them, I thought this could be interesting for other people.
As usual, the disclaimer:
- I am no expert on Django and Rails, and do not claim to be one
- I probably started with a bias in favor of Rails (or, more correctly, of the Ruby language)
This said, I’ve tried to highlight the differences and similarities I’ve encountered more than selecting an “all-time winner” (whether for us of for the world). Should I be wrong on some subjects, please kindly point them to me, I would be happy to learn more on this.
Two good options
My main feedback confirms and completes my first impression: those are two very good languages/frameworks (“very good” meaning: adapted to what they aim to achieve), and in fine, while the rest of the post will show some differences, very similar in the concepts and features offered. One can more speak of different tastes than of different capacities. Python itself revealed a joy to work with, dissipating my initial reserves on it.
Moreover, when one of the two seems to be significantly lacking in one aspect, a plugin almost always exists to come to the rescue (as Django and Rails have both a rich plugin ecosystem).
- Linux Ubuntu (seems I’m not switching back. The windows partition hasn’t been start since a while)
- Aptana Studio (both Python & Ruby capacities are good, and the “terminal-friendliness” is a boon in both cases)
- Ruby 1.8.7
- Rails 3.0.8
- Python 2.7
- Django 1.3.0
While being two Model-View-Controller frameworks, Rails and Django differ in terminology :
- Your business objects are the Model in both
- The code that manipulates them is the Controller in Rails but the View in Django (I disagree with Django on this one: even if this could be justified, terminology is supposed to give everyone the same understanding of the same words, which fails in this case)
- The dynamic templates that show your information are the View in Rails (damn) but the Template in Django
Once the (for me) surprising choices of Django are known, the roles and responsibilities of those different component are actually very similar.
Scaffolding versus Admin console
This one require a bit of explanation, as one could think that this is quite a “apple to orange” comparison. While I agree the mechanisms of code generation in Rails and admin console in Django do (totally) differ, I pretend that their purpose is actually very similar: both frameworks are knows to be “rapid/agile development” tools. And those points are the reason :
- Rails code generation is used via several command line commands (rails generate…), to generate a fully functional (while simplistic and certainly not production ready!) application from (basically) your model info
- Django creates for each model an “admin” functionality, with advanced CRUD features, allowing you to use your model immediately.
In the two cases, you find yourself with a functional application mere minutes after having started. I actually do like both approach, for different reasons.
Django Admin Console
Shortly said, Django’s admin console is nothing short of impressive. Not only it gives to you the basic CRUD options (which I expected), but it goes far further:
- The generate web pages are actually quite nice, and can largely serve as a prototype to demonstrate to the customer (in addition to giving you a nice form to fill some data in your database)
- The admin manage all declared relationship so, if you create an Employee that has a “many-to-one” relation to its Company, it allows you to select it in a combo box, or search for it, using any declared attribute, in a nicely formatted search panel
- Icing on the cake, the admin console is fully configurable with only a few line of codes, for example to remove some attributes or allow in-line editing of children object (the lines of an order, for example).
While the features and results of scaffolding fails short of the Django admin console, their main advantage is for me that the code is actually generated: you can see it (and when you are a beginner, it gives you many examples, on your own code), you can edit it, and it will probably serve as your “initial codebase”. Of course you will most probably rewrite all of it during the iterative process, but it does not void this advantage: you have a starting point.
I spoke of plugins before. Those interested by Django-like functionalities for rails may take a look at the Typus plugin. While not as rich as its inspiration, it is actually quite nice.
Implicit versus Explicit Model
Rails favours what I’ll call an “implicit model”: once your class is created, the attributes are reverse-engineered from the database, following (quite fanatically) Rails “Don’t Repeat Yourself” principle (DRY). This lead to some quite concise models:
class Company < ActiveRecord::Base has_many :employees end
So, on the class, no name, no description or other (prossible) attributes. There is beauty in conciseness, sure. Compare to the Django version:
class Company(models.Model): name = models.CharField(max_length = 100) description = models.CharField(max_length = 200) owner = models.CharField(max_length = 50)
Surprisingly, the reverse is true for the relationships, as (supposing that the relation between Company and Employee is a “one-to-many”), the “many-side” is explicit on the Rails version and implicit on the Django one. On a less important point, note that Rails favours the “One file per class” style (so company.rb), while Python models are, by default, on a single “models.py” source file.
Syncdb versus Migrations
Both Rails and Django suppose a very close relationship between the Model and the database schema, with the Model being the main element. As such, both provide commands to keep those two elements in sync.
The Rails migration system is well thought, if not always simple. A migration in Rails is some file with Ruby code representing DDL operations. Basically:
- When you generate a new model, Rails generates its migration based on the informations given to the generate command, and a conversion between Ruby types and the chosen database, creating a file like this one :
class CreateCompanies < ActiveRecord::Migration def self.up create_table :companies do |t| t.string :name t.text :description end end def self.down drop_table :companies end end
- When you want to add a column to a given Model, you need to generate a migration manually (Rails generates a “placeholder”, but you have to fill it):
class AddAgeToEmployee < ActiveRecord::Migration def self.up add_column :employees, :age, :integer end def self.down remove_column :employees, :age end end
- When you need to add a relationship (typically a many-to-many) between two elements, you need to generate a migration and fill it in (your join table and the columns it contains)
class CreateCompanyEmployeeJoinTable < ActiveRecord::Migration def self.up create_table :companies_employees, :id => false do |t| t.integer :company_id t.integer :employee_id end end def self.down drop_table :companies_employees end end
This done, you can run “rake db:migrate” at any point to update the database with the latest changes. More interesting, you can navigate your database back and forth the different migrations, using Rails internal “Version Schema” table. This can be a lifesaver if you need to rollback a version (and its related database changes), as the database schema itself it actually versioned.
Django Syncdb command
The Django mechanism is simple to the point of black magic: edit a model, make some changes, and when you want your database updated, simply type the “syndb” command. Django will then create all required tables and columns from your model, without any additional action required.
While very simple and convenient, the key point is to understand exactly what the command does (and what it does not !). To the risk of repetition: it creates missing tables. That’s it. So, taking the example from above, if you forget a field on your model, and need to update it afterwards, calling syncdb will not update your schema. You then have two possibilitie :
- Update it yourself with SQL
- Scratch the database, and ask Django to create it anew
I was initially quite pleased with Django transparent database management… but I’m now a bit suspicious on using this system on a large project (with changes, rollbacks, …), finding Rails explicit migration system much safer. Once more, I’m not the first to have that idea, and Django users interested in “Rails-like migration” may found help by the South plugin.
Once more, those are more intents of purpose than of implementation. This is more a shortlist that I did write for myself while prototyping both framework, and the main reason beyond my statement that both frameworks are actually quite similar:
|routes||URLConf||Where to define the link between the url’s and your controllers|
|controller||view||The, well, controller of the MVC|
|view||template||The view of the MVC|
|console||shell||Command line to play with your model|
|scaffold||generic views||How to have quick functionalities in your controllers|
|helpers||custom template tags||Where to place code to be used in your views|
|layouts||base templates||System to repeat some element on each page (header/footer for example)|
Finally, a short equivalence between typical idioms, which could give you an idea of the “taste” of each language :
|DateTime.now||datetime.datetime.now||Get the actual date|
|def to_s||def __unicode__(self)||Define a string representation for an object|
|def initialize(a,b)||def __init__(self,a,b)||Constructor with two parameters|
|c.employees << e||c.employee_set.add(e)||Add an employee e to a company c|
|c.employees.each |empl|||for empl in c.employee_set.all||Iterate on the company employees|
Both Rails and Django where pleasant to use, full of surprises (more good than bad), well documented, with great communities (visible in many Stack Overflow tags). The largest differences that I found where Django impressive Admin console and Rails superior migration system. While functionalities mirroring both of those can be found as plugins on the other side, I think that a plugin (however well done, as it seems to be the case for both South and Typus) will never have the quality and large user-base of a core functionality, so the difference still need to be noted.
I can not emphasis enough the importance of personal, hands-on experience for this kind of evaluation, as, once more, wherever road you decide to go, it will be more a question of choice than one of superiority of one or the other. I can only hope that this “sane rivalry” will serve to make the two frameworks better in the future.