45 final_output = [] |
40 final_output = [] |
46 table_output = [] |
41 table_output = [] |
47 pending_references = {} |
42 pending_references = {} |
48 qn = self.connection.ops.quote_name |
43 qn = self.connection.ops.quote_name |
49 for f in opts.local_fields: |
44 for f in opts.local_fields: |
50 col_type = f.db_type() |
45 col_type = f.db_type(connection=self.connection) |
51 tablespace = f.db_tablespace or opts.db_tablespace |
46 tablespace = f.db_tablespace or opts.db_tablespace |
52 if col_type is None: |
47 if col_type is None: |
53 # Skip ManyToManyFields, because they're not represented as |
48 # Skip ManyToManyFields, because they're not represented as |
54 # database columns in this table. |
49 # database columns in this table. |
55 continue |
50 continue |
71 if pending: |
66 if pending: |
72 pr = pending_references.setdefault(f.rel.to, []).append((model, f)) |
67 pr = pending_references.setdefault(f.rel.to, []).append((model, f)) |
73 else: |
68 else: |
74 field_output.extend(ref_output) |
69 field_output.extend(ref_output) |
75 table_output.append(' '.join(field_output)) |
70 table_output.append(' '.join(field_output)) |
76 if opts.order_with_respect_to: |
|
77 table_output.append(style.SQL_FIELD(qn('_order')) + ' ' + \ |
|
78 style.SQL_COLTYPE(models.IntegerField().db_type())) |
|
79 for field_constraints in opts.unique_together: |
71 for field_constraints in opts.unique_together: |
80 table_output.append(style.SQL_KEYWORD('UNIQUE') + ' (%s)' % \ |
72 table_output.append(style.SQL_KEYWORD('UNIQUE') + ' (%s)' % \ |
81 ", ".join([style.SQL_FIELD(qn(opts.get_field(f).column)) for f in field_constraints])) |
73 ", ".join([style.SQL_FIELD(qn(opts.get_field(f).column)) for f in field_constraints])) |
82 |
74 |
83 full_statement = [style.SQL_KEYWORD('CREATE TABLE') + ' ' + style.SQL_TABLE(qn(opts.db_table)) + ' ('] |
75 full_statement = [style.SQL_KEYWORD('CREATE TABLE') + ' ' + style.SQL_TABLE(qn(opts.db_table)) + ' ('] |
143 del pending_references[model] |
135 del pending_references[model] |
144 return final_output |
136 return final_output |
145 |
137 |
146 def sql_for_many_to_many(self, model, style): |
138 def sql_for_many_to_many(self, model, style): |
147 "Return the CREATE TABLE statments for all the many-to-many tables defined on a model" |
139 "Return the CREATE TABLE statments for all the many-to-many tables defined on a model" |
|
140 import warnings |
|
141 warnings.warn( |
|
142 'Database creation API for m2m tables has been deprecated. M2M models are now automatically generated', |
|
143 PendingDeprecationWarning |
|
144 ) |
|
145 |
148 output = [] |
146 output = [] |
149 for f in model._meta.local_many_to_many: |
147 for f in model._meta.local_many_to_many: |
150 if model._meta.managed or f.rel.to._meta.managed: |
148 if model._meta.managed or f.rel.to._meta.managed: |
151 output.extend(self.sql_for_many_to_many_field(model, f, style)) |
149 output.extend(self.sql_for_many_to_many_field(model, f, style)) |
152 return output |
150 return output |
153 |
151 |
154 def sql_for_many_to_many_field(self, model, f, style): |
152 def sql_for_many_to_many_field(self, model, f, style): |
155 "Return the CREATE TABLE statements for a single m2m field" |
153 "Return the CREATE TABLE statements for a single m2m field" |
|
154 import warnings |
|
155 warnings.warn( |
|
156 'Database creation API for m2m tables has been deprecated. M2M models are now automatically generated', |
|
157 PendingDeprecationWarning |
|
158 ) |
|
159 |
156 from django.db import models |
160 from django.db import models |
157 from django.db.backends.util import truncate_name |
161 from django.db.backends.util import truncate_name |
158 |
162 |
159 output = [] |
163 output = [] |
160 if f.creates_table: |
164 if f.auto_created: |
161 opts = model._meta |
165 opts = model._meta |
162 qn = self.connection.ops.quote_name |
166 qn = self.connection.ops.quote_name |
163 tablespace = f.db_tablespace or opts.db_tablespace |
167 tablespace = f.db_tablespace or opts.db_tablespace |
164 if tablespace: |
168 if tablespace: |
165 sql = self.connection.ops.tablespace_sql(tablespace, inline=True) |
169 sql = self.connection.ops.tablespace_sql(tablespace, inline=True) |
171 tablespace_sql = '' |
175 tablespace_sql = '' |
172 table_output = [style.SQL_KEYWORD('CREATE TABLE') + ' ' + \ |
176 table_output = [style.SQL_KEYWORD('CREATE TABLE') + ' ' + \ |
173 style.SQL_TABLE(qn(f.m2m_db_table())) + ' ('] |
177 style.SQL_TABLE(qn(f.m2m_db_table())) + ' ('] |
174 table_output.append(' %s %s %s%s,' % |
178 table_output.append(' %s %s %s%s,' % |
175 (style.SQL_FIELD(qn('id')), |
179 (style.SQL_FIELD(qn('id')), |
176 style.SQL_COLTYPE(models.AutoField(primary_key=True).db_type()), |
180 style.SQL_COLTYPE(models.AutoField(primary_key=True).db_type(connection=self.connection)), |
177 style.SQL_KEYWORD('NOT NULL PRIMARY KEY'), |
181 style.SQL_KEYWORD('NOT NULL PRIMARY KEY'), |
178 tablespace_sql)) |
182 tablespace_sql)) |
179 |
183 |
180 deferred = [] |
184 deferred = [] |
181 inline_output, deferred = self.sql_for_inline_many_to_many_references(model, f, style) |
185 inline_output, deferred = self.sql_for_inline_many_to_many_references(model, f, style) |
208 output.append(stmt) |
212 output.append(stmt) |
209 return output |
213 return output |
210 |
214 |
211 def sql_for_inline_many_to_many_references(self, model, field, style): |
215 def sql_for_inline_many_to_many_references(self, model, field, style): |
212 "Create the references to other tables required by a many-to-many table" |
216 "Create the references to other tables required by a many-to-many table" |
|
217 import warnings |
|
218 warnings.warn( |
|
219 'Database creation API for m2m tables has been deprecated. M2M models are now automatically generated', |
|
220 PendingDeprecationWarning |
|
221 ) |
|
222 |
213 from django.db import models |
223 from django.db import models |
214 opts = model._meta |
224 opts = model._meta |
215 qn = self.connection.ops.quote_name |
225 qn = self.connection.ops.quote_name |
216 |
226 |
217 table_output = [ |
227 table_output = [ |
218 ' %s %s %s %s (%s)%s,' % |
228 ' %s %s %s %s (%s)%s,' % |
219 (style.SQL_FIELD(qn(field.m2m_column_name())), |
229 (style.SQL_FIELD(qn(field.m2m_column_name())), |
220 style.SQL_COLTYPE(models.ForeignKey(model).db_type()), |
230 style.SQL_COLTYPE(models.ForeignKey(model).db_type(connection=self.connection)), |
221 style.SQL_KEYWORD('NOT NULL REFERENCES'), |
231 style.SQL_KEYWORD('NOT NULL REFERENCES'), |
222 style.SQL_TABLE(qn(opts.db_table)), |
232 style.SQL_TABLE(qn(opts.db_table)), |
223 style.SQL_FIELD(qn(opts.pk.column)), |
233 style.SQL_FIELD(qn(opts.pk.column)), |
224 self.connection.ops.deferrable_sql()), |
234 self.connection.ops.deferrable_sql()), |
225 ' %s %s %s %s (%s)%s,' % |
235 ' %s %s %s %s (%s)%s,' % |
226 (style.SQL_FIELD(qn(field.m2m_reverse_name())), |
236 (style.SQL_FIELD(qn(field.m2m_reverse_name())), |
227 style.SQL_COLTYPE(models.ForeignKey(field.rel.to).db_type()), |
237 style.SQL_COLTYPE(models.ForeignKey(field.rel.to).db_type(connection=self.connection)), |
228 style.SQL_KEYWORD('NOT NULL REFERENCES'), |
238 style.SQL_KEYWORD('NOT NULL REFERENCES'), |
229 style.SQL_TABLE(qn(field.rel.to._meta.db_table)), |
239 style.SQL_TABLE(qn(field.rel.to._meta.db_table)), |
230 style.SQL_FIELD(qn(field.rel.to._meta.pk.column)), |
240 style.SQL_FIELD(qn(field.rel.to._meta.pk.column)), |
231 self.connection.ops.deferrable_sql()) |
241 self.connection.ops.deferrable_sql()) |
232 ] |
242 ] |
243 output.extend(self.sql_indexes_for_field(model, f, style)) |
253 output.extend(self.sql_indexes_for_field(model, f, style)) |
244 return output |
254 return output |
245 |
255 |
246 def sql_indexes_for_field(self, model, f, style): |
256 def sql_indexes_for_field(self, model, f, style): |
247 "Return the CREATE INDEX SQL statements for a single model field" |
257 "Return the CREATE INDEX SQL statements for a single model field" |
|
258 from django.db.backends.util import truncate_name |
|
259 |
248 if f.db_index and not f.unique: |
260 if f.db_index and not f.unique: |
249 qn = self.connection.ops.quote_name |
261 qn = self.connection.ops.quote_name |
250 tablespace = f.db_tablespace or model._meta.db_tablespace |
262 tablespace = f.db_tablespace or model._meta.db_tablespace |
251 if tablespace: |
263 if tablespace: |
252 sql = self.connection.ops.tablespace_sql(tablespace) |
264 sql = self.connection.ops.tablespace_sql(tablespace) |
254 tablespace_sql = ' ' + sql |
266 tablespace_sql = ' ' + sql |
255 else: |
267 else: |
256 tablespace_sql = '' |
268 tablespace_sql = '' |
257 else: |
269 else: |
258 tablespace_sql = '' |
270 tablespace_sql = '' |
|
271 i_name = '%s_%s' % (model._meta.db_table, self._digest(f.column)) |
259 output = [style.SQL_KEYWORD('CREATE INDEX') + ' ' + |
272 output = [style.SQL_KEYWORD('CREATE INDEX') + ' ' + |
260 style.SQL_TABLE(qn('%s_%s' % (model._meta.db_table, f.column))) + ' ' + |
273 style.SQL_TABLE(qn(truncate_name(i_name, self.connection.ops.max_name_length()))) + ' ' + |
261 style.SQL_KEYWORD('ON') + ' ' + |
274 style.SQL_KEYWORD('ON') + ' ' + |
262 style.SQL_TABLE(qn(model._meta.db_table)) + ' ' + |
275 style.SQL_TABLE(qn(model._meta.db_table)) + ' ' + |
263 "(%s)" % style.SQL_FIELD(qn(f.column)) + |
276 "(%s)" % style.SQL_FIELD(qn(f.column)) + |
264 "%s;" % tablespace_sql] |
277 "%s;" % tablespace_sql] |
265 else: |
278 else: |
298 r_name = '%s_refs_%s_%s' % (col, r_col, self._digest(table, r_table)) |
311 r_name = '%s_refs_%s_%s' % (col, r_col, self._digest(table, r_table)) |
299 output.append('%s %s %s %s;' % \ |
312 output.append('%s %s %s %s;' % \ |
300 (style.SQL_KEYWORD('ALTER TABLE'), |
313 (style.SQL_KEYWORD('ALTER TABLE'), |
301 style.SQL_TABLE(qn(table)), |
314 style.SQL_TABLE(qn(table)), |
302 style.SQL_KEYWORD(self.connection.ops.drop_foreignkey_sql()), |
315 style.SQL_KEYWORD(self.connection.ops.drop_foreignkey_sql()), |
303 style.SQL_FIELD(truncate_name(r_name, self.connection.ops.max_name_length())))) |
316 style.SQL_FIELD(qn(truncate_name(r_name, self.connection.ops.max_name_length()))))) |
304 del references_to_delete[model] |
317 del references_to_delete[model] |
305 return output |
318 return output |
306 |
319 |
307 def sql_destroy_many_to_many(self, model, f, style): |
320 def sql_destroy_many_to_many(self, model, f, style): |
308 "Returns the DROP TABLE statements for a single m2m field" |
321 "Returns the DROP TABLE statements for a single m2m field" |
|
322 import warnings |
|
323 warnings.warn( |
|
324 'Database creation API for m2m tables has been deprecated. M2M models are now automatically generated', |
|
325 PendingDeprecationWarning |
|
326 ) |
|
327 |
309 qn = self.connection.ops.quote_name |
328 qn = self.connection.ops.quote_name |
310 output = [] |
329 output = [] |
311 if f.creates_table: |
330 if f.auto_created: |
312 output.append("%s %s;" % (style.SQL_KEYWORD('DROP TABLE'), |
331 output.append("%s %s;" % (style.SQL_KEYWORD('DROP TABLE'), |
313 style.SQL_TABLE(qn(f.m2m_db_table())))) |
332 style.SQL_TABLE(qn(f.m2m_db_table())))) |
314 ds = self.connection.ops.drop_sequence_sql("%s_%s" % (model._meta.db_table, f.column)) |
333 ds = self.connection.ops.drop_sequence_sql("%s_%s" % (model._meta.db_table, f.column)) |
315 if ds: |
334 if ds: |
316 output.append(ds) |
335 output.append(ds) |
320 """ |
339 """ |
321 Creates a test database, prompting the user for confirmation if the |
340 Creates a test database, prompting the user for confirmation if the |
322 database already exists. Returns the name of the test database created. |
341 database already exists. Returns the name of the test database created. |
323 """ |
342 """ |
324 if verbosity >= 1: |
343 if verbosity >= 1: |
325 print "Creating test database..." |
344 print "Creating test database '%s'..." % self.connection.alias |
326 |
345 |
327 test_database_name = self._create_test_db(verbosity, autoclobber) |
346 test_database_name = self._create_test_db(verbosity, autoclobber) |
328 |
347 |
329 self.connection.close() |
348 self.connection.close() |
330 settings.DATABASE_NAME = test_database_name |
349 self.connection.settings_dict["NAME"] = test_database_name |
331 self.connection.settings_dict["DATABASE_NAME"] = test_database_name |
|
332 can_rollback = self._rollback_works() |
350 can_rollback = self._rollback_works() |
333 settings.DATABASE_SUPPORTS_TRANSACTIONS = can_rollback |
351 self.connection.settings_dict["SUPPORTS_TRANSACTIONS"] = can_rollback |
334 self.connection.settings_dict["DATABASE_SUPPORTS_TRANSACTIONS"] = can_rollback |
352 |
335 |
353 call_command('syncdb', verbosity=verbosity, interactive=False, database=self.connection.alias) |
336 call_command('syncdb', verbosity=verbosity, interactive=False) |
|
337 |
354 |
338 if settings.CACHE_BACKEND.startswith('db://'): |
355 if settings.CACHE_BACKEND.startswith('db://'): |
339 from django.core.cache import parse_backend_uri |
356 from django.core.cache import parse_backend_uri |
340 _, cache_name, _ = parse_backend_uri(settings.CACHE_BACKEND) |
357 _, cache_name, _ = parse_backend_uri(settings.CACHE_BACKEND) |
341 call_command('createcachetable', cache_name) |
358 call_command('createcachetable', cache_name) |
348 |
365 |
349 def _create_test_db(self, verbosity, autoclobber): |
366 def _create_test_db(self, verbosity, autoclobber): |
350 "Internal implementation - creates the test db tables." |
367 "Internal implementation - creates the test db tables." |
351 suffix = self.sql_table_creation_suffix() |
368 suffix = self.sql_table_creation_suffix() |
352 |
369 |
353 if settings.TEST_DATABASE_NAME: |
370 if self.connection.settings_dict['TEST_NAME']: |
354 test_database_name = settings.TEST_DATABASE_NAME |
371 test_database_name = self.connection.settings_dict['TEST_NAME'] |
355 else: |
372 else: |
356 test_database_name = TEST_DATABASE_PREFIX + settings.DATABASE_NAME |
373 test_database_name = TEST_DATABASE_PREFIX + self.connection.settings_dict['NAME'] |
357 |
374 |
358 qn = self.connection.ops.quote_name |
375 qn = self.connection.ops.quote_name |
359 |
376 |
360 # Create the test database and connect to it. We need to autocommit |
377 # Create the test database and connect to it. We need to autocommit |
361 # if the database supports it because PostgreSQL doesn't allow |
378 # if the database supports it because PostgreSQL doesn't allow |
401 """ |
418 """ |
402 Destroy a test database, prompting the user for confirmation if the |
419 Destroy a test database, prompting the user for confirmation if the |
403 database already exists. Returns the name of the test database created. |
420 database already exists. Returns the name of the test database created. |
404 """ |
421 """ |
405 if verbosity >= 1: |
422 if verbosity >= 1: |
406 print "Destroying test database..." |
423 print "Destroying test database '%s'..." % self.connection.alias |
407 self.connection.close() |
424 self.connection.close() |
408 test_database_name = settings.DATABASE_NAME |
425 test_database_name = self.connection.settings_dict['NAME'] |
409 settings.DATABASE_NAME = old_database_name |
426 self.connection.settings_dict['NAME'] = old_database_name |
410 self.connection.settings_dict["DATABASE_NAME"] = old_database_name |
|
411 |
427 |
412 self._destroy_test_db(test_database_name, verbosity) |
428 self._destroy_test_db(test_database_name, verbosity) |
413 |
429 |
414 def _destroy_test_db(self, test_database_name, verbosity): |
430 def _destroy_test_db(self, test_database_name, verbosity): |
415 "Internal implementation - remove the test db tables." |
431 "Internal implementation - remove the test db tables." |