Changeset 8296
- Timestamp:
- 08/11/08 07:11:25 (4 months ago)
- Files:
-
- django/trunk/django/contrib/gis/db/backend/mysql/creation.py (modified) (1 diff)
- django/trunk/django/contrib/gis/db/backend/oracle/creation.py (modified) (1 diff)
- django/trunk/django/contrib/gis/db/backend/postgis/creation.py (modified) (11 diffs)
- django/trunk/django/contrib/gis/management/commands/inspectdb.py (modified) (7 diffs)
- django/trunk/django/core/management/commands/dbshell.py (modified) (1 diff)
- django/trunk/django/core/management/commands/inspectdb.py (modified) (3 diffs)
- django/trunk/django/core/management/commands/syncdb.py (modified) (6 diffs)
- django/trunk/django/core/management/commands/testserver.py (modified) (2 diffs)
- django/trunk/django/core/management/sql.py (modified) (13 diffs)
- django/trunk/django/core/management/validation.py (modified) (1 diff)
- django/trunk/django/db/backends/creation.py (modified) (1 diff)
- django/trunk/django/db/backends/dummy/base.py (modified) (3 diffs)
- django/trunk/django/db/backends/dummy/client.py (modified) (1 diff)
- django/trunk/django/db/backends/dummy/creation.py (modified) (1 diff)
- django/trunk/django/db/backends/dummy/introspection.py (modified) (1 diff)
- django/trunk/django/db/backends/__init__.py (modified) (3 diffs)
- django/trunk/django/db/backends/mysql/base.py (modified) (4 diffs)
- django/trunk/django/db/backends/mysql/client.py (modified) (1 diff)
- django/trunk/django/db/backends/mysql/creation.py (modified) (1 diff)
- django/trunk/django/db/backends/mysql/introspection.py (modified) (1 diff)
- django/trunk/django/db/backends/mysql/validation.py (added)
- django/trunk/django/db/backends/oracle/base.py (modified) (4 diffs)
- django/trunk/django/db/backends/oracle/client.py (modified) (1 diff)
- django/trunk/django/db/backends/oracle/creation.py (modified) (1 diff)
- django/trunk/django/db/backends/oracle/introspection.py (modified) (1 diff)
- django/trunk/django/db/backends/postgresql/base.py (modified) (3 diffs)
- django/trunk/django/db/backends/postgresql/client.py (modified) (1 diff)
- django/trunk/django/db/backends/postgresql/creation.py (modified) (1 diff)
- django/trunk/django/db/backends/postgresql/introspection.py (modified) (1 diff)
- django/trunk/django/db/backends/postgresql_psycopg2/base.py (modified) (3 diffs)
- django/trunk/django/db/backends/postgresql_psycopg2/client.py (modified) (1 diff)
- django/trunk/django/db/backends/postgresql_psycopg2/creation.py (modified) (1 diff)
- django/trunk/django/db/backends/postgresql_psycopg2/introspection.py (modified) (1 diff)
- django/trunk/django/db/backends/sqlite3/base.py (modified) (4 diffs)
- django/trunk/django/db/backends/sqlite3/client.py (modified) (1 diff)
- django/trunk/django/db/backends/sqlite3/creation.py (modified) (1 diff)
- django/trunk/django/db/backends/sqlite3/introspection.py (modified) (3 diffs)
- django/trunk/django/db/__init__.py (modified) (3 diffs)
- django/trunk/django/db/models/fields/__init__.py (modified) (3 diffs)
- django/trunk/django/test/simple.py (modified) (2 diffs)
- django/trunk/django/test/utils.py (modified) (2 diffs)
- django/trunk/docs/testing.txt (modified) (2 diffs)
- django/trunk/tests/regressiontests/backends/models.py (modified) (3 diffs)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
django/trunk/django/contrib/gis/db/backend/mysql/creation.py
r8219 r8296 1 from django.test.utils import create_test_db2 1 3 2 def create_spatial_db(test=True, verbosity=1, autoclobber=False): 4 3 if not test: raise NotImplementedError('This uses `create_test_db` from test/utils.py') 5 create_test_db(verbosity, autoclobber) 4 from django.db import connection 5 connection.creation.create_test_db(verbosity, autoclobber) django/trunk/django/contrib/gis/db/backend/oracle/creation.py
r8219 r8296 1 from django.db.backends.oracle.creation import create_test_db2 1 3 2 def create_spatial_db(test=True, verbosity=1, autoclobber=False): 4 3 "A wrapper over the Oracle `create_test_db` routine." 5 4 if not test: raise NotImplementedError('This uses `create_test_db` from db/backends/oracle/creation.py') 6 from django.conf import settings7 5 from django.db import connection 8 c reate_test_db(settings, connection,verbosity, autoclobber)6 connection.creation.create_test_db(verbosity, autoclobber) django/trunk/django/contrib/gis/db/backend/postgis/creation.py
r8219 r8296 2 2 from django.core.management import call_command 3 3 from django.db import connection 4 from django. test.utils import _set_autocommit,TEST_DATABASE_PREFIX4 from django.db.backends.creation import TEST_DATABASE_PREFIX 5 5 import os, re, sys 6 6 … … 39 39 if settings.DATABASE_USER: 40 40 create_sql += ' OWNER %s' % settings.DATABASE_USER 41 41 42 42 cursor = connection.cursor() 43 _set_autocommit(connection)43 connection.creation.set_autocommit(connection) 44 44 45 45 try: … … 59 59 raise Exception('Spatial Database Creation canceled.') 60 60 foo = _create_with_cursor 61 61 62 62 created_regex = re.compile(r'^createdb: database creation failed: ERROR: database ".+" already exists') 63 63 def _create_with_shell(db_name, verbosity=1, autoclobber=False): 64 64 """ 65 If no spatial database already exists, then using a cursor will not work. 66 Thus, a `createdb` command will be issued through the shell to bootstrap 65 If no spatial database already exists, then using a cursor will not work. 66 Thus, a `createdb` command will be issued through the shell to bootstrap 67 67 creation of the spatial database. 68 68 """ … … 84 84 drop_cmd = 'dropdb %s%s' % (options, db_name) 85 85 status, output = getstatusoutput(drop_cmd) 86 if status != 0: 86 if status != 0: 87 87 raise Exception('Could not drop database %s: %s' % (db_name, output)) 88 88 if verbosity >= 1: print 'Creating new spatial database...' … … 103 103 104 104 # Getting the spatial database name 105 if test: 105 if test: 106 106 db_name = get_spatial_db(test=True) 107 107 _create_with_cursor(db_name, verbosity=verbosity, autoclobber=autoclobber) 108 else: 108 else: 109 109 db_name = get_spatial_db() 110 110 _create_with_shell(db_name, verbosity=verbosity, autoclobber=autoclobber) … … 126 126 # Syncing the database 127 127 call_command('syncdb', verbosity=verbosity, interactive=interactive) 128 128 129 129 def drop_db(db_name=False, test=False): 130 130 """ … … 152 152 def get_spatial_db(test=False): 153 153 """ 154 Returns the name of the spatial database. The 'test' keyword may be set 154 Returns the name of the spatial database. The 'test' keyword may be set 155 155 to return the test spatial database name. 156 156 """ … … 168 168 def load_postgis_sql(db_name, verbosity=1): 169 169 """ 170 This routine loads up the PostGIS SQL files lwpostgis.sql and 170 This routine loads up the PostGIS SQL files lwpostgis.sql and 171 171 spatial_ref_sys.sql. 172 172 """ … … 174 174 # Getting the path to the PostGIS SQL 175 175 try: 176 # POSTGIS_SQL_PATH may be placed in settings to tell GeoDjango where the 176 # POSTGIS_SQL_PATH may be placed in settings to tell GeoDjango where the 177 177 # PostGIS SQL files are located. This is especially useful on Win32 178 178 # platforms since the output of pg_config looks like "C:/PROGRA~1/..". … … 194 194 options = get_cmd_options(db_name) 195 195 cmd_fmt = 'psql %s-f "%%s"' % options 196 196 197 197 # Now trying to load up the PostGIS functions 198 198 cmd = cmd_fmt % lwpostgis_file … … 212 212 # of the spatial_ref_sys and geometry_columns tables is always 213 213 # the postgres user, regardless of how the db is created. 214 if os.name == 'nt': set_permissions(db_name) 215 214 if os.name == 'nt': set_permissions(db_name) 215 216 216 def set_permissions(db_name): 217 217 """ django/trunk/django/contrib/gis/management/commands/inspectdb.py
r8219 r8296 8 8 9 9 class Command(InspectCommand): 10 10 11 11 # Mapping from lower-case OGC type to the corresponding GeoDjango field. 12 12 geofield_mapping = {'point' : 'PointField', … … 22 22 def geometry_columns(self): 23 23 """ 24 Returns a datastructure of metadata information associated with the 24 Returns a datastructure of metadata information associated with the 25 25 `geometry_columns` (or equivalent) table. 26 26 """ 27 27 # The `geo_cols` is a dictionary data structure that holds information 28 # about any geographic columns in the database. 28 # about any geographic columns in the database. 29 29 geo_cols = {} 30 30 def add_col(table, column, coldata): … … 48 48 # On MySQL have to get all table metadata before hand; this means walking through 49 49 # each table and seeing if any column types are spatial. Can't detect this with 50 # `cursor.description` (what the introspection module does) because all spatial types 50 # `cursor.description` (what the introspection module does) because all spatial types 51 51 # have the same integer type (255 for GEOMETRY). 52 52 from django.db import connection … … 68 68 def handle_inspection(self): 69 69 "Overloaded from Django's version to handle geographic database tables." 70 from django.db import connection , get_introspection_module70 from django.db import connection 71 71 import keyword 72 72 73 introspection_module = get_introspection_module()73 geo_cols = self.geometry_columns() 74 74 75 geo_cols = self.geometry_columns()76 77 75 table2model = lambda table_name: table_name.title().replace('_', '') 78 76 … … 89 87 yield 'from django.contrib.gis.db import models' 90 88 yield '' 91 for table_name in introspection_module.get_table_list(cursor):89 for table_name in connection.introspection.get_table_list(cursor): 92 90 # Getting the geographic table dictionary. 93 91 geo_table = geo_cols.get(table_name, {}) … … 95 93 yield 'class %s(models.Model):' % table2model(table_name) 96 94 try: 97 relations = introspection_module.get_relations(cursor, table_name)95 relations = connection.introspection.get_relations(cursor, table_name) 98 96 except NotImplementedError: 99 97 relations = {} 100 98 try: 101 indexes = introspection_module.get_indexes(cursor, table_name)99 indexes = connection.introspection.get_indexes(cursor, table_name) 102 100 except NotImplementedError: 103 101 indexes = {} 104 for i, row in enumerate( introspection_module.get_table_description(cursor, table_name)):102 for i, row in enumerate(connection.introspection.get_table_description(cursor, table_name)): 105 103 att_name, iatt_name = row[0].lower(), row[0] 106 104 comment_notes = [] # Holds Field notes, to be displayed in a Python comment. … … 134 132 else: 135 133 try: 136 field_type = introspection_module.DATA_TYPES_REVERSE[row[1]]134 field_type = connection.introspection.data_types_reverse[row[1]] 137 135 except KeyError: 138 136 field_type = 'TextField' 139 137 comment_notes.append('This field type is a guess.') 140 138 141 # This is a hook for DATA_TYPES_REVERSEto return a tuple of139 # This is a hook for data_types_reverse to return a tuple of 142 140 # (field_type, extra_params_dict). 143 141 if type(field_type) is tuple: django/trunk/django/core/management/commands/dbshell.py
r7294 r8296 7 7 8 8 def handle_noargs(self, **options): 9 from django.db import runshell10 runshell()9 from django.db import connection 10 connection.client.runshell() django/trunk/django/core/management/commands/inspectdb.py
r7294 r8296 14 14 15 15 def handle_inspection(self): 16 from django.db import connection , get_introspection_module16 from django.db import connection 17 17 import keyword 18 19 introspection_module = get_introspection_module()20 18 21 19 table2model = lambda table_name: table_name.title().replace('_', '') … … 33 31 yield 'from django.db import models' 34 32 yield '' 35 for table_name in introspection_module.get_table_list(cursor):33 for table_name in connection.introspection.get_table_list(cursor): 36 34 yield 'class %s(models.Model):' % table2model(table_name) 37 35 try: 38 relations = introspection_module.get_relations(cursor, table_name)36 relations = connection.introspection.get_relations(cursor, table_name) 39 37 except NotImplementedError: 40 38 relations = {} 41 39 try: 42 indexes = introspection_module.get_indexes(cursor, table_name)40 indexes = connection.introspection.get_indexes(cursor, table_name) 43 41 except NotImplementedError: 44 42 indexes = {} 45 for i, row in enumerate( introspection_module.get_table_description(cursor, table_name)):43 for i, row in enumerate(connection.introspection.get_table_description(cursor, table_name)): 46 44 att_name = row[0].lower() 47 45 comment_notes = [] # Holds Field notes, to be displayed in a Python comment. … … 66 64 else: 67 65 try: 68 field_type = introspection_module.DATA_TYPES_REVERSE[row[1]]66 field_type = connection.introspection.data_types_reverse[row[1]] 69 67 except KeyError: 70 68 field_type = 'TextField' django/trunk/django/core/management/commands/syncdb.py
r8133 r8296 22 22 from django.db import connection, transaction, models 23 23 from django.conf import settings 24 from django.core.management.sql import table_names, installed_models, sql_model_create, sql_for_pending_references, many_to_many_sql_for_model, custom_sql_for_model, sql_indexes_for_model, emit_post_sync_signal24 from django.core.management.sql import custom_sql_for_model, emit_post_sync_signal 25 25 26 26 verbosity = int(options.get('verbosity', 1)) … … 51 51 cursor = connection.cursor() 52 52 53 if connection.features.uses_case_insensitive_names:54 table_name_converter = lambda x: x.upper()55 else:56 table_name_converter = lambda x: x57 # Get a list of all existing database tables, so we know what needs to58 # be added.59 tables = [table_name_converter(name) for name in table_names()]60 61 53 # Get a list of already installed *models* so that references work right. 62 seen_models = installed_models(tables) 54 tables = connection.introspection.table_names() 55 seen_models = connection.introspection.installed_models(tables) 63 56 created_models = set() 64 57 pending_references = {} … … 72 65 if verbosity >= 2: 73 66 print "Processing %s.%s model" % (app_name, model._meta.object_name) 74 if table_name_converter(model._meta.db_table) in tables:67 if connection.introspection.table_name_converter(model._meta.db_table) in tables: 75 68 continue 76 sql, references = sql_model_create(model, self.style, seen_models)69 sql, references = connection.creation.sql_create_model(model, self.style, seen_models) 77 70 seen_models.add(model) 78 71 created_models.add(model) … … 80 73 pending_references.setdefault(refto, []).extend(refs) 81 74 if refto in seen_models: 82 sql.extend( sql_for_pending_references(refto, self.style, pending_references))83 sql.extend( sql_for_pending_references(model, self.style, pending_references))75 sql.extend(connection.creation.sql_for_pending_references(refto, self.style, pending_references)) 76 sql.extend(connection.creation.sql_for_pending_references(model, self.style, pending_references)) 84 77 if verbosity >= 1: 85 78 print "Creating table %s" % model._meta.db_table 86 79 for statement in sql: 87 80 cursor.execute(statement) 88 tables.append( table_name_converter(model._meta.db_table))81 tables.append(connection.introspection.table_name_converter(model._meta.db_table)) 89 82 90 83 # Create the m2m tables. This must be done after all tables have been created … … 95 88 for model in model_list: 96 89 if model in created_models: 97 sql = many_to_many_sql_for_model(model, self.style)90 sql = connection.creation.sql_for_many_to_many(model, self.style) 98 91 if sql: 99 92 if verbosity >= 2: … … 141 134 for model in models.get_models(app): 142 135 if model in created_models: 143 index_sql = sql_indexes_for_model(model, self.style)136 index_sql = connection.creation.sql_indexes_for_model(model, self.style) 144 137 if index_sql: 145 138 if verbosity >= 1: django/trunk/django/core/management/commands/testserver.py
r8046 r8296 19 19 def handle(self, *fixture_labels, **options): 20 20 from django.core.management import call_command 21 from django. test.utils import create_test_db21 from django.db import connection 22 22 23 23 verbosity = int(options.get('verbosity', 1)) … … 25 25 26 26 # Create a test database. 27 db_name = c reate_test_db(verbosity=verbosity)27 db_name = connection.creation.create_test_db(verbosity=verbosity) 28 28 29 29 # Import the fixture data into the test database. django/trunk/django/core/management/sql.py
r8223 r8296 8 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_module13 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 and19 are in INSTALLED_APPS.20 21 If only_existing is True, the resulting list will only include the tables22 that actually exist in the database.23 """24 from django.db import models25 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 tables33 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, models37 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: x45 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 models50 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_list65 66 10 def sql_create(app, style): 67 11 "Returns a list of the CREATE TABLE SQL statements for the given app." 68 from django.db import models12 from django.db import connection, models 69 13 from django.conf import settings 70 14 … … 82 26 app_models = models.get_models(app) 83 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 30 pending_references = {} 86 31 87 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 34 final_output.extend(output) 90 35 for refto, refs in references.items(): 91 36 pending_references.setdefault(refto, []).extend(refs) 92 37 if refto in known_models: 93 final_output.extend( sql_for_pending_references(refto, style, pending_references))94 final_output.extend( sql_for_pending_references(model, style, pending_references))38 final_output.extend(connection.creation.sql_for_pending_references(refto, style, pending_references)) 39 final_output.extend(connection.creation.sql_for_pending_references(model, style, pending_references)) 95 40 # Keep track of the fact that we've created the table for this model. 96 41 known_models.add(model) … … 98 43 # Create the many-to-many join tables. 99 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 47 # Handle references to tables that are from other apps … … 107 52 for model in not_installed_models: 108 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 55 if alter_sql: 111 56 final_output.append('-- The following references should be added but depend on non-existent tables:') … … 116 61 def sql_delete(app, style): 117 62 "Returns a list of the DROP TABLE SQL statements for the given app." 118 from django.db import connection, models , get_introspection_module63 from django.db import connection, models 119 64 from django.db.backends.util import truncate_name 120 65 from django.contrib.contenttypes import generic 121 introspection = get_introspection_module()122 66 123 67 # This should work even if a connection isn't available … … 129 73 # Figure out which tables already exist 130 74 if cursor: 131 table_names = introspection.get_table_list(cursor)75 table_names = connection.introspection.get_table_list(cursor) 132 76 else: 133 77 table_names = [] 134 if connection.features.uses_case_insensitive_names: 135 table_name_converter = lambda x: x.upper() 136 else: 137 table_name_converter = lambda x: x 138 139 output = [] 140 qn = connection.ops.quote_name 78 79 output = [] 141 80 142 81 # Output DROP TABLE statements for standard application tables. … … 146 85 app_models = models.get_models(app) 147 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 88 # The table exists, so it needs to be dropped 150 89 opts = model._meta … … 156 95 157 96 for model in app_models: 158 if cursor and table_name_converter(model._meta.db_table) in table_names: 159 # Drop the table now 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) 97 if connection.introspection.table_name_converter(model._meta.db_table) in table_names: 98 output.extend(connection.creation.sql_destroy_model(model, references_to_delete, style)) 179 99 180 100 # Output DROP TABLE statements for many-to-many tables. … … 182 102 opts = model._meta 183 103 for f in opts.local_many_to_many: 184 if not f.creates_table: 185 continue 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) 104 if cursor and connection.introspection.table_name_converter(f.m2m_db_table()) in table_names: 105 output.extend(connection.creation.sql_destroy_many_to_many(model, f, style)) 192 106 193 107 app_label = app_models[0]._meta.app_label … … 214 128 from django.db import connection 215 129 if only_django: 216 tables = django_table_names()130 tables = connection.introspection.django_table_names() 217 131 else: 218 tables = table_names()219 statements = connection.ops.sql_flush(style, tables, sequence_list())132 tables = connection.introspection.table_names() 133 statements = connection.ops.sql_flush(style, tables, connection.introspection.sequence_list()) 220 134 return statements 221 135 … … 235 149 def sql_indexes(app, style): 236 150 "Returns a list of the CREATE INDEX SQL statements for all models in the given app." 237 from django.db import models151 from django.db import connection, models 238 152 output = [] 239 153 for model in models.get_models(app): 240 output.extend( sql_indexes_for_model(model, style))154 output.extend(connection.creation.sql_indexes_for_model(model, style)) 241 155 return output 242 156 … … 244 158 "Returns a list of CREATE TABLE SQL, initial-data inserts, and CREATE INDEX SQL for the given module." 245 159 return sql_create(app, style) + sql_custom(app, style) + sql_indexes(app, style) 246 247 def sql_model_create(model, style, known_models=set()):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, models253 254 opts = model._meta255 final_output = []256 table_output = []257 pending_references = {}258 qn = connection.ops.quote_name259 inline_references = connection.features.inline_fk_references260 for f in opts.local_fields:261 col_type = f.db_type()262 tablespace = f.db_tablespace or opts.db_tablespace263 if col_type is None:264 # Skip ManyToManyFields, because they're not represented as265 # database columns in this table.266 continue267 # 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.primary_key:272 field_output.append(style.SQL_KEYWORD('PRIMARY KEY'))273 elif f.unique:274 field_output.append(style.SQL_KEYWORD('UNIQUE'))275 if tablespace and connection.features.supports_tablespaces and f.unique:276 # We must specify the index tablespace inline, because we277 # 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 field288 # 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.name311 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_references317 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 connection323 from django.db.backends.util import truncate_name324 325 qn = connection.ops.quote_name326 final_output = []327 if connection.features.supports_constraints:328 opts = model._meta329 if model in pending_references:330 for rel_class, f in pending_references[model]:331 rel_opts = rel_class._meta332 r_table = rel_opts.db_table333 r_col = f.column334 table = opts.db_table335 col = opts.get_field(f.rel.field_name).column336 # 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_output345 346 def many_to_many_sql_for_model(model, style):347 from django.db import connection, models348 from django.contrib.contenttypes import generic349 from django.db.backends.util import truncate_name350 351 opts = model._meta352 final_output = []353 qn = connection.ops.quote_name354 inline_references = connection.features.inline_fk_references355 for f in opts.local_many_to_many:356 if f.creates_table:357 tablespace = f.db_tablespace or opts.db_tablespace358 if tablespace and connection.features.supports_tablespaces: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
