shaib avatar shaib committed 1fd2473

Make generation of M2M tables use correct name shortening

Comments (0)

Files changed (2)


         # Adding M2M table for field %(field_name)s on '%(model_name)s'
-        db.create_table(%(table_name)r, (
+        m2m_table_name = %(table_name)s
+        db.create_table(m2m_table_name, (
             ('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True)),
             (%(left_field)r, models.ForeignKey(orm[%(left_model_key)r], null=False)),
             (%(right_field)r, models.ForeignKey(orm[%(right_model_key)r], null=False))
-        db.create_unique(%(table_name)r, [%(left_column)r, %(right_column)r])'''[1:] + "\n"
+        db.create_unique(m2m_table_name, [%(left_column)r, %(right_column)r])'''[1:] + "\n"
         # Removing M2M table for field %(field_name)s on '%(model_name)s'
-        db.delete_table('%(table_name)s')'''[1:] + "\n"
+        db.delete_table(%(table_name)s)'''[1:] + "\n"
     def __init__(self, model, field):
         self.model = model
+    def table_name(self):
+        # This is part of a workaround for the fact that Django uses
+        # different shortening for automatically generated m2m table names 
+        # (as opposed to any explicitly specified table name)
+        f = self.field
+        explicit = f.db_table
+        if explicit:
+            return "%r" % explicit
+        else:
+            auto = "%s_%s" % (self.model._meta.db_table,
+            return 'db.shorten_name(%r)' % auto
     def forwards_code(self):
         return self.FORWARDS_TEMPLATE % {
             "model_name": self.model._meta.object_name,
-            "table_name": self.field.m2m_db_table(),
+            "table_name": self.table_name(),
             "left_field": self.field.m2m_column_name()[:-3], # Remove the _id part
             "left_column": self.field.m2m_column_name(),
             "left_model_key": model_key(self.model),
         return self.BACKWARDS_TEMPLATE % {
             "model_name": self.model._meta.object_name,
-            "table_name": self.field.m2m_db_table(),
+            "table_name": self.table_name(),


         constraint_name = '%s_refs_%s_%x' % (from_column_name, to_column_name, abs(hash((from_table_name, to_table_name))))
         return 'ALTER TABLE %s ADD CONSTRAINT %s FOREIGN KEY (%s) REFERENCES %s (%s)%s;' % (
-            self.quote_name(truncate_name(constraint_name, self._get_connection().ops.max_name_length())),
+            self.quote_name(self.shorten_name(constraint_name)),
             self._django_db_creation = BaseDatabaseCreation(self._get_connection())
         return self._django_db_creation._digest(*args)
+    def shorten_name(self, name):
+        return truncate_name(name, self._get_connection().ops.max_name_length())
     def create_index_name(self, table_name, column_names, suffix=""):
         Generate a unique name for the index
         # If there is just one column in the index, use a default algorithm from Django
         if len(column_names) == 1 and not suffix:
-            return truncate_name(
-                '%s_%s' % (table_name, self._digest(column_names[0])),
-                self._get_connection().ops.max_name_length()
+            return self.shorten_name(
+                '%s_%s' % (table_name, self._digest(column_names[0]))
         # Else generate the name for the index by South
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.