diff --git a/TODO.TXT b/TODO.TXT index e4f2dd0e8c..c525bccdec 100644 --- a/TODO.TXT +++ b/TODO.TXT @@ -28,7 +28,6 @@ that need to be done. I'm trying to be as granular as possible. 4) Rig up the test harness to work with multiple databases. This includes: - * Move all ``TEST_*`` settings to go in ``DATABASE_OPTIONS``. * Figure out how we can actually test multiple databases. If the user has more than one database in ``settings.DATABASES`` we can just use the test database for each of them. Otherwise we are going to have to make some diff --git a/django/db/__init__.py b/django/db/__init__.py index fca992cd74..9da54541da 100644 --- a/django/db/__init__.py +++ b/django/db/__init__.py @@ -4,10 +4,13 @@ from django.core.exceptions import ImproperlyConfigured from django.db.utils import ConnectionHandler, load_backend from django.utils.functional import curry -__all__ = ('backend', 'connection', 'DatabaseError', 'IntegrityError') +__all__ = ('backend', 'connection', 'connections', 'DatabaseError', + 'IntegrityError', 'DEFAULT_DB_ALIAS') -if not settings.DATABASES or 'default' not in settings.DATABASES: - settings.DATABASES['default'] = { +DEFAULT_DB_ALIAS = 'default' + +if not settings.DATABASES or DEFAULT_DB_ALIAS not in settings.DATABASES: + settings.DATABASES[DEFAULT_DB_ALIAS] = { 'DATABASE_ENGINE': settings.DATABASE_ENGINE, 'DATABASE_HOST': settings.DATABASE_HOST, 'DATABASE_NAME': settings.DATABASE_NAME, @@ -16,6 +19,10 @@ if not settings.DATABASES or 'default' not in settings.DATABASES: 'DATABASE_PORT': settings.DATABASE_PORT, 'DATABASE_USER': settings.DATABASE_USER, 'TIME_ZONE': settings.TIME_ZONE, + + 'TEST_DATABASE_CHARSET': settings.TEST_DATABASE_CHARSET, + 'TEST_DATABASE_COLLATION': settings.TEST_DATABASE_COLLATION, + 'TEST_DATABASE_NAME': settings.TEST_DATABASE_NAME, } connections = ConnectionHandler(settings.DATABASES) diff --git a/django/db/backends/__init__.py b/django/db/backends/__init__.py index 579bf80aaf..0f7bf45402 100644 --- a/django/db/backends/__init__.py +++ b/django/db/backends/__init__.py @@ -557,7 +557,9 @@ class BaseDatabaseValidation(object): """ This class encapsualtes all backend-specific model validation. """ + def __init__(self, connection): + self.connection = connection + def validate_field(self, errors, opts, f): "By default, there is no backend-specific validation" pass - diff --git a/django/db/backends/creation.py b/django/db/backends/creation.py index f6041c73f3..2f8677f153 100644 --- a/django/db/backends/creation.py +++ b/django/db/backends/creation.py @@ -321,10 +321,8 @@ class BaseDatabaseCreation(object): test_database_name = self._create_test_db(verbosity, autoclobber) self.connection.close() - settings.DATABASE_NAME = test_database_name self.connection.settings_dict["DATABASE_NAME"] = test_database_name can_rollback = self._rollback_works() - settings.DATABASE_SUPPORTS_TRANSACTIONS = can_rollback self.connection.settings_dict["DATABASE_SUPPORTS_TRANSACTIONS"] = can_rollback call_command('syncdb', verbosity=verbosity, interactive=False) @@ -344,10 +342,10 @@ class BaseDatabaseCreation(object): "Internal implementation - creates the test db tables." suffix = self.sql_table_creation_suffix() - if settings.TEST_DATABASE_NAME: - test_database_name = settings.TEST_DATABASE_NAME + if self.connection.settings_dict['TEST_DATABASE_NAME']: + test_database_name = self.connection.settings_dict['TEST_DATABASE_NAME'] else: - test_database_name = TEST_DATABASE_PREFIX + settings.DATABASE_NAME + test_database_name = TEST_DATABASE_PREFIX + self.connection.settings_dict['DATABASE_NAME'] qn = self.connection.ops.quote_name @@ -399,9 +397,8 @@ class BaseDatabaseCreation(object): if verbosity >= 1: print "Destroying test database..." self.connection.close() - test_database_name = settings.DATABASE_NAME - settings.DATABASE_NAME = old_database_name - self.connection.settings_dict["DATABASE_NAME"] = old_database_name + test_database_name = self.connection.settings_dict['DATABASE_NAME'] + self.connection.settings_dict['DATABASE_NAME'] = old_database_name self._destroy_test_db(test_database_name, verbosity) @@ -430,4 +427,3 @@ class BaseDatabaseCreation(object): def sql_table_creation_suffix(self): "SQL to append to the end of the test table creation statements" return '' - diff --git a/django/db/backends/mysql/base.py b/django/db/backends/mysql/base.py index f71e5cd99b..bd3e551ed9 100644 --- a/django/db/backends/mysql/base.py +++ b/django/db/backends/mysql/base.py @@ -242,7 +242,7 @@ class DatabaseWrapper(BaseDatabaseWrapper): self.client = DatabaseClient(self) self.creation = DatabaseCreation(self) self.introspection = DatabaseIntrospection(self) - self.validation = DatabaseValidation() + self.validation = DatabaseValidation(self) def _valid_connection(self): if self.connection is not None: diff --git a/django/db/backends/mysql/creation.py b/django/db/backends/mysql/creation.py index 0611e01643..76e743d36a 100644 --- a/django/db/backends/mysql/creation.py +++ b/django/db/backends/mysql/creation.py @@ -1,4 +1,3 @@ -from django.conf import settings from django.db.backends.creation import BaseDatabaseCreation class DatabaseCreation(BaseDatabaseCreation): @@ -31,21 +30,21 @@ class DatabaseCreation(BaseDatabaseCreation): def sql_table_creation_suffix(self): suffix = [] - if settings.TEST_DATABASE_CHARSET: - suffix.append('CHARACTER SET %s' % settings.TEST_DATABASE_CHARSET) - if settings.TEST_DATABASE_COLLATION: - suffix.append('COLLATE %s' % settings.TEST_DATABASE_COLLATION) + if self.connection.settings_dict['TEST_DATABASE_CHARSET']: + suffix.append('CHARACTER SET %s' % self.connection.settings_dict['TEST_DATABASE_CHARSET']) + if self.connection.settings_dict['TEST_DATABASE_COLLATION']: + suffix.append('COLLATE %s' % self.connection.settings_dict['TEST_DATABASE_COLLATION']) return ' '.join(suffix) def sql_for_inline_foreign_key_references(self, field, known_models, style): "All inline references are pending under MySQL" return [], True - + def sql_for_inline_many_to_many_references(self, model, field, style): from django.db import models opts = model._meta qn = self.connection.ops.quote_name - + table_output = [ ' %s %s %s,' % (style.SQL_FIELD(qn(field.m2m_column_name())), @@ -63,4 +62,3 @@ class DatabaseCreation(BaseDatabaseCreation): field.rel.to._meta.db_table, field.rel.to._meta.pk.column) ] return table_output, deferred - \ No newline at end of file diff --git a/django/db/backends/mysql/validation.py b/django/db/backends/mysql/validation.py index 0b3d4ad0bd..197f91310e 100644 --- a/django/db/backends/mysql/validation.py +++ b/django/db/backends/mysql/validation.py @@ -11,8 +11,7 @@ class DatabaseValidation(BaseDatabaseValidation): characters if they have a unique index on them. """ from django.db import models - from django.db import connection - db_version = connection.get_server_version() + db_version = self.connection.get_server_version() varchar_fields = (models.CharField, models.CommaSeparatedIntegerField, models.SlugField) if isinstance(f, varchar_fields) and f.max_length > 255: @@ -25,4 +24,3 @@ class DatabaseValidation(BaseDatabaseValidation): if msg: errors.add(opts, msg % {'name': f.name, 'cls': f.__class__.__name__, 'version': '.'.join([str(n) for n in db_version[:3]])}) - diff --git a/django/db/backends/oracle/base.py b/django/db/backends/oracle/base.py index 8f96049cc4..a0fa06283e 100644 --- a/django/db/backends/oracle/base.py +++ b/django/db/backends/oracle/base.py @@ -282,7 +282,7 @@ class DatabaseWrapper(BaseDatabaseWrapper): self.client = DatabaseClient(self) self.creation = DatabaseCreation(self) self.introspection = DatabaseIntrospection(self) - self.validation = BaseDatabaseValidation() + self.validation = BaseDatabaseValidation(self) def _valid_connection(self): return self.connection is not None diff --git a/django/db/backends/oracle/creation.py b/django/db/backends/oracle/creation.py index 43d8760fca..06f55242bc 100644 --- a/django/db/backends/oracle/creation.py +++ b/django/db/backends/oracle/creation.py @@ -1,5 +1,4 @@ import sys, time -from django.conf import settings from django.core import management from django.db.backends.creation import BaseDatabaseCreation @@ -42,11 +41,11 @@ class DatabaseCreation(BaseDatabaseCreation): remember = {} def _create_test_db(self, verbosity=1, autoclobber=False): - TEST_DATABASE_NAME = self._test_database_name(settings) - TEST_DATABASE_USER = self._test_database_user(settings) - TEST_DATABASE_PASSWD = self._test_database_passwd(settings) - TEST_DATABASE_TBLSPACE = self._test_database_tblspace(settings) - TEST_DATABASE_TBLSPACE_TMP = self._test_database_tblspace_tmp(settings) + TEST_DATABASE_NAME = self._test_database_name() + TEST_DATABASE_USER = self._test_database_user() + TEST_DATABASE_PASSWD = self._test_database_passwd() + TEST_DATABASE_TBLSPACE = self._test_database_tblspace() + TEST_DATABASE_TBLSPACE_TMP = self._test_database_tblspace_tmp() parameters = { 'dbname': TEST_DATABASE_NAME, @@ -56,11 +55,11 @@ class DatabaseCreation(BaseDatabaseCreation): 'tblspace_temp': TEST_DATABASE_TBLSPACE_TMP, } - self.remember['user'] = settings.DATABASE_USER - self.remember['passwd'] = settings.DATABASE_PASSWORD + self.remember['user'] = self.connection.settings_dict['DATABASE_USER'] + self.remember['passwd'] = self.connection.settings_dict['DATABASE_PASSWORD'] cursor = self.connection.cursor() - if self._test_database_create(settings): + if self._test_database_create(): if verbosity >= 1: print 'Creating test database...' try: @@ -84,7 +83,7 @@ class DatabaseCreation(BaseDatabaseCreation): print "Tests cancelled." sys.exit(1) - if self._test_user_create(settings): + if self._test_user_create(): if verbosity >= 1: print "Creating test user..." try: @@ -108,24 +107,24 @@ class DatabaseCreation(BaseDatabaseCreation): print "Tests cancelled." sys.exit(1) - settings.TEST_DATABASE_USER = settings.DATABASE_USER = self.connection.settings_dict["DATABASE_USER"] = TEST_DATABASE_USER - settings.DATABASE_PASSWORD = self.connection.settings_dict["DATABASE_PASSWORD"] = TEST_DATABASE_PASSWD + self.connection.settings_dict['TEST_DATABASE_USER'] = self.connection.settings_dict["DATABASE_USER"] = TEST_DATABASE_USER + self.connection.settings_dict["DATABASE_PASSWORD"] = TEST_DATABASE_PASSWD - return settings.DATABASE_NAME + return self.connection.settings_dict['DATABASE_NAME'] def _destroy_test_db(self, test_database_name, verbosity=1): """ Destroy a test database, prompting the user for confirmation if the database already exists. Returns the name of the test database created. """ - TEST_DATABASE_NAME = self._test_database_name(settings) - TEST_DATABASE_USER = self._test_database_user(settings) - TEST_DATABASE_PASSWD = self._test_database_passwd(settings) - TEST_DATABASE_TBLSPACE = self._test_database_tblspace(settings) - TEST_DATABASE_TBLSPACE_TMP = self._test_database_tblspace_tmp(settings) + TEST_DATABASE_NAME = self._test_database_name() + TEST_DATABASE_USER = self._test_database_user() + TEST_DATABASE_PASSWD = self._test_database_passwd() + TEST_DATABASE_TBLSPACE = self._test_database_tblspace() + TEST_DATABASE_TBLSPACE_TMP = self._test_database_tblspace_tmp() - settings.DATABASE_USER = self.connection.settings_dict["DATABASE_USER"] = self.remember['user'] - settings.DATABASE_PASSWORD = self.connection.settings_dict["DATABASE_PASSWORD"] = self.remember['passwd'] + self.connection.settings_dict["DATABASE_USER"] = self.remember['user'] + self.connection.settings_dict["DATABASE_PASSWORD"] = self.remember['passwd'] parameters = { 'dbname': TEST_DATABASE_NAME, @@ -135,16 +134,16 @@ class DatabaseCreation(BaseDatabaseCreation): 'tblspace_temp': TEST_DATABASE_TBLSPACE_TMP, } - self.remember['user'] = settings.DATABASE_USER - self.remember['passwd'] = settings.DATABASE_PASSWORD + self.remember['user'] = self.connection.settings_dict['DATABASE_USER'] + self.remember['passwd'] = self.connection.settings_dict['DATABASE_PASSWORD'] cursor = self.connection.cursor() time.sleep(1) # To avoid "database is being accessed by other users" errors. - if self._test_user_create(settings): + if self._test_user_create(): if verbosity >= 1: print 'Destroying test user...' self._destroy_test_user(cursor, parameters, verbosity) - if self._test_database_create(settings): + if self._test_database_create(): if verbosity >= 1: print 'Destroying test database tables...' self._execute_test_db_destruction(cursor, parameters, verbosity) @@ -208,10 +207,10 @@ class DatabaseCreation(BaseDatabaseCreation): raise def _test_database_name(self, settings): - name = TEST_DATABASE_PREFIX + settings.DATABASE_NAME + name = TEST_DATABASE_PREFIX + self.connection.settings_dict['DATABASE_NAME'] try: - if settings.TEST_DATABASE_NAME: - name = settings.TEST_DATABASE_NAME + if self.connection.settings_dict['TEST_DATABASE_NAME']: + name = self.connection.settings_dict['TEST_DATABASE_NAME'] except AttributeError: pass except: @@ -221,11 +220,11 @@ class DatabaseCreation(BaseDatabaseCreation): def _test_database_create(self, settings): name = True try: - if settings.TEST_DATABASE_CREATE: + if self.connection.setting_dict['TEST_DATABASE_CREATE']: name = True else: name = False - except AttributeError: + except KeyError: pass except: raise @@ -234,32 +233,32 @@ class DatabaseCreation(BaseDatabaseCreation): def _test_user_create(self, settings): name = True try: - if settings.TEST_USER_CREATE: + if self.connection.settings_dict['TEST_USER_CREATE']: name = True else: name = False - except AttributeError: + except KeyError: pass except: raise return name - def _test_database_user(self, settings): - name = TEST_DATABASE_PREFIX + settings.DATABASE_USER + def _test_database_user(self): + name = TEST_DATABASE_PREFIX + self.settings_dict['DATABASE_USER'] try: - if settings.TEST_DATABASE_USER: - name = settings.TEST_DATABASE_USER + if self.connection.settings_dict['TEST_DATABASE_USER']: + name = self.connection.settings_dict['TEST_DATABASE_USER'] except AttributeError: pass except: raise return name - def _test_database_passwd(self, settings): + def _test_database_passwd(self): name = PASSWORD try: - if settings.TEST_DATABASE_PASSWD: - name = settings.TEST_DATABASE_PASSWD + if self.connection.settings_dict['TEST_DATABASE_PASSWD']: + name = self.connection.settings_dict['TEST_DATABASE_PASSWD'] except AttributeError: pass except: @@ -267,10 +266,10 @@ class DatabaseCreation(BaseDatabaseCreation): return name def _test_database_tblspace(self, settings): - name = TEST_DATABASE_PREFIX + settings.DATABASE_NAME + name = TEST_DATABASE_PREFIX + self.connection.settings_dict['DATABASE_NAME'] try: - if settings.TEST_DATABASE_TBLSPACE: - name = settings.TEST_DATABASE_TBLSPACE + if self.connection.settings_dict['TEST_DATABASE_TBLSPACE']: + name = self.connection.settings_dict['TEST_DATABASE_TBLSPACE'] except AttributeError: pass except: @@ -278,10 +277,10 @@ class DatabaseCreation(BaseDatabaseCreation): return name def _test_database_tblspace_tmp(self, settings): - name = TEST_DATABASE_PREFIX + settings.DATABASE_NAME + '_temp' + name = TEST_DATABASE_PREFIX + self.connection.settings_dict['DATABASE_NAME'] + '_temp' try: - if settings.TEST_DATABASE_TBLSPACE_TMP: - name = settings.TEST_DATABASE_TBLSPACE_TMP + if self.connection.settings_dict['TEST_DATABASE_TBLSPACE_TMP']: + name = self.connection.settings_dict['TEST_DATABASE_TBLSPACE_TMP'] except AttributeError: pass except: diff --git a/django/db/backends/postgresql/base.py b/django/db/backends/postgresql/base.py index 19d5ea74d8..84429dc45d 100644 --- a/django/db/backends/postgresql/base.py +++ b/django/db/backends/postgresql/base.py @@ -94,7 +94,7 @@ class DatabaseWrapper(BaseDatabaseWrapper): self.client = DatabaseClient(self) self.creation = DatabaseCreation(self) self.introspection = DatabaseIntrospection(self) - self.validation = BaseDatabaseValidation() + self.validation = BaseDatabaseValidation(self) def _cursor(self): set_tz = False diff --git a/django/db/backends/postgresql/creation.py b/django/db/backends/postgresql/creation.py index 8f329feca4..7e1b8a8a58 100644 --- a/django/db/backends/postgresql/creation.py +++ b/django/db/backends/postgresql/creation.py @@ -1,4 +1,3 @@ -from django.conf import settings from django.db.backends.creation import BaseDatabaseCreation class DatabaseCreation(BaseDatabaseCreation): @@ -30,7 +29,7 @@ class DatabaseCreation(BaseDatabaseCreation): } def sql_table_creation_suffix(self): - assert settings.TEST_DATABASE_COLLATION is None, "PostgreSQL does not support collation setting at database creation time." - if settings.TEST_DATABASE_CHARSET: - return "WITH ENCODING '%s'" % settings.TEST_DATABASE_CHARSET + assert self.connection.settings_dict['TEST_DATABASE_COLLATION'] is None, "PostgreSQL does not support collation setting at database creation time." + if self.connection.settings_dict['TEST_DATABASE_CHARSET']: + return "WITH ENCODING '%s'" % self.connection.settings_dict['TEST_DATABASE_CHARSET'] return '' diff --git a/django/db/backends/postgresql_psycopg2/base.py b/django/db/backends/postgresql_psycopg2/base.py index d4ad3da646..3d804f09b9 100644 --- a/django/db/backends/postgresql_psycopg2/base.py +++ b/django/db/backends/postgresql_psycopg2/base.py @@ -4,7 +4,6 @@ PostgreSQL database backend for Django. Requires psycopg 2: http://initd.org/projects/psycopg2 """ -from django.conf import settings from django.db.backends import * from django.db.backends.signals import connection_created from django.db.backends.postgresql.operations import DatabaseOperations as PostgresqlDatabaseOperations @@ -71,7 +70,7 @@ class DatabaseWrapper(BaseDatabaseWrapper): self.client = DatabaseClient(self) self.creation = DatabaseCreation(self) self.introspection = DatabaseIntrospection(self) - self.validation = BaseDatabaseValidation() + self.validation = BaseDatabaseValidation(self) def _cursor(self): set_tz = False @@ -150,4 +149,3 @@ class DatabaseWrapper(BaseDatabaseWrapper): finally: self.isolation_level = level self.features.uses_savepoints = bool(level) - diff --git a/django/db/backends/sqlite3/base.py b/django/db/backends/sqlite3/base.py index f9be87d00a..d7781d0cd9 100644 --- a/django/db/backends/sqlite3/base.py +++ b/django/db/backends/sqlite3/base.py @@ -154,7 +154,7 @@ class DatabaseWrapper(BaseDatabaseWrapper): self.client = DatabaseClient(self) self.creation = DatabaseCreation(self) self.introspection = DatabaseIntrospection(self) - self.validation = BaseDatabaseValidation() + self.validation = BaseDatabaseValidation(self) def _cursor(self): if self.connection is None: diff --git a/django/db/backends/sqlite3/creation.py b/django/db/backends/sqlite3/creation.py index e9e0a94634..05d7f8e4ce 100644 --- a/django/db/backends/sqlite3/creation.py +++ b/django/db/backends/sqlite3/creation.py @@ -1,6 +1,5 @@ import os import sys -from django.conf import settings from django.db.backends.creation import BaseDatabaseCreation class DatabaseCreation(BaseDatabaseCreation): @@ -29,7 +28,7 @@ class DatabaseCreation(BaseDatabaseCreation): 'TextField': 'text', 'TimeField': 'time', } - + def sql_for_pending_references(self, model, style, pending_references): "SQLite3 doesn't support constraints" return [] @@ -37,10 +36,10 @@ class DatabaseCreation(BaseDatabaseCreation): def sql_remove_table_constraints(self, model, references_to_delete, style): "SQLite3 doesn't support constraints" return [] - + def _create_test_db(self, verbosity, autoclobber): - if settings.TEST_DATABASE_NAME and settings.TEST_DATABASE_NAME != ":memory:": - test_database_name = settings.TEST_DATABASE_NAME + test_database_name = self.connection.settings_dict['TEST_DATABASE_NAME'] + if test_database_name and test_database_name != ":memory:": # Erase the old test database if verbosity >= 1: print "Destroying old test database..." @@ -63,7 +62,7 @@ class DatabaseCreation(BaseDatabaseCreation): else: test_database_name = ":memory:" return test_database_name - + def _destroy_test_db(self, test_database_name, verbosity): if test_database_name and test_database_name != ":memory:": # Remove the SQLite database file diff --git a/django/test/testcases.py b/django/test/testcases.py index 8c73c63796..fa319b3c09 100644 --- a/django/test/testcases.py +++ b/django/test/testcases.py @@ -436,7 +436,7 @@ class TestCase(TransactionTestCase): """ def _fixture_setup(self): - if not settings.DATABASE_SUPPORTS_TRANSACTIONS: + if not connection.settings_dict['DATABASE_SUPPORTS_TRANSACTIONS']: return super(TestCase, self)._fixture_setup() transaction.enter_transaction_management() @@ -453,7 +453,7 @@ class TestCase(TransactionTestCase): }) def _fixture_teardown(self): - if not settings.DATABASE_SUPPORTS_TRANSACTIONS: + if not connection.settings_dict['DATABASE_SUPPORTS_TRANSACTIONS']: return super(TestCase, self)._fixture_teardown() restore_transaction_methods()