Rails / Django: The showdown

Introduction

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).

The environnment

  • 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

The showdown

Terminology

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).

Rails Scaffolding

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.

Rails migrations

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.

Equivalence Table

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:

Rails Django Notes
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)

Some idioms

Finally, a short equivalence between typical idioms, which could give you an idea of the “taste” of each language :

Rails Django Notes
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

Conclusion

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.





7 thoughts on “Rails / Django: The showdown

  1. leoluk

    For Django, there is South, which is a complete database migration utility (changing existing tables).

    Reply
  2. Rafael

    Being a newbie on both languages (Ruby and Python). I tried both of them for a couple of weeks now. I feel more comfortable with Django, for some reason, everything seems more logical to me in Python. (But that is just a personal preference).
    I did hear that Ruby falls short when scaling comes into place for high traffic web apps, and that Python provides better scaling capabilities. What are your thoughts on that?
    Great article Martin, it helped me realize that in the end, choosing RoR or Django might only be a matter of preference as both frameworks offer great features and functionalism.

    Reply
    1. Martin Post author

      I think you nailed it : those are two great framework that would be good choices. The rest is for me a matter of preference. I could use your own argument : for some reason, I find myself more comfortable in Ruby. It is not that the language is insomuch better, it’s just working more like me.

      I would not worry about scaling for either framework, for two main reasons : one, this is a good problem to have – later, two, big websites with heavy traffic uses Django or Rails (GitHub for instance). If it works for them, it should works for you.

      Have a happy journey !

      Martin

      Reply

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>