Rails and Django - Database and Models (part 6/15)
Database and Models
A lot of complexity is encapsulated by database abstraction and mapping to application objects. Both Rails and Django share robust support, including:
- Both frameworks use an ORM model (object relational mapping), which means there's an mapping between database tables and corresponding object classes. Rails' ORM is called ActiveRecord. Django's is named Model. In other words, both frameworks provide an API customized to your database “for free”.
- Both have you declare the field names, types and attributes in the class definitions. You can set constraints on each field (e.g. max number of characters), automatic values (e.g. creation date, update date), and relations to other tables (foreign keys) for one-to-many and many-to-many relations.
- Both frameworks support “lazy access” which means the database is queried at the last possible moment, avoiding redundant operations and improving performance. Both also support transactions (atomic database operations), provided the underlying database supports.
- Both let you define "hooks", functions that are attached to specific operations without having to change the model code itself, such as before create, after create, before save, after save, etc. In Rails they're called "observers". In Django they're called "signals".
- Support the leading database servers, including MySQL, PostgreSQL, and SQLite. Rails also supports Oracle and MSSQL (in development for Django). I will not address the lower level database abstraction and driver layers, although there appears plenty of room for discussion in that area too.
Rails
Rails includes a powerful migration tool that lets you define your database schema in a series of files called “migrations.” Migration files, named something like db/001_create_mymodel.rb, db/002_adding_a_column.rb, etc, define your tables' field names and types (text, integer, date, etc). Migrations are subclass of ActiveRecord::Migration
When you run the migrate command (rake db:migrate ) your database is (re)structured accordingly. Migrate keeps track of the current migration level, processing only new scripts since the last time it was run. And it lets you roll back to an earlier schema.
Next, you define the model class for each data table, containing the business logic associated with that data (ie. app/models/mymodel.rb). The model may define validation rules, such as required, unique, or length, and used in user input forms. The model also defines any relations with other tables (such as one-to-many relationships). You would also define any model-specific methods helpful for accessing and updating data.
The Rails naming “magic” is really quite funky so I'll give an example here. Let's say you create a model “line_item” with the command
$ ruby script/generate model line_item
This may create a file db/migrate/006_create_line_items.rb which defines a class CreateLineItems < ActiveRecord::Migration. It also creates a file app/models/line_item.rb (note singular) which defines a class LineItem < ActiveRecord::Base . Thus the rule is: Classes are singular, Tables are plural.
The model inspects at the database columns (produced by the migration) to determine the method names available to the model object.
Rails also provides a tool for creating “fixtures”, pre-defined data sets used (and re-used) in testing. Fixture data is specified in a simple popular language called YAML (which is easier to read and write than XML).
Rails supports model inheritance through a fairly simple mechanism of a single table with a collection of all columns from all child classes. This can lead to wide tables with many empty fields.
Finally, Rails has built in accommodation for 3 databases-- development, testing, and production. This is very handy and shows the framework is well footed in the real world.
Django
In Django, a model's table schema and methods are defined in a single models.py file. You add class variables which will become the database table columns.
Then, use the command to generate the database table from the model, such as
$ python manage.py syncdb
The manage.py script actually can do a lot of things. Before syncdb, for example, you might want to try
$ python manage.py sql myapp
which will dump the SQL statements that syncdb will use to create the table, lets you doublecheck for errors in the model.
Django does not have a tool for migrations. It's under discussion (http://code.djangoproject.com/wiki/SchemaEvolution) but doesn't appear to even be slated for the 1.0 release. We're told basic migrations are easy to do directly in SQL, and the “hard” stuff, well, even Rails can't do properly (ref: irc log 2/18/07)
Django is working on model inheritance for the 1.0 Release. The plan is to use "joins" of separate tables for each subclass, a more thorough approach than the Rails one, but also more complex to implement.
Django can easily integrate with legacy databases, using a utility that introspects an existing database and produces a corresponding models.py file.
Opinion
To summarize, in Rails you create the database table separately, and the Model class inspects the table column definitions to determine its attributes. Django is opposite, you define the data attributes in your Model class, and that is used to create and drive the database table. Rails does pluralization magic; Django is explicit.
The Rails approach makes it difficult (if not impossible) for it to integrate with legacy databases.
The Rails migration tool is a powerful approach supporting agile development, and in my opinion, it's an significant deficit in Django. I also really like how Rails has integrated the notions of development, testing, and production databases into its configuration.
Overall, the Django approach to Models is cleaner. The Rails implementation is more mature and more supportive of the whole development process.
Conclusion: Both frameworks appear to provide a robust and complete ORM model. Django is weaker without features like migrations and model inheritance (and legacy support is not so important to me). Rails wins 4 to 3.
| Database / Model | Rails | Django |
| Schema migration | "Migrations" | manual (SQL) |
| ORM class | "ActiveRecord" | "Model" |
| Model attributes | introspection | declarative |
| Relations (1:1, 1:N, N:M) | yes | yes |
| Pluralization | yes | no |
| Hooks | "observers" | "signals" |
| Transactions | yes | yes |
| Model inheritance | yes (single table) | under devel (joins) |
| Devel vs Testing vs Production | built in | |
| SQL servers | MySQL, SQLite, Postgres, MSSQL, Oracle, Db2, Sybase, more | MySQL, SQLite, PostgreSQL (MSSQL and Oracle in devel) |
| MY RATING: (1=worst, 5=best) | 4 | 3 |




Rails and Django - Database and Models (part 6/15)
Posted by: carlivar on March 05, 2007 09:12 PM#