Jacob Kaplan-Moss

What can Django learn from Rails?

I wrote this post in 2005, more than 18 years ago. It may be very out of date, partially or totally incorrect. I may even no longer agree with this, or might approach things differently if I wrote this post today. I rarely edit posts after writing them, but if I have there'll be a note at the bottom about what I changed and why. If something in this post is actively harmful or dangerous please get in touch and I'll fix it.

One of the questions asked at Snakes & Rubies was about what Django could learn from Rails (and vice versa). Once I finish wrestling Final Cut Pro to the ground you’ll be able to see how Adrian and David answered the question, but in the meantime it got me thinking about some cool features of Rails that are worth ripping off… er… being inspired by:

  • find_or_create convenience methods. Pretty simple, so expect to see a similar method in Django pretty soon.

  • The through option for many-to-many relationships. The only way to add attributes to ManyToMany relationships in Django is with an explicit middle table, but then you lose the join methods that you’re used to.

  • Integrated unit of your models. It’s nice that Rails creates the tests directory automatically when you start a project (David I think referred to this as encouraging developers to do the right thing) but in general I don’t like the way Rails shits all over your project directory. All those folders are confusing.

    It seems that django-admin startapp should have a “simple” and a “complete” option so you could choose between the two.

  • Generic relationships (David called these “polymorphic”, but I’m not sure that’s the right term). You actually can already do this in Django by doing something like:

    class TaggedObject(meta.Model):
        content_type = meta.ForeignKey(core.ContentType)
        object_id = meta.IntegerField()
    
        def get_content_object(self):
            return self.get_content_type().get_object_for_this_type(self.object_id)
    

    However, it could be simpler; I’d love to see:

    class TaggedObject(meta.Model):
        content_object = meta.GenericForeignKey()
    

    or:

    class TaggedObject(meta.Model):
        content_objects = meta.GenericManyToMany()
    
  • It struck me while watching David speak that our python-level many-to-many API isn’t so hot. Right now, to add a M2M relationship you’ve got to do something like:

    story = stories.get_object(...)
    story_categories = [c.id for c in story.get_category_list()]
    if new_category.id not in story_categories:
        story_categories.append(new_category.id)
    story.set_categories(story_categories)
    

    That’s lame. This should work:

    story = stories.get_object(...)
    story.add_category(new_category)
    story.remove_category(category_to_remove)
    
  • Something akin to routes. I actually don’t like the implementation in Rails all that much, but get_absolute_url() breaks the entire idea of URL abstraction, so it needs to get fixed. Simon suggested that the urlconf could define both forward and reverse lookups (which is a cool idea) but I’ve been unable (so far) to figure out a good syntax for this.