Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

Fixed #5729 -- For MySQL (only), always delay the creation of foreign…

… key

references, for all tables, until after the table has been created. This means
that when using the InnoDB storage engine, true foreign key constraints are
created (inline "REFERENCES" are ignored by InnoDB, unfortunately).

Fully backwards compatible.


git-svn-id: http://code.djangoproject.com/svn/django/trunk@6650 bcc190cf-cafb-0310-a4f2-bffc1f526a37
  • Loading branch information...
commit 595e75e8dd5db5982574d5d3222054186ba190d8 1 parent 3f1ce2e
Malcolm Tredinnick authored November 04, 2007
63  django/core/management/sql.py
@@ -252,6 +252,7 @@ def sql_model_create(model, style, known_models=set()):
252 252
     table_output = []
253 253
     pending_references = {}
254 254
     qn = connection.ops.quote_name
  255
+    inline_references = connection.features.inline_fk_references
255 256
     for f in opts.fields:
256 257
         col_type = f.db_type()
257 258
         tablespace = f.db_tablespace or opts.db_tablespace
@@ -272,7 +273,7 @@ def sql_model_create(model, style, known_models=set()):
272 273
             # won't be generating a CREATE INDEX statement for this field.
273 274
             field_output.append(connection.ops.tablespace_sql(tablespace, inline=True))
274 275
         if f.rel:
275  
-            if f.rel.to in known_models:
  276
+            if inline_references and f.rel.to in known_models:
276 277
                 field_output.append(style.SQL_KEYWORD('REFERENCES') + ' ' + \
277 278
                     style.SQL_TABLE(qn(f.rel.to._meta.db_table)) + ' (' + \
278 279
                     style.SQL_FIELD(qn(f.rel.to._meta.get_field(f.rel.field_name).column)) + ')' +
@@ -341,10 +342,12 @@ def sql_for_pending_references(model, style, pending_references):
341 342
 def many_to_many_sql_for_model(model, style):
342 343
     from django.db import connection, models
343 344
     from django.contrib.contenttypes import generic
  345
+    from django.db.backends.util import truncate_name
344 346
 
345 347
     opts = model._meta
346 348
     final_output = []
347 349
     qn = connection.ops.quote_name
  350
+    inline_references = connection.features.inline_fk_references
348 351
     for f in opts.many_to_many:
349 352
         if not isinstance(f.rel, generic.GenericRel):
350 353
             tablespace = f.db_tablespace or opts.db_tablespace
@@ -354,26 +357,43 @@ def many_to_many_sql_for_model(model, style):
354 357
                 tablespace_sql = ''
355 358
             table_output = [style.SQL_KEYWORD('CREATE TABLE') + ' ' + \
356 359
                 style.SQL_TABLE(qn(f.m2m_db_table())) + ' (']
357  
-            table_output.append('    %s %s %s%s,' % \
  360
+            table_output.append('    %s %s %s%s,' %
358 361
                 (style.SQL_FIELD(qn('id')),
359 362
                 style.SQL_COLTYPE(models.AutoField(primary_key=True).db_type()),
360 363
                 style.SQL_KEYWORD('NOT NULL PRIMARY KEY'),
361 364
                 tablespace_sql))
362  
-            table_output.append('    %s %s %s %s (%s)%s,' % \
363  
-                (style.SQL_FIELD(qn(f.m2m_column_name())),
364  
-                style.SQL_COLTYPE(models.ForeignKey(model).db_type()),
365  
-                style.SQL_KEYWORD('NOT NULL REFERENCES'),
366  
-                style.SQL_TABLE(qn(opts.db_table)),
367  
-                style.SQL_FIELD(qn(opts.pk.column)),
368  
-                connection.ops.deferrable_sql()))
369  
-            table_output.append('    %s %s %s %s (%s)%s,' % \
370  
-                (style.SQL_FIELD(qn(f.m2m_reverse_name())),
371  
-                style.SQL_COLTYPE(models.ForeignKey(f.rel.to).db_type()),
372  
-                style.SQL_KEYWORD('NOT NULL REFERENCES'),
373  
-                style.SQL_TABLE(qn(f.rel.to._meta.db_table)),
374  
-                style.SQL_FIELD(qn(f.rel.to._meta.pk.column)),
375  
-                connection.ops.deferrable_sql()))
376  
-            table_output.append('    %s (%s, %s)%s' % \
  365
+            if inline_references:
  366
+                deferred = []
  367
+                table_output.append('    %s %s %s %s (%s)%s,' %
  368
+                    (style.SQL_FIELD(qn(f.m2m_column_name())),
  369
+                    style.SQL_COLTYPE(models.ForeignKey(model).db_type()),
  370
+                    style.SQL_KEYWORD('NOT NULL REFERENCES'),
  371
+                    style.SQL_TABLE(qn(opts.db_table)),
  372
+                    style.SQL_FIELD(qn(opts.pk.column)),
  373
+                    connection.ops.deferrable_sql()))
  374
+                table_output.append('    %s %s %s %s (%s)%s,' %
  375
+                    (style.SQL_FIELD(qn(f.m2m_reverse_name())),
  376
+                    style.SQL_COLTYPE(models.ForeignKey(f.rel.to).db_type()),
  377
+                    style.SQL_KEYWORD('NOT NULL REFERENCES'),
  378
+                    style.SQL_TABLE(qn(f.rel.to._meta.db_table)),
  379
+                    style.SQL_FIELD(qn(f.rel.to._meta.pk.column)),
  380
+                    connection.ops.deferrable_sql()))
  381
+            else:
  382
+                table_output.append('    %s %s %s,' %
  383
+                    (style.SQL_FIELD(qn(f.m2m_column_name())),
  384
+                    style.SQL_COLTYPE(models.ForeignKey(model).db_type()),
  385
+                    style.SQL_KEYWORD('NOT NULL')))
  386
+                table_output.append('    %s %s %s,' %
  387
+                    (style.SQL_FIELD(qn(f.m2m_reverse_name())),
  388
+                    style.SQL_COLTYPE(models.ForeignKey(f.rel.to).db_type()),
  389
+                    style.SQL_KEYWORD('NOT NULL')))
  390
+                deferred = [
  391
+                    (f.m2m_db_table(), f.m2m_column_name(), opts.db_table,
  392
+                        opts.pk.column),
  393
+                    ( f.m2m_db_table(), f.m2m_reverse_name(),
  394
+                        f.rel.to._meta.db_table, f.rel.to._meta.pk.column)
  395
+                    ]
  396
+            table_output.append('    %s (%s, %s)%s' %
377 397
                 (style.SQL_KEYWORD('UNIQUE'),
378 398
                 style.SQL_FIELD(qn(f.m2m_column_name())),
379 399
                 style.SQL_FIELD(qn(f.m2m_reverse_name())),
@@ -385,6 +405,15 @@ def many_to_many_sql_for_model(model, style):
385 405
             table_output.append(';')
386 406
             final_output.append('\n'.join(table_output))
387 407
 
  408
+            for r_table, r_col, table, col in deferred:
  409
+                r_name = '%s_refs_%s_%x' % (r_col, col,
  410
+                        abs(hash((r_table, table))))
  411
+                final_output.append(style.SQL_KEYWORD('ALTER TABLE') + ' %s ADD CONSTRAINT %s FOREIGN KEY (%s) REFERENCES %s (%s)%s;' % 
  412
+                (qn(r_table),
  413
+                truncate_name(r_name, connection.ops.max_name_length()),
  414
+                qn(r_col), qn(table), qn(col),
  415
+                connection.ops.deferrable_sql()))
  416
+
388 417
             # Add any extra SQL needed to support auto-incrementing PKs
389 418
             autoinc_sql = connection.ops.autoinc_sql(f.m2m_db_table(), 'id')
390 419
             if autoinc_sql:
1  django/db/backends/__init__.py
@@ -43,6 +43,7 @@ class BaseDatabaseFeatures(object):
43 43
     allows_group_by_ordinal = True
44 44
     allows_unique_and_pk = True
45 45
     autoindexes_primary_keys = True
  46
+    inline_fk_references = True
46 47
     needs_datetime_string_cast = True
47 48
     needs_upper_for_iops = False
48 49
     supports_constraints = True
1  django/db/backends/mysql/base.py
@@ -61,6 +61,7 @@
61 61
 
62 62
 class DatabaseFeatures(BaseDatabaseFeatures):
63 63
     autoindexes_primary_keys = False
  64
+    inline_fk_references = False
64 65
 
65 66
 class DatabaseOperations(BaseDatabaseOperations):
66 67
     def date_extract_sql(self, lookup_type, field_name):
1  django/db/backends/mysql_old/base.py
@@ -65,6 +65,7 @@ def __getattr__(self, attr):
65 65
 
66 66
 class DatabaseFeatures(BaseDatabaseFeatures):
67 67
     autoindexes_primary_keys = False
  68
+    inline_fk_references = False
68 69
 
69 70
 class DatabaseOperations(BaseDatabaseOperations):
70 71
     def date_extract_sql(self, lookup_type, field_name):

0 notes on commit 595e75e

Please sign in to comment.
Something went wrong with that request. Please try again.