Ticket #3163: create_db_schema-trunk6977.diff

File create_db_schema-trunk6977.diff, 13.4 KB (added by honeyman, 16 years ago)

create_db_schema Mera option implementation (svn diff, Django trunk 6977)

  • django/db/models/options.py

     
    1515
    1616DEFAULT_NAMES = ('verbose_name', 'db_table', 'ordering',
    1717                 'unique_together', 'permissions', 'get_latest_by',
    18                  'order_with_respect_to', 'app_label', 'db_tablespace')
     18                 'order_with_respect_to', 'app_label', 'db_tablespace', 'create_db_schema')
    1919
    2020class Options(object):
    2121    def __init__(self, meta):
     
    3030        self.get_latest_by = None
    3131        self.order_with_respect_to = None
    3232        self.db_tablespace = settings.DEFAULT_TABLESPACE
     33        self.create_db_schema = True
    3334        self.admin = None
    3435        self.meta = meta
    3536        self.pk = None
  • django/core/management/sql.py

     
    1313    cursor = connection.cursor()
    1414    return get_introspection_module().get_table_list(cursor)
    1515
    16 def django_table_list(only_existing=False):
     16def django_table_list(only_existing=False, filter_not_generated_tables=False):
    1717    """
    1818    Returns a list of all table names that have associated Django models and
    1919    are in INSTALLED_APPS.
    2020
    2121    If only_existing is True, the resulting list will only include the tables
    2222    that actually exist in the database.
     23
     24    If filter_not_generated_tables is True, then all tables with associated Django models
     25    which have Meta option create_db_schema=False will not be added to the list.
    2326    """
    2427    from django.db import models
    2528    tables = []
    2629    for app in models.get_apps():
    2730        for model in models.get_models(app):
    28             tables.append(model._meta.db_table)
    29             tables.extend([f.m2m_db_table() for f in model._meta.many_to_many])
     31            if (not filter_not_generated_tables) or (model._meta.create_db_schema):
     32                tables.append(model._meta.db_table)
     33                tables.extend([f.m2m_db_table() for f in model._meta.many_to_many])
    3034    if only_existing:
    3135        existing = table_list()
    3236        tables = [t for t in tables if t in existing]
     
    4549        converter = lambda x: x
    4650    return set([m for m in all_models if converter(m._meta.db_table) in map(converter, table_list)])
    4751
    48 def sequence_list():
    49     "Returns a list of information about all DB sequences for all models in all apps."
     52def sequence_list(filter_not_generated_tables=False):
     53    """
     54    Returns a list of information about all DB sequences for all models in all apps.
     55
     56    If filter_not_generated_tables is True, then only the sequences for the Django models
     57    which have Meta option create_db_schema=False will be added to the list.
     58    """
    5059    from django.db import models
    5160
    5261    apps = models.get_apps()
     
    5463
    5564    for app in apps:
    5665        for model in models.get_models(app):
    57             for f in model._meta.fields:
    58                 if isinstance(f, models.AutoField):
    59                     sequence_list.append({'table': model._meta.db_table, 'column': f.column})
    60                     break # Only one AutoField is allowed per model, so don't bother continuing.
     66            if (not filter_not_generated_tables) or (model._meta.create_db_schema):
     67                for f in model._meta.fields:
     68                    if isinstance(f, models.AutoField):
     69                        sequence_list.append({'table': model._meta.db_table, 'column': f.column})
     70                        break # Only one AutoField is allowed per model, so don't bother continuing.
    6171
    6272            for f in model._meta.many_to_many:
    6373                sequence_list.append({'table': f.m2m_db_table(), 'column': None})
     
    156166    for model in app_models:
    157167        if cursor and table_name_converter(model._meta.db_table) in table_names:
    158168            # Drop the table now
    159             output.append('%s %s;' % (style.SQL_KEYWORD('DROP TABLE'),
    160                 style.SQL_TABLE(qn(model._meta.db_table))))
     169            if model._meta.create_db_schema:
     170                output.append('%s %s;' % (style.SQL_KEYWORD('DROP TABLE'),
     171                    style.SQL_TABLE(qn(model._meta.db_table))))
    161172            if connection.features.supports_constraints and model in references_to_delete:
    162173                for rel_class, f in references_to_delete[model]:
    163174                    table = rel_class._meta.db_table
     
    165176                    r_table = model._meta.db_table
    166177                    r_col = model._meta.get_field(f.rel.field_name).column
    167178                    r_name = '%s_refs_%s_%x' % (col, r_col, abs(hash((table, r_table))))
    168                     output.append('%s %s %s %s;' % \
    169                         (style.SQL_KEYWORD('ALTER TABLE'),
    170                         style.SQL_TABLE(qn(table)),
    171                         style.SQL_KEYWORD(connection.ops.drop_foreignkey_sql()),
    172                         style.SQL_FIELD(truncate_name(r_name, connection.ops.max_name_length()))))
     179                    if rel_class._meta.create_db_schema:
     180                        output.append('%s %s %s %s;' % \
     181                            (style.SQL_KEYWORD('ALTER TABLE'),
     182                            style.SQL_TABLE(qn(table)),
     183                            style.SQL_KEYWORD(connection.ops.drop_foreignkey_sql()),
     184                            style.SQL_FIELD(truncate_name(r_name, connection.ops.max_name_length()))))
    173185                del references_to_delete[model]
    174186            if model._meta.has_auto_field:
    175187                ds = connection.ops.drop_sequence_sql(model._meta.db_table)
     
    206218def sql_flush(style, only_django=False):
    207219    """
    208220    Returns a list of the SQL statements used to flush the database.
    209    
     221
    210222    If only_django is True, then only table names that have associated Django
    211223    models and are in INSTALLED_APPS will be included.
    212224    """
    213225    from django.db import connection
    214226    if only_django:
    215         tables = django_table_list()
     227        tables = django_table_list(filter_not_generated_tables=True)
    216228    else:
    217229        tables = table_list()
    218     statements = connection.ops.sql_flush(style, tables, sequence_list())
     230    statements = connection.ops.sql_flush(style, tables, sequence_list(filter_not_generated_tables=True))
    219231    return statements
    220232
    221233def sql_custom(app):
     
    295307        table_output.append(style.SQL_KEYWORD('UNIQUE') + ' (%s)' % \
    296308            ", ".join([qn(style.SQL_FIELD(opts.get_field(f).column)) for f in field_constraints]))
    297309
    298     full_statement = [style.SQL_KEYWORD('CREATE TABLE') + ' ' + style.SQL_TABLE(qn(opts.db_table)) + ' (']
    299     for i, line in enumerate(table_output): # Combine and add commas.
    300         full_statement.append('    %s%s' % (line, i < len(table_output)-1 and ',' or ''))
    301     full_statement.append(')')
    302     if opts.db_tablespace and connection.features.supports_tablespaces:
    303         full_statement.append(connection.ops.tablespace_sql(opts.db_tablespace))
    304     full_statement.append(';')
    305     final_output.append('\n'.join(full_statement))
     310    # Now build up the CREATE TABLE section but only if the model requires it
     311    if opts.create_db_schema:
     312        full_statement = [style.SQL_KEYWORD('CREATE TABLE') + ' ' + style.SQL_TABLE(qn(opts.db_table)) + ' (']
     313        for i, line in enumerate(table_output): # Combine and add commas.
     314            full_statement.append('    %s%s' % (line, i < len(table_output)-1 and ',' or ''))
     315        full_statement.append(')')
     316        if opts.db_tablespace and connection.features.supports_tablespaces:
     317            full_statement.append(connection.ops.tablespace_sql(opts.db_tablespace))
     318        full_statement.append(';')
     319        final_output.append('\n'.join(full_statement))
    306320
    307     if opts.has_auto_field:
    308         # Add any extra SQL needed to support auto-incrementing primary keys.
    309         auto_column = opts.auto_field.db_column or opts.auto_field.name
    310         autoinc_sql = connection.ops.autoinc_sql(opts.db_table, auto_column)
    311         if autoinc_sql:
    312             for stmt in autoinc_sql:
    313                 final_output.append(stmt)
     321        if opts.has_auto_field:
     322            # Add any extra SQL needed to support auto-incrementing primary keys.
     323            auto_column = opts.auto_field.db_column or opts.auto_field.name
     324            autoinc_sql = connection.ops.autoinc_sql(opts.db_table, auto_column)
     325            if autoinc_sql:
     326                for stmt in autoinc_sql:
     327                    final_output.append(stmt)
    314328
    315329    return final_output, pending_references
    316330
     
    335349                # For MySQL, r_name must be unique in the first 64 characters.
    336350                # So we are careful with character usage here.
    337351                r_name = '%s_refs_%s_%x' % (r_col, col, abs(hash((r_table, table))))
    338                 final_output.append(style.SQL_KEYWORD('ALTER TABLE') + ' %s ADD CONSTRAINT %s FOREIGN KEY (%s) REFERENCES %s (%s)%s;' % \
    339                     (qn(r_table), truncate_name(r_name, connection.ops.max_name_length()),
    340                     qn(r_col), qn(table), qn(col),
    341                     connection.ops.deferrable_sql()))
     352                if rel_opts.create_db_schema:
     353                    final_output.append(style.SQL_KEYWORD('ALTER TABLE') + ' %s ADD CONSTRAINT %s FOREIGN KEY (%s) REFERENCES %s (%s)%s;' % \
     354                        (qn(r_table), truncate_name(r_name, connection.ops.max_name_length()),
     355                        qn(r_col), qn(table), qn(col),
     356                        connection.ops.deferrable_sql()))
    342357            del pending_references[model]
    343358    return final_output
    344359
     
    411426            for r_table, r_col, table, col in deferred:
    412427                r_name = '%s_refs_%s_%x' % (r_col, col,
    413428                        abs(hash((r_table, table))))
    414                 final_output.append(style.SQL_KEYWORD('ALTER TABLE') + ' %s ADD CONSTRAINT %s FOREIGN KEY (%s) REFERENCES %s (%s)%s;' % 
     429                final_output.append(style.SQL_KEYWORD('ALTER TABLE') + ' %s ADD CONSTRAINT %s FOREIGN KEY (%s) REFERENCES %s (%s)%s;' %
    415430                (qn(r_table),
    416431                truncate_name(r_name, connection.ops.max_name_length()),
    417432                qn(r_col), qn(table), qn(col),
     
    458473    output = []
    459474
    460475    qn = connection.ops.quote_name
    461     for f in model._meta.fields:
    462         if f.db_index and not ((f.primary_key or f.unique) and connection.features.autoindexes_primary_keys):
    463             unique = f.unique and 'UNIQUE ' or ''
    464             tablespace = f.db_tablespace or model._meta.db_tablespace
    465             if tablespace and connection.features.supports_tablespaces:
    466                 tablespace_sql = ' ' + connection.ops.tablespace_sql(tablespace)
    467             else:
    468                 tablespace_sql = ''
    469             output.append(
    470                 style.SQL_KEYWORD('CREATE %sINDEX' % unique) + ' ' + \
    471                 style.SQL_TABLE(qn('%s_%s' % (model._meta.db_table, f.column))) + ' ' + \
    472                 style.SQL_KEYWORD('ON') + ' ' + \
    473                 style.SQL_TABLE(qn(model._meta.db_table)) + ' ' + \
    474                 "(%s)" % style.SQL_FIELD(qn(f.column)) + \
    475                 "%s;" % tablespace_sql
    476             )
     476    if model._meta.create_db_schema:
     477        for f in model._meta.fields:
     478            if f.db_index and not ((f.primary_key or f.unique) and connection.features.autoindexes_primary_keys):
     479                unique = f.unique and 'UNIQUE ' or ''
     480                tablespace = f.db_tablespace or model._meta.db_tablespace
     481                if tablespace and connection.features.supports_tablespaces:
     482                    tablespace_sql = ' ' + connection.ops.tablespace_sql(tablespace)
     483                else:
     484                    tablespace_sql = ''
     485                output.append(
     486                    style.SQL_KEYWORD('CREATE %sINDEX' % unique) + ' ' + \
     487                    style.SQL_TABLE(qn('%s_%s' % (model._meta.db_table, f.column))) + ' ' + \
     488                    style.SQL_KEYWORD('ON') + ' ' + \
     489                    style.SQL_TABLE(qn(model._meta.db_table)) + ' ' + \
     490                    "(%s)" % style.SQL_FIELD(qn(f.column)) + \
     491                    "%s;" % tablespace_sql
     492                )
    477493    return output
    478494
    479495def emit_post_sync_signal(created_models, verbosity, interactive):
  • docs/model-api.txt

     
    10511051that aren't allowed in Python variable names -- notably, the hyphen --
    10521052that's OK. Django quotes column and table names behind the scenes.
    10531053
     1054``create_db_schema``
     1055--------------------
     1056
     1057**New in Django development version**
     1058
     1059Marks this model as requiring SQL operations when calling ``manage.py``::
     1060
     1061    create_db_schema = False
     1062
     1063If this isn't given, Django will use ``create_db_schema = True``
     1064what means that the operations like ``manage.py sqlreset``, ``manage.py syncdb``
     1065and others will regenerate the appropriate table when needed.
     1066If the option is set to False, the appropriate table will not be affected with
     1067any SQL operations.
     1068
     1069This is useful for databases where some DB tables are controlled by Django models,
     1070but some other DB tables and views are created via raw SQL and should not be affected
     1071by any ``manage.py`` actions.
     1072Note that if the initial SQL data is provided (see `Providing initial SQL
     1073data`_ below), it still will be present in the output of
     1074``sqlall``/``sqlcustom`` commands.
     1075
    10541076``db_tablespace``
    10551077-----------------
    10561078
Back to Top