Index: django/db/models/options.py
===================================================================
--- django/db/models/options.py	(revision 8599)
+++ django/db/models/options.py	(working copy)
@@ -21,7 +21,7 @@
 DEFAULT_NAMES = ('verbose_name', 'db_table', 'ordering',
                  'unique_together', 'permissions', 'get_latest_by',
                  'order_with_respect_to', 'app_label', 'db_tablespace',
-                 'abstract')
+                 'abstract', 'create_db_schema')
 
 class Options(object):
     def __init__(self, meta, app_label=None):
@@ -36,6 +36,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/db/backends/__init__.py
===================================================================
--- django/db/backends/__init__.py	(revision 8599)
+++ django/db/backends/__init__.py	(working copy)
@@ -382,20 +382,24 @@
         cursor = self.connection.cursor()
         return self.get_table_list(cursor)
 
-    def django_table_names(self, only_existing=False):
+    def django_table_names(self, 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 = set()
         for app in models.get_apps():
             for model in models.get_models(app):
-                tables.add(model._meta.db_table)
-                tables.update([f.m2m_db_table() for f in model._meta.local_many_to_many])
+                if (not filter_not_generated_tables) or (model._meta.create_db_schema):
+                    tables.add(model._meta.db_table)
+                    tables.update([f.m2m_db_table() for f in model._meta.local_many_to_many])
         if only_existing:
             tables = [t for t in tables if t in self.table_names()]
         return tables
@@ -411,8 +415,13 @@
             if self.table_name_converter(m._meta.db_table) in map(self.table_name_converter, tables)
         ])
 
-    def sequence_list(self):
-        "Returns a list of information about all DB sequences for all models in all apps."
+    def sequence_list(self, 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()
@@ -420,13 +429,14 @@
 
         for app in apps:
             for model in models.get_models(app):
-                for f in model._meta.local_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.local_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.local_many_to_many:
-                    sequence_list.append({'table': f.m2m_db_table(), 'column': None})
+                    for f in model._meta.local_many_to_many:
+                        sequence_list.append({'table': f.m2m_db_table(), 'column': None})
 
         return sequence_list
 
@@ -445,4 +455,3 @@
     def validate_field(self, errors, opts, f):
         "By default, there is no backend-specific validation"
         pass
-
Index: django/db/backends/creation.py
===================================================================
--- django/db/backends/creation.py	(revision 8599)
+++ django/db/backends/creation.py	(working copy)
@@ -71,22 +71,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:
-            full_statement.append(self.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:
+                full_statement.append(self.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 = self.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 = self.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
 
@@ -125,10 +127,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, self.connection.ops.max_name_length()),
-                    qn(r_col), qn(table), qn(col),
-                    self.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, self.connection.ops.max_name_length()),
+                        qn(r_col), qn(table), qn(col),
+                        self.connection.ops.deferrable_sql()))
             del pending_references[model]
         return final_output
 
@@ -259,7 +262,7 @@
         qn = self.connection.ops.quote_name
         output = ['%s %s;' % (style.SQL_KEYWORD('DROP TABLE'),
                               style.SQL_TABLE(qn(model._meta.db_table)))]
-        if model in references_to_delete:
+        if model in references_to_delete and model._meta.create_db_schema:
             output.extend(self.sql_remove_table_constraints(model, references_to_delete, style))
 
         if model._meta.has_auto_field:
@@ -279,11 +282,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(self.connection.ops.drop_foreignkey_sql()),
-                style.SQL_FIELD(truncate_name(r_name, self.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(self.connection.ops.drop_foreignkey_sql()),
+                    style.SQL_FIELD(truncate_name(r_name, self.connection.ops.max_name_length()))))
         del references_to_delete[model]
         return output
 
@@ -401,4 +405,3 @@
     def sql_table_creation_suffix(self):
         "SQL to append to the end of the test table creation statements"
         return ''
-
Index: django/core/management/commands/reset.py
===================================================================
--- django/core/management/commands/reset.py	(revision 8599)
+++ django/core/management/commands/reset.py	(working copy)
@@ -45,8 +45,8 @@
   * The database isn't running or isn't configured correctly.
   * At least one of the database tables doesn't exist.
   * The SQL was invalid.
-Hint: Look at the output of 'django-admin.py sqlreset %s'. That's the SQL this command wasn't able to run.
-The full error: %s""" % (app_name, app_name, e))
+Hint: Look at the output of 'django-admin.py sqlreset %s'. That's the SQL this command wasn't able to run:\n%s.
+The full error: %s""" % (app_name, app_name, sql, e))
             transaction.commit_unless_managed()
         else:
             print "Reset cancelled."
Index: django/core/management/commands/syncdb.py
===================================================================
--- django/core/management/commands/syncdb.py	(revision 8599)
+++ django/core/management/commands/syncdb.py	(working copy)
@@ -41,7 +41,7 @@
                 # but raises an ImportError for some reason. The only way we
                 # can do this is to check the text of the exception. Note that
                 # we're a bit broad in how we check the text, because different
-                # Python implementations may not use the same text. 
+                # Python implementations may not use the same text.
                 # CPython uses the text "No module named management"
                 # PyPy uses "No module named myproject.myapp.management"
                 msg = exc.args[0]
@@ -60,7 +60,7 @@
         for app in models.get_apps():
             app_name = app.__name__.split('.')[-2]
             model_list = models.get_models(app)
-            for model in model_list:
+            for model in (m for m in model_list if m._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)
@@ -99,10 +99,10 @@
         # Send the post_syncdb signal, so individual apps can do whatever they need
         # to do at this point.
         emit_post_sync_signal(created_models, verbosity, interactive)
-        
+
         # The connection may have been closed by a syncdb handler.
         cursor = connection.cursor()
-        
+
         # Install custom SQL for the app (but only if this
         # is a model we've just created)
         for app in models.get_apps():
@@ -132,7 +132,7 @@
         for app in models.get_apps():
             app_name = app.__name__.split('.')[-2]
             for model in models.get_models(app):
-                if model in created_models:
+                if model in created_models and model._meta.create_db_schema:
                     index_sql = connection.creation.sql_indexes_for_model(model, self.style)
                     if index_sql:
                         if verbosity >= 1:
Index: django/core/management/sql.py
===================================================================
--- django/core/management/sql.py	(revision 8599)
+++ django/core/management/sql.py	(working copy)
@@ -119,16 +119,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 = connection.introspection.django_table_names()
+        tables = connection.introspection.django_table_names(filter_not_generated_tables=True)
     else:
         tables = connection.introspection.table_names()
-    statements = connection.ops.sql_flush(style, tables, connection.introspection.sequence_list())
+    statements = connection.ops.sql_flush(style, tables, connection.introspection.sequence_list(filter_not_generated_tables=True))
     return statements
 
 def sql_custom(app, style):
@@ -148,7 +148,7 @@
     "Returns a list of the CREATE INDEX SQL statements for all models in the given app."
     from django.db import connection, models
     output = []
-    for model in models.get_models(app):
+    for model in (m for m in models.get_models(app) if m._meta.create_db_schema):
         output.extend(connection.creation.sql_indexes_for_model(model, style))
     return output
 
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 8599)
+++ AUTHORS	(working copy)
@@ -430,6 +430,7 @@
     ymasuda@ethercube.com
     Jarek Zgoda <jarek.zgoda@gmail.com>
     Cheng Zhang
+    Alexander Myodov <alex@myodov.com>
 
 A big THANK YOU goes to:
 
