Django and mysql names

Using django 1.1.1 framework with dmigrations tool, I’ve discovered that they don’t honour mysql naming conventions correctly. In fact, mysql has a limit of 64 characters on table names, index names and column names, but django doesn’t take it into account when generating tables and indices from models.

In vanilla django, using “manage.py sql” or “manage.py sqlindexes” you can generate respectively “CREATE TABLE” and “CREATE INDEX” sql statements to setup your database schema (if you use manage.py syncdb, generated sql is feeded into your database). Table names are defined in db_table variable in model’s meta class and default name is generated using the following statement in django.db.models.options:

self.db_table = "%s_%s" % (self.app_label, self.module_name)

Now, if your generated db_table is greater than 64 characters (quite easy if your application name is long), django doesn’t truncate it and when sql is feeded into mysql, table creation routine will fail. A similar trouble happens for index creation routine (typically used with unique constraints) and using dmigrations tool instead of plain syncdb doesn’t get any better.

At this point, there are two options for table naming:

  1. Renaming tables in models.py by hand (quite boring if your project is big).
  2. Patching django to apply a truncation to db_table.

For option 2, here’s the simple one-liner patch you need for django 1.1.1:

--- django/db/backends/mysql/base.py.orig
+++ django/db/backends/mysql/base.py
@@ -214,6 +214,9 @@
         second = '%s-12-31 23:59:59.99'
         return [first % value, second % value]

+    def max_name_length(self):
+        return 64
+
 class DatabaseWrapper(BaseDatabaseWrapper):

     operators = {

In dmigrations, index names are defined as:

index_name = '%s_%s_%s' % (app, model, column)

You can fix the length problem in r29 with this simple patch:

--- dmigrations/mysql/migrations.py.orig
+++ dmigrations/mysql/migrations.py
@@ -141,7 +141,7 @@
     def __init__(self, app, model, column):
         model = model.lower()
         self.app, self.model, self.column = app, model, column
-        index_name = '%s_%s_%s' % (app, model, column)
+        index_name = '%s_refs_id_%s' % (column, abs(hash((app, model, column))))
         super(AddIndex, self).__init__(
             sql_up = [self.add_index_sql % (index_name, app, model, column)],
             sql_down = [self.drop_index_sql % (app, model, index_name)],
This entry was posted in Coding, How-tos and tagged , , , . Bookmark the permalink. Post a comment or leave a trackback: Trackback URL.

2 Comments

  1. Posted January 22, 2010 at 1:44 PM | Permalink

    I think failing syncdb is better than truncating table names silently. Having a >64 char table name means either your appname or your model class name or both are too long. Can you provide an example where long names actually make sense?

    Also is there a reason for your preference of dmigrations over south?

  2. Posted January 22, 2010 at 2:25 PM | Permalink

    @Atamert: South was a definitely superior in terms of architecture (plus it's not database dependent), however when I tried to integrate it into my project I found it had several bugs that made it unusable in my setup, so I chose dmigrations because I had no time to fix those bugs and submit patches to the upstream.

    Regarding silent failure, I have to disagree: if a developer chooses not to deal with custom db_table variable, it means that he wants ORM to take care of the hidden details without unexpected results (models development in django should be database independent). Furthermore, table name truncation is already implemented as default strategy in django, it's just that mysql implementation lacked proper limits declaration.

Post a Comment

Your email is never published nor shared. 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>