Index: django/db/models/options.py
===================================================================
--- django/db/models/options.py	(revision 7027)
+++ django/db/models/options.py	(working copy)
@@ -15,7 +15,7 @@
 
 DEFAULT_NAMES = ('verbose_name', 'db_table', 'ordering',
                  'unique_together', 'permissions', 'get_latest_by',
-                 'order_with_respect_to', 'app_label', 'db_tablespace')
+                 'order_with_respect_to', 'app_label', 'db_tablespace', 'create_db_schema')
 
 class Options(object):
     def __init__(self, meta):
@@ -30,6 +30,7 @@
         self.get_latest_by = None
         self.order_with_respect_to = None
         self.db_tablespace = settings.DEFAULT_TABLESPACE
+        self.create_db_schema = True
         self.admin = None
         self.meta = meta
         self.pk = None
Index: django/core/management/commands/syncdb.py
===================================================================
--- django/core/management/commands/syncdb.py	(revision 7027)
+++ django/core/management/commands/syncdb.py	(working copy)
@@ -57,22 +57,23 @@
             app_name = app.__name__.split('.')[-2]
             model_list = models.get_models(app)
             for model in model_list:
-                # Create the model's database table, if it doesn't already exist.
-                if verbosity >= 2:
-                    print "Processing %s.%s model" % (app_name, model._meta.object_name)
-                if table_name_converter(model._meta.db_table) in tables:
-                    continue
-                sql, references = sql_model_create(model, self.style, seen_models)
-                seen_models.add(model)
-                created_models.add(model)
-                for refto, refs in references.items():
-                    pending_references.setdefault(refto, []).extend(refs)
-                sql.extend(sql_for_pending_references(model, self.style, pending_references))
-                if verbosity >= 1:
-                    print "Creating table %s" % model._meta.db_table
-                for statement in sql:
-                    cursor.execute(statement)
-                tables.append(table_name_converter(model._meta.db_table))
+                if model._meta.create_db_schema:
+                    # Create the model's database table, if it doesn't already exist.
+                    if verbosity >= 2:
+                        print "Processing %s.%s model" % (app_name, model._meta.object_name)
+                    if table_name_converter(model._meta.db_table) in tables:
+                        continue
+                    sql, references = sql_model_create(model, self.style, seen_models)
+                    seen_models.add(model)
+                    created_models.add(model)
+                    for refto, refs in references.items():
+                        pending_references.setdefault(refto, []).extend(refs)
+                    sql.extend(sql_for_pending_references(model, self.style, pending_references))
+                    if verbosity >= 1:
+                        print "Creating table %s" % model._meta.db_table
+                    for statement in sql:
+                        cursor.execute(statement)
+                    tables.append(table_name_converter(model._meta.db_table))
 
         # Create the m2m tables. This must be done after all tables have been created
         # to ensure that all referred tables will exist.
@@ -119,19 +120,20 @@
             app_name = app.__name__.split('.')[-2]
             for model in models.get_models(app):
                 if model in created_models:
-                    index_sql = sql_indexes_for_model(model, self.style)
-                    if index_sql:
-                        if verbosity >= 1:
-                            print "Installing index for %s.%s model" % (app_name, model._meta.object_name)
-                        try:
-                            for sql in index_sql:
-                                cursor.execute(sql)
-                        except Exception, e:
-                            sys.stderr.write("Failed to install index for %s.%s model: %s" % \
-                                                (app_name, model._meta.object_name, e))
-                            transaction.rollback_unless_managed()
-                        else:
-                            transaction.commit_unless_managed()
+                    if model._meta.create_db_schema:
+                        index_sql = sql_indexes_for_model(model, self.style)
+                        if index_sql:
+                            if verbosity >= 1:
+                                print "Installing index for %s.%s model" % (app_name, model._meta.object_name)
+                            try:
+                                for sql in index_sql:
+                                    cursor.execute(sql)
+                            except Exception, e:
+                                sys.stderr.write("Failed to install index for %s.%s model: %s" % \
+                                                    (app_name, model._meta.object_name, e))
+                                transaction.rollback_unless_managed()
+                            else:
+                                transaction.commit_unless_managed()
 
         # Install the 'initial_data' fixture, using format discovery
         from django.core.management import call_command
Index: django/core/management/sql.py
===================================================================
--- django/core/management/sql.py	(revision 7027)
+++ django/core/management/sql.py	(working copy)
@@ -13,20 +13,24 @@
     cursor = connection.cursor()
     return get_introspection_module().get_table_list(cursor)
 
-def django_table_list(only_existing=False):
+def django_table_list(only_existing=False, filter_not_generated_tables=False):
     """
     Returns a list of all table names that have associated Django models and
     are in INSTALLED_APPS.
 
     If only_existing is True, the resulting list will only include the tables
     that actually exist in the database.
+
+    If filter_not_generated_tables is True, then all tables with associated Django models
+    which have Meta option create_db_schema=False will not be added to the list.
     """
     from django.db import models
     tables = []
     for app in models.get_apps():
         for model in models.get_models(app):
-            tables.append(model._meta.db_table)
-            tables.extend([f.m2m_db_table() for f in model._meta.many_to_many])
+            if (not filter_not_generated_tables) or (model._meta.create_db_schema):
+                tables.append(model._meta.db_table)
+                tables.extend([f.m2m_db_table() for f in model._meta.many_to_many])
     if only_existing:
         existing = table_list()
         tables = [t for t in tables if t in existing]
@@ -45,8 +49,13 @@
         converter = lambda x: x
     return set([m for m in all_models if converter(m._meta.db_table) in map(converter, table_list)])
 
-def sequence_list():
-    "Returns a list of information about all DB sequences for all models in all apps."
+def sequence_list(filter_not_generated_tables=False):
+    """
+    Returns a list of information about all DB sequences for all models in all apps.
+
+    If filter_not_generated_tables is True, then only the sequences for the Django models
+    which have Meta option create_db_schema=False will be added to the list.
+    """
     from django.db import models
 
     apps = models.get_apps()
@@ -54,10 +63,11 @@
 
     for app in apps:
         for model in models.get_models(app):
-            for f in model._meta.fields:
-                if isinstance(f, models.AutoField):
-                    sequence_list.append({'table': model._meta.db_table, 'column': f.column})
-                    break # Only one AutoField is allowed per model, so don't bother continuing.
+            if (not filter_not_generated_tables) or (model._meta.create_db_schema):
+                for f in model._meta.fields:
+                    if isinstance(f, models.AutoField):
+                        sequence_list.append({'table': model._meta.db_table, 'column': f.column})
+                        break # Only one AutoField is allowed per model, so don't bother continuing.
 
             for f in model._meta.many_to_many:
                 sequence_list.append({'table': f.m2m_db_table(), 'column': None})
@@ -156,8 +166,9 @@
     for model in app_models:
         if cursor and table_name_converter(model._meta.db_table) in table_names:
             # Drop the table now
-            output.append('%s %s;' % (style.SQL_KEYWORD('DROP TABLE'),
-                style.SQL_TABLE(qn(model._meta.db_table))))
+            if model._meta.create_db_schema:
+                output.append('%s %s;' % (style.SQL_KEYWORD('DROP TABLE'),
+                    style.SQL_TABLE(qn(model._meta.db_table))))
             if connection.features.supports_constraints and model in references_to_delete:
                 for rel_class, f in references_to_delete[model]:
                     table = rel_class._meta.db_table
@@ -165,11 +176,12 @@
                     r_table = model._meta.db_table
                     r_col = model._meta.get_field(f.rel.field_name).column
                     r_name = '%s_refs_%s_%x' % (col, r_col, abs(hash((table, r_table))))
-                    output.append('%s %s %s %s;' % \
-                        (style.SQL_KEYWORD('ALTER TABLE'),
-                        style.SQL_TABLE(qn(table)),
-                        style.SQL_KEYWORD(connection.ops.drop_foreignkey_sql()),
-                        style.SQL_FIELD(truncate_name(r_name, connection.ops.max_name_length()))))
+                    if rel_class._meta.create_db_schema:
+                        output.append('%s %s %s %s;' % \
+                            (style.SQL_KEYWORD('ALTER TABLE'),
+                            style.SQL_TABLE(qn(table)),
+                            style.SQL_KEYWORD(connection.ops.drop_foreignkey_sql()),
+                            style.SQL_FIELD(truncate_name(r_name, connection.ops.max_name_length()))))
                 del references_to_delete[model]
             if model._meta.has_auto_field:
                 ds = connection.ops.drop_sequence_sql(model._meta.db_table)
@@ -206,16 +218,16 @@
 def sql_flush(style, only_django=False):
     """
     Returns a list of the SQL statements used to flush the database.
-    
+
     If only_django is True, then only table names that have associated Django
     models and are in INSTALLED_APPS will be included.
     """
     from django.db import connection
     if only_django:
-        tables = django_table_list()
+        tables = django_table_list(filter_not_generated_tables=True)
     else:
         tables = table_list()
-    statements = connection.ops.sql_flush(style, tables, sequence_list())
+    statements = connection.ops.sql_flush(style, tables, sequence_list(filter_not_generated_tables=True))
     return statements
 
 def sql_custom(app):
@@ -295,22 +307,24 @@
         table_output.append(style.SQL_KEYWORD('UNIQUE') + ' (%s)' % \
             ", ".join([style.SQL_FIELD(qn(opts.get_field(f).column)) for f in field_constraints]))
 
-    full_statement = [style.SQL_KEYWORD('CREATE TABLE') + ' ' + style.SQL_TABLE(qn(opts.db_table)) + ' (']
-    for i, line in enumerate(table_output): # Combine and add commas.
-        full_statement.append('    %s%s' % (line, i < len(table_output)-1 and ',' or ''))
-    full_statement.append(')')
-    if opts.db_tablespace and connection.features.supports_tablespaces:
-        full_statement.append(connection.ops.tablespace_sql(opts.db_tablespace))
-    full_statement.append(';')
-    final_output.append('\n'.join(full_statement))
+    # Now build up the CREATE TABLE section but only if the model requires it
+    if opts.create_db_schema:
+        full_statement = [style.SQL_KEYWORD('CREATE TABLE') + ' ' + style.SQL_TABLE(qn(opts.db_table)) + ' (']
+        for i, line in enumerate(table_output): # Combine and add commas.
+            full_statement.append('    %s%s' % (line, i < len(table_output)-1 and ',' or ''))
+        full_statement.append(')')
+        if opts.db_tablespace and connection.features.supports_tablespaces:
+            full_statement.append(connection.ops.tablespace_sql(opts.db_tablespace))
+        full_statement.append(';')
+        final_output.append('\n'.join(full_statement))
 
-    if opts.has_auto_field:
-        # Add any extra SQL needed to support auto-incrementing primary keys.
-        auto_column = opts.auto_field.db_column or opts.auto_field.name
-        autoinc_sql = connection.ops.autoinc_sql(opts.db_table, auto_column)
-        if autoinc_sql:
-            for stmt in autoinc_sql:
-                final_output.append(stmt)
+        if opts.has_auto_field:
+            # Add any extra SQL needed to support auto-incrementing primary keys.
+            auto_column = opts.auto_field.db_column or opts.auto_field.name
+            autoinc_sql = connection.ops.autoinc_sql(opts.db_table, auto_column)
+            if autoinc_sql:
+                for stmt in autoinc_sql:
+                    final_output.append(stmt)
 
     return final_output, pending_references
 
@@ -335,10 +349,11 @@
                 # For MySQL, r_name must be unique in the first 64 characters.
                 # So we are careful with character usage here.
                 r_name = '%s_refs_%s_%x' % (r_col, col, abs(hash((r_table, table))))
-                final_output.append(style.SQL_KEYWORD('ALTER TABLE') + ' %s ADD CONSTRAINT %s FOREIGN KEY (%s) REFERENCES %s (%s)%s;' % \
-                    (qn(r_table), truncate_name(r_name, connection.ops.max_name_length()),
-                    qn(r_col), qn(table), qn(col),
-                    connection.ops.deferrable_sql()))
+                if rel_opts.create_db_schema:
+                    final_output.append(style.SQL_KEYWORD('ALTER TABLE') + ' %s ADD CONSTRAINT %s FOREIGN KEY (%s) REFERENCES %s (%s)%s;' % \
+                        (qn(r_table), truncate_name(r_name, connection.ops.max_name_length()),
+                        qn(r_col), qn(table), qn(col),
+                        connection.ops.deferrable_sql()))
             del pending_references[model]
     return final_output
 
@@ -411,7 +426,7 @@
             for r_table, r_col, table, col in deferred:
                 r_name = '%s_refs_%s_%x' % (r_col, col,
                         abs(hash((r_table, table))))
-                final_output.append(style.SQL_KEYWORD('ALTER TABLE') + ' %s ADD CONSTRAINT %s FOREIGN KEY (%s) REFERENCES %s (%s)%s;' % 
+                final_output.append(style.SQL_KEYWORD('ALTER TABLE') + ' %s ADD CONSTRAINT %s FOREIGN KEY (%s) REFERENCES %s (%s)%s;' %
                 (qn(r_table),
                 truncate_name(r_name, connection.ops.max_name_length()),
                 qn(r_col), qn(table), qn(col),
@@ -458,22 +473,23 @@
     output = []
 
     qn = connection.ops.quote_name
-    for f in model._meta.fields:
-        if f.db_index and not ((f.primary_key or f.unique) and connection.features.autoindexes_primary_keys):
-            unique = f.unique and 'UNIQUE ' or ''
-            tablespace = f.db_tablespace or model._meta.db_tablespace
-            if tablespace and connection.features.supports_tablespaces:
-                tablespace_sql = ' ' + connection.ops.tablespace_sql(tablespace)
-            else:
-                tablespace_sql = ''
-            output.append(
-                style.SQL_KEYWORD('CREATE %sINDEX' % unique) + ' ' + \
-                style.SQL_TABLE(qn('%s_%s' % (model._meta.db_table, f.column))) + ' ' + \
-                style.SQL_KEYWORD('ON') + ' ' + \
-                style.SQL_TABLE(qn(model._meta.db_table)) + ' ' + \
-                "(%s)" % style.SQL_FIELD(qn(f.column)) + \
-                "%s;" % tablespace_sql
-            )
+    if model._meta.create_db_schema:
+        for f in model._meta.fields:
+            if f.db_index and not ((f.primary_key or f.unique) and connection.features.autoindexes_primary_keys):
+                unique = f.unique and 'UNIQUE ' or ''
+                tablespace = f.db_tablespace or model._meta.db_tablespace
+                if tablespace and connection.features.supports_tablespaces:
+                    tablespace_sql = ' ' + connection.ops.tablespace_sql(tablespace)
+                else:
+                    tablespace_sql = ''
+                output.append(
+                    style.SQL_KEYWORD('CREATE %sINDEX' % unique) + ' ' + \
+                    style.SQL_TABLE(qn('%s_%s' % (model._meta.db_table, f.column))) + ' ' + \
+                    style.SQL_KEYWORD('ON') + ' ' + \
+                    style.SQL_TABLE(qn(model._meta.db_table)) + ' ' + \
+                    "(%s)" % style.SQL_FIELD(qn(f.column)) + \
+                    "%s;" % tablespace_sql
+                )
     return output
 
 def emit_post_sync_signal(created_models, verbosity, interactive):
Index: tests/modeltests/create_db_schema/__init__.py
===================================================================
Index: tests/modeltests/create_db_schema/models.py
===================================================================
--- tests/modeltests/create_db_schema/models.py	(revision 0)
+++ tests/modeltests/create_db_schema/models.py	(revision 0)
@@ -0,0 +1,201 @@
+"""
+xx. create_db_schema
+
+Models can have a ``create_db_schema`` attribute, which specifies
+whether the SQL code is generated for the table on various manage.py operations
+or not.
+"""
+
+from django.db import models
+
+"""
+General test strategy:
+* All tests are numbered (01, 02, 03... etc).
+* Each test contains three models (A, B, C, followed with the number of test),
+  containing both indexed and non-indexed fields (to verify sql_index),
+  usual fields (model A), foreign keys (model B) and many-to-many fields (model C).
+  D table is generated automatically as intermediate M2M one.
+* The normal (default; create_db_schema = True) behaviour during the manage.py
+  operations is not thoroughly checked; it is the duty of the appropriate tests
+  for the primary functionality of these operations.
+  The most attention is paid to whether the create_db_schema = False
+  disables the SQL generation properly.
+* The intermediate table for M2M relations is not ever verified explicitly,
+  because it is not ever marked with create_db_schema explicitly.
+"""
+
+# This dictionary maps the name of the model/SQL table (like 'A01')
+# to the boolean specifying whether this name should appear in the final SQL
+checks = {}
+
+
+"""
+01: create_db_schema is not set.
+    In such case, it should be equal (by default) to True,
+    and SQL is generated for all three models.
+"""
+checks['A01'] = True
+checks['B01'] = True
+checks['C01'] = True
+
+class A01(models.Model):
+    class Meta: db_table = 'A01'
+
+    f_a = models.TextField(db_index = True)
+    f_b = models.IntegerField()
+
+class B01(models.Model):
+    class Meta: db_table = 'B01'
+
+    fk_a = models.ForeignKey(A01)
+    f_a = models.TextField(db_index = True)
+    f_b = models.IntegerField()
+
+class C01(models.Model):
+    class Meta: db_table = 'C01'
+
+    mm_a = models.ManyToManyField(A01, db_table = 'D01')
+    f_a = models.TextField(db_index = True)
+    f_b = models.IntegerField()
+
+
+"""
+02: create_db_schema is set to True.
+    SQL is generated for all three models.
+"""
+checks['A02'] = True
+checks['B02'] = True
+checks['C02'] = True
+
+class A02(models.Model):
+    class Meta:
+        db_table = 'A02'
+        create_db_schema = True
+
+    f_a = models.TextField(db_index = True)
+    f_b = models.IntegerField()
+
+class B02(models.Model):
+    class Meta:
+        db_table = 'B02'
+        create_db_schema = True
+
+    fk_a = models.ForeignKey(A02)
+    f_a = models.TextField(db_index = True)
+    f_b = models.IntegerField()
+
+class C02(models.Model):
+    class Meta:
+        db_table = 'C02'
+        create_db_schema = True
+
+    mm_a = models.ManyToManyField(A02, db_table = 'D02')
+    f_a = models.TextField(db_index = True)
+    f_b = models.IntegerField()
+
+
+"""
+03: create_db_schema is set to False.
+    SQL is NOT generated for any of the three models.
+"""
+checks['A03'] = False
+checks['B03'] = False
+checks['C03'] = False
+
+class A03(models.Model):
+    class Meta:
+        db_table = 'A03'
+        create_db_schema = False
+
+    f_a = models.TextField(db_index = True)
+    f_b = models.IntegerField()
+
+class B03(models.Model):
+    class Meta:
+        db_table = 'B03'
+        create_db_schema = False
+
+    fk_a = models.ForeignKey(A03)
+    f_a = models.TextField(db_index = True)
+    f_b = models.IntegerField()
+
+class C03(models.Model):
+    class Meta:
+        db_table = 'C03'
+        create_db_schema = False
+
+    mm_a = models.ManyToManyField(A03, db_table = 'D03')
+    f_a = models.TextField(db_index = True)
+    f_b = models.IntegerField()
+
+
+# We will use short names for these templates
+sql_templates = {
+	'create table': 'CREATE TABLE "%s"',
+	'create index': 'CREATE INDEX "%s_f_a"',
+	'drop table': 'DROP TABLE "%s"',
+	'delete from': 'DELETE FROM "%s"'
+}
+
+def get_failed_models(arr_sql, sql_template_names):
+    """
+    Find the models which should not be in the SQL but they are present,
+    or they should be in the SQL but they are missing.
+    """
+    txt_sql = ' '.join(arr_sql)
+    for (model, should_be_present) in checks.iteritems():
+        # Do we expect to see the model name in the SQL text?
+        for sql_template_name in sql_template_names:
+            # We are interested not in just the model name like "A01",
+            # but in the whole string like 'CREATE TABLE "A01"'
+            # so we apply the model name to the template
+            # to find out the expected string
+            expected = (sql_templates[sql_template_name])%model
+            if ((expected in txt_sql) != should_be_present):
+                # Our expectations failed!
+                yield 'The string %s %s present in SQL but it %s.'%(
+                    expected,
+                    {False: 'is not', True: 'is'}[expected in txt_sql],
+                    {False: 'should not be', True: 'should be'}[should_be_present]
+                    )
+
+
+__test__ = {'API_TESTS':"""
+>>> from django.db.models import get_app
+>>> from django.core.management.sql import *
+>>> from django.core.management.color import no_style
+>>> import sys
+
+>>> myapp = get_app('create_db_schema')
+>>> mystyle = no_style()
+
+# a. Verify sql_create
+>>> list(get_failed_models( sql_create(myapp, mystyle), ['create table'] ))
+[]
+
+# b. Verify sql_delete
+>>> list(get_failed_models( sql_delete(myapp, mystyle), ['drop table'] ))
+[]
+
+# c. Verify sql_reset
+>>> list(get_failed_models( sql_reset(myapp, mystyle), ['drop table', 'create table', 'create index'] ))
+[]
+
+# d. Verify sql_flush
+>>> # sql_flush(mystyle)
+>>> list(get_failed_models( sql_flush(mystyle), ['delete from'] ))
+[]
+
+# e. Verify sql_custom
+# No custom data provided, should not be no output.
+>>> sql_custom(myapp)
+[]
+
+# f. Verify sql_indexes
+>>> list(get_failed_models( sql_indexes(myapp, mystyle), ['create index'] ))
+[]
+
+# g. Verify sql_all
+>>> list(get_failed_models( sql_all(myapp, mystyle), ['create table', 'create index'] ))
+[]
+"""}
Index: AUTHORS
===================================================================
--- AUTHORS	(revision 7027)
+++ AUTHORS	(working copy)
@@ -353,6 +353,7 @@
     ymasuda@ethercube.com
     Jarek Zgoda <jarek.zgoda@gmail.com>
     Cheng Zhang
+    Alexander Myodov <amyodov@gmail.com>
 
 A big THANK YOU goes to:
 
Index: docs/model-api.txt
===================================================================
--- docs/model-api.txt	(revision 7027)
+++ docs/model-api.txt	(working copy)
@@ -1051,6 +1051,28 @@
 that aren't allowed in Python variable names -- notably, the hyphen --
 that's OK. Django quotes column and table names behind the scenes.
 
+``create_db_schema``
+--------------------
+
+**New in Django development version**
+
+Marks this model as requiring SQL operations when calling ``manage.py``::
+
+    create_db_schema = False
+
+If this isn't given, Django will use ``create_db_schema = True``
+what means that the operations like ``manage.py sqlreset``, ``manage.py syncdb``
+and others will regenerate the appropriate table when needed.
+If the option is set to False, the appropriate table will not be affected with
+any SQL operations.
+
+This is useful for databases where some DB tables are controlled by Django models,
+but some other DB tables and views are created via raw SQL and should not be affected
+by any ``manage.py`` actions.
+Note that if the initial SQL data is provided (see `Providing initial SQL
+data`_ below), it still will be present in the output of
+``sqlall``/``sqlcustom`` commands.
+
 ``db_tablespace``
 -----------------
 
