app/django/core/management/sql.py
changeset 323 ff1a9aa48cfd
parent 54 03e267d67478
equal deleted inserted replaced
322:6641e941ef1e 323:ff1a9aa48cfd
     5 try:
     5 try:
     6     set
     6     set
     7 except NameError:
     7 except NameError:
     8     from sets import Set as set   # Python 2.3 fallback
     8     from sets import Set as set   # Python 2.3 fallback
     9 
     9 
    10 def table_names():
       
    11     "Returns a list of all table names that exist in the database."
       
    12     from django.db import connection, get_introspection_module
       
    13     cursor = connection.cursor()
       
    14     return set(get_introspection_module().get_table_list(cursor))
       
    15 
       
    16 def django_table_names(only_existing=False):
       
    17     """
       
    18     Returns a list of all table names that have associated Django models and
       
    19     are in INSTALLED_APPS.
       
    20 
       
    21     If only_existing is True, the resulting list will only include the tables
       
    22     that actually exist in the database.
       
    23     """
       
    24     from django.db import models
       
    25     tables = set()
       
    26     for app in models.get_apps():
       
    27         for model in models.get_models(app):
       
    28             tables.add(model._meta.db_table)
       
    29             tables.update([f.m2m_db_table() for f in model._meta.local_many_to_many])
       
    30     if only_existing:
       
    31         tables = [t for t in tables if t in table_names()]
       
    32     return tables
       
    33 
       
    34 def installed_models(table_list):
       
    35     "Returns a set of all models that are installed, given a list of existing table names."
       
    36     from django.db import connection, models
       
    37     all_models = []
       
    38     for app in models.get_apps():
       
    39         for model in models.get_models(app):
       
    40             all_models.append(model)
       
    41     if connection.features.uses_case_insensitive_names:
       
    42         converter = lambda x: x.upper()
       
    43     else:
       
    44         converter = lambda x: x
       
    45     return set([m for m in all_models if converter(m._meta.db_table) in map(converter, table_list)])
       
    46 
       
    47 def sequence_list():
       
    48     "Returns a list of information about all DB sequences for all models in all apps."
       
    49     from django.db import models
       
    50 
       
    51     apps = models.get_apps()
       
    52     sequence_list = []
       
    53 
       
    54     for app in apps:
       
    55         for model in models.get_models(app):
       
    56             for f in model._meta.local_fields:
       
    57                 if isinstance(f, models.AutoField):
       
    58                     sequence_list.append({'table': model._meta.db_table, 'column': f.column})
       
    59                     break # Only one AutoField is allowed per model, so don't bother continuing.
       
    60 
       
    61             for f in model._meta.local_many_to_many:
       
    62                 sequence_list.append({'table': f.m2m_db_table(), 'column': None})
       
    63 
       
    64     return sequence_list
       
    65 
       
    66 def sql_create(app, style):
    10 def sql_create(app, style):
    67     "Returns a list of the CREATE TABLE SQL statements for the given app."
    11     "Returns a list of the CREATE TABLE SQL statements for the given app."
    68     from django.db import models
    12     from django.db import connection, models
    69     from django.conf import settings
    13     from django.conf import settings
    70 
    14 
    71     if settings.DATABASE_ENGINE == 'dummy':
    15     if settings.DATABASE_ENGINE == 'dummy':
    72         # This must be the "dummy" database backend, which means the user
    16         # This must be the "dummy" database backend, which means the user
    73         # hasn't set DATABASE_ENGINE.
    17         # hasn't set DATABASE_ENGINE.
    79     # We trim models from the current app so that the sqlreset command does not
    23     # We trim models from the current app so that the sqlreset command does not
    80     # generate invalid SQL (leaving models out of known_models is harmless, so
    24     # generate invalid SQL (leaving models out of known_models is harmless, so
    81     # we can be conservative).
    25     # we can be conservative).
    82     app_models = models.get_models(app)
    26     app_models = models.get_models(app)
    83     final_output = []
    27     final_output = []
    84     known_models = set([model for model in installed_models(table_names()) if model not in app_models])
    28     tables = connection.introspection.table_names()
       
    29     known_models = set([model for model in connection.introspection.installed_models(tables) if model not in app_models])
    85     pending_references = {}
    30     pending_references = {}
    86 
    31 
    87     for model in app_models:
    32     for model in app_models:
    88         output, references = sql_model_create(model, style, known_models)
    33         output, references = connection.creation.sql_create_model(model, style, known_models)
    89         final_output.extend(output)
    34         final_output.extend(output)
    90         for refto, refs in references.items():
    35         for refto, refs in references.items():
    91             pending_references.setdefault(refto, []).extend(refs)
    36             pending_references.setdefault(refto, []).extend(refs)
    92             if refto in known_models:
    37             if refto in known_models:
    93                 final_output.extend(sql_for_pending_references(refto, style, pending_references))
    38                 final_output.extend(connection.creation.sql_for_pending_references(refto, style, pending_references))
    94         final_output.extend(sql_for_pending_references(model, style, pending_references))
    39         final_output.extend(connection.creation.sql_for_pending_references(model, style, pending_references))
    95         # Keep track of the fact that we've created the table for this model.
    40         # Keep track of the fact that we've created the table for this model.
    96         known_models.add(model)
    41         known_models.add(model)
    97 
    42 
    98     # Create the many-to-many join tables.
    43     # Create the many-to-many join tables.
    99     for model in app_models:
    44     for model in app_models:
   100         final_output.extend(many_to_many_sql_for_model(model, style))
    45         final_output.extend(connection.creation.sql_for_many_to_many(model, style))
   101 
    46 
   102     # Handle references to tables that are from other apps
    47     # Handle references to tables that are from other apps
   103     # but don't exist physically.
    48     # but don't exist physically.
   104     not_installed_models = set(pending_references.keys())
    49     not_installed_models = set(pending_references.keys())
   105     if not_installed_models:
    50     if not_installed_models:
   106         alter_sql = []
    51         alter_sql = []
   107         for model in not_installed_models:
    52         for model in not_installed_models:
   108             alter_sql.extend(['-- ' + sql for sql in
    53             alter_sql.extend(['-- ' + sql for sql in
   109                 sql_for_pending_references(model, style, pending_references)])
    54                 connection.creation.sql_for_pending_references(model, style, pending_references)])
   110         if alter_sql:
    55         if alter_sql:
   111             final_output.append('-- The following references should be added but depend on non-existent tables:')
    56             final_output.append('-- The following references should be added but depend on non-existent tables:')
   112             final_output.extend(alter_sql)
    57             final_output.extend(alter_sql)
   113 
    58 
   114     return final_output
    59     return final_output
   115 
    60 
   116 def sql_delete(app, style):
    61 def sql_delete(app, style):
   117     "Returns a list of the DROP TABLE SQL statements for the given app."
    62     "Returns a list of the DROP TABLE SQL statements for the given app."
   118     from django.db import connection, models, get_introspection_module
    63     from django.db import connection, models
   119     from django.db.backends.util import truncate_name
    64     from django.db.backends.util import truncate_name
   120     from django.contrib.contenttypes import generic
    65     from django.contrib.contenttypes import generic
   121     introspection = get_introspection_module()
       
   122 
    66 
   123     # This should work even if a connection isn't available
    67     # This should work even if a connection isn't available
   124     try:
    68     try:
   125         cursor = connection.cursor()
    69         cursor = connection.cursor()
   126     except:
    70     except:
   127         cursor = None
    71         cursor = None
   128 
    72 
   129     # Figure out which tables already exist
    73     # Figure out which tables already exist
   130     if cursor:
    74     if cursor:
   131         table_names = introspection.get_table_list(cursor)
    75         table_names = connection.introspection.get_table_list(cursor)
   132     else:
    76     else:
   133         table_names = []
    77         table_names = []
   134     if connection.features.uses_case_insensitive_names:
    78 
   135         table_name_converter = lambda x: x.upper()
    79     output = []
   136     else:
       
   137         table_name_converter = lambda x: x
       
   138 
       
   139     output = []
       
   140     qn = connection.ops.quote_name
       
   141 
    80 
   142     # Output DROP TABLE statements for standard application tables.
    81     # Output DROP TABLE statements for standard application tables.
   143     to_delete = set()
    82     to_delete = set()
   144 
    83 
   145     references_to_delete = {}
    84     references_to_delete = {}
   146     app_models = models.get_models(app)
    85     app_models = models.get_models(app)
   147     for model in app_models:
    86     for model in app_models:
   148         if cursor and table_name_converter(model._meta.db_table) in table_names:
    87         if cursor and connection.introspection.table_name_converter(model._meta.db_table) in table_names:
   149             # The table exists, so it needs to be dropped
    88             # The table exists, so it needs to be dropped
   150             opts = model._meta
    89             opts = model._meta
   151             for f in opts.local_fields:
    90             for f in opts.local_fields:
   152                 if f.rel and f.rel.to not in to_delete:
    91                 if f.rel and f.rel.to not in to_delete:
   153                     references_to_delete.setdefault(f.rel.to, []).append( (model, f) )
    92                     references_to_delete.setdefault(f.rel.to, []).append( (model, f) )
   154 
    93 
   155             to_delete.add(model)
    94             to_delete.add(model)
   156 
    95 
   157     for model in app_models:
    96     for model in app_models:
   158         if cursor and table_name_converter(model._meta.db_table) in table_names:
    97         if connection.introspection.table_name_converter(model._meta.db_table) in table_names:
   159             # Drop the table now
    98             output.extend(connection.creation.sql_destroy_model(model, references_to_delete, style))
   160             output.append('%s %s;' % (style.SQL_KEYWORD('DROP TABLE'),
       
   161                 style.SQL_TABLE(qn(model._meta.db_table))))
       
   162             if connection.features.supports_constraints and model in references_to_delete:
       
   163                 for rel_class, f in references_to_delete[model]:
       
   164                     table = rel_class._meta.db_table
       
   165                     col = f.column
       
   166                     r_table = model._meta.db_table
       
   167                     r_col = model._meta.get_field(f.rel.field_name).column
       
   168                     r_name = '%s_refs_%s_%x' % (col, r_col, abs(hash((table, r_table))))
       
   169                     output.append('%s %s %s %s;' % \
       
   170                         (style.SQL_KEYWORD('ALTER TABLE'),
       
   171                         style.SQL_TABLE(qn(table)),
       
   172                         style.SQL_KEYWORD(connection.ops.drop_foreignkey_sql()),
       
   173                         style.SQL_FIELD(truncate_name(r_name, connection.ops.max_name_length()))))
       
   174                 del references_to_delete[model]
       
   175             if model._meta.has_auto_field:
       
   176                 ds = connection.ops.drop_sequence_sql(model._meta.db_table)
       
   177                 if ds:
       
   178                     output.append(ds)
       
   179 
    99 
   180     # Output DROP TABLE statements for many-to-many tables.
   100     # Output DROP TABLE statements for many-to-many tables.
   181     for model in app_models:
   101     for model in app_models:
   182         opts = model._meta
   102         opts = model._meta
   183         for f in opts.local_many_to_many:
   103         for f in opts.local_many_to_many:
   184             if isinstance(f.rel, generic.GenericRel):
   104             if cursor and connection.introspection.table_name_converter(f.m2m_db_table()) in table_names:
   185                 continue
   105                 output.extend(connection.creation.sql_destroy_many_to_many(model, f, style))
   186             if cursor and table_name_converter(f.m2m_db_table()) in table_names:
       
   187                 output.append("%s %s;" % (style.SQL_KEYWORD('DROP TABLE'),
       
   188                     style.SQL_TABLE(qn(f.m2m_db_table()))))
       
   189                 ds = connection.ops.drop_sequence_sql("%s_%s" % (model._meta.db_table, f.column))
       
   190                 if ds:
       
   191                     output.append(ds)
       
   192 
       
   193     app_label = app_models[0]._meta.app_label
       
   194 
   106 
   195     # Close database connection explicitly, in case this output is being piped
   107     # Close database connection explicitly, in case this output is being piped
   196     # directly into a database client, to avoid locking issues.
   108     # directly into a database client, to avoid locking issues.
   197     if cursor:
   109     if cursor:
   198         cursor.close()
   110         cursor.close()
   211     If only_django is True, then only table names that have associated Django
   123     If only_django is True, then only table names that have associated Django
   212     models and are in INSTALLED_APPS will be included.
   124     models and are in INSTALLED_APPS will be included.
   213     """
   125     """
   214     from django.db import connection
   126     from django.db import connection
   215     if only_django:
   127     if only_django:
   216         tables = django_table_names()
   128         tables = connection.introspection.django_table_names()
   217     else:
   129     else:
   218         tables = table_names()
   130         tables = connection.introspection.table_names()
   219     statements = connection.ops.sql_flush(style, tables, sequence_list())
   131     statements = connection.ops.sql_flush(style, tables, connection.introspection.sequence_list())
   220     return statements
   132     return statements
   221 
   133 
   222 def sql_custom(app):
   134 def sql_custom(app, style):
   223     "Returns a list of the custom table modifying SQL statements for the given app."
   135     "Returns a list of the custom table modifying SQL statements for the given app."
   224     from django.db.models import get_models
   136     from django.db.models import get_models
   225     output = []
   137     output = []
   226 
   138 
   227     app_models = get_models(app)
   139     app_models = get_models(app)
   228     app_dir = os.path.normpath(os.path.join(os.path.dirname(app.__file__), 'sql'))
   140     app_dir = os.path.normpath(os.path.join(os.path.dirname(app.__file__), 'sql'))
   229 
   141 
   230     for model in app_models:
   142     for model in app_models:
   231         output.extend(custom_sql_for_model(model))
   143         output.extend(custom_sql_for_model(model, style))
   232 
   144 
   233     return output
   145     return output
   234 
   146 
   235 def sql_indexes(app, style):
   147 def sql_indexes(app, style):
   236     "Returns a list of the CREATE INDEX SQL statements for all models in the given app."
   148     "Returns a list of the CREATE INDEX SQL statements for all models in the given app."
   237     from django.db import models
   149     from django.db import connection, models
   238     output = []
   150     output = []
   239     for model in models.get_models(app):
   151     for model in models.get_models(app):
   240         output.extend(sql_indexes_for_model(model, style))
   152         output.extend(connection.creation.sql_indexes_for_model(model, style))
   241     return output
   153     return output
   242 
   154 
   243 def sql_all(app, style):
   155 def sql_all(app, style):
   244     "Returns a list of CREATE TABLE SQL, initial-data inserts, and CREATE INDEX SQL for the given module."
   156     "Returns a list of CREATE TABLE SQL, initial-data inserts, and CREATE INDEX SQL for the given module."
   245     return sql_create(app, style) + sql_custom(app) + sql_indexes(app, style)
   157     return sql_create(app, style) + sql_custom(app, style) + sql_indexes(app, style)
   246 
   158 
   247 def sql_model_create(model, style, known_models=set()):
   159 def custom_sql_for_model(model, style):
   248     """
       
   249     Returns the SQL required to create a single model, as a tuple of:
       
   250         (list_of_sql, pending_references_dict)
       
   251     """
       
   252     from django.db import connection, models
       
   253 
       
   254     opts = model._meta
       
   255     final_output = []
       
   256     table_output = []
       
   257     pending_references = {}
       
   258     qn = connection.ops.quote_name
       
   259     inline_references = connection.features.inline_fk_references
       
   260     for f in opts.local_fields:
       
   261         col_type = f.db_type()
       
   262         tablespace = f.db_tablespace or opts.db_tablespace
       
   263         if col_type is None:
       
   264             # Skip ManyToManyFields, because they're not represented as
       
   265             # database columns in this table.
       
   266             continue
       
   267         # Make the definition (e.g. 'foo VARCHAR(30)') for this field.
       
   268         field_output = [style.SQL_FIELD(qn(f.column)),
       
   269             style.SQL_COLTYPE(col_type)]
       
   270         field_output.append(style.SQL_KEYWORD('%sNULL' % (not f.null and 'NOT ' or '')))
       
   271         if f.unique and (not f.primary_key or connection.features.allows_unique_and_pk):
       
   272             field_output.append(style.SQL_KEYWORD('UNIQUE'))
       
   273         if f.primary_key:
       
   274             field_output.append(style.SQL_KEYWORD('PRIMARY KEY'))
       
   275         if tablespace and connection.features.supports_tablespaces and (f.unique or f.primary_key) and connection.features.autoindexes_primary_keys:
       
   276             # We must specify the index tablespace inline, because we
       
   277             # won't be generating a CREATE INDEX statement for this field.
       
   278             field_output.append(connection.ops.tablespace_sql(tablespace, inline=True))
       
   279         if f.rel:
       
   280             if inline_references and f.rel.to in known_models:
       
   281                 field_output.append(style.SQL_KEYWORD('REFERENCES') + ' ' + \
       
   282                     style.SQL_TABLE(qn(f.rel.to._meta.db_table)) + ' (' + \
       
   283                     style.SQL_FIELD(qn(f.rel.to._meta.get_field(f.rel.field_name).column)) + ')' +
       
   284                     connection.ops.deferrable_sql()
       
   285                 )
       
   286             else:
       
   287                 # We haven't yet created the table to which this field
       
   288                 # is related, so save it for later.
       
   289                 pr = pending_references.setdefault(f.rel.to, []).append((model, f))
       
   290         table_output.append(' '.join(field_output))
       
   291     if opts.order_with_respect_to:
       
   292         table_output.append(style.SQL_FIELD(qn('_order')) + ' ' + \
       
   293             style.SQL_COLTYPE(models.IntegerField().db_type()) + ' ' + \
       
   294             style.SQL_KEYWORD('NULL'))
       
   295     for field_constraints in opts.unique_together:
       
   296         table_output.append(style.SQL_KEYWORD('UNIQUE') + ' (%s)' % \
       
   297             ", ".join([style.SQL_FIELD(qn(opts.get_field(f).column)) for f in field_constraints]))
       
   298 
       
   299     full_statement = [style.SQL_KEYWORD('CREATE TABLE') + ' ' + style.SQL_TABLE(qn(opts.db_table)) + ' (']
       
   300     for i, line in enumerate(table_output): # Combine and add commas.
       
   301         full_statement.append('    %s%s' % (line, i < len(table_output)-1 and ',' or ''))
       
   302     full_statement.append(')')
       
   303     if opts.db_tablespace and connection.features.supports_tablespaces:
       
   304         full_statement.append(connection.ops.tablespace_sql(opts.db_tablespace))
       
   305     full_statement.append(';')
       
   306     final_output.append('\n'.join(full_statement))
       
   307 
       
   308     if opts.has_auto_field:
       
   309         # Add any extra SQL needed to support auto-incrementing primary keys.
       
   310         auto_column = opts.auto_field.db_column or opts.auto_field.name
       
   311         autoinc_sql = connection.ops.autoinc_sql(opts.db_table, auto_column)
       
   312         if autoinc_sql:
       
   313             for stmt in autoinc_sql:
       
   314                 final_output.append(stmt)
       
   315 
       
   316     return final_output, pending_references
       
   317 
       
   318 def sql_for_pending_references(model, style, pending_references):
       
   319     """
       
   320     Returns any ALTER TABLE statements to add constraints after the fact.
       
   321     """
       
   322     from django.db import connection
       
   323     from django.db.backends.util import truncate_name
       
   324 
       
   325     qn = connection.ops.quote_name
       
   326     final_output = []
       
   327     if connection.features.supports_constraints:
       
   328         opts = model._meta
       
   329         if model in pending_references:
       
   330             for rel_class, f in pending_references[model]:
       
   331                 rel_opts = rel_class._meta
       
   332                 r_table = rel_opts.db_table
       
   333                 r_col = f.column
       
   334                 table = opts.db_table
       
   335                 col = opts.get_field(f.rel.field_name).column
       
   336                 # For MySQL, r_name must be unique in the first 64 characters.
       
   337                 # So we are careful with character usage here.
       
   338                 r_name = '%s_refs_%s_%x' % (r_col, col, abs(hash((r_table, table))))
       
   339                 final_output.append(style.SQL_KEYWORD('ALTER TABLE') + ' %s ADD CONSTRAINT %s FOREIGN KEY (%s) REFERENCES %s (%s)%s;' % \
       
   340                     (qn(r_table), truncate_name(r_name, connection.ops.max_name_length()),
       
   341                     qn(r_col), qn(table), qn(col),
       
   342                     connection.ops.deferrable_sql()))
       
   343             del pending_references[model]
       
   344     return final_output
       
   345 
       
   346 def many_to_many_sql_for_model(model, style):
       
   347     from django.db import connection, models
       
   348     from django.contrib.contenttypes import generic
       
   349     from django.db.backends.util import truncate_name
       
   350 
       
   351     opts = model._meta
       
   352     final_output = []
       
   353     qn = connection.ops.quote_name
       
   354     inline_references = connection.features.inline_fk_references
       
   355     for f in opts.local_many_to_many:
       
   356         if not isinstance(f.rel, generic.GenericRel):
       
   357             tablespace = f.db_tablespace or opts.db_tablespace
       
   358             if tablespace and connection.features.supports_tablespaces and connection.features.autoindexes_primary_keys:
       
   359                 tablespace_sql = ' ' + connection.ops.tablespace_sql(tablespace, inline=True)
       
   360             else:
       
   361                 tablespace_sql = ''
       
   362             table_output = [style.SQL_KEYWORD('CREATE TABLE') + ' ' + \
       
   363                 style.SQL_TABLE(qn(f.m2m_db_table())) + ' (']
       
   364             table_output.append('    %s %s %s%s,' %
       
   365                 (style.SQL_FIELD(qn('id')),
       
   366                 style.SQL_COLTYPE(models.AutoField(primary_key=True).db_type()),
       
   367                 style.SQL_KEYWORD('NOT NULL PRIMARY KEY'),
       
   368                 tablespace_sql))
       
   369             if inline_references:
       
   370                 deferred = []
       
   371                 table_output.append('    %s %s %s %s (%s)%s,' %
       
   372                     (style.SQL_FIELD(qn(f.m2m_column_name())),
       
   373                     style.SQL_COLTYPE(models.ForeignKey(model).db_type()),
       
   374                     style.SQL_KEYWORD('NOT NULL REFERENCES'),
       
   375                     style.SQL_TABLE(qn(opts.db_table)),
       
   376                     style.SQL_FIELD(qn(opts.pk.column)),
       
   377                     connection.ops.deferrable_sql()))
       
   378                 table_output.append('    %s %s %s %s (%s)%s,' %
       
   379                     (style.SQL_FIELD(qn(f.m2m_reverse_name())),
       
   380                     style.SQL_COLTYPE(models.ForeignKey(f.rel.to).db_type()),
       
   381                     style.SQL_KEYWORD('NOT NULL REFERENCES'),
       
   382                     style.SQL_TABLE(qn(f.rel.to._meta.db_table)),
       
   383                     style.SQL_FIELD(qn(f.rel.to._meta.pk.column)),
       
   384                     connection.ops.deferrable_sql()))
       
   385             else:
       
   386                 table_output.append('    %s %s %s,' %
       
   387                     (style.SQL_FIELD(qn(f.m2m_column_name())),
       
   388                     style.SQL_COLTYPE(models.ForeignKey(model).db_type()),
       
   389                     style.SQL_KEYWORD('NOT NULL')))
       
   390                 table_output.append('    %s %s %s,' %
       
   391                     (style.SQL_FIELD(qn(f.m2m_reverse_name())),
       
   392                     style.SQL_COLTYPE(models.ForeignKey(f.rel.to).db_type()),
       
   393                     style.SQL_KEYWORD('NOT NULL')))
       
   394                 deferred = [
       
   395                     (f.m2m_db_table(), f.m2m_column_name(), opts.db_table,
       
   396                         opts.pk.column),
       
   397                     ( f.m2m_db_table(), f.m2m_reverse_name(),
       
   398                         f.rel.to._meta.db_table, f.rel.to._meta.pk.column)
       
   399                     ]
       
   400             table_output.append('    %s (%s, %s)%s' %
       
   401                 (style.SQL_KEYWORD('UNIQUE'),
       
   402                 style.SQL_FIELD(qn(f.m2m_column_name())),
       
   403                 style.SQL_FIELD(qn(f.m2m_reverse_name())),
       
   404                 tablespace_sql))
       
   405             table_output.append(')')
       
   406             if opts.db_tablespace and connection.features.supports_tablespaces:
       
   407                 # f.db_tablespace is only for indices, so ignore its value here.
       
   408                 table_output.append(connection.ops.tablespace_sql(opts.db_tablespace))
       
   409             table_output.append(';')
       
   410             final_output.append('\n'.join(table_output))
       
   411 
       
   412             for r_table, r_col, table, col in deferred:
       
   413                 r_name = '%s_refs_%s_%x' % (r_col, col,
       
   414                         abs(hash((r_table, table))))
       
   415                 final_output.append(style.SQL_KEYWORD('ALTER TABLE') + ' %s ADD CONSTRAINT %s FOREIGN KEY (%s) REFERENCES %s (%s)%s;' % 
       
   416                 (qn(r_table),
       
   417                 truncate_name(r_name, connection.ops.max_name_length()),
       
   418                 qn(r_col), qn(table), qn(col),
       
   419                 connection.ops.deferrable_sql()))
       
   420 
       
   421             # Add any extra SQL needed to support auto-incrementing PKs
       
   422             autoinc_sql = connection.ops.autoinc_sql(f.m2m_db_table(), 'id')
       
   423             if autoinc_sql:
       
   424                 for stmt in autoinc_sql:
       
   425                     final_output.append(stmt)
       
   426 
       
   427     return final_output
       
   428 
       
   429 def custom_sql_for_model(model):
       
   430     from django.db import models
   160     from django.db import models
   431     from django.conf import settings
   161     from django.conf import settings
   432 
   162 
   433     opts = model._meta
   163     opts = model._meta
   434     app_dir = os.path.normpath(os.path.join(os.path.dirname(models.get_app(model._meta.app_label).__file__), 'sql'))
   164     app_dir = os.path.normpath(os.path.join(os.path.dirname(models.get_app(model._meta.app_label).__file__), 'sql'))
   435     output = []
   165     output = []
       
   166 
       
   167     # Post-creation SQL should come before any initial SQL data is loaded.
       
   168     # However, this should not be done for fields that are part of a a parent
       
   169     # model (via model inheritance).
       
   170     nm = opts.init_name_map()
       
   171     post_sql_fields = [f for f in opts.local_fields if hasattr(f, 'post_create_sql')]
       
   172     for f in post_sql_fields:
       
   173         output.extend(f.post_create_sql(style, model._meta.db_table))
   436 
   174 
   437     # Some backends can't execute more than one SQL statement at a time,
   175     # Some backends can't execute more than one SQL statement at a time,
   438     # so split into separate statements.
   176     # so split into separate statements.
   439     statements = re.compile(r";[ \t]*$", re.M)
   177     statements = re.compile(r";[ \t]*$", re.M)
   440 
   178 
   444     for sql_file in sql_files:
   182     for sql_file in sql_files:
   445         if os.path.exists(sql_file):
   183         if os.path.exists(sql_file):
   446             fp = open(sql_file, 'U')
   184             fp = open(sql_file, 'U')
   447             for statement in statements.split(fp.read().decode(settings.FILE_CHARSET)):
   185             for statement in statements.split(fp.read().decode(settings.FILE_CHARSET)):
   448                 # Remove any comments from the file
   186                 # Remove any comments from the file
   449                 statement = re.sub(ur"--.*[\n\Z]", "", statement)
   187                 statement = re.sub(ur"--.*([\n\Z]|$)", "", statement)
   450                 if statement.strip():
   188                 if statement.strip():
   451                     output.append(statement + u";")
   189                     output.append(statement + u";")
   452             fp.close()
   190             fp.close()
   453 
   191 
   454     return output
   192     return output
   455 
   193 
   456 def sql_indexes_for_model(model, style):
       
   457     "Returns the CREATE INDEX SQL statements for a single model"
       
   458     from django.db import connection
       
   459     output = []
       
   460 
       
   461     qn = connection.ops.quote_name
       
   462     for f in model._meta.local_fields:
       
   463         if f.db_index and not ((f.primary_key or f.unique) and connection.features.autoindexes_primary_keys):
       
   464             unique = f.unique and 'UNIQUE ' or ''
       
   465             tablespace = f.db_tablespace or model._meta.db_tablespace
       
   466             if tablespace and connection.features.supports_tablespaces:
       
   467                 tablespace_sql = ' ' + connection.ops.tablespace_sql(tablespace)
       
   468             else:
       
   469                 tablespace_sql = ''
       
   470             output.append(
       
   471                 style.SQL_KEYWORD('CREATE %sINDEX' % unique) + ' ' + \
       
   472                 style.SQL_TABLE(qn('%s_%s' % (model._meta.db_table, f.column))) + ' ' + \
       
   473                 style.SQL_KEYWORD('ON') + ' ' + \
       
   474                 style.SQL_TABLE(qn(model._meta.db_table)) + ' ' + \
       
   475                 "(%s)" % style.SQL_FIELD(qn(f.column)) + \
       
   476                 "%s;" % tablespace_sql
       
   477             )
       
   478     return output
       
   479 
   194 
   480 def emit_post_sync_signal(created_models, verbosity, interactive):
   195 def emit_post_sync_signal(created_models, verbosity, interactive):
   481     from django.db import models
   196     from django.db import models
   482     from django.dispatch import dispatcher
   197     from django.dispatch import dispatcher
   483     # Emit the post_sync signal for every application.
   198     # Emit the post_sync signal for every application.
   484     for app in models.get_apps():
   199     for app in models.get_apps():
   485         app_name = app.__name__.split('.')[-2]
   200         app_name = app.__name__.split('.')[-2]
   486         if verbosity >= 2:
   201         if verbosity >= 2:
   487             print "Running post-sync handlers for application", app_name
   202             print "Running post-sync handlers for application", app_name
   488         dispatcher.send(signal=models.signals.post_syncdb, sender=app,
   203         models.signals.post_syncdb.send(sender=app, app=app,
   489             app=app, created_models=created_models,
   204             created_models=created_models, verbosity=verbosity,
   490             verbosity=verbosity, interactive=interactive)
   205             interactive=interactive)