Changeset 3760
- Timestamp:
- 09/14/06 15:18:24 (2 years ago)
- Files:
-
- django/branches/multiple-db-support/django/core/management.py (modified) (4 diffs)
- django/branches/multiple-db-support/django/db/backends/ansi/sql.py (modified) (6 diffs)
- django/branches/multiple-db-support/django/db/models/manager.py (modified) (3 diffs)
- django/branches/multiple-db-support/django/test/simple.py (modified) (1 diff)
- django/branches/multiple-db-support/django/test/utils.py (modified) (3 diffs)
- django/branches/multiple-db-support/tests/modeltests/multiple_databases/models.py (modified) (2 diffs)
- django/branches/multiple-db-support/tests/regressiontests/ansi_sql/models.py (modified) (2 diffs)
- django/branches/multiple-db-support/tests/regressiontests/ansi_sql/sql/car.sql (modified) (1 diff)
- django/branches/multiple-db-support/tests/regressiontests/manager_schema_manipulation/tests.py (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
django/branches/multiple-db-support/django/core/management.py
r3757 r3760 74 74 # named connection, if there are any named connections 75 75 connection_output = {} 76 pending _references= {}76 pending = {} 77 77 final_output = [] 78 78 79 79 app_models = models.get_models(app, creation_order=True) 80 80 for model in app_models: 81 82 print "Get create sql for model", model 83 81 84 opts = model._meta 82 85 connection_name = model_connection_name(model) … … 110 113 tables = [] 111 114 112 installed_models = [ m odel for modelin115 installed_models = [ m for m in 113 116 manager.get_installed_models(tables) 114 if m odelnot in app_models ]117 if m not in app_models ] 115 118 models_output = set(installed_models) 116 119 builder = creation.builder 117 120 builder.models_already_seen.update(models_output) 118 model_output, references = builder.get_create_table(model, style)121 model_output, pending = builder.get_create_table(model, style, pending) 119 122 output.extend(model_output) 120 for refto, refs in references.items():121 try:122 pending_references[refto].extend(refs)123 except KeyError:124 pending_references[refto] = refs125 if model in pending_references:126 output.extend(pending_references.pop(model))127 123 128 124 # Create the many-to-many join tables. … … 132 128 133 129 final_output = _collate(connection_output) 130 134 131 # Handle references to tables that are from other apps 135 132 # but don't exist physically 136 not_installed_models = set(pending _references.keys())133 not_installed_models = set(pending.keys()) 137 134 if not_installed_models: 138 135 alter_sql = [] 139 136 for model in not_installed_models: 140 alter_sql.extend(['-- ' + sql 141 for sql in pending_references.pop(model)]) 137 builder = model._default_manager.db.builder.get_creation_module().builder 138 139 for rel_class, f in pending[model]: 140 sql = builder._ref_sql(model, rel_class, f, style) 141 alter_sql.extend(['-- ', str(sql)]) 142 142 if alter_sql: 143 143 final_output.append('-- The following references should be added ' … … 407 407 # Don't re-install already-installed models 408 408 if not model in models_installed: 409 new_pending = manager.install(initial_data=initial_data) 409 pending = manager.install(initial_data=initial_data, 410 pending=pending) 410 411 created_models.append(model) 411 for dep_model, statements in new_pending.items(): 412 pending.setdefault(dep_model, []).extend(statements) 413 # Execute any pending statements that were waiting for this model 414 if model in pending: 415 for statement in pending.pop(model): 416 statement.execute() 412 417 413 if pending: 418 for model, statements in pending.items(): 419 manager = model._default_manager 420 tables = manager.get_table_list() 421 models_installed = manager.get_installed_models(tables) 414 models_installed = manager.get_installed_models(tables) 415 416 for model in pending.keys(): 422 417 if model in models_installed: 423 for statement in statements: 424 statement.execute() 418 for rel_class, f in pending[model]: 419 manager = model._default_manager 420 for statement in manager.get_pending(rel_class, f): 421 statement.execute() 422 pending.pop(model) 425 423 else: 426 424 raise Exception("%s is not installed, but there are " django/branches/multiple-db-support/django/db/backends/ansi/sql.py
r3581 r3760 51 51 self.tables = None 52 52 53 def get_create_table(self, model, style=None ):53 def get_create_table(self, model, style=None, pending=None): 54 54 """Construct and return the SQL expression(s) needed to create the 55 55 table for the given model, and any constraints on that … … 62 62 if style is None: 63 63 style = default_style 64 if pending is None: 65 pending = {} 64 66 self.models_already_seen.add(model) 65 67 … … 71 73 table_output = [] 72 74 73 # pending field references, keyed by the model class74 # they reference75 pending_references = {}76 77 # pending statements to execute, keyed by78 # the model class they reference79 pending = {}80 75 for f in opts.fields: 81 76 if isinstance(f, models.ForeignKey): … … 109 104 # We haven't yet created the table to which this field 110 105 # is related, so save it for later. 111 pending _references.setdefault(f.rel.to, []).append(f)106 pending.setdefault(f.rel.to, []).append((model, f)) 112 107 table_output.append(' '.join(field_output)) 113 108 if opts.order_with_respect_to: … … 129 124 create = [BoundStatement('\n'.join(full_statement), db.connection)] 130 125 131 if (pending_references and 126 # Pull out any pending statements for me 127 if (pending and 132 128 backend.supports_constraints): 133 for rel_class, cols in pending_references.items(): 134 for f in cols: 135 rel_opts = rel_class._meta 136 r_table = rel_opts.db_table 137 r_col = f.column 138 table = opts.db_table 139 col = opts.get_field(f.rel.field_name).column 140 # For MySQL, r_name must be unique in the first 64 141 # characters. So we are careful with character usage here. 142 r_name = '%s_refs_%s_%x' % (col, r_col, 143 abs(hash((r_table, table)))) 144 sql = style.SQL_KEYWORD('ALTER TABLE') + ' %s ADD CONSTRAINT %s FOREIGN KEY (%s) REFERENCES %s (%s);' % \ 145 (quote_name(table), quote_name(r_name), 146 quote_name(r_col), quote_name(r_table), quote_name(col)) 147 pending.setdefault(rel_class, []).append( 148 BoundStatement(sql, db.connection)) 129 if model in pending: 130 for rel_class, f in pending[model]: 131 create.append(self.get_ref_sql(model, rel_class, f, 132 style=style)) 133 # What was pending for me is now no longer pending 134 pending.pop(model) 149 135 return (create, pending) 150 136 … … 323 309 and 'IntegerField' \ 324 310 or f.get_internal_type() 325 311 312 def get_ref_sql(self, model, rel_class, f, style=None): 313 """Get sql statement for a reference between model and rel_class on 314 field f. 315 """ 316 if style is None: 317 style = default_style 318 319 db = model._default_manager.db 320 qn = db.backend.quote_name 321 opts = model._meta 322 rel_opts = rel_class._meta 323 table = rel_opts.db_table 324 r_col = f.column 325 r_table = opts.db_table 326 col = opts.get_field(f.rel.field_name).column 327 # For MySQL, r_name must be unique in the first 64 328 # characters. So we are careful with character usage here. 329 r_name = '%s_refs_%s_%x' % (col, r_col, 330 abs(hash((r_table, table)))) 331 sql = style.SQL_KEYWORD('ALTER TABLE') + \ 332 ' %s ADD CONSTRAINT %s FOREIGN KEY (%s) REFERENCES %s (%s);' % \ 333 (qn(table), qn(r_name), 334 qn(r_col), qn(r_table), qn(col)) 335 return BoundStatement(sql, db.connection) 336 326 337 def get_references(self): 327 338 """Fill (if needed) and return the reference cache. django/branches/multiple-db-support/django/db/models/manager.py
r3667 r3760 119 119 ####################### 120 120 121 def install(self, initial_data=False ):121 def install(self, initial_data=False, pending=None): 122 122 """Install my model's table, indexes and (if requested) initial data. 123 123 … … 128 128 install time.) 129 129 """ 130 if pending is None: 131 pending = {} 130 132 builder = self.db.get_creation_module().builder 131 run, pending = builder.get_create_table(self.model )133 run, pending = builder.get_create_table(self.model, pending=pending) 132 134 run += builder.get_create_indexes(self.model) 133 135 many_many = builder.get_create_many_to_many(self.model) … … 144 146 self.load_initial_data() 145 147 return pending 148 149 def get_pending(self, rel_class, f): 150 builder = self.db.get_creation_module().builder 151 return builder.get_ref_sql(self.model, rel_class, f) 146 152 147 153 def load_initial_data(self): django/branches/multiple-db-support/django/test/simple.py
r3755 r3760 79 79 old_name = settings.DATABASE_NAME 80 80 create_test_db(verbosity) 81 management.syncdb(verbosity, interactive=False) 82 unittest.TextTestRunner(verbosity=verbosity).run(suite) 83 destroy_test_db(old_name, verbosity) 84 85 teardown_test_environment() 81 try: 82 management.syncdb(verbosity, interactive=False) 83 unittest.TextTestRunner(verbosity=verbosity).run(suite) 84 finally: 85 destroy_test_db(old_name, verbosity) 86 teardown_test_environment() django/branches/multiple-db-support/django/test/utils.py
r3739 r3760 67 67 _set_autocommit(connection) 68 68 try: 69 cursor.execute("CREATE DATABASE %s" % qn( db_name))69 cursor.execute("CREATE DATABASE %s" % qn(TEST_DATABASE_NAME)) 70 70 except Exception, e: 71 71 sys.stderr.write("Got an error creating the test database: %s\n" % e) 72 72 if not autoclobber: 73 confirm = raw_input("It appears the test database, %s, already exists. Type 'yes' to delete it, or 'no' to cancel: " % db_name)73 confirm = raw_input("It appears the test database, %s, already exists. Type 'yes' to delete it, or 'no' to cancel: " % TEST_DATABASE_NAME) 74 74 if autoclobber or confirm == 'yes': 75 75 try: 76 76 if verbosity >= 1: 77 77 print "Destroying old test database..." 78 cursor.execute("DROP DATABASE %s" % qn( db_name))78 cursor.execute("DROP DATABASE %s" % qn(TEST_DATABASE_NAME)) 79 79 if verbosity >= 1: 80 80 print "Creating test database..." 81 cursor.execute("CREATE DATABASE %s" % qn( db_name))81 cursor.execute("CREATE DATABASE %s" % qn(TEST_DATABASE_NAME)) 82 82 except Exception, e: 83 83 sys.stderr.write("Got an error recreating the test database: %s\n" % e) … … 119 119 if verbosity >= 1: 120 120 print "Destroying test database..." 121 connection.close() 121 for cnx in connections.keys(): 122 connections[cnx].close() 122 123 TEST_DATABASE_NAME = settings.DATABASE_NAME 123 124 settings.DATABASE_NAME = old_database_name … … 125 126 if settings.DATABASE_ENGINE != "sqlite3": 126 127 settings.OTHER_DATABASES = old_databases 128 for cnx in connections.keys(): 129 connections[cnx].connection.cursor() 127 130 cursor = connection.cursor() 128 131 _set_autocommit(connection) django/branches/multiple-db-support/tests/modeltests/multiple_databases/models.py
r3712 r3760 79 79 >>> from django.conf import settings 80 80 81 # The default connection is in there, but let's ignore it 81 # Connections are referenced by name 82 >>> connections['_a'] 83 Connection: ... 84 >>> connections['_b'] 85 Connection: ... 86 87 # Let's see what connections are available.The default connection is 88 # in there, but let's ignore it 82 89 83 90 >>> non_default = connections.keys() … … 86 93 >>> non_default 87 94 ['_a', '_b'] 88 89 # Each connection references its settings90 >>> connections['_a'].settings.DATABASE_NAME == settings.OTHER_DATABASES['_a']['DATABASE_NAME']91 True92 >>> connections['_b'].settings.DATABASE_NAME == settings.OTHER_DATABASES['_b']['DATABASE_NAME']93 True94 95 95 96 # Invalid connection names raise ImproperlyConfigured django/branches/multiple-db-support/tests/regressiontests/ansi_sql/models.py
r3712 r3760 21 21 >>> builder.models_already_seen = set() 22 22 >>> builder.get_create_table(Mod) 23 ([BoundStatement('CREATE TABLE "ansi_sql_mod" (..."car_id" integer NOT NULL,...);')], {<class 'regressiontests.ansi_sql.models.Car'>: [ BoundStatement('ALTER TABLE "ansi_sql_mod" ADD CONSTRAINT ... FOREIGN KEY ("car_id") REFERENCES "ansi_sql_car" ("id");')]})23 ([BoundStatement('CREATE TABLE "ansi_sql_mod" (..."car_id" integer NOT NULL,...);')], {<class 'regressiontests.ansi_sql.models.Car'>: [(<class 'regressiontests.ansi_sql.models.Mod'>, <django.db.models.fields.related.ForeignKey...>)]}) 24 24 >>> builder.models_already_seen = set() 25 25 >>> builder.get_create_table(Car) … … 46 46 # >>> builder.get_initialdata_path = othertests_sql 47 47 >>> builder.get_initialdata(Car) 48 [BoundStatement( 'insert into ansi_sql_car (...)...values (...);')]48 [BoundStatement("insert into ansi_sql_car (...)...values (...);...")] 49 49 50 50 # test drop django/branches/multiple-db-support/tests/regressiontests/ansi_sql/sql/car.sql
r3712 r3760 1 1 insert into ansi_sql_car (make, model, year, condition) 2 values ( "Chevy", "Impala", 1966, "mint");2 values ('Chevy', 'Impala', 1966, 'mint'); django/branches/multiple-db-support/tests/regressiontests/manager_schema_manipulation/tests.py
r3712 r3760 124 124 >>> result = PA.objects.install() 125 125 >>> result 126 {<class 'regressiontests.manager_schema_manipulation.tests.PC'>: [ BoundStatement('ALTER TABLE "msm_pa" ADD CONSTRAINT "id_refs_c_id..." FOREIGN KEY ("c_id") REFERENCES "msm_pc" ("id");')]}126 {<class 'regressiontests.manager_schema_manipulation.tests.PC'>: [(<class 'regressiontests.manager_schema_manipulation.tests.PA'>, <django.db.models.fields.related.ForeignKey ...>)]} 127 127 128 128 # NOTE: restore real constraint flag
