Ticket #6148: 6148-r16443-2.diff
File 6148-r16443-2.diff, 78.5 KB (added by , 13 years ago) |
---|
-
docs/topics/db/models.txt
626 626 verbose_name_plural = "oxen" 627 627 628 628 Model metadata is "anything that's not a field", such as ordering options 629 (:attr:`~Options.ordering`), database table name (:attr:`~Options.db_table`), or 629 (:attr:`~Options.ordering`), database table name (:attr:`~Options.db_table`), 630 custom schema for the tables (:attr:`~Options.db_schema`), or 630 631 human-readable singular and plural names (:attr:`~Options.verbose_name` and 631 632 :attr:`~Options.verbose_name_plural`). None are required, and adding ``class 632 633 Meta`` to a model is completely optional. -
docs/ref/models/options.txt
61 61 aren't allowed in Python variable names -- notably, the hyphen -- that's OK. 62 62 Django quotes column and table names behind the scenes. 63 63 64 .. _db_schema: 65 66 ``db_schema`` 67 ------------- 68 69 .. attribute:: Options.db_schema 70 71 .. versionadded:: 1.3 72 73 The name of the database schema to use for the model. If the backend 74 doesn't support multiple schemas, this option is ignored. 75 76 If this is used then Django will prefix the model table names with the schema 77 name. For example with MySQL Django would use ``db_schema + '.' + db_table``. 78 Be aware that PostgreSQL supports different schemas within the database. 79 MySQL solves the same thing by treating it as just another database. 80 64 81 ``db_tablespace`` 65 82 ----------------- 66 83 -
docs/ref/settings.txt
510 510 The port to use when connecting to the database. An empty string means the 511 511 default port. Not used with SQLite. 512 512 513 .. setting:: SCHEMA 514 515 SCHEMA 516 ~~~~~~ 517 518 .. versionadded:: 1.3 519 520 Default: ``''`` (Empty string) 521 522 The name of the database schema to use for models. If the backend 523 doesn't support multiple schemas, this option is ignored. An empty 524 string means the default schema. 525 526 If this is used then Django will prefix any table names with the schema name. 527 The schema can be overriden on a per-model basis, for details see 528 :ref:`db_schema`. 529 513 530 .. setting:: USER 514 531 515 532 USER -
django/db/models/sql/compiler.py
23 23 might not have all the pieces in place at that time. 24 24 """ 25 25 if not self.query.tables: 26 self.query.join((None, self.query.model._meta. db_table, None, None))26 self.query.join((None, self.query.model._meta.qualified_name, None, None)) 27 27 if (not self.query.select and self.query.default_cols and not 28 28 self.query.included_inherited_models): 29 29 self.query.setup_inherited_models() … … 261 261 alias = start_alias 262 262 else: 263 263 link_field = opts.get_ancestor_link(model) 264 alias = self.query.join((start_alias, model._meta. db_table,264 alias = self.query.join((start_alias, model._meta.qualified_name, 265 265 link_field.column, model._meta.pk.column)) 266 266 seen[model] = alias 267 267 else: … … 462 462 result.append('%s%s%s' % (connector, qn(name), alias_str)) 463 463 first = False 464 464 for t in self.query.extra_tables: 465 alias, unused = self.query.table_alias( t)465 alias, unused = self.query.table_alias(qn(t)) 466 466 # Only add the alias if it's not already present (the table_alias() 467 467 # calls increments the refcount, so an alias refcount of one means 468 468 # this is the only reference. … … 550 550 # what "used" specifies). 551 551 avoid = avoid_set.copy() 552 552 dupe_set = orig_dupe_set.copy() 553 table = f.rel.to._meta. db_table553 table = f.rel.to._meta.qualified_name 554 554 promote = nullable or f.null 555 555 if model: 556 556 int_opts = opts … … 571 571 ())) 572 572 dupe_set.add((opts, lhs_col)) 573 573 int_opts = int_model._meta 574 alias = self.query.join((alias, int_opts. db_table, lhs_col,574 alias = self.query.join((alias, int_opts.qualified_name, lhs_col, 575 575 int_opts.pk.column), exclusions=used, 576 576 promote=promote) 577 577 alias_chain.append(alias) … … 623 623 # what "used" specifies). 624 624 avoid = avoid_set.copy() 625 625 dupe_set = orig_dupe_set.copy() 626 table = model._meta. db_table626 table = model._meta.qualified_name 627 627 628 628 int_opts = opts 629 629 alias = root_alias … … 646 646 dupe_set.add((opts, lhs_col)) 647 647 int_opts = int_model._meta 648 648 alias = self.query.join( 649 (alias, int_opts. db_table, lhs_col, int_opts.pk.column),649 (alias, int_opts.qualified_name, lhs_col, int_opts.pk.column), 650 650 exclusions=used, promote=True, reuse=used 651 651 ) 652 652 alias_chain.append(alias) … … 793 793 # going to be column names (so we can avoid the extra overhead). 794 794 qn = self.connection.ops.quote_name 795 795 opts = self.query.model._meta 796 result = ['INSERT INTO %s' % qn(opts.db_table)]796 result = ['INSERT INTO %s' % opts.qualified_name] 797 797 result.append('(%s)' % ', '.join([qn(c) for c in self.query.columns])) 798 798 values = [self.placeholder(*v) for v in self.query.values] 799 799 result.append('VALUES (%s)' % ', '.join(values)) 800 800 params = self.query.params 801 801 if self.return_id and self.connection.features.can_return_id_from_insert: 802 col = "%s.%s" % ( qn(opts.db_table), qn(opts.pk.column))802 col = "%s.%s" % (opts.qualified_name, qn(opts.pk.column)) 803 803 r_fmt, r_params = self.connection.ops.return_insert_id() 804 804 result.append(r_fmt % col) 805 805 params = params + r_params … … 813 813 if self.connection.features.can_return_id_from_insert: 814 814 return self.connection.ops.fetch_returned_insert_id(cursor) 815 815 return self.connection.ops.last_insert_id(cursor, 816 self.query.model._meta.db_table, self.query.model._meta.pk.column) 816 self.query.model._meta.db_schema, self.query.model._meta.db_table, 817 self.query.model._meta.pk.column) 817 818 818 819 819 820 class SQLDeleteCompiler(SQLCompiler): -
django/db/models/sql/query.py
620 620 Callback used by deferred_to_columns(). The "target" parameter should 621 621 be a set instance. 622 622 """ 623 table = model._meta. db_table623 table = model._meta.qualified_name 624 624 if table not in target: 625 625 target[table] = set() 626 626 for field in fields: … … 809 809 alias = self.tables[0] 810 810 self.ref_alias(alias) 811 811 else: 812 alias = self.join((None, self.model._meta.db_table, None, None)) 812 alias = self.join((None, self.model._meta.qualified_name, 813 None, None)) 813 814 return alias 814 815 815 816 def count_active_tables(self): … … 922 923 seen[model] = root_alias 923 924 else: 924 925 link_field = opts.get_ancestor_link(model) 925 seen[model] = self.join((root_alias, model._meta.db_table, 926 seen[model] = self.join((root_alias, 927 model._meta.qualified_name, 926 928 link_field.column, model._meta.pk.column)) 927 929 self.included_inherited_models = seen 928 930 … … 1269 1271 (id(opts), lhs_col), ())) 1270 1272 dupe_set.add((opts, lhs_col)) 1271 1273 opts = int_model._meta 1272 alias = self.join((alias, opts.db_table, lhs_col, 1273 opts.pk.column), exclusions=exclusions) 1274 alias = self.join((alias, opts.qualified_name, 1275 lhs_col, opts.pk.column), 1276 exclusions=exclusions) 1274 1277 joins.append(alias) 1275 1278 exclusions.add(alias) 1276 1279 for (dupe_opts, dupe_col) in dupe_set: … … 1295 1298 (table1, from_col1, to_col1, table2, from_col2, 1296 1299 to_col2, opts, target) = cached_data 1297 1300 else: 1298 table1 = field.m2m_ db_table()1301 table1 = field.m2m_qualified_name() 1299 1302 from_col1 = opts.get_field_by_name( 1300 1303 field.m2m_target_field_name())[0].column 1301 1304 to_col1 = field.m2m_column_name() 1302 1305 opts = field.rel.to._meta 1303 table2 = opts. db_table1306 table2 = opts.qualified_name 1304 1307 from_col2 = field.m2m_reverse_name() 1305 1308 to_col2 = opts.get_field_by_name( 1306 1309 field.m2m_reverse_target_field_name())[0].column … … 1328 1331 else: 1329 1332 opts = field.rel.to._meta 1330 1333 target = field.rel.get_related_field() 1331 table = opts. db_table1334 table = opts.qualified_name 1332 1335 from_col = field.column 1333 1336 to_col = target.column 1334 1337 orig_opts._join_cache[name] = (table, from_col, to_col, … … 1350 1353 (table1, from_col1, to_col1, table2, from_col2, 1351 1354 to_col2, opts, target) = cached_data 1352 1355 else: 1353 table1 = field.m2m_ db_table()1356 table1 = field.m2m_qualified_name() 1354 1357 from_col1 = opts.get_field_by_name( 1355 1358 field.m2m_reverse_target_field_name())[0].column 1356 1359 to_col1 = field.m2m_reverse_name() 1357 1360 opts = orig_field.opts 1358 table2 = opts. db_table1361 table2 = opts.qualified_name 1359 1362 from_col2 = field.m2m_column_name() 1360 1363 to_col2 = opts.get_field_by_name( 1361 1364 field.m2m_target_field_name())[0].column … … 1379 1382 local_field = opts.get_field_by_name( 1380 1383 field.rel.field_name)[0] 1381 1384 opts = orig_field.opts 1382 table = opts. db_table1385 table = opts.qualified_name 1383 1386 from_col = local_field.column 1384 1387 to_col = field.column 1385 1388 # In case of a recursive FK, use the to_field for … … 1649 1652 else: 1650 1653 opts = self.model._meta 1651 1654 if not self.select: 1652 count = self.aggregates_module.Count((self.join((None, opts.db_table, None, None)), opts.pk.column), 1655 count = self.aggregates_module.Count((self.join((None, 1656 opts.qualified_name, None, None)), opts.pk.column), 1653 1657 is_summary=True, distinct=True) 1654 1658 else: 1655 1659 # Because of SQL portability issues, multi-column, distinct -
django/db/models/sql/subqueries.py
41 41 where = self.where_class() 42 42 where.add((Constraint(None, field.column, field), 'in', 43 43 pk_list[offset : offset + GET_ITERATOR_CHUNK_SIZE]), AND) 44 self.do_query(self.model._meta. db_table, where, using=using)44 self.do_query(self.model._meta.qualified_name, where, using=using) 45 45 46 46 class UpdateQuery(Query): 47 47 """ -
django/db/models/options.py
17 17 DEFAULT_NAMES = ('verbose_name', 'verbose_name_plural', 'db_table', 'ordering', 18 18 'unique_together', 'permissions', 'get_latest_by', 19 19 'order_with_respect_to', 'app_label', 'db_tablespace', 20 'abstract', 'managed', 'proxy', 'auto_created' )20 'abstract', 'managed', 'proxy', 'auto_created', 'db_schema') 21 21 22 22 class Options(object): 23 23 def __init__(self, meta, app_label=None): … … 26 26 self.module_name, self.verbose_name = None, None 27 27 self.verbose_name_plural = None 28 28 self.db_table = '' 29 #self.db_schema = settings.DATABASE_SCHEMA 30 self.db_schema = None 31 self.qualified_name = '' 29 32 self.ordering = [] 30 33 self.unique_together = [] 31 34 self.permissions = [] … … 55 58 self.related_fkey_lookups = [] 56 59 57 60 def contribute_to_class(self, cls, name): 58 from django.db import connection 61 from django.db import connections, router 59 62 from django.db.backends.util import truncate_name 63 conn = connections[router.db_for_read(cls)] 60 64 61 65 cls._meta = self 62 66 self.installed = re.sub('\.models$', '', cls.__module__) in settings.INSTALLED_APPS … … 64 68 self.object_name = cls.__name__ 65 69 self.module_name = self.object_name.lower() 66 70 self.verbose_name = get_verbose_name(self.object_name) 71 self.db_schema = conn.settings_dict['SCHEMA'] 67 72 68 73 # Next, apply any overridden values from 'class Meta'. 69 74 if self.meta: … … 103 108 # If the db_table wasn't provided, use the app_label + module_name. 104 109 if not self.db_table: 105 110 self.db_table = "%s_%s" % (self.app_label, self.module_name) 106 self.db_table = truncate_name(self.db_table, conn ection.ops.max_name_length())111 self.db_table = truncate_name(self.db_table, conn.ops.max_name_length()) 107 112 113 # Construct qualified table name. 114 self.qualified_name = conn.ops.prep_db_table(self.db_schema, 115 self.db_table) 116 if self.qualified_name == conn.ops.quote_name(self.db_table): 117 # If unchanged, the backend doesn't support schemas. 118 self.db_schema = '' 108 119 def _prepare(self, model): 109 120 if self.order_with_respect_to: 110 121 self.order_with_respect_to = self.get_field(self.order_with_respect_to) … … 184 195 self.pk = target._meta.pk 185 196 self.proxy_for_model = target 186 197 self.db_table = target._meta.db_table 198 self.db_schema = target._meta.db_schema 199 self.qualified_name = target._meta.qualified_name 187 200 188 201 def __repr__(self): 189 202 return '<Options for %s>' % self.object_name -
django/db/models/fields/related.py
892 892 if isinstance(self.rel.to, basestring): 893 893 target = self.rel.to 894 894 else: 895 target = self.rel.to._meta. db_table895 target = self.rel.to._meta.qualified_name 896 896 cls._meta.duplicate_targets[self.column] = (target, "o2m") 897 897 898 898 def contribute_to_related_class(self, cls, related): … … 983 983 to = to.lower() 984 984 meta = type('Meta', (object,), { 985 985 'db_table': field._get_m2m_db_table(klass._meta), 986 'db_schema': field._get_m2m_db_schema(klass._meta), 986 987 'managed': managed, 987 988 'auto_created': klass, 988 989 'app_label': klass._meta.app_label, … … 1014 1015 through=kwargs.pop('through', None)) 1015 1016 1016 1017 self.db_table = kwargs.pop('db_table', None) 1018 self.db_schema = kwargs.pop('db_schema', '') 1017 1019 if kwargs['rel'].through is not None: 1018 1020 assert self.db_table is None, "Cannot specify a db_table if an intermediary model is used." 1019 1021 … … 1035 1037 return util.truncate_name('%s_%s' % (opts.db_table, self.name), 1036 1038 connection.ops.max_name_length()) 1037 1039 1040 def _get_m2m_db_schema(self, opts): 1041 "Function that can be curried to provide the m2m schema name for this relation" 1042 if self.rel.through is not None and self.rel.through._meta.db_schema: 1043 return self.rel.through._meta.db_schema 1044 return self.db_schema 1045 1046 def _get_m2m_qualified_name(self, opts): 1047 "Function that can be curried to provide the qualified m2m table name for this relation" 1048 schema = self._get_m2m_db_schema(opts) 1049 table = self._get_m2m_db_table(opts) 1050 return connection.ops.prep_db_table(schema, table) 1051 1038 1052 def _get_m2m_attr(self, related, attr): 1039 1053 "Function that can be curried to provide the source accessor or DB column name for the m2m table" 1040 1054 cache_attr = '_m2m_%s_cache' % attr … … 1105 1119 1106 1120 # Set up the accessor for the m2m table name for the relation 1107 1121 self.m2m_db_table = curry(self._get_m2m_db_table, cls._meta) 1122 self.m2m_db_schema = curry(self._get_m2m_db_schema, cls._meta) 1123 self.m2m_qualified_name = curry(self._get_m2m_qualified_name, 1124 cls._meta) 1108 1125 1109 1126 # Populate some necessary rel arguments so that cross-app relations 1110 1127 # work correctly. … … 1116 1133 if isinstance(self.rel.to, basestring): 1117 1134 target = self.rel.to 1118 1135 else: 1119 target = self.rel.to._meta. db_table1136 target = self.rel.to._meta.qualified_name 1120 1137 cls._meta.duplicate_targets[self.column] = (target, "m2m") 1121 1138 1122 1139 def contribute_to_related_class(self, cls, related): -
django/db/__init__.py
7 7 __all__ = ('backend', 'connection', 'connections', 'router', 'DatabaseError', 8 8 'IntegrityError', 'DEFAULT_DB_ALIAS') 9 9 10 10 11 11 if DEFAULT_DB_ALIAS not in settings.DATABASES: 12 12 raise ImproperlyConfigured("You must define a '%s' database" % DEFAULT_DB_ALIAS) 13 13 -
django/db/utils.py
67 67 conn['ENGINE'] = 'django.db.backends.dummy' 68 68 conn.setdefault('OPTIONS', {}) 69 69 conn.setdefault('TIME_ZONE', settings.TIME_ZONE) 70 for setting in ['NAME', 'USER', 'PASSWORD', 'HOST', 'PORT']: 70 71 for setting in ('NAME', 'USER', 'PASSWORD', 'HOST', 'PORT', 'SCHEMA'): 71 72 conn.setdefault(setting, '') 72 73 for setting in ['TEST_CHARSET', 'TEST_COLLATION', 'TEST_NAME', 'TEST_MIRROR']: 73 74 conn.setdefault(setting, None) -
django/db/backends/postgresql/base.py
80 80 81 81 class DatabaseFeatures(BaseDatabaseFeatures): 82 82 uses_savepoints = True 83 default_schema_name = u'public' 83 84 84 85 class DatabaseWrapper(BaseDatabaseWrapper): 85 86 operators = { -
django/db/backends/postgresql/introspection.py
31 31 AND pg_catalog.pg_table_is_visible(c.oid)""") 32 32 return [row[0] for row in cursor.fetchall()] 33 33 34 def get_schema_list(self, cursor): 35 cursor.execute(""" 36 SELECT DISTINCT n.nspname 37 FROM pg_catalog.pg_class c 38 LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace 39 WHERE c.relkind IN ('r', 'v', '') 40 AND n.nspname NOT IN ('pg_catalog', 'pg_toast', 'information_schema')""") 41 return [row[0] for row in cursor.fetchall()] 42 43 def get_schema_table_list(self, cursor, schema): 44 cursor.execute(""" 45 SELECT c.relname 46 FROM pg_catalog.pg_class c 47 LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace 48 WHERE c.relkind IN ('r', 'v', '') 49 AND n.nspname = '%s'""" % schema) 50 return [row[0] for row in cursor.fetchall()] 51 34 52 def get_table_description(self, cursor, table_name): 35 53 "Returns a description of the table, with the DB-API cursor.description interface." 36 54 cursor.execute("SELECT * FROM %s LIMIT 1" % self.connection.ops.quote_name(table_name)) -
django/db/backends/postgresql/operations.py
53 53 return 'HOST(%s)' 54 54 return '%s' 55 55 56 def last_insert_id(self, cursor, table_name, pk_name):56 def last_insert_id(self, cursor, schema_name, table_name, pk_name): 57 57 # Use pg_get_serial_sequence to get the underlying sequence name 58 58 # from the table name and column name (available since PostgreSQL 8) 59 table_name = self.prep_db_table(schema_name, table_name) 59 60 cursor.execute("SELECT CURRVAL(pg_get_serial_sequence('%s','%s'))" % (table_name, pk_name)) 60 61 return cursor.fetchone()[0] 61 62 … … 67 68 return name # Quoting once is enough. 68 69 return '"%s"' % name 69 70 71 def prep_db_table(self, db_schema, db_table): 72 qn = self.quote_name 73 if db_schema: 74 return "%s.%s" % (qn(db_schema), qn(db_table)) 75 else: 76 return qn(db_table) 77 70 78 def sql_flush(self, style, tables, sequences): 71 79 if tables: 80 qnames = [self.prep_db_table(schema, table) 81 for (schema, table) in tables] 72 82 if self.postgres_version[0:2] >= (8,1): 73 83 # Postgres 8.1+ can do 'TRUNCATE x, y, z...;'. In fact, it *has to* 74 84 # in order to be able to truncate tables referenced by a foreign … … 76 86 # statement. 77 87 sql = ['%s %s;' % \ 78 88 (style.SQL_KEYWORD('TRUNCATE'), 79 style.SQL_FIELD(', '.join( [self.quote_name(table) for table in tables]))89 style.SQL_FIELD(', '.join(qnames)) 80 90 )] 81 91 else: 82 92 # Older versions of Postgres can't do TRUNCATE in a single call, so … … 84 94 sql = ['%s %s %s;' % \ 85 95 (style.SQL_KEYWORD('DELETE'), 86 96 style.SQL_KEYWORD('FROM'), 87 style.SQL_FIELD( self.quote_name(table))88 ) for table in tables]97 style.SQL_FIELD(qname) 98 ) for qname in qnames] 89 99 90 100 # 'ALTER SEQUENCE sequence_name RESTART WITH 1;'... style SQL statements 91 101 # to reset sequence indices 92 102 for sequence_info in sequences: 103 schema_name = sequence_info['schema'] 93 104 table_name = sequence_info['table'] 94 105 column_name = sequence_info['column'] 95 106 if not (column_name and len(column_name) > 0): 96 107 # This will be the case if it's an m2m using an autogenerated 97 108 # intermediate table (see BaseDatabaseIntrospection.sequence_list) 98 109 column_name = 'id' 110 table_name = self.prep_db_table(schema_name, table_name) 99 111 sql.append("%s setval(pg_get_serial_sequence('%s','%s'), 1, false);" % \ 100 112 (style.SQL_KEYWORD('SELECT'), 101 113 style.SQL_TABLE(table_name), … … 118 130 119 131 for f in model._meta.local_fields: 120 132 if isinstance(f, models.AutoField): 133 table_name = self.prep_db_table(model._meta.db_schema, model._meta.db_table) # XXX: generic schemas support. 121 134 output.append("%s setval(pg_get_serial_sequence('%s','%s'), coalesce(max(%s), 1), max(%s) %s null) %s %s;" % \ 122 135 (style.SQL_KEYWORD('SELECT'), 123 style.SQL_TABLE( model._meta.db_table),124 style.SQL_FIELD(f.column), 136 style.SQL_TABLE(table_name), 137 style.SQL_FIELD(f.column), # XXX: Do we need qn() here? 125 138 style.SQL_FIELD(qn(f.column)), 126 139 style.SQL_FIELD(qn(f.column)), 127 140 style.SQL_KEYWORD('IS NOT'), 128 141 style.SQL_KEYWORD('FROM'), 129 style.SQL_TABLE( qn(model._meta.db_table))))142 style.SQL_TABLE(model._meta.qualified_name))) 130 143 break # Only one AutoField is allowed per model, so don't bother continuing. 131 144 for f in model._meta.many_to_many: 132 145 if not f.rel.through: 146 table_name = self.prep_db_table(f.m2m_db_schema(), f.m2m_db_table()) # XXX: Do we need qn(f.m2m_db_table()) here? / XXX: generic schemas support. 133 147 output.append("%s setval(pg_get_serial_sequence('%s','%s'), coalesce(max(%s), 1), max(%s) %s null) %s %s;" % \ 134 148 (style.SQL_KEYWORD('SELECT'), 135 style.SQL_TABLE( model._meta.db_table),136 style.SQL_FIELD('id'), 149 style.SQL_TABLE(table_name), 150 style.SQL_FIELD('id'), # XXX: Do we need qn() here? 137 151 style.SQL_FIELD(qn('id')), 138 152 style.SQL_FIELD(qn('id')), 139 153 style.SQL_KEYWORD('IS NOT'), 140 154 style.SQL_KEYWORD('FROM'), 141 style.SQL_TABLE(qn(f.m2m_ db_table()))))155 style.SQL_TABLE(qn(f.m2m_qualified_name())))) 142 156 return output 143 157 144 158 def savepoint_create_sql(self, sid): -
django/db/backends/postgresql/creation.py
51 51 tablespace_sql = '' 52 52 53 53 def get_index_sql(index_name, opclass=''): 54 index_name = truncate_name(index_name, self.connection.ops.max_name_length()) 55 index_name = self.connection.ops.prep_db_index(model._meta.db_schema, index_name) 54 56 return (style.SQL_KEYWORD('CREATE INDEX') + ' ' + 55 style.SQL_TABLE( qn(truncate_name(index_name,self.connection.ops.max_name_length()))) + ' ' +57 style.SQL_TABLE(index_name) + ' ' + 56 58 style.SQL_KEYWORD('ON') + ' ' + 57 style.SQL_TABLE( qn(db_table)) + ' ' +59 style.SQL_TABLE(model._meta.qualified_name) + ' ' + 58 60 "(%s%s)" % (style.SQL_FIELD(qn(f.column)), opclass) + 59 61 "%s;" % tablespace_sql) 60 62 -
django/db/backends/sqlite3/base.py
123 123 (style.SQL_KEYWORD('DELETE'), 124 124 style.SQL_KEYWORD('FROM'), 125 125 style.SQL_FIELD(self.quote_name(table)) 126 ) for tablein tables]126 ) for (_, table) in tables] 127 127 # Note: No requirement for reset of auto-incremented indices (cf. other 128 128 # sql_flush() implementations). Just return SQL at this point 129 129 return sql -
django/db/backends/sqlite3/creation.py
45 45 return test_database_name 46 46 return ':memory:' 47 47 48 def _create_test_db(self, verbosity, autoclobber ):48 def _create_test_db(self, verbosity, autoclobber, schemas): 49 49 test_database_name = self._get_test_db_name() 50 50 if test_database_name != ':memory:': 51 51 # Erase the old test database -
django/db/backends/mysql/base.py
206 206 return name # Quoting once is enough. 207 207 return "`%s`" % name 208 208 209 def prep_db_table(self, db_schema, db_table): 210 qn = self.quote_name 211 if db_schema: 212 return "%s.%s" % (qn(db_schema), qn(db_table)) 213 else: 214 return qn(db_table) 215 216 def prep_db_index(self, db_schema, db_index): 217 return self.prep_db_table(db_schema, db_index) 218 209 219 def random_function_sql(self): 210 220 return 'RAND()' 211 221 … … 215 225 # to clear all tables of all data 216 226 if tables: 217 227 sql = ['SET FOREIGN_KEY_CHECKS = 0;'] 218 for tablein tables:219 sql.append('%s %s;' % (style.SQL_KEYWORD('TRUNCATE'), style.SQL_FIELD(self. quote_name(table))))228 for (schema, table) in tables: 229 sql.append('%s %s;' % (style.SQL_KEYWORD('TRUNCATE'), style.SQL_FIELD(self.prep_db_table(schema, table)))) 220 230 sql.append('SET FOREIGN_KEY_CHECKS = 1;') 221 231 222 232 # 'ALTER TABLE table AUTO_INCREMENT = 1;'... style SQL statements 223 233 # to reset sequence indices 224 sql.extend(["%s %s %s %s %s;" % \ 225 (style.SQL_KEYWORD('ALTER'), 226 style.SQL_KEYWORD('TABLE'), 227 style.SQL_TABLE(self.quote_name(sequence['table'])), 228 style.SQL_KEYWORD('AUTO_INCREMENT'), 229 style.SQL_FIELD('= 1'), 230 ) for sequence in sequences]) 234 for sequence_info in sequences: 235 schema_name = sequence_info['schema'] 236 table_name = self.prep_db_table(schema_name, sequence_info['table']) 237 sql.append("%s %s %s %s %s;" % \ 238 (style.SQL_KEYWORD('ALTER'), 239 style.SQL_KEYWORD('TABLE'), 240 style.SQL_TABLE(table_name), 241 style.SQL_KEYWORD('AUTO_INCREMENT'), 242 style.SQL_FIELD('= 1'), 243 )) 231 244 return sql 232 245 else: 233 246 return [] -
django/db/backends/mysql/introspection.py
33 33 cursor.execute("SHOW TABLES") 34 34 return [row[0] for row in cursor.fetchall()] 35 35 36 def get_schema_list(self, cursor): 37 cursor.execute("SHOW SCHEMAS") 38 return [row[0] for row in cursor.fetchall()] 39 40 def get_schema_table_list(self, cursor, schema): 41 cursor.execute("SHOW TABLES FROM %s" % self.connection.ops.quote_name(schema)) 42 return [schema + "." + row[0] for row in cursor.fetchall()] 43 36 44 def get_table_description(self, cursor, table_name): 37 45 "Returns a description of the table, with the DB-API cursor.description interface." 38 46 cursor.execute("SELECT * FROM %s LIMIT 1" % self.connection.ops.quote_name(table_name)) -
django/db/backends/mysql/creation.py
64 64 field.rel.to._meta.db_table, field.rel.to._meta.pk.column) 65 65 ] 66 66 return table_output, deferred 67 68 def default_schema(self): 69 return settings.DATABASE_NAME 70 71 def sql_create_schema(self, schema, style): 72 """ 73 Returns the SQL required to create a single schema. 74 In MySQL schemas are synonymous to databases 75 """ 76 qn = self.connection.ops.quote_name 77 output = "%s %s;" % (style.SQL_KEYWORD('CREATE DATABASE'), qn(schema)) 78 return output 79 80 def sql_destroy_schema(self, schema, style): 81 """" 82 Returns the SQL required to destroy a single schema. 83 """ 84 qn = self.connection.ops.quote_name 85 output = "%s %s;" % (style.SQL_KEYWORD('DROP DATABASE IF EXISTS'), qn(schema)) 86 return output -
django/db/backends/oracle/base.py
82 82 class DatabaseOperations(BaseDatabaseOperations): 83 83 compiler_module = "django.db.backends.oracle.compiler" 84 84 85 def autoinc_sql(self, table, column):85 def autoinc_sql(self, schema, table, column): 86 86 # To simulate auto-incrementing primary keys in Oracle, we have to 87 87 # create a sequence and a trigger. 88 88 sq_name = self._get_sequence_name(table) 89 89 tr_name = self._get_trigger_name(table) 90 tbl_name = self.quote_name(table) 90 tbl_name = self.prep_db_table(schema, table) 91 sq_qname = self.prep_db_table(schema, sq_name) 92 tr_qname = self.prep_db_table(schema, tr_name) 91 93 col_name = self.quote_name(column) 92 94 sequence_sql = """ 93 95 DECLARE … … 96 98 SELECT COUNT(*) INTO i FROM USER_CATALOG 97 99 WHERE TABLE_NAME = '%(sq_name)s' AND TABLE_TYPE = 'SEQUENCE'; 98 100 IF i = 0 THEN 99 EXECUTE IMMEDIATE 'CREATE SEQUENCE "%(sq_name)s"';101 EXECUTE IMMEDIATE 'CREATE SEQUENCE %(sq_qname)s'; 100 102 END IF; 101 103 END; 102 104 /""" % locals() 103 105 trigger_sql = """ 104 CREATE OR REPLACE TRIGGER "%(tr_name)s"106 CREATE OR REPLACE TRIGGER %(tr_qname)s 105 107 BEFORE INSERT ON %(tbl_name)s 106 108 FOR EACH ROW 107 109 WHEN (new.%(col_name)s IS NULL) 108 110 BEGIN 109 SELECT "%(sq_name)s".nextval111 SELECT %(sq_qname)s.nextval 110 112 INTO :new.%(col_name)s FROM dual; 111 113 END; 112 114 /""" % locals() … … 191 193 def deferrable_sql(self): 192 194 return " DEFERRABLE INITIALLY DEFERRED" 193 195 194 def drop_sequence_sql(self, table): 195 return "DROP SEQUENCE %s;" % self.quote_name(self._get_sequence_name(table)) 196 def drop_sequence_sql(self, schema, table): 197 sequence_name = self.prep_db_table(schema, get_sequence_name(table)) 198 return "DROP SEQUENCE %s;" % sequence_name 196 199 197 200 def fetch_returned_insert_id(self, cursor): 198 201 return long(cursor._insert_id_var.getvalue()) … … 203 206 else: 204 207 return "%s" 205 208 209 def last_insert_id(self, cursor, schema_name, table_name, pk_name): 210 sq_name = self.prep_db_table(schema_name, get_sequence_name(table_name)) 211 cursor.execute('SELECT %s.currval FROM dual' % sq_name) 212 206 213 def last_executed_query(self, cursor, sql, params): 207 214 # http://cx-oracle.sourceforge.net/html/cursor.html#Cursor.statement 208 215 # The DB API definition does not define this attribute. 209 216 return cursor.statement 210 217 211 def last_insert_id(self, cursor, table_name, pk_name):212 sq_name = self._get_sequence_name(table_name)213 cursor.execute('SELECT "%s".currval FROM dual' % sq_name)214 return cursor.fetchone()[0]215 216 218 def lookup_cast(self, lookup_type): 217 219 if lookup_type in ('iexact', 'icontains', 'istartswith', 'iendswith'): 218 220 return "UPPER(%s)" … … 224 226 def max_name_length(self): 225 227 return 30 226 228 229 def prep_db_table(self, db_schema, db_table): 230 qn = self.quote_name 231 if db_schema: 232 return "%s.%s" % (qn(db_schema), qn(db_table)) 233 else: 234 return qn(db_table) 235 236 def prep_db_index(self, db_schema, db_index): 237 return self.prep_db_table(db_schema, db_index) 238 227 239 def prep_for_iexact_query(self, x): 228 240 return x 229 241 … … 273 285 def sql_flush(self, style, tables, sequences): 274 286 # Return a list of 'TRUNCATE x;', 'TRUNCATE y;', 275 287 # 'TRUNCATE z;'... style SQL statements 288 sql = [] 276 289 if tables: 277 290 # Oracle does support TRUNCATE, but it seems to get us into 278 291 # FK referential trouble, whereas DELETE FROM table works. 279 sql = ['%s %s %s;' % \ 280 (style.SQL_KEYWORD('DELETE'), 281 style.SQL_KEYWORD('FROM'), 282 style.SQL_FIELD(self.quote_name(table))) 283 for table in tables] 292 for schema, table in tables: 293 table = self.prep_db_table(schema, table) 294 sql.append('%s %s %s;' % \ 295 (style.SQL_KEYWORD('DELETE'), 296 style.SQL_KEYWORD('FROM'), 297 style.SQL_FIELD(table))) 284 298 # Since we've just deleted all the rows, running our sequence 285 299 # ALTER code will reset the sequence to 0. 286 300 for sequence_info in sequences: 287 sequence_name = self._get_sequence_name(sequence_info['table']) 288 table_name = self.quote_name(sequence_info['table']) 301 schema_name = sequence_info['schema'] 302 sequence_name = self.prep_db_table(schema_name, 303 get_sequence_name(sequence_info['table'])) 304 table_name = self.prep_db_table(schema_name, 305 sequence_info['table']) 306 289 307 column_name = self.quote_name(sequence_info['column'] or 'id') 290 308 query = _get_sequence_reset_sql() % {'sequence': sequence_name, 291 309 'table': table_name, 292 310 'column': column_name} 293 311 sql.append(query) 294 return sql 295 else: 296 return [] 312 return sql 297 313 298 314 def sequence_reset_sql(self, style, model_list): 299 315 from django.db import models … … 302 318 for model in model_list: 303 319 for f in model._meta.local_fields: 304 320 if isinstance(f, models.AutoField): 305 table_name = self.quote_name(model._meta.db_table) 306 sequence_name = self._get_sequence_name(model._meta.db_table) 321 table_name = model._meta.qualified_name 322 sequence_name = self.prep_db_table(model._meta.db_schema, 323 get_sequence_name(model._meta.db_table)) 324 307 325 column_name = self.quote_name(f.column) 308 326 output.append(query % {'sequence': sequence_name, 309 327 'table': table_name, … … 313 331 break 314 332 for f in model._meta.many_to_many: 315 333 if not f.rel.through: 316 table_name = self.quote_name(f.m2m_db_table()) 317 sequence_name = self._get_sequence_name(f.m2m_db_table()) 334 table_name = self.quote_name(f.m2m_qualified_name()) 335 sequence_name = self.prep_db_table(f.m2m_db_schema(), 336 get_sequence_name(f.m2m_db_table())) 337 318 338 column_name = self.quote_name('id') 319 339 output.append(query % {'sequence': sequence_name, 320 340 'table': table_name, -
django/db/backends/oracle/introspection.py
120 120 for row in cursor.fetchall(): 121 121 indexes[row[0]] = {'primary_key': row[1], 'unique': row[2]} 122 122 return indexes 123 124 def schema_name_converter(self, name): 125 """Convert to lowercase for case-sensitive schema name comparison.""" 126 return name.lower() 127 128 def get_schema_list(self, cursor): 129 "Returns a list of schemas that exist in the database." 130 sql = """ 131 select distinct username 132 from all_users, all_objects 133 where username = owner 134 """ 135 cursor.execute(sql) 136 return [schema.lower() for (schema,) in cursor] 137 138 def get_schema_table_list(self, cursor, schema): 139 "Returns a list of tables in a specific schema." 140 sql = """ 141 select table_name from all_tables 142 where owner = upper(%s) 143 """ 144 cursor.execute(sql, [schema]) 145 return [table.lower() for (table,) in cursor] -
django/db/backends/oracle/creation.py
38 38 'TimeField': 'TIMESTAMP', 39 39 'URLField': 'VARCHAR2(%(max_length)s)', 40 40 } 41 42 41 42 def __init__(self, connection): 43 43 self.remember = {} 44 44 super(DatabaseCreation, self).__init__(connection) 45 46 def sql_create_schema(self, schema, style, password=None, 47 tablespace=None, temp_tablespace=None): 48 qn = self.connection.ops.quote_name 49 lock_account = (password is None) 50 if lock_account: 51 password = schema 52 output = [] 53 output.append("%s %s %s %s" % (style.SQL_KEYWORD('CREATE USER'), 54 qn(schema), 55 style.SQL_KEYWORD('IDENTIFIED BY'), 56 qn(password))) 57 if tablespace: 58 output.append("%s %s" % (style.SQL_KEYWORD('DEFAULT TABLESPACE'), 59 qn(tablespace))) 60 if temp_tablespace: 61 output.append("%s %s" % (style.SQL_KEYWORD('TEMPORARY TABLESPACE'), 62 qn(temp_tablespace))) 63 if lock_account: 64 output.append(style.SQL_KEYWORD('ACCOUNT LOCK')) 65 return '\n'.join(output) 45 66 46 def _create_test_db(self, verbosity=1, autoclobber=False): 67 def sql_destroy_schema(self, schema, style): 68 qn = self.connection.ops.quote_name 69 return "%s %s %s" % (style.SQL_KEYWORD('DROP USER'), qn(schema), 70 style.SQL_KEYWORD('CASCADE')) 71 72 def _create_test_db(self, verbosity=1, autoclobber=False, schema=None): 47 73 TEST_NAME = self._test_database_name() 48 74 TEST_USER = self._test_database_user() 49 75 TEST_PASSWD = self._test_database_passwd() … … 169 195 DEFAULT TABLESPACE %(tblspace)s 170 196 TEMPORARY TABLESPACE %(tblspace_temp)s 171 197 """, 172 """GRANT CONNECT, RESOURCE TO %(user)s""",198 """GRANT CONNECT, RESOURCE, CREATE USER, DROP USER, CREATE ANY TABLE, ALTER ANY TABLE, CREATE ANY INDEX, CREATE ANY SEQUENCE, CREATE ANY TRIGGER, SELECT ANY TABLE, INSERT ANY TABLE, UPDATE ANY TABLE, DELETE ANY TABLE TO %(user)s""", 173 199 ] 174 200 self._execute_statements(cursor, statements, parameters, verbosity) 175 201 -
django/db/backends/__init__.py
279 279 # integer primary keys. 280 280 related_fields_match_type = False 281 281 allow_sliced_subqueries = True 282 283 default_schema_name = '' 284 282 285 has_select_for_update = False 283 286 has_select_for_update_nowait = False 284 287 … … 394 397 self.connection = connection 395 398 self._cache = None 396 399 397 def autoinc_sql(self, table, column):400 def autoinc_sql(self, schema, table, column): 398 401 """ 399 402 Returns any SQL needed to support auto-incrementing primary keys, or 400 403 None if no SQL is necessary. … … 446 449 """ 447 450 return "DROP CONSTRAINT" 448 451 449 def drop_sequence_sql(self, table):452 def drop_sequence_sql(self, schema, table): 450 453 """ 451 454 Returns any SQL necessary to drop the sequence for the given table. 452 455 Returns None if no SQL is necessary. … … 516 519 517 520 return smart_unicode(sql) % u_params 518 521 519 def last_insert_id(self, cursor, table_name, pk_name):522 def last_insert_id(self, cursor, schema_name, table_name, pk_name): 520 523 """ 521 524 Given a cursor object that has just performed an INSERT statement into 522 525 a table that has an auto-incrementing ID, returns the newly created ID. … … 595 598 """ 596 599 raise NotImplementedError() 597 600 601 def prep_db_table(self, db_schema, db_table): 602 """ 603 Prepares and formats the table name if necessary. 604 Just returns quoted db_table if not supported. 605 """ 606 return self.quote_name(db_table) 607 608 def prep_db_index(self, db_schema, db_index): 609 """ 610 Prepares and formats the table index name if necessary. 611 Just returns quoted db_index if not supported. 612 """ 613 return self.quote_name(db_index) 614 598 615 def random_function_sql(self): 599 616 """ 600 617 Returns a SQL expression that returns a random value. … … 799 816 return name 800 817 801 818 def table_names(self): 802 "Returns a list of names of all tables that exist in the d atabase."819 "Returns a list of names of all tables that exist in the default schema." 803 820 cursor = self.connection.cursor() 804 821 return self.get_table_list(cursor) 805 822 823 def schema_name_converter(self, name): 824 """Apply a conversion to the name for the purposes of comparison. 825 826 The default schema name converter is for case sensitive comparison. 827 """ 828 return name 829 830 def get_schema_list(self, cursor): 831 "Returns a list of schemas that exist in the database" 832 return [] 833 834 def get_schema_table_list(self, cursor, schema): 835 "Returns a list of tables in a specific schema" 836 return [] 837 838 def schema_names(self): 839 cursor = self.connection.cursor() 840 return self.get_schema_list(cursor) 841 842 def schema_table_names(self, schema): 843 "Returns a list of names of all tables that exist in the database schema." 844 cursor = self.connection.cursor() 845 return self.get_schema_table_list(cursor, schema) 846 806 847 def django_table_names(self, only_existing=False): 807 848 """ 808 Returns a list of all table names that have associated Django models and809 are in INSTALLED_APPS.849 Returns a list of tuples containing all schema and table names that 850 have associated Django models and are in INSTALLED_APPS. 810 851 811 If only_existing is True, the resulting list will only include the tables812 t hat actually exist in the database.852 If only_existing is True, the resulting list will only include the 853 tables that actually exist in the database. 813 854 """ 814 855 from django.db import models, router 815 856 tables = set() 816 for app in models.get_apps():817 for model in models.get_models(app):818 if not model._meta.managed:819 continue820 if not router.allow_syncdb(self.connection.alias, model):821 continue822 tables.add(model._meta.db_table)823 tables.update([f.m2m_db_table() for f in model._meta.local_many_to_many])824 857 if only_existing: 825 existing_tables = self.table_names() 826 tables = [ 827 t 828 for t in tables 829 if self.table_name_converter(t) in existing_tables 830 ] 858 existing_tables = set([('', tn) for tn in self.table_names()]) 859 seen_schemas = set() 860 for model in models.get_models(): 861 if not model._meta.managed: 862 continue 863 if not router.allow_syncdb(self.connection.alias, model): 864 continue 865 db_schema = model._meta.db_schema 866 if only_existing and db_schema and db_schema not in seen_schemas: 867 existing_tables.update([(db_schema, tn) for tn in 868 self.schema_table_names(db_schema)]) 869 seen_schemas.add(db_schema) 870 tables.add((db_schema, model._meta.db_table)) 871 m2m_tables = [] 872 for f in model._meta.local_many_to_many: 873 m2m_schema = f.m2m_db_schema() 874 m2m_table = f.m2m_db_table() 875 if only_existing and m2m_schema and m2m_schema not in seen_schemas: 876 existing_tables.update([(m2m_schema, tn) for tn in 877 self.schema_table_names(m2m_schema)]) 878 seen_schemas.add(m2m_schema) 879 m2m_tables.append((m2m_schema, m2m_table)) 880 tables.update(m2m_tables) 881 if only_existing: 882 tables = [(s, t) for (s, t) in tables 883 if (self.schema_name_converter(s), 884 self.table_name_converter(t)) in existing_tables] 831 885 return tables 832 886 833 887 def installed_models(self, tables): … … 859 913 continue 860 914 for f in model._meta.local_fields: 861 915 if isinstance(f, models.AutoField): 862 sequence_list.append({'table': model._meta.db_table, 'column': f.column}) 916 sequence_list.append({'table': model._meta.db_table, 917 'column': f.column, 918 'schema': model._meta.db_schema}) 863 919 break # Only one AutoField is allowed per model, so don't bother continuing. 864 920 865 921 for f in model._meta.local_many_to_many: 922 schema = f.m2m_db_schema() 866 923 # If this is an m2m using an intermediate table, 867 924 # we don't need to reset the sequence. 868 925 if f.rel.through is None: 869 sequence_list.append({'table': f.m2m_db_table(), 'column': None}) 926 sequence_list.append({'table': f.m2m_db_table(), 927 'column': None, 928 'schema': schema}) 870 929 871 930 return sequence_list 872 931 -
django/db/backends/postgresql_psycopg2/base.py
72 72 can_defer_constraint_checks = True 73 73 has_select_for_update = True 74 74 has_select_for_update_nowait = True 75 default_schema_name = u'public' 75 76 76 77 77 78 class DatabaseWrapper(BaseDatabaseWrapper): -
django/db/backends/creation.py
26 26 """ 27 27 return '%x' % (abs(hash(args)) % 4294967296L) # 2**32 28 28 29 def default_schema(self): 30 return "" 31 32 def sql_create_schema(self, schema, style): 33 """" 34 Returns the SQL required to create a single schema 35 """ 36 qn = self.connection.ops.quote_name 37 output = "%s %s;" % (style.SQL_KEYWORD('CREATE SCHEMA'), qn(schema)) 38 return output 39 29 40 def sql_create_model(self, model, style, known_models=set()): 30 41 """ 31 42 Returns the SQL required to create a single model, as a tuple of: … … 69 80 table_output.append(style.SQL_KEYWORD('UNIQUE') + ' (%s)' % \ 70 81 ", ".join([style.SQL_FIELD(qn(opts.get_field(f).column)) for f in field_constraints])) 71 82 72 full_statement = [style.SQL_KEYWORD('CREATE TABLE') + ' ' + style.SQL_TABLE( qn(opts.db_table)) + ' (']83 full_statement = [style.SQL_KEYWORD('CREATE TABLE') + ' ' + style.SQL_TABLE(opts.qualified_name) + ' ('] 73 84 for i, line in enumerate(table_output): # Combine and add commas. 74 85 full_statement.append(' %s%s' % (line, i < len(table_output)-1 and ',' or '')) 75 86 full_statement.append(')') … … 81 92 if opts.has_auto_field: 82 93 # Add any extra SQL needed to support auto-incrementing primary keys. 83 94 auto_column = opts.auto_field.db_column or opts.auto_field.name 84 autoinc_sql = self.connection.ops.autoinc_sql(opts.db_table, auto_column) 95 autoinc_sql = self.connection.ops.autoinc_sql(opts.db_schema, 96 opts.db_table, 97 auto_column) 85 98 if autoinc_sql: 86 99 for stmt in autoinc_sql: 87 100 final_output.append(stmt) … … 93 106 qn = self.connection.ops.quote_name 94 107 if field.rel.to in known_models: 95 108 output = [style.SQL_KEYWORD('REFERENCES') + ' ' + \ 96 style.SQL_TABLE( qn(field.rel.to._meta.db_table)) + ' (' + \109 style.SQL_TABLE(field.rel.to._meta.qualified_name) + ' (' + \ 97 110 style.SQL_FIELD(qn(field.rel.to._meta.get_field(field.rel.field_name).column)) + ')' + 98 111 self.connection.ops.deferrable_sql() 99 112 ] … … 119 132 for rel_class, f in pending_references[model]: 120 133 rel_opts = rel_class._meta 121 134 r_table = rel_opts.db_table 135 r_qname = rel_opts.qualified_name 122 136 r_col = f.column 123 137 table = opts.db_table 138 qname = opts.qualified_name 124 139 col = opts.get_field(f.rel.field_name).column 125 140 # For MySQL, r_name must be unique in the first 64 characters. 126 141 # So we are careful with character usage here. 127 142 r_name = '%s_refs_%s_%s' % (r_col, col, self._digest(r_table, table)) 128 143 final_output.append(style.SQL_KEYWORD('ALTER TABLE') + ' %s ADD CONSTRAINT %s FOREIGN KEY (%s) REFERENCES %s (%s)%s;' % \ 129 ( qn(r_table), qn(truncate_name(r_name, self.connection.ops.max_name_length())),130 qn(r_col), qn (table), qn(col),144 (r_qname, qn(truncate_name(r_name, self.connection.ops.max_name_length())), 145 qn(r_col), qname, qn(col), 131 146 self.connection.ops.deferrable_sql())) 132 147 del pending_references[model] 133 148 return final_output 134 149 150 def sql_for_many_to_many(self, model, style): 151 "Return the CREATE TABLE statments for all the many-to-many tables defined on a model" 152 import warnings 153 warnings.warn( 154 'Database creation API for m2m tables has been deprecated. M2M models are now automatically generated', 155 PendingDeprecationWarning 156 ) 157 158 output = [] 159 for f in model._meta.local_many_to_many: 160 if model._meta.managed or f.rel.to._meta.managed: 161 output.extend(self.sql_for_many_to_many_field(model, f, style)) 162 return output 163 164 def sql_for_many_to_many_field(self, model, f, style): 165 "Return the CREATE TABLE statements for a single m2m field" 166 import warnings 167 warnings.warn( 168 'Database creation API for m2m tables has been deprecated. M2M models are now automatically generated', 169 PendingDeprecationWarning 170 ) 171 172 from django.db import models 173 from django.db.backends.util import truncate_name 174 175 output = [] 176 if f.rel.through._meta.auto_created: 177 opts = model._meta 178 qn = self.connection.ops.quote_name 179 tablespace = f.db_tablespace or opts.db_tablespace 180 if tablespace: 181 sql = self.connection.ops.tablespace_sql(tablespace, inline=True) 182 if sql: 183 tablespace_sql = ' ' + sql 184 else: 185 tablespace_sql = '' 186 else: 187 tablespace_sql = '' 188 table_output = [style.SQL_KEYWORD('CREATE TABLE') + ' ' + \ 189 style.SQL_TABLE(qn(f.m2m_qualified_name())) + ' ('] 190 table_output.append(' %s %s %s%s,' % 191 (style.SQL_FIELD(qn('id')), 192 style.SQL_COLTYPE(models.AutoField(primary_key=True).db_type(connection=self.connection)), 193 style.SQL_KEYWORD('NOT NULL PRIMARY KEY'), 194 tablespace_sql)) 195 196 deferred = [] 197 inline_output, deferred = self.sql_for_inline_many_to_many_references(model, f, style) 198 table_output.extend(inline_output) 199 200 table_output.append(' %s (%s, %s)%s' % 201 (style.SQL_KEYWORD('UNIQUE'), 202 style.SQL_FIELD(qn(f.m2m_column_name())), 203 style.SQL_FIELD(qn(f.m2m_reverse_name())), 204 tablespace_sql)) 205 table_output.append(')') 206 if opts.db_tablespace: 207 # f.db_tablespace is only for indices, so ignore its value here. 208 table_output.append(self.connection.ops.tablespace_sql(opts.db_tablespace)) 209 table_output.append(';') 210 output.append('\n'.join(table_output)) 211 212 for r_table, r_col, table, col in deferred: 213 r_name = '%s_refs_%s_%s' % (r_col, col, self._digest(r_table, table)) 214 output.append(style.SQL_KEYWORD('ALTER TABLE') + ' %s ADD CONSTRAINT %s FOREIGN KEY (%s) REFERENCES %s (%s)%s;' % 215 (qn(r_table), 216 qn(truncate_name(r_name, self.connection.ops.max_name_length())), 217 qn(r_col), qn(table), qn(col), 218 self.connection.ops.deferrable_sql())) 219 220 # Add any extra SQL needed to support auto-incrementing PKs 221 autoinc_sql = self.connection.ops.autoinc_sql(f.m2m_db_schema(), 222 f.m2m_db_table(), 223 'id') 224 if autoinc_sql: 225 for stmt in autoinc_sql: 226 output.append(stmt) 227 return output 228 229 def sql_for_inline_many_to_many_references(self, model, field, style): 230 "Create the references to other tables required by a many-to-many table" 231 import warnings 232 warnings.warn( 233 'Database creation API for m2m tables has been deprecated. M2M models are now automatically generated', 234 PendingDeprecationWarning 235 ) 236 237 from django.db import models 238 opts = model._meta 239 qn = self.connection.ops.quote_name 240 241 table_output = [ 242 ' %s %s %s %s (%s)%s,' % 243 (style.SQL_FIELD(qn(field.m2m_column_name())), 244 style.SQL_COLTYPE(models.ForeignKey(model).db_type(connection=self.connection)), 245 style.SQL_KEYWORD('NOT NULL REFERENCES'), 246 style.SQL_TABLE(opts.qualified_name), 247 style.SQL_FIELD(qn(opts.pk.column)), 248 self.connection.ops.deferrable_sql()), 249 ' %s %s %s %s (%s)%s,' % 250 (style.SQL_FIELD(qn(field.m2m_reverse_name())), 251 style.SQL_COLTYPE(models.ForeignKey(field.rel.to).db_type(connection=self.connection)), 252 style.SQL_KEYWORD('NOT NULL REFERENCES'), 253 style.SQL_TABLE(field.rel.to._meta.qualified_name), 254 style.SQL_FIELD(qn(field.rel.to._meta.pk.column)), 255 self.connection.ops.deferrable_sql()) 256 ] 257 deferred = [] 258 259 return table_output, deferred 260 135 261 def sql_indexes_for_model(self, model, style): 136 262 "Returns the CREATE INDEX SQL statements for a single model" 137 263 if not model._meta.managed or model._meta.proxy: … … 157 283 else: 158 284 tablespace_sql = '' 159 285 i_name = '%s_%s' % (model._meta.db_table, self._digest(f.column)) 286 i_name = self.connection.ops.prep_db_index(model._meta.db_schema, i_name) 160 287 output = [style.SQL_KEYWORD('CREATE INDEX') + ' ' + 161 288 style.SQL_TABLE(qn(truncate_name(i_name, self.connection.ops.max_name_length()))) + ' ' + 162 289 style.SQL_KEYWORD('ON') + ' ' + 163 style.SQL_TABLE( qn(model._meta.db_table)) + ' ' +290 style.SQL_TABLE(model._meta.qualified_name) + ' ' + 164 291 "(%s)" % style.SQL_FIELD(qn(f.column)) + 165 292 "%s;" % tablespace_sql] 166 293 else: 167 294 output = [] 168 295 return output 169 296 297 def sql_destroy_schema(self, schema, style): 298 """" 299 Returns the SQL required to destroy a single schema. 300 """ 301 qn = self.connection.ops.quote_name 302 output = "%s %s CASCADE;" % (style.SQL_KEYWORD('DROP SCHEMA IF EXISTS'), qn(schema)) 303 return output 304 170 305 def sql_destroy_model(self, model, references_to_delete, style): 171 306 "Return the DROP TABLE and restraint dropping statements for a single model" 172 307 if not model._meta.managed or model._meta.proxy: … … 174 309 # Drop the table now 175 310 qn = self.connection.ops.quote_name 176 311 output = ['%s %s;' % (style.SQL_KEYWORD('DROP TABLE'), 177 style.SQL_TABLE( qn(model._meta.db_table)))]312 style.SQL_TABLE(model._meta.qualified_name))] 178 313 if model in references_to_delete: 179 314 output.extend(self.sql_remove_table_constraints(model, references_to_delete, style)) 180 315 181 316 if model._meta.has_auto_field: 182 ds = self.connection.ops.drop_sequence_sql(model._meta.db_table) 317 ds = self.connection.ops.drop_sequence_sql(model._meta.db_schema, 318 model._meta.db_table) 183 319 if ds: 184 320 output.append(ds) 185 321 return output … … 193 329 qn = self.connection.ops.quote_name 194 330 for rel_class, f in references_to_delete[model]: 195 331 table = rel_class._meta.db_table 332 qname = rel_class._meta.qualified_name 196 333 col = f.column 197 334 r_table = model._meta.db_table 198 335 r_col = model._meta.get_field(f.rel.field_name).column 199 336 r_name = '%s_refs_%s_%s' % (col, r_col, self._digest(table, r_table)) 200 337 output.append('%s %s %s %s;' % \ 201 338 (style.SQL_KEYWORD('ALTER TABLE'), 202 style.SQL_TABLE(qn (table)),339 style.SQL_TABLE(qname), 203 340 style.SQL_KEYWORD(self.connection.ops.drop_foreignkey_sql()), 204 341 style.SQL_FIELD(qn(truncate_name(r_name, self.connection.ops.max_name_length()))))) 205 342 del references_to_delete[model] 206 343 return output 207 344 345 def sql_destroy_many_to_many(self, model, f, style): 346 "Returns the DROP TABLE statements for a single m2m field" 347 import warnings 348 warnings.warn( 349 'Database creation API for m2m tables has been deprecated. M2M models are now automatically generated', 350 PendingDeprecationWarning 351 ) 352 353 qn = self.connection.ops.quote_name 354 output = [] 355 if f.rel.through._meta.auto_created: 356 output.append("%s %s;" % (style.SQL_KEYWORD('DROP TABLE'), 357 style.SQL_TABLE(f.m2m_qualified_name()))) 358 ds = self.connection.ops.drop_sequence_sql(model._meta.db_schema, 359 "%s_%s" % (model._meta.db_table, f.column)) 360 if ds: 361 output.append(ds) 362 return output 363 208 364 def create_test_db(self, verbosity=1, autoclobber=False): 209 365 """ 210 366 Creates a test database, prompting the user for confirmation if the … … 221 377 test_db_repr = " ('%s')" % test_database_name 222 378 print "Creating test database for alias '%s'%s..." % (self.connection.alias, test_db_repr) 223 379 224 self._create_test_db(verbosity, autoclobber) 380 schema_apps = self._get_app_with_schemas() 381 schemas = self._get_schemas(schema_apps) 382 test_database_name = self._create_test_db(verbosity, autoclobber, schemas) 225 383 226 384 self.connection.close() 227 385 self.connection.settings_dict["NAME"] = test_database_name 228 386 387 # Create the test schemas. 388 cursor = self.connection.cursor() 389 self._create_test_schemas(verbosity, schemas, cursor) 390 391 call_command('syncdb', verbosity=verbosity, interactive=False, database=self.connection.alias) 229 392 # Confirm the feature set of the test database 230 393 self.connection.features.confirm() 231 394 … … 271 434 272 435 return test_database_name 273 436 437 def _create_test_schemas(self, verbosity, schemas, cursor): 438 from django.core.management.color import no_style 439 style = no_style() 440 for schema in schemas: 441 if verbosity >= 1: 442 print "Creating schema %s" % schema 443 cursor.execute(self.sql_create_schema(schema, style)) 444 445 def _destroy_test_schemas(self, verbosity, schemas, cursor): 446 from django.core.management.color import no_style 447 style = no_style() 448 for schema in schemas: 449 if verbosity >= 1: 450 print "Destroying schema %s" % schema 451 cursor.execute(self.sql_destroy_schema(schema, style)) 452 if verbosity >= 1: 453 print "Schema %s destroyed" % schema 454 455 def _get_schemas(self, apps): 456 from django.db import models 457 schemas = set() 458 for app in apps: 459 app_models = models.get_models(app) 460 for model in app_models: 461 schema = model._meta.db_schema 462 if not schema or schema in schemas: 463 continue 464 schemas.add(schema) 465 return schemas 466 467 def _get_app_with_schemas(self): 468 from django.db import models 469 apps = models.get_apps() 470 schema_apps = set() 471 for app in apps: 472 app_models = models.get_models(app) 473 for model in app_models: 474 schema = model._meta.db_schema 475 if not schema or app in schema_apps: 476 continue 477 schema_apps.add(app) 478 return schema_apps 479 274 480 def _get_test_db_name(self): 275 481 """ 276 482 Internal implementation - returns the name of the test DB that will be … … 282 488 return self.connection.settings_dict['TEST_NAME'] 283 489 return TEST_DATABASE_PREFIX + self.connection.settings_dict['NAME'] 284 490 285 def _create_test_db(self, verbosity, autoclobber ):491 def _create_test_db(self, verbosity, autoclobber, schemas): 286 492 "Internal implementation - creates the test db tables." 287 493 suffix = self.sql_table_creation_suffix() 288 494 … … 305 511 try: 306 512 if verbosity >= 1: 307 513 print "Destroying old test database '%s'..." % self.connection.alias 514 self._destroy_test_schemas(verbosity, schemas, cursor) 308 515 cursor.execute("DROP DATABASE %s" % qn(test_database_name)) 309 516 cursor.execute("CREATE DATABASE %s %s" % (qn(test_database_name), suffix)) 310 517 except Exception, e: -
django/conf/project_template/settings.py
17 17 'PASSWORD': '', # Not used with sqlite3. 18 18 'HOST': '', # Set to empty string for localhost. Not used with sqlite3. 19 19 'PORT': '', # Set to empty string for default. Not used with sqlite3. 20 'SCHEMA': '', # Set to empty string for default. 20 21 } 21 22 } 22 23 -
django/conf/global_settings.py
150 150 DATABASE_HOST = '' # Set to empty string for localhost. Not used with sqlite3. 151 151 DATABASE_PORT = '' # Set to empty string for default. Not used with sqlite3. 152 152 DATABASE_OPTIONS = {} # Set to empty dictionary for default. 153 DATABASE_SCHEMA = '' # Set to empty string for default. 153 154 154 155 # New format 155 156 DATABASES = { -
django/core/management/commands/syncdb.py
56 56 cursor = connection.cursor() 57 57 58 58 # Get a list of already installed *models* so that references work right. 59 tables = connection.introspection.table_names() 59 schemas = connection.introspection.schema_names() 60 if schemas: 61 tables = [] 62 default_schema_name = connection.features.default_schema_name 63 for schema in connection.introspection.schema_names(): 64 if default_schema_name and schema == default_schema_name: 65 sn = '' 66 else: 67 sn = schema 68 for tn in connection.introspection.schema_table_names(schema): 69 tables.append((sn, tn)) 70 else: 71 tables = [('', tn) for tn in connection.introspection.table_names()] 60 72 seen_models = connection.introspection.installed_models(tables) 73 seen_schemas = set() 61 74 created_models = set() 62 75 pending_references = {} 63 76 … … 68 81 if router.allow_syncdb(db, m)]) 69 82 for app in models.get_apps() 70 83 ] 84 85 def model_schema(model): 86 db_schema = model._meta.db_schema 87 if db_schema: 88 db_schema = connection.introspection.table_name_converter(db_schema) 89 return db_schema 90 71 91 def model_installed(model): 72 92 opts = model._meta 73 93 converter = connection.introspection.table_name_converter 74 return not ((converter(opts.db_table) in tables) or 75 (opts.auto_created and converter(opts.auto_created._meta.db_table) in tables)) 94 db_schema = model_schema(model) 95 schema_table = (db_schema, converter(opts.db_table)) 96 return not ((schema_table in tables) or 97 (opts.auto_created and \ 98 (db_schema, converter(opts.auto_created._meta.db_table)) in tables) 99 #(model_schema(opts.auto_created), converter(opts.auto_created._meta.db_table)) in tables) 100 ) 76 101 77 102 manifest = SortedDict( 78 103 (app_name, filter(model_installed, model_list)) … … 84 109 print "Creating tables ..." 85 110 for app_name, model_list in manifest.items(): 86 111 for model in model_list: 112 # Add model-defined schema tables if any. 113 db_schema = model_schema(model) 114 if db_schema and db_schema not in seen_schemas: 115 tables += [(db_schema, tn) for tn in 116 connection.introspection.schema_table_names(db_schema)] 117 seen_schemas.add(db_schema) 118 87 119 # Create the model's database table, if it doesn't already exist. 88 120 if verbosity >= 3: 89 121 print "Processing %s.%s model" % (app_name, model._meta.object_name) … … 96 128 sql.extend(connection.creation.sql_for_pending_references(refto, self.style, pending_references)) 97 129 sql.extend(connection.creation.sql_for_pending_references(model, self.style, pending_references)) 98 130 if verbosity >= 1 and sql: 99 print "Creating table %s" % model._meta.db_table 131 if db_schema: 132 print "Creating table %s.%s" % (db_schema, model._meta.db_table) 133 else: 134 print "Creating table %s" % model._meta.db_table 100 135 for statement in sql: 101 136 cursor.execute(statement) 102 tables.append(connection.introspection.table_name_converter(model._meta.db_table)) 137 if sql: 138 tables.append((db_schema, connection.introspection.table_name_converter(model._meta.db_table))) 103 139 104 140 105 141 transaction.commit_unless_managed(using=db) -
django/core/management/sql.py
63 63 64 64 # Figure out which tables already exist 65 65 if cursor: 66 table_names = connection.introspection.get_table_list(cursor) 66 table_names = [('', tn) for tn in 67 connection.introspection.get_table_list(cursor)] 67 68 else: 68 69 table_names = [] 69 70 … … 74 75 75 76 references_to_delete = {} 76 77 app_models = models.get_models(app, include_auto_created=True) 78 seen_schemas = set() 77 79 for model in app_models: 78 if cursor and connection.introspection.table_name_converter(model._meta.db_table) in table_names: 80 db_schema = model._meta.db_schema 81 # Find additional tables in model-defined schemas. 82 if db_schema: 83 db_schema = connection.introspection.schema_name_converter(db_schema) 84 if db_schema not in seen_schemas: 85 table_names += [(db_schema, tn) for tn in connection.introspection.get_schema_table_list(cursor, db_schema)] 86 seen_schemas.add(db_schema) 87 schema_table = (db_schema, 88 connection.introspection.table_name_converter(model._meta.db_table)) 89 90 if cursor and schema_table in table_names: 79 91 # The table exists, so it needs to be dropped 80 92 opts = model._meta 81 93 for f in opts.local_fields: … … 85 97 to_delete.add(model) 86 98 87 99 for model in app_models: 88 if connection.introspection.table_name_converter(model._meta.db_table) in table_names: 100 db_schema = model._meta.db_schema 101 if db_schema: 102 db_schema = connection.introspection.schema_name_converter(db_schema) 103 schema_table = (db_schema, 104 connection.introspection.table_name_converter(model._meta.db_table)) 105 if schema_table in table_names: 89 106 output.extend(connection.creation.sql_destroy_model(model, references_to_delete, style)) 90 107 91 108 # Close database connection explicitly, in case this output is being piped … … 116 133 if only_django: 117 134 tables = connection.introspection.django_table_names(only_existing=True) 118 135 else: 119 tables = connection.introspection.table_names()136 tables = [('', tn) for tn in connection.introspection.table_names()] 120 137 statements = connection.ops.sql_flush( 121 138 style, tables, connection.introspection.sequence_list() 122 139 ) -
django/contrib/contenttypes/generic.py
133 133 def m2m_reverse_name(self): 134 134 return self.rel.to._meta.pk.column 135 135 136 def m2m_db_schema(self): 137 return self.rel.to._meta.db_schema 138 139 def m2m_qualified_name(self): 140 schema = self.m2m_db_schema() 141 table = self.m2m_db_table() 142 return connection.ops.prep_db_table(schema, table) 143 136 144 def m2m_target_field_name(self): 137 145 return self.model._meta.pk.name 138 146 -
tests/regressiontests/introspection/tests.py
58 58 59 59 def test_sequence_list(self): 60 60 sequences = connection.introspection.sequence_list() 61 expected = {'table': Reporter._meta.db_table, 'column': 'id' }61 expected = {'table': Reporter._meta.db_table, 'column': 'id', 'schema': ''} 62 62 self.assertTrue(expected in sequences, 63 63 'Reporter sequence not found in sequence_list()') 64 64 -
tests/regressiontests/backends/tests.py
157 157 # A full flush is expensive to the full test, so we dig into the 158 158 # internals to generate the likely offending SQL and run it manually 159 159 160 # Some convenience aliases 161 VLM = models.VeryLongModelNameZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ 162 VLM_m2m = VLM.m2m_also_quite_long_zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz.through 163 tables = [ 164 VLM._meta.db_table, 165 VLM_m2m._meta.db_table, 166 ] 167 sequences = [ 168 { 169 'column': VLM._meta.pk.column, 170 'table': VLM._meta.db_table 171 }, 172 ] 173 cursor = connection.cursor() 174 for statement in connection.ops.sql_flush(no_style(), tables, sequences): 175 cursor.execute(statement) 160 # Some convenience aliases 161 VLM = models.VeryLongModelNameZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ 162 VLM_m2m = VLM.m2m_also_quite_long_zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz.through 163 tables = [ 164 (VLM._meta.db_schema, VLM._meta.db_table), 165 (VLM_m2m._meta.db_schema, VLM_m2m._meta.db_table), 166 ] 167 sequences = [ 168 { 169 'column': VLM._meta.pk.column, 170 'table': VLM._meta.db_table, 171 'schema': VLM._meta.db_schema, 172 }, 173 ] 174 cursor = connection.cursor() 175 for statement in connection.ops.sql_flush(no_style(), tables, sequences): 176 cursor.execute(statement) 176 177 177 178 class SequenceResetTest(TestCase): 178 179 def test_generic_relation(self):