From 4e36fffab2d1b47c10bcf462d9309d40e63dabb9 Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Mon, 23 Nov 2009 16:45:41 +0000 Subject: [PATCH] [soc2009/multidb] Renaming of database attributes - you now use NAME, ENGINE, etc rather than DATABASE_NAME, DATABASE_ENGINE inside DATABASES. Also deprecates the use of short names (.e.g., ``sqlite3`` for backends in ENGINE). Patch from Russell Keith-Magee. Conflicts: docs/releases/1.2.txt git-svn-id: http://code.djangoproject.com/svn/django/branches/soc2009/multidb@11775 bcc190cf-cafb-0310-a4f2-bffc1f526a37 --- TODO | 3 - django/conf/project_template/settings.py | 13 +- django/contrib/localflavor/us/models.py | 4 +- django/core/management/commands/flush.py | 4 +- django/core/management/commands/reset.py | 2 +- django/core/management/sql.py | 12 +- django/db/__init__.py | 37 ++-- django/db/backends/__init__.py | 5 +- django/db/backends/creation.py | 17 +- django/db/backends/dummy/base.py | 4 +- django/db/backends/mysql/base.py | 26 +-- django/db/backends/mysql/client.py | 12 +- django/db/backends/mysql/creation.py | 8 +- django/db/backends/oracle/base.py | 20 +- django/db/backends/oracle/creation.py | 92 ++++----- django/db/backends/postgresql/base.py | 26 +-- django/db/backends/postgresql/client.py | 14 +- django/db/backends/postgresql/creation.py | 6 +- .../db/backends/postgresql_psycopg2/base.py | 26 +-- django/db/backends/sqlite3/base.py | 10 +- django/db/backends/sqlite3/client.py | 2 +- django/db/backends/sqlite3/creation.py | 2 +- django/db/utils.py | 29 +-- django/test/simple.py | 2 +- django/test/testcases.py | 2 +- django/views/debug.py | 2 +- docs/howto/custom-model-fields.txt | 4 +- docs/howto/initial-data.txt | 34 ++-- docs/howto/legacy-databases.txt | 16 +- docs/internals/contributing.txt | 24 +-- docs/intro/tutorial01.txt | 47 +++-- docs/man/django-admin.1 | 4 +- docs/ref/databases.txt | 87 ++++---- docs/ref/django-admin.txt | 6 +- docs/ref/settings.txt | 185 ++++++++++++++---- docs/releases/0.96.txt | 30 +-- docs/releases/1.2.txt | 75 +++++++ docs/topics/testing.txt | 79 ++++---- tests/modeltests/basic/models.py | 4 +- tests/modeltests/custom_pk/models.py | 2 +- tests/modeltests/fixtures/models.py | 2 +- tests/modeltests/lookup/models.py | 6 +- tests/modeltests/transactions/models.py | 2 +- tests/regressiontests/admin_scripts/tests.py | 23 +-- .../aggregation_regress/models.py | 2 +- tests/regressiontests/backends/tests.py | 6 +- tests/regressiontests/datatypes/models.py | 2 +- .../regressiontests/delete_regress/models.py | 14 +- .../expressions_regress/models.py | 2 +- .../fixtures_regress/models.py | 2 +- tests/regressiontests/introspection/tests.py | 2 +- tests/regressiontests/model_regress/models.py | 4 +- tests/regressiontests/queries/models.py | 4 +- .../serializers_regress/tests.py | 4 +- tests/runtests.py | 1 - 55 files changed, 628 insertions(+), 425 deletions(-) diff --git a/TODO b/TODO index cb53fb88fd..82fdfcd9f4 100644 --- a/TODO +++ b/TODO @@ -7,9 +7,6 @@ Required for v1.2 * Finalize the sql.Query internals * Clean up the use of db.backend.query_class() * Verify it still works with GeoDjango - * Resolve the public facing UI issues around using multi-db - * Should we take the opportunity to modify DB backends to use fully qualified paths? - * Should we clean up DATABASES['DATABASE_NAME'] to DATABASES['NAME'] etc? * Cleanup of new API entry points * validate() on a field * name/purpose clash with Honza? diff --git a/django/conf/project_template/settings.py b/django/conf/project_template/settings.py index 7038bba56e..7cba5de26d 100644 --- a/django/conf/project_template/settings.py +++ b/django/conf/project_template/settings.py @@ -11,16 +11,15 @@ MANAGERS = ADMINS DATABASES = { 'default': { - 'DATABASE_ENGINE': '', # 'postgresql_psycopg2', 'postgresql', 'mysql', 'sqlite3' or 'oracle'. - 'DATABASE_NAME': '', # Or path to database file if using sqlite3. - 'DATABASE_USER': '', # Not used with sqlite3. - 'DATABASE_PASSWORD': '', # Not used with sqlite3. - 'DATABASE_HOST': '', # Set to empty string for localhost. Not used with sqlite3. - 'DATABASE_PORT': '', # Set to empty string for default. Not used with sqlite3. + 'ENGINE': 'django.db.backends.', # Add 'postgresql_psycopg2', 'postgresql', 'mysql', 'sqlite3' or 'oracle'. + 'NAME': '', # Or path to database file if using sqlite3. + 'USER': '', # Not used with sqlite3. + 'PASSWORD': '', # Not used with sqlite3. + 'HOST': '', # Set to empty string for localhost. Not used with sqlite3. + 'PORT': '', # Set to empty string for default. Not used with sqlite3. } } - # Local time zone for this installation. Choices can be found here: # http://en.wikipedia.org/wiki/List_of_tz_zones_by_name # although not all choices may be available on all operating systems. diff --git a/django/contrib/localflavor/us/models.py b/django/contrib/localflavor/us/models.py index 444035b251..209bb9051e 100644 --- a/django/contrib/localflavor/us/models.py +++ b/django/contrib/localflavor/us/models.py @@ -5,7 +5,7 @@ class USStateField(Field): return "USStateField" def db_type(self, connection): - if connection.settings_dict['DATABASE_ENGINE'] == 'oracle': + if connection.settings_dict['ENGINE'] == 'django.db.backends.oracle': return 'CHAR(2)' else: return 'varchar(2)' @@ -21,7 +21,7 @@ class PhoneNumberField(Field): return "PhoneNumberField" def db_type(self, connection): - if connection.settings_dict['DATABASE_ENGINE'] == 'oracle': + if connection.settings_dict['ENGINE'] == 'django.db.backends.oracle': return 'VARCHAR2(20)' else: return 'varchar(20)' diff --git a/django/core/management/commands/flush.py b/django/core/management/commands/flush.py index 12967690c0..c94072fd02 100644 --- a/django/core/management/commands/flush.py +++ b/django/core/management/commands/flush.py @@ -49,7 +49,7 @@ class Command(NoArgsCommand): and return each table to the state it was in after syncdb. Are you sure you want to do this? - Type 'yes' to continue, or 'no' to cancel: """ % connection.settings_dict['DATABASE_NAME']) + Type 'yes' to continue, or 'no' to cancel: """ % connection.settings_dict['NAME']) else: confirm = 'yes' @@ -65,7 +65,7 @@ class Command(NoArgsCommand): * At least one of the expected database tables doesn't exist. * The SQL was invalid. Hint: Look at the output of 'django-admin.py sqlflush'. That's the SQL this command wasn't able to run. - The full error: %s""" % (connection.settings_dict.DATABASE_NAME, e)) + The full error: %s""" % (connection.settings_dict['NAME'], e)) transaction.commit_unless_managed(using=db) # Emit the post sync signal. This allows individual diff --git a/django/core/management/commands/reset.py b/django/core/management/commands/reset.py index b46251b7b3..9b43a6b6d0 100644 --- a/django/core/management/commands/reset.py +++ b/django/core/management/commands/reset.py @@ -35,7 +35,7 @@ This will IRREVERSIBLY DESTROY any data for the "%s" application in the database "%s". Are you sure you want to do this? -Type 'yes' to continue, or 'no' to cancel: """ % (app_name, connection.settings_dict['DATABASE_NAME'])) +Type 'yes' to continue, or 'no' to cancel: """ % (app_name, connection.settings_dict['NAME'])) else: confirm = 'yes' diff --git a/django/core/management/sql.py b/django/core/management/sql.py index 7025586693..93a76f1c18 100644 --- a/django/core/management/sql.py +++ b/django/core/management/sql.py @@ -17,12 +17,13 @@ except NameError: def sql_create(app, style, connection): "Returns a list of the CREATE TABLE SQL statements for the given app." - if connection.settings_dict['DATABASE_ENGINE'] == 'dummy': + if connection.settings_dict['ENGINE'] == 'django.db.backends.dummy': # This must be the "dummy" database backend, which means the user - # hasn't set DATABASE_ENGINE. + # hasn't set ENGINE for the databse. raise CommandError("Django doesn't know which syntax to use for your SQL statements,\n" + - "because you haven't specified the DATABASE_ENGINE setting.\n" + - "Edit your settings file and change DATABASE_ENGINE to something like 'postgresql' or 'mysql'.") + "because you haven't specified the ENGINE setting for the database.\n" + + "Edit your settings file and change DATBASES['default']['ENGINE'] to something like\n" + + "'django.db.backends.postgresql' or 'django.db.backends.mysql'") # Get installed models, so we generate REFERENCES right. # We trim models from the current app so that the sqlreset command does not @@ -162,7 +163,8 @@ def custom_sql_for_model(model, style, connection): statements = re.compile(r";[ \t]*$", re.M) # Find custom SQL, if it's available. - sql_files = [os.path.join(app_dir, "%s.%s.sql" % (opts.object_name.lower(), connection.settings_dict['DATABASE_ENGINE'])), + backend_name = connection.settings_dict['ENGINE'].split('.')[-1] + sql_files = [os.path.join(app_dir, "%s.%s.sql" % (opts.object_name.lower(), backend_name)), os.path.join(app_dir, "%s.sql" % opts.object_name.lower())] for sql_file in sql_files: if os.path.exists(sql_file): diff --git a/django/db/__init__.py b/django/db/__init__.py index 2bb9cfafcd..216405e48e 100644 --- a/django/db/__init__.py +++ b/django/db/__init__.py @@ -9,22 +9,31 @@ __all__ = ('backend', 'connection', 'connections', 'DatabaseError', 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, - 'DATABASE_OPTIONS': settings.DATABASE_OPTIONS, - 'DATABASE_PASSWORD': settings.DATABASE_PASSWORD, - 'DATABASE_PORT': settings.DATABASE_PORT, - 'DATABASE_USER': settings.DATABASE_USER, - 'TIME_ZONE': settings.TIME_ZONE, +# For backwards compatibility - Port any old database settings over to +# the new values. +if not settings.DATABASES: + import warnings + warnings.warn( + "settings.DATABASE_* is deprecated; use settings.DATABASES instead.", + PendingDeprecationWarning + ) - 'TEST_DATABASE_CHARSET': settings.TEST_DATABASE_CHARSET, - 'TEST_DATABASE_COLLATION': settings.TEST_DATABASE_COLLATION, - 'TEST_DATABASE_NAME': settings.TEST_DATABASE_NAME, + settings.DATABASES[DEFAULT_DB_ALIAS] = { + 'ENGINE': settings.DATABASE_ENGINE, + 'HOST': settings.DATABASE_HOST, + 'NAME': settings.DATABASE_NAME, + 'OPTIONS': settings.DATABASE_OPTIONS, + 'PASSWORD': settings.DATABASE_PASSWORD, + 'PORT': settings.DATABASE_PORT, + 'USER': settings.DATABASE_USER, + 'TEST_CHARSET': settings.TEST_DATABASE_CHARSET, + 'TEST_COLLATION': settings.TEST_DATABASE_COLLATION, + 'TEST_NAME': settings.TEST_DATABASE_NAME, } +if DEFAULT_DB_ALIAS not in settings.DATABASES: + raise ImproperlyConfigured("You must default a '%s' database" % DEFAULT_DB_ALIAS) + connections = ConnectionHandler(settings.DATABASES) @@ -38,7 +47,7 @@ connections = ConnectionHandler(settings.DATABASES) # we load all these up for backwards compatibility, you should use # connections['default'] instead. connection = connections[DEFAULT_DB_ALIAS] -backend = load_backend(connection.settings_dict['DATABASE_ENGINE']) +backend = load_backend(connection.settings_dict['ENGINE']) DatabaseError = backend.DatabaseError IntegrityError = backend.IntegrityError diff --git a/django/db/backends/__init__.py b/django/db/backends/__init__.py index 966ab0354e..e64e1d8318 100644 --- a/django/db/backends/__init__.py +++ b/django/db/backends/__init__.py @@ -29,9 +29,8 @@ class BaseDatabaseWrapper(local): def __init__(self, settings_dict, alias=DEFAULT_DB_ALIAS): # `settings_dict` should be a dictionary containing keys such as - # DATABASE_NAME, DATABASE_USER, etc. It's called `settings_dict` - # instead of `settings` to disambiguate it from Django settings - # modules. + # NAME, USER, etc. It's called `settings_dict` instead of `settings` + # to disambiguate it from Django settings modules. self.connection = None self.queries = [] self.settings_dict = settings_dict diff --git a/django/db/backends/creation.py b/django/db/backends/creation.py index 6de9484324..46e243aaf8 100644 --- a/django/db/backends/creation.py +++ b/django/db/backends/creation.py @@ -327,13 +327,10 @@ class BaseDatabaseCreation(object): test_database_name = self._create_test_db(verbosity, autoclobber) self.connection.close() - self.connection.settings_dict["DATABASE_NAME"] = test_database_name + self.connection.settings_dict["NAME"] = test_database_name can_rollback = self._rollback_works() - self.connection.settings_dict["DATABASE_SUPPORTS_TRANSACTIONS"] = can_rollback + self.connection.settings_dict["SUPPORTS_TRANSACTIONS"] = can_rollback - # FIXME we end up loading the same fixture into the default DB for each - # DB we have, this causes various test failures, but can't really be - # fixed until we have an API for saving to a specific DB call_command('syncdb', verbosity=verbosity, interactive=False, database=self.connection.alias) if settings.CACHE_BACKEND.startswith('db://'): @@ -351,10 +348,10 @@ class BaseDatabaseCreation(object): "Internal implementation - creates the test db tables." suffix = self.sql_table_creation_suffix() - if self.connection.settings_dict['TEST_DATABASE_NAME']: - test_database_name = self.connection.settings_dict['TEST_DATABASE_NAME'] + if self.connection.settings_dict['TEST_NAME']: + test_database_name = self.connection.settings_dict['TEST_NAME'] else: - test_database_name = TEST_DATABASE_PREFIX + self.connection.settings_dict['DATABASE_NAME'] + test_database_name = TEST_DATABASE_PREFIX + self.connection.settings_dict['NAME'] qn = self.connection.ops.quote_name @@ -406,8 +403,8 @@ class BaseDatabaseCreation(object): if verbosity >= 1: print "Destroying test database '%s'..." % self.connection.alias self.connection.close() - test_database_name = self.connection.settings_dict['DATABASE_NAME'] - self.connection.settings_dict['DATABASE_NAME'] = old_database_name + test_database_name = self.connection.settings_dict['NAME'] + self.connection.settings_dict['NAME'] = old_database_name self._destroy_test_db(test_database_name, verbosity) diff --git a/django/db/backends/dummy/base.py b/django/db/backends/dummy/base.py index a6d9092478..e3ab4564ea 100644 --- a/django/db/backends/dummy/base.py +++ b/django/db/backends/dummy/base.py @@ -1,7 +1,7 @@ """ Dummy database backend for Django. -Django uses this if the DATABASE_ENGINE setting is empty (None or empty string). +Django uses this if the database ENGINE setting is empty (None or empty string). Each of these API functions, except connection.close(), raises ImproperlyConfigured. @@ -12,7 +12,7 @@ from django.db.backends import * from django.db.backends.creation import BaseDatabaseCreation def complain(*args, **kwargs): - raise ImproperlyConfigured, "You haven't set the DATABASE_ENGINE setting yet." + raise ImproperlyConfigured, "You haven't set the database ENGINE setting yet." def ignore(*args, **kwargs): pass diff --git a/django/db/backends/mysql/base.py b/django/db/backends/mysql/base.py index bd3e551ed9..5c6abce8aa 100644 --- a/django/db/backends/mysql/base.py +++ b/django/db/backends/mysql/base.py @@ -262,22 +262,22 @@ class DatabaseWrapper(BaseDatabaseWrapper): 'use_unicode': True, } settings_dict = self.settings_dict - if settings_dict['DATABASE_USER']: - kwargs['user'] = settings_dict['DATABASE_USER'] - if settings_dict['DATABASE_NAME']: - kwargs['db'] = settings_dict['DATABASE_NAME'] - if settings_dict['DATABASE_PASSWORD']: - kwargs['passwd'] = settings_dict['DATABASE_PASSWORD'] - if settings_dict['DATABASE_HOST'].startswith('/'): - kwargs['unix_socket'] = settings_dict['DATABASE_HOST'] - elif settings_dict['DATABASE_HOST']: - kwargs['host'] = settings_dict['DATABASE_HOST'] - if settings_dict['DATABASE_PORT']: - kwargs['port'] = int(settings_dict['DATABASE_PORT']) + if settings_dict['USER']: + kwargs['user'] = settings_dict['USER'] + if settings_dict['NAME']: + kwargs['db'] = settings_dict['NAME'] + if settings_dict['PASSWORD']: + kwargs['passwd'] = settings_dict['PASSWORD'] + if settings_dict['HOST'].startswith('/'): + kwargs['unix_socket'] = settings_dict['HOST'] + elif settings_dict['HOST']: + kwargs['host'] = settings_dict['HOST'] + if settings_dict['PORT']: + kwargs['port'] = int(settings_dict['PORT']) # We need the number of potentially affected rows after an # "UPDATE", not the number of changed rows. kwargs['client_flag'] = CLIENT.FOUND_ROWS - kwargs.update(settings_dict['DATABASE_OPTIONS']) + kwargs.update(settings_dict['OPTIONS']) self.connection = Database.connect(**kwargs) self.connection.encoders[SafeUnicode] = self.connection.encoders[unicode] self.connection.encoders[SafeString] = self.connection.encoders[str] diff --git a/django/db/backends/mysql/client.py b/django/db/backends/mysql/client.py index 3743225957..ff5b64d1e0 100644 --- a/django/db/backends/mysql/client.py +++ b/django/db/backends/mysql/client.py @@ -9,12 +9,12 @@ class DatabaseClient(BaseDatabaseClient): def runshell(self): settings_dict = self.connection.settings_dict args = [self.executable_name] - db = settings_dict['DATABASE_OPTIONS'].get('db', settings_dict['DATABASE_NAME']) - user = settings_dict['DATABASE_OPTIONS'].get('user', settings_dict['DATABASE_USER']) - passwd = settings_dict['DATABASE_OPTIONS'].get('passwd', settings_dict['DATABASE_PASSWORD']) - host = settings_dict['DATABASE_OPTIONS'].get('host', settings_dict['DATABASE_HOST']) - port = settings_dict['DATABASE_OPTIONS'].get('port', settings_dict['DATABASE_PORT']) - defaults_file = settings_dict['DATABASE_OPTIONS'].get('read_default_file') + db = settings_dict['OPTIONS'].get('db', settings_dict['NAME']) + user = settings_dict['OPTIONS'].get('user', settings_dict['USER']) + passwd = settings_dict['OPTIONS'].get('passwd', settings_dict['PASSWORD']) + host = settings_dict['OPTIONS'].get('host', settings_dict['HOST']) + port = settings_dict['OPTIONS'].get('port', settings_dict['PORT']) + defaults_file = settings_dict['OPTIONS'].get('read_default_file') # Seems to be no good way to set sql_mode with CLI. if defaults_file: diff --git a/django/db/backends/mysql/creation.py b/django/db/backends/mysql/creation.py index f4a86027ea..f6243d5d91 100644 --- a/django/db/backends/mysql/creation.py +++ b/django/db/backends/mysql/creation.py @@ -30,10 +30,10 @@ class DatabaseCreation(BaseDatabaseCreation): def sql_table_creation_suffix(self): suffix = [] - 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']) + if self.connection.settings_dict['TEST_CHARSET']: + suffix.append('CHARACTER SET %s' % self.connection.settings_dict['TEST_CHARSET']) + if self.connection.settings_dict['TEST_COLLATION']: + suffix.append('COLLATE %s' % self.connection.settings_dict['TEST_COLLATION']) return ' '.join(suffix) def sql_for_inline_foreign_key_references(self, field, known_models, style): diff --git a/django/db/backends/oracle/base.py b/django/db/backends/oracle/base.py index e9b952138d..cc85685e5b 100644 --- a/django/db/backends/oracle/base.py +++ b/django/db/backends/oracle/base.py @@ -342,22 +342,22 @@ class DatabaseWrapper(BaseDatabaseWrapper): def _connect_string(self): settings_dict = self.settings_dict - if len(settings_dict['DATABASE_HOST'].strip()) == 0: - settings_dict['DATABASE_HOST'] = 'localhost' - if len(settings_dict['DATABASE_PORT'].strip()) != 0: - dsn = Database.makedsn(settings_dict['DATABASE_HOST'], - int(settings_dict['DATABASE_PORT']), - settings_dict['DATABASE_NAME']) + if len(settings_dict['HOST'].strip()) == 0: + settings_dict['HOST'] = 'localhost' + if len(settings_dict['PORT'].strip()) != 0: + dsn = Database.makedsn(settings_dict['HOST'], + int(settings_dict['PORT']), + settings_dict['NAME']) else: - dsn = settings_dict['DATABASE_NAME'] - return "%s/%s@%s" % (settings_dict['DATABASE_USER'], - settings_dict['DATABASE_PASSWORD'], dsn) + dsn = settings_dict['NAME'] + return "%s/%s@%s" % (settings_dict['USER'], + settings_dict['PASSWORD'], dsn) def _cursor(self): cursor = None if not self._valid_connection(): conn_string = convert_unicode(self._connect_string()) - self.connection = Database.connect(conn_string, **self.settings_dict['DATABASE_OPTIONS']) + self.connection = Database.connect(conn_string, **self.settings_dict['OPTIONS']) cursor = FormatStylePlaceholderCursor(self.connection) # Set oracle date to ansi date format. This only needs to execute # once when we create a new connection. We also set the Territory diff --git a/django/db/backends/oracle/creation.py b/django/db/backends/oracle/creation.py index 685708aaea..1b13f7b27c 100644 --- a/django/db/backends/oracle/creation.py +++ b/django/db/backends/oracle/creation.py @@ -41,22 +41,22 @@ class DatabaseCreation(BaseDatabaseCreation): remember = {} def _create_test_db(self, verbosity=1, autoclobber=False): - 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() + TEST_NAME = self._test_database_name() + TEST_USER = self._test_database_user() + TEST_PASSWD = self._test_database_passwd() + TEST_TBLSPACE = self._test_database_tblspace() + TEST_TBLSPACE_TMP = self._test_database_tblspace_tmp() parameters = { - 'dbname': TEST_DATABASE_NAME, - 'user': TEST_DATABASE_USER, - 'password': TEST_DATABASE_PASSWD, - 'tblspace': TEST_DATABASE_TBLSPACE, - 'tblspace_temp': TEST_DATABASE_TBLSPACE_TMP, + 'dbname': TEST_NAME, + 'user': TEST_USER, + 'password': TEST_PASSWD, + 'tblspace': TEST_TBLSPACE, + 'tblspace_temp': TEST_TBLSPACE_TMP, } - self.remember['user'] = self.connection.settings_dict['DATABASE_USER'] - self.remember['passwd'] = self.connection.settings_dict['DATABASE_PASSWORD'] + self.remember['user'] = self.connection.settings_dict['USER'] + self.remember['passwd'] = self.connection.settings_dict['PASSWORD'] cursor = self.connection.cursor() if self._test_database_create(): @@ -67,7 +67,7 @@ class DatabaseCreation(BaseDatabaseCreation): except Exception, e: sys.stderr.write("Got an error creating the test database: %s\n" % e) if not autoclobber: - confirm = raw_input("It appears the test database, %s, already exists. Type 'yes' to delete it, or 'no' to cancel: " % TEST_DATABASE_NAME) + confirm = raw_input("It appears the test database, %s, already exists. Type 'yes' to delete it, or 'no' to cancel: " % TEST_NAME) if autoclobber or confirm == 'yes': try: if verbosity >= 1: @@ -91,7 +91,7 @@ class DatabaseCreation(BaseDatabaseCreation): except Exception, e: sys.stderr.write("Got an error creating the test user: %s\n" % e) if not autoclobber: - confirm = raw_input("It appears the test user, %s, already exists. Type 'yes' to delete it, or 'no' to cancel: " % TEST_DATABASE_USER) + confirm = raw_input("It appears the test user, %s, already exists. Type 'yes' to delete it, or 'no' to cancel: " % TEST_USER) if autoclobber or confirm == 'yes': try: if verbosity >= 1: @@ -107,35 +107,35 @@ class DatabaseCreation(BaseDatabaseCreation): print "Tests cancelled." sys.exit(1) - 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 + self.connection.settings_dict['TEST_USER'] = self.connection.settings_dict["USER"] = TEST_USER + self.connection.settings_dict["PASSWORD"] = TEST_PASSWD - return self.connection.settings_dict['DATABASE_NAME'] + return self.connection.settings_dict['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() - 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() + TEST_NAME = self._test_database_name() + TEST_USER = self._test_database_user() + TEST_PASSWD = self._test_database_passwd() + TEST_TBLSPACE = self._test_database_tblspace() + TEST_TBLSPACE_TMP = self._test_database_tblspace_tmp() - self.connection.settings_dict["DATABASE_USER"] = self.remember['user'] - self.connection.settings_dict["DATABASE_PASSWORD"] = self.remember['passwd'] + self.connection.settings_dict["USER"] = self.remember['user'] + self.connection.settings_dict["PASSWORD"] = self.remember['passwd'] parameters = { - 'dbname': TEST_DATABASE_NAME, - 'user': TEST_DATABASE_USER, - 'password': TEST_DATABASE_PASSWD, - 'tblspace': TEST_DATABASE_TBLSPACE, - 'tblspace_temp': TEST_DATABASE_TBLSPACE_TMP, + 'dbname': TEST_NAME, + 'user': TEST_USER, + 'password': TEST_PASSWD, + 'tblspace': TEST_TBLSPACE, + 'tblspace_temp': TEST_TBLSPACE_TMP, } - self.remember['user'] = self.connection.settings_dict['DATABASE_USER'] - self.remember['passwd'] = self.connection.settings_dict['DATABASE_PASSWORD'] + self.remember['user'] = self.connection.settings_dict['USER'] + self.remember['passwd'] = self.connection.settings_dict['PASSWORD'] cursor = self.connection.cursor() time.sleep(1) # To avoid "database is being accessed by other users" errors. @@ -207,10 +207,10 @@ class DatabaseCreation(BaseDatabaseCreation): raise def _test_database_name(self): - name = TEST_DATABASE_PREFIX + self.connection.settings_dict['DATABASE_NAME'] + name = TEST_DATABASE_PREFIX + self.connection.settings_dict['NAME'] try: - if self.connection.settings_dict['TEST_DATABASE_NAME']: - name = self.connection.settings_dict['TEST_DATABASE_NAME'] + if self.connection.settings_dict['TEST_NAME']: + name = self.connection.settings_dict['TEST_NAME'] except AttributeError: pass except: @@ -220,7 +220,7 @@ class DatabaseCreation(BaseDatabaseCreation): def _test_database_create(self): name = True try: - if self.connection.settings_dict['TEST_DATABASE_CREATE']: + if self.connection.settings_dict['TEST_CREATE']: name = True else: name = False @@ -244,10 +244,10 @@ class DatabaseCreation(BaseDatabaseCreation): return name def _test_database_user(self): - name = TEST_DATABASE_PREFIX + self.connection.settings_dict['DATABASE_USER'] + name = TEST_DATABASE_PREFIX + self.connection.settings_dict['USER'] try: - if self.connection.settings_dict['TEST_DATABASE_USER']: - name = self.connection.settings_dict['TEST_DATABASE_USER'] + if self.connection.settings_dict['TEST_USER']: + name = self.connection.settings_dict['TEST_USER'] except KeyError: pass except: @@ -257,8 +257,8 @@ class DatabaseCreation(BaseDatabaseCreation): def _test_database_passwd(self): name = PASSWORD try: - if self.connection.settings_dict['TEST_DATABASE_PASSWD']: - name = self.connection.settings_dict['TEST_DATABASE_PASSWD'] + if self.connection.settings_dict['TEST_PASSWD']: + name = self.connection.settings_dict['TEST_PASSWD'] except KeyError: pass except: @@ -266,10 +266,10 @@ class DatabaseCreation(BaseDatabaseCreation): return name def _test_database_tblspace(self): - name = TEST_DATABASE_PREFIX + self.connection.settings_dict['DATABASE_NAME'] + name = TEST_DATABASE_PREFIX + self.connection.settings_dict['NAME'] try: - if self.connection.settings_dict['TEST_DATABASE_TBLSPACE']: - name = self.connection.settings_dict['TEST_DATABASE_TBLSPACE'] + if self.connection.settings_dict['TEST_TBLSPACE']: + name = self.connection.settings_dict['TEST_TBLSPACE'] except KeyError: pass except: @@ -277,10 +277,10 @@ class DatabaseCreation(BaseDatabaseCreation): return name def _test_database_tblspace_tmp(self): - name = TEST_DATABASE_PREFIX + self.connection.settings_dict['DATABASE_NAME'] + '_temp' + name = TEST_DATABASE_PREFIX + self.connection.settings_dict['NAME'] + '_temp' try: - if self.connection.settings_dict['TEST_DATABASE_TBLSPACE_TMP']: - name = self.connection.settings_dict['TEST_DATABASE_TBLSPACE_TMP'] + if self.connection.settings_dict['TEST_TBLSPACE_TMP']: + name = self.connection.settings_dict['TEST_TBLSPACE_TMP'] except KeyError: pass except: diff --git a/django/db/backends/postgresql/base.py b/django/db/backends/postgresql/base.py index 282606a06d..119df9f171 100644 --- a/django/db/backends/postgresql/base.py +++ b/django/db/backends/postgresql/base.py @@ -101,19 +101,19 @@ class DatabaseWrapper(BaseDatabaseWrapper): settings_dict = self.settings_dict if self.connection is None: set_tz = True - if settings_dict['DATABASE_NAME'] == '': + if settings_dict['NAME'] == '': from django.core.exceptions import ImproperlyConfigured - raise ImproperlyConfigured("You need to specify DATABASE_NAME in your Django settings file.") - conn_string = "dbname=%s" % settings_dict['DATABASE_NAME'] - if settings_dict['DATABASE_USER']: - conn_string = "user=%s %s" % (settings_dict['DATABASE_USER'], conn_string) - if settings_dict['DATABASE_PASSWORD']: - conn_string += " password='%s'" % settings_dict['DATABASE_PASSWORD'] - if settings_dict['DATABASE_HOST']: - conn_string += " host=%s" % settings_dict['DATABASE_HOST'] - if settings_dict['DATABASE_PORT']: - conn_string += " port=%s" % settings_dict['DATABASE_PORT'] - self.connection = Database.connect(conn_string, **settings_dict['DATABASE_OPTIONS']) + raise ImproperlyConfigured("You need to specify NAME in your Django settings file.") + conn_string = "dbname=%s" % settings_dict['NAME'] + if settings_dict['USER']: + conn_string = "user=%s %s" % (settings_dict['USER'], conn_string) + if settings_dict['PASSWORD']: + conn_string += " password='%s'" % settings_dict['PASSWORD'] + if settings_dict['HOST']: + conn_string += " host=%s" % settings_dict['HOST'] + if settings_dict['PORT']: + conn_string += " port=%s" % settings_dict['PORT'] + self.connection = Database.connect(conn_string, **settings_dict['OPTIONS']) self.connection.set_isolation_level(1) # make transactions transparent to all cursors connection_created.send(sender=self.__class__) cursor = self.connection.cursor() @@ -142,7 +142,7 @@ def typecast_string(s): try: Database.register_type(Database.new_type((1082,), "DATE", util.typecast_date)) except AttributeError: - raise Exception("You appear to be using psycopg version 2. Set your DATABASE_ENGINE to 'postgresql_psycopg2' instead of 'postgresql'.") + raise Exception("You appear to be using psycopg version 2. Set your DATABASES.ENGINE to 'postgresql_psycopg2' instead of 'postgresql'.") Database.register_type(Database.new_type((1083,1266), "TIME", util.typecast_time)) Database.register_type(Database.new_type((1114,1184), "TIMESTAMP", util.typecast_timestamp)) Database.register_type(Database.new_type((16,), "BOOLEAN", util.typecast_boolean)) diff --git a/django/db/backends/postgresql/client.py b/django/db/backends/postgresql/client.py index 13273b9fb5..a5c02969ea 100644 --- a/django/db/backends/postgresql/client.py +++ b/django/db/backends/postgresql/client.py @@ -9,13 +9,13 @@ class DatabaseClient(BaseDatabaseClient): def runshell(self): settings_dict = self.connection.settings_dict args = [self.executable_name] - if settings_dict['DATABASE_USER']: - args += ["-U", settings_dict['DATABASE_USER']] - if settings_dict['DATABASE_HOST']: - args.extend(["-h", settings_dict['DATABASE_HOST']]) - if settings_dict['DATABASE_PORT']: - args.extend(["-p", str(settings_dict['DATABASE_PORT'])]) - args += [settings_dict['DATABASE_NAME']] + if settings_dict['USER']: + args += ["-U", settings_dict['USER']] + if settings_dict['HOST']: + args.extend(["-h", settings_dict['HOST']]) + if settings_dict['PORT']: + args.extend(["-p", str(settings_dict['PORT'])]) + args += [settings_dict['NAME']] if os.name == 'nt': sys.exit(os.system(" ".join(args))) else: diff --git a/django/db/backends/postgresql/creation.py b/django/db/backends/postgresql/creation.py index 7e1b8a8a58..fe1b9023b5 100644 --- a/django/db/backends/postgresql/creation.py +++ b/django/db/backends/postgresql/creation.py @@ -29,7 +29,7 @@ class DatabaseCreation(BaseDatabaseCreation): } def sql_table_creation_suffix(self): - 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'] + assert self.connection.settings_dict['TEST_COLLATION'] is None, "PostgreSQL does not support collation setting at database creation time." + if self.connection.settings_dict['TEST_CHARSET']: + return "WITH ENCODING '%s'" % self.connection.settings_dict['TEST_CHARSET'] return '' diff --git a/django/db/backends/postgresql_psycopg2/base.py b/django/db/backends/postgresql_psycopg2/base.py index b2a0e943ef..fcd84cd290 100644 --- a/django/db/backends/postgresql_psycopg2/base.py +++ b/django/db/backends/postgresql_psycopg2/base.py @@ -63,7 +63,7 @@ class DatabaseWrapper(BaseDatabaseWrapper): super(DatabaseWrapper, self).__init__(*args, **kwargs) self.features = DatabaseFeatures() - autocommit = self.settings_dict["DATABASE_OPTIONS"].get('autocommit', False) + autocommit = self.settings_dict["OPTIONS"].get('autocommit', False) self.features.uses_autocommit = autocommit self._set_isolation_level(int(not autocommit)) self.ops = DatabaseOperations(self) @@ -77,23 +77,23 @@ class DatabaseWrapper(BaseDatabaseWrapper): settings_dict = self.settings_dict if self.connection is None: set_tz = True - if settings_dict['DATABASE_NAME'] == '': + if settings_dict['NAME'] == '': from django.core.exceptions import ImproperlyConfigured - raise ImproperlyConfigured("You need to specify DATABASE_NAME in your Django settings file.") + raise ImproperlyConfigured("You need to specify NAME in your Django settings file.") conn_params = { - 'database': settings_dict['DATABASE_NAME'], + 'database': settings_dict['NAME'], } - conn_params.update(settings_dict['DATABASE_OPTIONS']) + conn_params.update(settings_dict['OPTIONS']) if 'autocommit' in conn_params: del conn_params['autocommit'] - if settings_dict['DATABASE_USER']: - conn_params['user'] = settings_dict['DATABASE_USER'] - if settings_dict['DATABASE_PASSWORD']: - conn_params['password'] = settings_dict['DATABASE_PASSWORD'] - if settings_dict['DATABASE_HOST']: - conn_params['host'] = settings_dict['DATABASE_HOST'] - if settings_dict['DATABASE_PORT']: - conn_params['port'] = settings_dict['DATABASE_PORT'] + if settings_dict['USER']: + conn_params['user'] = settings_dict['USER'] + if settings_dict['PASSWORD']: + conn_params['password'] = settings_dict['PASSWORD'] + if settings_dict['HOST']: + conn_params['host'] = settings_dict['HOST'] + if settings_dict['PORT']: + conn_params['port'] = settings_dict['PORT'] self.connection = Database.connect(**conn_params) self.connection.set_client_encoding('UTF8') self.connection.set_isolation_level(self.isolation_level) diff --git a/django/db/backends/sqlite3/base.py b/django/db/backends/sqlite3/base.py index d7781d0cd9..7f31290fe9 100644 --- a/django/db/backends/sqlite3/base.py +++ b/django/db/backends/sqlite3/base.py @@ -159,14 +159,14 @@ class DatabaseWrapper(BaseDatabaseWrapper): def _cursor(self): if self.connection is None: settings_dict = self.settings_dict - if not settings_dict['DATABASE_NAME']: + if not settings_dict['NAME']: from django.core.exceptions import ImproperlyConfigured - raise ImproperlyConfigured, "Please fill out DATABASE_NAME in the settings module before using the database." + raise ImproperlyConfigured, "Please fill out the database NAME in the settings module before using the database." kwargs = { - 'database': settings_dict['DATABASE_NAME'], + 'database': settings_dict['NAME'], 'detect_types': Database.PARSE_DECLTYPES | Database.PARSE_COLNAMES, } - kwargs.update(settings_dict['DATABASE_OPTIONS']) + kwargs.update(settings_dict['OPTIONS']) self.connection = Database.connect(**kwargs) # Register extract, date_trunc, and regexp functions. self.connection.create_function("django_extract", 2, _sqlite_extract) @@ -179,7 +179,7 @@ class DatabaseWrapper(BaseDatabaseWrapper): # If database is in memory, closing the connection destroys the # database. To prevent accidental data loss, ignore close requests on # an in-memory db. - if self.settings_dict['DATABASE_NAME'] != ":memory:": + if self.settings_dict['NAME'] != ":memory:": BaseDatabaseWrapper.close(self) class SQLiteCursorWrapper(Database.Cursor): diff --git a/django/db/backends/sqlite3/client.py b/django/db/backends/sqlite3/client.py index 8836b09899..5b5b7326f2 100644 --- a/django/db/backends/sqlite3/client.py +++ b/django/db/backends/sqlite3/client.py @@ -8,7 +8,7 @@ class DatabaseClient(BaseDatabaseClient): def runshell(self): args = [self.executable_name, - self.connection.settings_dict['DATABASE_NAME']] + self.connection.settings_dict['NAME']] if os.name == 'nt': sys.exit(os.system(" ".join(args))) else: diff --git a/django/db/backends/sqlite3/creation.py b/django/db/backends/sqlite3/creation.py index 05d7f8e4ce..fc4040103c 100644 --- a/django/db/backends/sqlite3/creation.py +++ b/django/db/backends/sqlite3/creation.py @@ -38,7 +38,7 @@ class DatabaseCreation(BaseDatabaseCreation): return [] def _create_test_db(self, verbosity, autoclobber): - test_database_name = self.connection.settings_dict['TEST_DATABASE_NAME'] + test_database_name = self.connection.settings_dict['TEST_NAME'] if test_database_name and test_database_name != ":memory:": # Erase the old test database if verbosity >= 1: diff --git a/django/db/utils.py b/django/db/utils.py index aeee8bbfcb..75ac5726ca 100644 --- a/django/db/utils.py +++ b/django/db/utils.py @@ -6,13 +6,15 @@ from django.utils.importlib import import_module def load_backend(backend_name): try: - # Most of the time, the database backend will be one of the official - # backends that ships with Django, so look there first. - return import_module('.base', 'django.db.backends.%s' % backend_name) + module = import_module('.base', 'django.db.backends.%s' % backend_name) + import warnings + warnings.warn( + "Short names for DATABASE_ENGINE are deprecated; prepend with 'django.db.backends.'", + PendingDeprecationWarning + ) + return module except ImportError, e: - raise - # If the import failed, we might be looking for a database backend - # distributed external to Django. So we'll try that next. + # Look for a fully qualified database backend name try: return import_module('.base', backend_name) except ImportError, e_user: @@ -50,14 +52,13 @@ class ConnectionHandler(object): conn = self.databases[alias] except KeyError: raise ConnectionDoesNotExist("The connection %s doesn't exist" % alias) - conn.setdefault('DATABASE_ENGINE', 'dummy') - conn.setdefault('DATABASE_OPTIONS', {}) - conn.setdefault('TEST_DATABASE_CHARSET', None) - conn.setdefault('TEST_DATABASE_COLLATION', None) - conn.setdefault('TEST_DATABASE_NAME', None) + conn.setdefault('ENGINE', 'dummy') + conn.setdefault('OPTIONS', {}) + conn.setdefault('TEST_CHARSET', None) + conn.setdefault('TEST_COLLATION', None) + conn.setdefault('TEST_NAME', None) conn.setdefault('TIME_ZONE', settings.TIME_ZONE) - for setting in ('DATABASE_NAME', 'DATABASE_USER', 'DATABASE_PASSWORD', - 'DATABASE_HOST', 'DATABASE_PORT'): + for setting in ('NAME', 'USER', 'PASSWORD', 'HOST', 'PORT'): conn.setdefault(setting, '') def __getitem__(self, alias): @@ -66,7 +67,7 @@ class ConnectionHandler(object): self.ensure_defaults(alias) db = self.databases[alias] - backend = load_backend(db['DATABASE_ENGINE']) + backend = load_backend(db['ENGINE']) conn = backend.DatabaseWrapper(db, alias) self._connections[alias] = conn return conn diff --git a/django/test/simple.py b/django/test/simple.py index c850d0634d..4c4d7324f9 100644 --- a/django/test/simple.py +++ b/django/test/simple.py @@ -190,7 +190,7 @@ def run_tests(test_labels, verbosity=1, interactive=True, extra_tests=[]): from django.db import connections for alias in connections: connection = connections[alias] - old_names.append((connection, connection.settings_dict['DATABASE_NAME'])) + old_names.append((connection, connection.settings_dict['NAME'])) connection.creation.create_test_db(verbosity, autoclobber=not interactive) result = unittest.TextTestRunner(verbosity=verbosity).run(suite) for connection, old_name in old_names: diff --git a/django/test/testcases.py b/django/test/testcases.py index d3bc1eaeba..2f33acec0b 100644 --- a/django/test/testcases.py +++ b/django/test/testcases.py @@ -446,7 +446,7 @@ def connections_support_transactions(): Returns True if all connections support transactions. This is messy because 2.4 doesn't support any or all. """ - return all(conn.settings_dict['DATABASE_SUPPORTS_TRANSACTIONS'] + return all(conn.settings_dict['SUPPORTS_TRANSACTIONS'] for conn in connections.all()) class TestCase(TransactionTestCase): diff --git a/django/views/debug.py b/django/views/debug.py index 6da89ffcf5..cdbe101b2e 100644 --- a/django/views/debug.py +++ b/django/views/debug.py @@ -809,7 +809,7 @@ EMPTY_URLCONF_TEMPLATE = """

Of course, you haven't actually done any work yet. Here's what to do next:

diff --git a/docs/howto/custom-model-fields.txt b/docs/howto/custom-model-fields.txt index d76028ec2c..801c9ceeef 100644 --- a/docs/howto/custom-model-fields.txt +++ b/docs/howto/custom-model-fields.txt @@ -290,13 +290,13 @@ If you aim to build a database-agnostic application, you should account for differences in database column types. For example, the date/time column type in PostgreSQL is called ``timestamp``, while the same column in MySQL is called ``datetime``. The simplest way to handle this in a ``db_type()`` method is to -check the ``connection.settings_dict['DATABASE_ENGINE']`` attribute. +check the ``connection.settings_dict['ENGINE']`` attribute. For example:: class MyDateField(models.Field): def db_type(self, connection): - if connection.settings_dict['DATABASE_ENGINE'] == 'mysql': + if connection.settings_dict['ENGINE'] == 'django.db.backends.mysql': return 'datetime' else: return 'timestamp' diff --git a/docs/howto/initial-data.txt b/docs/howto/initial-data.txt index 51a9c4742b..b071d6d529 100644 --- a/docs/howto/initial-data.txt +++ b/docs/howto/initial-data.txt @@ -118,23 +118,27 @@ The SQL files are read by the :djadmin:`sqlcustom`, :djadmin:`sqlreset`, `. Refer to the :ref:`manage.py documentation ` for more information. -Note that if you have multiple SQL data files, there's no guarantee of the order -in which they're executed. The only thing you can assume is that, by the time -your custom data files are executed, all the database tables already will have -been created. +Note that if you have multiple SQL data files, there's no guarantee of +the order in which they're executed. The only thing you can assume is +that, by the time your custom data files are executed, all the +database tables already will have been created. Database-backend-specific SQL data ---------------------------------- -There's also a hook for backend-specific SQL data. For example, you can have -separate initial-data files for PostgreSQL and MySQL. For each app, Django -looks for a file called ``/sql/..sql``, where -```` is your app directory, ```` is the model's name in -lowercase and ```` is the value of ``DATABASE_ENGINE`` for the given -database being set up in your settings file (e.g., ``postgresql``, ``mysql``). +There's also a hook for backend-specific SQL data. For example, you +can have separate initial-data files for PostgreSQL and MySQL. For +each app, Django looks for a file called +``/sql/..sql``, where ```` is +your app directory, ```` is the model's name in lowercase +and ```` is the last part of the module name provided for the +:setting:`ENGINE` in your settings file (e.g., if you have defined a +database with an :setting:`ENGINE` value of +``django.db.backends.postgresql``, Django will look for +``/sql/.postgresql.sql``). -Backend-specific SQL data is executed before non-backend-specific SQL data. For -example, if your app contains the files ``sql/person.sql`` and -``sql/person.postgresql.sql`` and you're installing the app on PostgreSQL, -Django will execute the contents of ``sql/person.postgresql.sql`` first, then -``sql/person.sql``. +Backend-specific SQL data is executed before non-backend-specific SQL +data. For example, if your app contains the files ``sql/person.sql`` +and ``sql/person.postgresql.sql`` and you're installing the app on +PostgreSQL, Django will execute the contents of +``sql/person.postgresql.sql`` first, then ``sql/person.sql``. diff --git a/docs/howto/legacy-databases.txt b/docs/howto/legacy-databases.txt index 1f3cd7ae80..b2aa7e4ea6 100644 --- a/docs/howto/legacy-databases.txt +++ b/docs/howto/legacy-databases.txt @@ -19,15 +19,15 @@ Give Django your database parameters You'll need to tell Django what your database connection parameters are, and what the name of the database is. Do that by editing the :setting:`DATABASES` -setting and assigning values to the following keys in the ``'default'`` -dictionary: +setting and assigning values to the following keys for the ``'default'`` +connection: - * ``DATABASE_NAME`` - * ``DATABASE_ENGINE`` - * ``DATABASE_USER`` - * ``DATABASE_PASSWORD`` - * ``DATABASE_HOST`` - * ``DATABASE_PORT`` + * :setting:`NAME` + * :setting:`ENGINE` + * :setting:`USER` + * :setting:`PASSWORD` + * :setting:`HOST` + * :setting:`PORT` Auto-generate the models ======================== diff --git a/docs/internals/contributing.txt b/docs/internals/contributing.txt index 30d8ed75fd..5bd4b0f6f1 100644 --- a/docs/internals/contributing.txt +++ b/docs/internals/contributing.txt @@ -763,18 +763,18 @@ info. Your :setting:`DATABASES` setting needs to define two databases: want. It doesn't need to use the same backend as the ``default`` database (although it can use the same backend if you want to). -If you're using the ``sqlite3`` database backend, you need to define -:setting:`DATABASE_ENGINE` for both databases, plus a -:setting:`TEST_DATABASE_NAME` for the ``other`` database. The +If you're using the SQLite database backend, you need to define +:setting:`ENGINE` for both databases, plus a +:setting:`TEST_NAME` for the ``other`` database. The following is a minimal settings file that can be used to test SQLite:: DATABASES = { 'default': { - 'DATABASE_ENGINE': 'sqlite3' + 'ENGINE': 'django.db.backends.sqlite3' }, 'other': { - 'DATABASE_ENGINE': 'sqlite3', - 'TEST_DATABASE_NAME: 'other_db' + 'ENGINE': 'django.db.backends.sqlite3', + 'TEST_NAME: 'other_db' } } @@ -782,22 +782,22 @@ following is a minimal settings file that can be used to test SQLite:: If you're using another backend, you will need to provide other details for each database: - * The :setting:`DATABASE_USER` option for each of your databases needs to + * The :setting:`USER` option for each of your databases needs to specify an existing user account for the database. - * The :setting:`DATABASE_PASSWORD` option needs to provide the password for - the :setting:`DATABASE_USER` that has been specified. + * The :setting:`PASSWORD` option needs to provide the password for + the :setting:`USER` that has been specified. - * The :setting:`DATABASE_NAME` option must be the name of an existing database to + * The :setting:`NAME` option must be the name of an existing database to which the given user has permission to connect. The unit tests will not touch this database; the test runner creates a new database whose name is - :setting:`DATABASE_NAME` prefixed with ``test_``, and this test database is + :setting:`NAME` prefixed with ``test_``, and this test database is deleted when the tests are finished. This means your user account needs permission to execute ``CREATE DATABASE``. You will also need to ensure that your database uses UTF-8 as the default character set. If your database server doesn't use UTF-8 as a default charset, -you will need to include a value for ``TEST_DATABASE_CHARSET`` in the settings +you will need to include a value for ``TEST_CHARSET`` in the settings dictionary for the applicable database. If you want to run the full suite of tests, you'll need to install a number of diff --git a/docs/intro/tutorial01.txt b/docs/intro/tutorial01.txt index ea4dff61bd..eacb3abdfa 100644 --- a/docs/intro/tutorial01.txt +++ b/docs/intro/tutorial01.txt @@ -158,35 +158,40 @@ It worked! Database setup -------------- -Now, edit :file:`settings.py`. It's a normal Python module with module-level -variables representing Django settings. Change the following keys in the -:setting:`DATABASES` ``'default'`` item to match your databases connection -settings. +Now, edit :file:`settings.py`. It's a normal Python module with +module-level variables representing Django settings. Change the +following keys in the :setting:`DATABASES` ``'default'`` item to match +your databases connection settings. - * ``DATABASE_ENGINE`` -- Either 'postgresql_psycopg2', 'mysql' or - 'sqlite3'. Other backends are :setting:`also available `. + * :setting:`ENGINE` -- Either + ``'django.db.backends.postgresql_psycopg2'``, + ``'django.db.backends.mysql'`` or + ``'django.db.backends.sqlite3'``. Other backends are + :setting:`also available `. - * ``DATABASE_NAME`` -- The name of your database. If you're using - SQLite, the database will be a file on your computer; in that case, - ``DATABASE_NAME`` should be the full absolute path, including filename, of - that file. If the file doesn't exist, it will automatically be created - when you synchronize the database for the first time (see below). + * :setting:`NAME` -- The name of your database. If you're using + SQLite, the database will be a file on your computer; in that + case, :setting:`NAME` should be the full absolute path, + including filename, of that file. If the file doesn't exist, it + will automatically be created when you synchronize the database + for the first time (see below). - When specifying the path, always use forward slashes, even on Windows - (e.g. ``C:/homes/user/mysite/sqlite3.db``). + When specifying the path, always use forward slashes, even on + Windows (e.g. ``C:/homes/user/mysite/sqlite3.db``). - * ``DATABASE_USER`` -- Your database username (not used for SQLite). + * :setting:`USER` -- Your database username (not used for SQLite). - * ``DATABASE_PASSWORD`` -- Your database password (not used for + * :setting:`PASSWORD` -- Your database password (not used for SQLite). - * ``DATABASE_HOST`` -- The host your database is on. Leave this as an - empty string if your database server is on the same physical machine (not - used for SQLite). + * :setting:`HOST` -- The host your database is on. Leave this as + an empty string if your database server is on the same physical + machine (not used for SQLite). -If you're new to databases, we recommend simply using SQLite (by setting -``DATABASE_ENGINE`` to ``'sqlite3'``). SQLite is included as part of -Python 2.5 and later, so you won't need to install anything else. +If you're new to databases, we recommend simply using SQLite (by +setting :setting:`ENGINE` to ``'django.db.backends.sqlite3'``). SQLite +is included as part of Python 2.5 and later, so you won't need to +install anything else. .. note:: diff --git a/docs/man/django-admin.1 b/docs/man/django-admin.1 index 6407ee5e1d..dff7d0d3da 100644 --- a/docs/man/django-admin.1 +++ b/docs/man/django-admin.1 @@ -28,8 +28,8 @@ Compiles .po files to .mo files for use with builtin gettext support. Creates the table needed to use the SQL cache backend .TP .B dbshell -Runs the command\-line client for the current -.BI DATABASE_ENGINE. +Runs the command\-line client for the specified +.BI database ENGINE. .TP .B diffsettings Displays differences between the current diff --git a/docs/ref/databases.txt b/docs/ref/databases.txt index ec47fbb1a9..bf92868342 100644 --- a/docs/ref/databases.txt +++ b/docs/ref/databases.txt @@ -44,18 +44,20 @@ Autocommit mode .. versionadded:: 1.1 -If your application is particularly read-heavy and doesn't make many database -writes, the overhead of a constantly open transaction can sometimes be -noticeable. For those situations, if you're using the ``postgresql_psycopg2`` -backend, you can configure Django to use *"autocommit"* behavior for the -connection, meaning that each database operation will normally be in its own -transaction, rather than having the transaction extend over multiple -operations. In this case, you can still manually start a transaction if you're -doing something that requires consistency across multiple database operations. -The autocommit behavior is enabled by setting the ``autocommit`` key in the -``DATABASE_OPTIONS`` part of your database in :setting:`DATABASES`:: +If your application is particularly read-heavy and doesn't make many +database writes, the overhead of a constantly open transaction can +sometimes be noticeable. For those situations, if you're using the +``postgresql_psycopg2`` backend, you can configure Django to use +*"autocommit"* behavior for the connection, meaning that each database +operation will normally be in its own transaction, rather than having +the transaction extend over multiple operations. In this case, you can +still manually start a transaction if you're doing something that +requires consistency across multiple database operations. The +autocommit behavior is enabled by setting the ``autocommit`` key in +the :setting:`OPTIONS` part of your database configuration in +:setting:`DATABASES`:: - DATABASE_OPTIONS = { + OPTIONS = { "autocommit": True, } @@ -67,11 +69,11 @@ objects are changed or none of them are. .. admonition:: This is database-level autocommit This functionality is not the same as the - :ref:`topics-db-transactions-autocommit` decorator. That decorator is a - Django-level implementation that commits automatically after data changing - operations. The feature enabled using the ``DATABASE_OPTIONS`` option - provides autocommit behavior at the database adapter level. It commits - after *every* operation. + :ref:`topics-db-transactions-autocommit` decorator. That decorator + is a Django-level implementation that commits automatically after + data changing operations. The feature enabled using the + :setting:`OPTIONS` option provides autocommit behavior at the + database adapter level. It commits after *every* operation. If you are using this feature and performing an operation akin to delete or updating that requires multiple operations, you are strongly recommended to @@ -234,14 +236,13 @@ Refer to the :ref:`settings documentation `. Connection settings are used in this order: - 1. ``DATABASE_OPTIONS``. - 2. ``DATABASE_NAME``, ``DATABASE_USER``, - ``DATABASE_PASSWORD``, ``DATABASE_HOST``, - ``DATABASE_PORT`` + 1. :setting:`OPTIONS`. + 2. :setting:`NAME`, :setting:`USER`, :setting:`PASSWORD`, + :setting:`HOST`, :setting:`PORT` 3. MySQL option files. -In other words, if you set the name of the database in ``DATABASE_OPTIONS``, -this will take precedence over ``DATABASE_NAME``, which would override +In other words, if you set the name of the database in ``OPTIONS``, +this will take precedence over ``NAME``, which would override anything in a `MySQL option file`_. Here's a sample configuration which uses a MySQL option file:: @@ -249,8 +250,8 @@ Here's a sample configuration which uses a MySQL option file:: # settings.py DATABASES = { 'default': { - 'DATABASE_ENGINE': "mysql", - 'DATABASE_OPTIONS': { + 'ENGINE': 'django.db.backends.mysql', + 'OPTIONS': { 'read_default_file': '/path/to/my.cnf', }, } @@ -258,9 +259,9 @@ Here's a sample configuration which uses a MySQL option file:: # my.cnf [client] - database = DATABASE_NAME - user = DATABASE_USER - password = DATABASE_PASSWORD + database = NAME + user = USER + password = PASSWORD default-character-set = utf8 Several other MySQLdb connection options may be useful, such as ``ssl``, @@ -291,7 +292,7 @@ storage engine, you have a couple of options. * Another option is to use the ``init_command`` option for MySQLdb prior to creating your tables:: - DATABASE_OPTIONS = { + OPTIONS = { "init_command": "SET storage_engine=INNODB", } @@ -456,7 +457,7 @@ If you're getting this error, you can solve it by: * Increase the default timeout value by setting the ``timeout`` database option option:: - DATABASE_OPTIONS = { + OPTIONS = { # ... "timeout": 20, # ... @@ -511,32 +512,32 @@ Your Django settings.py file should look something like this for Oracle:: DATABASES = { 'default': { - 'DATABASE_ENGINE': 'oracle', - 'DATABASE_NAME': 'xe', - 'DATABASE_USER': 'a_user', - 'DATABASE_PASSWORD': 'a_password', - 'DATABASE_HOST': '', - 'DATABASE_PORT': '' , + 'ENGINE': 'django.db.backends.oracle', + 'NAME': 'xe', + 'USER': 'a_user', + 'PASSWORD': 'a_password', + 'HOST': '', + 'PORT': '' , } } If you don't use a ``tnsnames.ora`` file or a similar naming method that recognizes the SID ("xe" in this example), then fill in both -``DATABASE_HOST`` and ``DATABASE_PORT`` like so:: +``HOST`` and ``PORT`` like so:: DATABASES = { 'default': { - 'DATABASE_ENGINE': 'oracle', - 'DATABASE_NAME': 'xe', - 'DATABASE_USER': 'a_user', - 'DATABASE_PASSWORD': 'a_password', - 'DATABASE_HOST': 'dbprod01ned.mycompany.com', - 'DATABASE_PORT': '1540', + 'ENGINE': 'django.db.backends.oracle', + 'NAME': 'xe', + 'USER': 'a_user', + 'PASSWORD': 'a_password', + 'HOST': 'dbprod01ned.mycompany.com', + 'PORT': '1540', } } -You should supply both ``DATABASE_HOST`` and ``DATABASE_PORT``, or leave both +You should supply both ``HOST`` and ``PORT``, or leave both as empty strings. Tablespace options diff --git a/docs/ref/django-admin.txt b/docs/ref/django-admin.txt index fa652b56ba..688b25cd86 100644 --- a/docs/ref/django-admin.txt +++ b/docs/ref/django-admin.txt @@ -160,8 +160,8 @@ dbshell .. django-admin:: dbshell Runs the command-line client for the database engine specified in your -``DATABASE_ENGINE`` setting, with the connection parameters specified in your -``DATABASE_USER``, ``DATABASE_PASSWORD``, etc., settings. +``ENGINE`` setting, with the connection parameters specified in your +``USER``, ``PASSWORD``, etc., settings. * For PostgreSQL, this runs the ``psql`` command-line client. * For MySQL, this runs the ``mysql`` command-line client. @@ -265,7 +265,7 @@ inspectdb .. django-admin:: inspectdb Introspects the database tables in the database pointed-to by the -``DATABASE_NAME`` setting and outputs a Django model module (a ``models.py`` +``NAME`` setting and outputs a Django model module (a ``models.py`` file) to standard output. Use this if you have a legacy database with which you'd like to use Django. diff --git a/docs/ref/settings.txt b/docs/ref/settings.txt index c93a0d067e..f108f5c63c 100644 --- a/docs/ref/settings.txt +++ b/docs/ref/settings.txt @@ -195,41 +195,60 @@ end users) indicating the reason the request was rejected. See DATABASES --------- +.. versionadded: 1.2 + Default: ``{}`` (Empty dictionary) -This is a dictionary containg the settings for all databases to be used with -Django. It is a nested dictionary who's contents maps aliases to a dictionary -containing the options for an individual database. The following inner options -are used: +A dictionary containing the settings for all databases to be used with +Django. It is a nested dictionary who's contents maps database aliases +to a dictionary containing the options for an individual database. -.. deprecated: 1.2 +The :setting:`DATABASES` setting must configure a ``default`` database; +any number of additional databases may also be specified. - In versions of Django prior to 1.2 each of the following were - individual settings. The usage of the standalone database settings - has been deprecated, and will be removed in Django 1.4. +The simplest possible settings file is for a single-database setup using +SQLite. This can be configured using the following:: + DATABASES = { + 'default': { + 'BACKEND': 'django.db.backends.sqlite3', + 'NAME': 'mydatabase' + } + } -.. setting:: DATABASE_ENGINE +For other database backends, or more complex SQLite configurations, other options +will be required. The following inner options are available. -DATABASE_ENGINE -~~~~~~~~~~~~~~~ +.. setting:: ENGINE + +ENGINE +~~~~~~ Default: ``''`` (Empty string) -The database backend to use. The built-in database backends are -``'postgresql_psycopg2'``, ``'postgresql'``, ``'mysql'``, ``'sqlite3'``, and -``'oracle'``. +The database backend to use. The built-in database backends are: + + * ``'django.db.backends.postgresql_psycopg2'`` + * ``'django.db.backends.postgresql'`` + * ``'django.db.backends.mysql'`` + * ``'django.db.backends.sqlite3'`` + * ``'django.db.backends.oracle'`` You can use a database backend that doesn't ship with Django by setting -``DATABASE_ENGINE`` to a fully-qualified path (i.e. +``ENGINE`` to a fully-qualified path (i.e. ``mypackage.backends.whatever``). Writing a whole new database backend from scratch is left as an exercise to the reader; see the other backends for examples. -.. versionadded:: 1.0 - Support for external database backends is new in 1.0. +.. note:: + Prior to Django 1.2, you could use a short version of the backend name + to reference the built-in database backends (e.g., you could use + ``'sqlite3'`` to refer to the SQLite backend). This format has been + deprecated, and will be removed in Django 1.4. -DATABASE_HOST -~~~~~~~~~~~~~ +.. setting:: HOST + +HOST +~~~~ Default: ``''`` (Empty string) @@ -239,7 +258,7 @@ localhost. Not used with SQLite. If this value starts with a forward slash (``'/'``) and you're using MySQL, MySQL will connect via a Unix socket to the specified socket. For example:: - "DATABASE_HOST": '/var/run/mysql' + "HOST": '/var/run/mysql' If you're using MySQL and this value *doesn't* start with a forward slash, then this value is assumed to be the host. @@ -249,8 +268,10 @@ for the connection, rather than a network connection to localhost. If you explicitly need to use a TCP/IP connection on the local machine with PostgreSQL, specify ``localhost`` here. -DATABASE_NAME -~~~~~~~~~~~~~ +.. setting:: NAME + +NAME +~~~~ Default: ``''`` (Empty string) @@ -258,41 +279,48 @@ The name of the database to use. For SQLite, it's the full path to the database file. When specifying the path, always use forward slashes, even on Windows (e.g. ``C:/homes/user/mysite/sqlite3.db``). -DATABASE_OPTIONS -~~~~~~~~~~~~~~~~ +.. setting:: OPTIONS + +OPTIONS +~~~~~~~ Default: ``{}`` (Empty dictionary) Extra parameters to use when connecting to the database. Consult backend module's document for available keywords. -DATABASE_PASSWORD -~~~~~~~~~~~~~~~~~ +.. setting:: PASSWORD + +PASSWORD +~~~~~~~~ Default: ``''`` (Empty string) The password to use when connecting to the database. Not used with SQLite. -DATABASE_PORT -~~~~~~~~~~~~~ +.. setting:: PORT + +PORT +~~~~ Default: ``''`` (Empty string) The port to use when connecting to the database. An empty string means the default port. Not used with SQLite. -DATABASE_USER -~~~~~~~~~~~~~ +.. setting:: USER + +USER +~~~~ Default: ``''`` (Empty string) The username to use when connecting to the database. Not used with SQLite. +.. setting:: TEST_CHARSET -TEST_DATABASE_CHARSET -~~~~~~~~~~~~~~~~~~~~~ - -.. versionadded:: 1.0 +TEST_CHARSET +~~~~~~~~~~~~ Default: ``None`` @@ -306,11 +334,10 @@ MySQL_ (``mysql``) backends. .. _PostgreSQL: http://www.postgresql.org/docs/8.2/static/multibyte.html .. _MySQL: http://www.mysql.org/doc/refman/5.0/en/charset-database.html +.. setting:: TEST_COLLATION -TEST_DATABASE_COLLATION -~~~~~~~~~~~~~~~~~~~~~~~ - -.. versionadded:: 1.0 +TEST_COLLATION +~~~~~~~~~~~~~~ Default: ``None`` @@ -322,8 +349,10 @@ manual for details). .. _section 10.3.2: http://www.mysql.org/doc/refman/5.0/en/charset-database.html -TEST_DATABASE_NAME -~~~~~~~~~~~~~~~~~~ +.. setting:: TEST_NAME + +TEST_NAME +~~~~~~~~~ Default: ``None`` @@ -1292,3 +1321,79 @@ Different locales have different formats. For example, U.S. English would say See :ttag:`allowed date format strings `. See also ``DATE_FORMAT``, ``DATETIME_FORMAT``, ``TIME_FORMAT`` and ``MONTH_DAY_FORMAT``. + +Deprecated settings +=================== + +.. setting:: DATABASE_ENGINE + +DATABASE_ENGINE +--------------- + +.. deprecated:: 1.2 + This setting has been replaced by :setting:`ENGINE` in + :setting:`DATABASES`. + +DATABASE_HOST +------------- + +.. deprecated:: 1.2 + This setting has been replaced by :setting:`HOST` in + :setting:`DATABASES`. + +DATABASE_NAME +------------- + +.. deprecated:: 1.2 + This setting has been replaced by :setting:`NAME` in + :setting:`DATABASES`. + +DATABASE_OPTIONS +---------------- + +.. deprecated:: 1.2 + This setting has been replaced by :setting:`OPTIONS` in + :setting:`DATABASES`. + +DATABASE_PASSWORD +----------------- + +.. deprecated:: 1.2 + This setting has been replaced by :setting:`PASSWORD` in + :setting:`DATABASES`. + +DATABASE_PORT +------------- + +.. deprecated:: 1.2 + This setting has been replaced by :setting:`PORT` in + :setting:`DATABASES`. + +DATABASE_USER +------------- + +.. deprecated:: 1.2 + This setting has been replaced by :setting:`USER` in + :setting:`DATABASES`. + +TEST_DATABASE_CHARSET +--------------------- + +.. deprecated:: 1.2 + This setting has been replaced by :setting:`TEST_CHARSET` in + :setting:`DATABASES`. + +TEST_DATABASE_COLLATION +----------------------- + +.. deprecated:: 1.2 + This setting has been replaced by :setting:`TEST_COLLATION` in + :setting:`DATABASES`. + +TEST_DATABASE_NAME +------------------ + +.. deprecated:: 1.2 + This setting has been replaced by :setting:`TEST_NAME` in + :setting:`DATABASES`. + diff --git a/docs/releases/0.96.txt b/docs/releases/0.96.txt index 186a0e8da9..7a8d64f5d7 100644 --- a/docs/releases/0.96.txt +++ b/docs/releases/0.96.txt @@ -96,7 +96,7 @@ support: * The ``sqlinitialdata`` command has been renamed to ``sqlcustom`` to emphasize that ``loaddata`` should be used for data (and ``sqlcustom`` for other custom SQL -- views, stored procedures, etc.). - + * The vestigial ``install`` command has been removed. Use ``syncdb``. Backslash escaping changed @@ -179,20 +179,20 @@ strings that referred to callables were allowed). This allows a much more natural use of URLconfs. For example, this URLconf:: from django.conf.urls.defaults import * - - urlpatterns = patterns('', + + urlpatterns = patterns('', ('^myview/$', 'mysite.myapp.views.myview') ) - + can now be rewritten as:: from django.conf.urls.defaults import * from mysite.myapp.views import myview - - urlpatterns = patterns('', + + urlpatterns = patterns('', ('^myview/$', myview) ) - + One useful application of this can be seen when using decorators; this change allows you to apply decorators to views *in your URLconf*. Thus, you can make a generic view require login very @@ -202,17 +202,17 @@ easily:: from django.contrib.auth.decorators import login_required from django.views.generic.list_detail import object_list from mysite.myapp.models import MyModel - + info = { "queryset" : MyModel.objects.all(), } - - urlpatterns = patterns('', + + urlpatterns = patterns('', ('^myview/$', login_required(object_list), info) ) Note that both syntaxes (strings and callables) are valid, and will continue to -be valid for the foreseeable future. +be valid for the foreseeable future. The test framework ------------------ @@ -248,19 +248,19 @@ all their hard work: * Russell Keith-Magee and Malcolm Tredinnick for their major code contributions. This release wouldn't have been possible without them. - + * Our new release manager, James Bennett, for his work in getting out 0.95.1, 0.96, and (hopefully) future release. - + * Our ticket managers Chris Beaven (aka SmileyChris), Simon Greenhill, Michael Radziej, and Gary Wilson. They agreed to take on the monumental task of wrangling our tickets into nicely cataloged submission. Figuring out what to work on is now about a million times easier; thanks again, guys. - + * Everyone who submitted a bug report, patch or ticket comment. We can't possibly thank everyone by name -- over 200 developers submitted patches that went into 0.96 -- but everyone who's contributed to Django is listed in AUTHORS_. - + .. _AUTHORS: http://code.djangoproject.com/browser/django/trunk/AUTHORS diff --git a/docs/releases/1.2.txt b/docs/releases/1.2.txt index afc2657786..de186ae755 100644 --- a/docs/releases/1.2.txt +++ b/docs/releases/1.2.txt @@ -67,6 +67,72 @@ changes: __members__ = property(lambda self: self.__dir__()) +Specifying databases +-------------------- + +Prior to Django 1.1, Django used a number of settings to control access to a +single database. Django 1.2 introduces support for multiple databases, and as +a result, the way you define database settings has changed. + +Previously, there were a number of ``DATABASE_`` settings at the top level of +your settings file. For example:: + + DATABASE_NAME = 'test_db' + DATABASE_BACKEND = 'postgresl_psycopg2' + DATABASE_USER = 'myusername' + DATABASE_PASSWORD = 's3krit' + +These settings are now contained inside a dictionary named +``DATABASES``. Each item in the dictionary corresponds to a single +database connection, with the name ``default`` describing the default +database connection. The setting names have also been shortened to +reflect the fact that they are stored in a dictionary. The sample +settings given previously would now be stored using:: + + DATABASES = { + 'default': { + 'NAME': 'test_db', + 'BACKEND': 'django.db.backends.postgresl_psycopg2', + 'USER': 'myusername', + 'PASSWORD': 's3krit', + } + +This affects the following settings: + + Old setting New Setting + ========================================= =========== + :setting:`DATABASE_ENGINE` ENGINE + :setting:`DATABASE_HOST` HOST + :setting:`DATABASE_NAME` NAME + :setting:`DATABASE_OPTIONS` OPTIONS + :setting:`DATABASE_PASSWORD` PASSWORD + :setting:`DATABASE_PORT` PORT + :setting:`DATABASE_USER` USER + :setting:`TEST_DATABASE_CHARSET` TEST_CHARSET + :setting:`TEST_DATABASE_COLLATION` TEST_COLLATION + :setting:`TEST_DATABASE_NAME` TEST_NAME + +These changes are also required if you have manually created a database +connection using + +In addition to the change in structure, Django 1.2 removes the special +handling for the built-in database backends. All database backends +must now be specified by a fully qualified class name (i.e., +``django.db.backends.postgresl_psycopg2``, rather than just +``postgresql_psycopg2``) + +``__dict__`` on Model instances +------------------------------- + +Historically, the ``__dict__`` attribute of a model instance has only contained +attributes corresponding to the fields on a model. + +In order to support multiple database configurations, Django 1.2 has +added a ``_state`` attribute to object instances. This attribute will +appear in ``__dict__`` for a model instance. If your code relies on +iterating over __dict__ to obtain a list of fields, you must now +filter out ``_state`` attribute of out ``__dict__``. + .. _deprecated-features-1.2: Features deprecated in 1.2 @@ -107,3 +173,12 @@ backend implementations that allow you to send email to a :ref:`memory` - you can even configure all email to be :ref:`thrown away`. +Support for multiple databases +------------------------------ + +Django 1.2 adds the ability to use :ref:`more than one database +`in your Django project. Queries can be +issued at a specific database with the `using()` method on +querysets; individual objects can be saved to a specific database +by providing a ``using`` argument when you save the instance. + diff --git a/docs/topics/testing.txt b/docs/topics/testing.txt index c8d7819c7b..45f7f49999 100644 --- a/docs/topics/testing.txt +++ b/docs/topics/testing.txt @@ -278,33 +278,35 @@ The test database ----------------- Tests that require a database (namely, model tests) will not use your "real" -(production) database. A separate, blank database is created for the tests. +(production) database. Separate, blank databases are created for the tests. -Regardless of whether the tests pass or fail, the test database is destroyed +Regardless of whether the tests pass or fail, the test databases are destroyed when all the tests have been executed. -By default this test database gets its name by prepending ``test_`` to the -value of the ``DATABASE_NAME`` setting. When using the SQLite database -engine the tests will by default use an in-memory database (i.e., the database -will be created in memory, bypassing the filesystem entirely!). If you want to -use a different database name, specify ``TEST_DATABASE_NAME`` in the dictionary -for any given database in :setting:`DATABASES`. +By default the test databases get their names by prepending ``test_`` +to the value of the :setting:`NAME`` settings for the databased +defined in :setting:`DATABASES`. When using the SQLite database engine +the tests will by default use an in-memory database (i.e., the +database will be created in memory, bypassing the filesystem +entirely!). If you want to use a different database name, specify +``TEST_NAME`` in the dictionary for any given database in +:setting:`DATABASES`. -Aside from using a separate database, the test runner will otherwise use all of -the same database settings you have in your settings file: -``DATABASE_ENGINE``, ``DATABASE_USER``, ``DATABASE_HOST``, -etc. The test database is created by the user specified by -``DATABASE_USER``, so you'll need to make sure that the given user -account has sufficient privileges to create a new database on the system. +Aside from using a separate database, the test runner will otherwise +use all of the same database settings you have in your settings file: +:setting:`ENGINE`, :setting:`USER`, :setting:`HOST`, etc. The test +database is created by the user specified by ``USER``, so you'll need +to make sure that the given user account has sufficient privileges to +create a new database on the system. .. versionadded:: 1.0 -For fine-grained control over the -character encoding of your test database, use the -``TEST_DATABASE_CHARSET`` option. If you're using MySQL, you can also -use the ``TEST_DATABASE_COLLATION`` option to control the particular -collation used by the test database. See the :ref:`settings documentation -` for details of these advanced settings. +For fine-grained control over the character encoding of your test +database, use the :setting:`TEST_CHARSET` option. If you're using +MySQL, you can also use the :setting:`TEST_COLLATION` option to +control the particular collation used by the test database. See the +:ref:`settings documentation ` for details of these +advanced settings. Other test conditions --------------------- @@ -1284,16 +1286,17 @@ utility methods in the ``django.test.utils`` module. .. function:: setup_test_environment() Performs any global pre-test setup, such as the installing the - instrumentation of the template rendering system and setting up the dummy - ``SMTPConnection``. + instrumentation of the template rendering system and setting up + the dummy ``SMTPConnection``. .. function:: teardown_test_environment() - Performs any global post-test teardown, such as removing the black magic - hooks into the template system and restoring normal e-mail services. + Performs any global post-test teardown, such as removing the black + magic hooks into the template system and restoring normal e-mail + services. -The creation module of the database backend (``connection.creation``) also -provides some utilities that can be useful during testing. +The creation module of the database backend (``connection.creation``) +also provides some utilities that can be useful during testing. .. function:: create_test_db(verbosity=1, autoclobber=False) @@ -1301,27 +1304,29 @@ provides some utilities that can be useful during testing. ``verbosity`` has the same behavior as in ``run_tests()``. - ``autoclobber`` describes the behavior that will occur if a database with - the same name as the test database is discovered: + ``autoclobber`` describes the behavior that will occur if a + database with the same name as the test database is discovered: - * If ``autoclobber`` is ``False``, the user will be asked to approve - destroying the existing database. ``sys.exit`` is called if the user - does not approve. + * If ``autoclobber`` is ``False``, the user will be asked to + approve destroying the existing database. ``sys.exit`` is + called if the user does not approve. - * If autoclobber is ``True``, the database will be destroyed without - consulting the user. + * If autoclobber is ``True``, the database will be destroyed + without consulting the user. Returns the name of the test database that it created. - ``create_test_db()`` has the side effect of modifying - ``settings.DATABASE_NAME`` to match the name of the test database. + ``create_test_db()`` has the side effect of modifying the value of + :setting:`NAME` in :setting:`DATABASES` to match the name of the test + database. .. versionchanged:: 1.0 ``create_test_db()`` now returns the name of the test database. .. function:: destroy_test_db(old_database_name, verbosity=1) - Destroys the database whose name is in the :setting:`DATABASE_NAME` setting - and restores the value of :setting:`DATABASE_NAME` to the provided name. + Destroys the database whose name is in stored in :setting:`NAME` in the + :setting:`DATABASES`, and sets :setting:`NAME` to use the + provided name. ``verbosity`` has the same behavior as in ``run_tests()``. diff --git a/tests/modeltests/basic/models.py b/tests/modeltests/basic/models.py index 07f5a1c55e..28b44a582f 100644 --- a/tests/modeltests/basic/models.py +++ b/tests/modeltests/basic/models.py @@ -365,7 +365,7 @@ from django.conf import settings building_docs = getattr(settings, 'BUILDING_DOCS', False) -if building_docs or settings.DATABASES[DEFAULT_DB_ALIAS]['DATABASE_ENGINE'] == 'postgresql': +if building_docs or settings.DATABASES[DEFAULT_DB_ALIAS]['ENGINE'] == 'django.db.backends.postgresql': __test__['API_TESTS'] += """ # In PostgreSQL, microsecond-level precision is available. >>> a9 = Article(headline='Article 9', pub_date=datetime(2005, 7, 31, 12, 30, 45, 180)) @@ -374,7 +374,7 @@ if building_docs or settings.DATABASES[DEFAULT_DB_ALIAS]['DATABASE_ENGINE'] == ' datetime.datetime(2005, 7, 31, 12, 30, 45, 180) """ -if building_docs or settings.DATABASES[DEFAULT_DB_ALIAS]['DATABASE_ENGINE'] == 'mysql': +if building_docs or settings.DATABASES[DEFAULT_DB_ALIAS]['ENGINE'] == 'django.db.backends.mysql': __test__['API_TESTS'] += """ # In MySQL, microsecond-level precision isn't available. You'll lose # microsecond-level precision once the data is saved. diff --git a/tests/modeltests/custom_pk/models.py b/tests/modeltests/custom_pk/models.py index 225b6316a2..84e6480af9 100644 --- a/tests/modeltests/custom_pk/models.py +++ b/tests/modeltests/custom_pk/models.py @@ -156,7 +156,7 @@ True # SQLite lets objects be saved with an empty primary key, even though an # integer is expected. So we can't check for an error being raised in that case # for SQLite. Remove it from the suite for this next bit. -if settings.DATABASES[DEFAULT_DB_ALIAS]['DATABASE_ENGINE'] != 'sqlite3': +if settings.DATABASES[DEFAULT_DB_ALIAS]['ENGINE'] != 'django.db.backends.sqlite3': __test__["API_TESTS"] += """ # The primary key must be specified, so an error is raised if you try to create # an object without it. diff --git a/tests/modeltests/fixtures/models.py b/tests/modeltests/fixtures/models.py index c685d1ef0d..97d1362185 100644 --- a/tests/modeltests/fixtures/models.py +++ b/tests/modeltests/fixtures/models.py @@ -100,7 +100,7 @@ __test__ = {'API_TESTS': """ # Database flushing does not work on MySQL with the default storage engine # because it requires transaction support. -if settings.DATABASES[DEFAULT_DB_ALIAS]['DATABASE_ENGINE'] != 'mysql': +if settings.DATABASES[DEFAULT_DB_ALIAS]['ENGINE'] != 'django.db.backends.mysql': __test__['API_TESTS'] += \ """ # Reset the database representation of this app. This will delete all data. diff --git a/tests/modeltests/lookup/models.py b/tests/modeltests/lookup/models.py index a6ad7c0dab..99eefffd66 100644 --- a/tests/modeltests/lookup/models.py +++ b/tests/modeltests/lookup/models.py @@ -43,7 +43,9 @@ False True """} -if settings.DATABASES[DEFAULT_DB_ALIAS]['DATABASE_ENGINE'] in ('postgresql', 'postgresql_pysycopg2'): +if settings.DATABASES[DEFAULT_DB_ALIAS]['ENGINE'] in ( + 'django.db.backends.postgresql', + 'django.db.backends.postgresql_pysycopg2'): __test__['API_TESTS'] += r""" # text matching tests for PostgreSQL 8.3 >>> Article.objects.filter(id__iexact='1') @@ -399,7 +401,7 @@ FieldError: Join on field 'headline' not permitted. Did you misspell 'starts' fo """ -if settings.DATABASES[DEFAULT_DB_ALIAS]['DATABASE_ENGINE'] != 'mysql': +if settings.DATABASES[DEFAULT_DB_ALIAS]['ENGINE'] != 'django.db.backends.mysql': __test__['API_TESTS'] += r""" # grouping and backreferences >>> Article.objects.filter(headline__regex=r'b(.).*b\1') diff --git a/tests/modeltests/transactions/models.py b/tests/modeltests/transactions/models.py index df63667d02..6b92fd01d6 100644 --- a/tests/modeltests/transactions/models.py +++ b/tests/modeltests/transactions/models.py @@ -28,7 +28,7 @@ from django.conf import settings building_docs = getattr(settings, 'BUILDING_DOCS', False) -if building_docs or settings.DATABASES[DEFAULT_DB_ALIAS]['DATABASE_ENGINE'] != 'mysql': +if building_docs or settings.DATABASES[DEFAULT_DB_ALIAS]['ENGINE'] != 'django.db.backends.mysql': __test__['API_TESTS'] += """ # the default behavior is to autocommit after each save() action >>> def create_a_reporter_then_fail(first, last): diff --git a/tests/regressiontests/admin_scripts/tests.py b/tests/regressiontests/admin_scripts/tests.py index 8678ee0c64..cdc9556afe 100644 --- a/tests/regressiontests/admin_scripts/tests.py +++ b/tests/regressiontests/admin_scripts/tests.py @@ -61,23 +61,25 @@ class AdminScriptTestCase(unittest.TestCase): except OSError: pass - def _ext_backend_path(self): + def _ext_backend_paths(self): """ - Returns the path for the external backend package, or None if no - external backend is detected. + Returns the paths for any external backend packages. """ + paths = [] first_package_re = re.compile(r'(^[^\.]+)\.') - result = first_package_re.findall(settings.DATABASE_ENGINE) - if result: - backend_pkg = __import__(result[0]) - backend_dir = os.path.dirname(backend_pkg.__file__) - return os.path.dirname(backend_dir) + for backend in settings.DATABASES.values(): + result = first_package_re.findall(backend['ENGINE']) + if result and result != 'django': + backend_pkg = __import__(result[0]) + backend_dir = os.path.dirname(backend_pkg.__file__) + paths.append(os.path.dirname(backend_dir)) + return paths def run_test(self, script, args, settings_file=None, apps=None): test_dir = os.path.dirname(os.path.dirname(__file__)) project_dir = os.path.dirname(test_dir) base_dir = os.path.dirname(project_dir) - ext_backend_base_dir = self._ext_backend_path() + ext_backend_base_dirs = self._ext_backend_paths() # Remember the old environment old_django_settings_module = os.environ.get('DJANGO_SETTINGS_MODULE', None) @@ -95,8 +97,7 @@ class AdminScriptTestCase(unittest.TestCase): elif 'DJANGO_SETTINGS_MODULE' in os.environ: del os.environ['DJANGO_SETTINGS_MODULE'] python_path = [test_dir, base_dir] - if ext_backend_base_dir: - python_path.append(ext_backend_base_dir) + python_path.extend(ext_backend_base_dirs) os.environ[python_path_var_name] = os.pathsep.join(python_path) # Build the command line diff --git a/tests/regressiontests/aggregation_regress/models.py b/tests/regressiontests/aggregation_regress/models.py index bbbb1386bb..7c51cd17a7 100644 --- a/tests/regressiontests/aggregation_regress/models.py +++ b/tests/regressiontests/aggregation_regress/models.py @@ -327,7 +327,7 @@ def run_stddev_tests(): Stddev and Variance are not guaranteed to be available for SQLite, and are not available for PostgreSQL before 8.2. """ - if settings.DATABASES[DEFAULT_DB_ALIAS]['DATABASE_ENGINE'] == 'sqlite3': + if settings.DATABASES[DEFAULT_DB_ALIAS]['ENGINE'] == 'django.db.backends.sqlite3': return False class StdDevPop(object): diff --git a/tests/regressiontests/backends/tests.py b/tests/regressiontests/backends/tests.py index 0735ce193e..31e4f10cef 100644 --- a/tests/regressiontests/backends/tests.py +++ b/tests/regressiontests/backends/tests.py @@ -10,7 +10,7 @@ class Callproc(unittest.TestCase): def test_dbms_session(self): # If the backend is Oracle, test that we can call a standard # stored procedure through our cursor wrapper. - if settings.DATABASES[DEFAULT_DB_ALIAS]['DATABASE_ENGINE'] == 'oracle': + if settings.DATABASES[DEFAULT_DB_ALIAS]['ENGINE'] == 'django.db.backends.oracle': convert_unicode = backend.convert_unicode cursor = connection.cursor() cursor.callproc(convert_unicode('DBMS_SESSION.SET_IDENTIFIER'), @@ -39,7 +39,7 @@ class LongString(unittest.TestCase): def test_long_string(self): # If the backend is Oracle, test that we can save a text longer # than 4000 chars and read it properly - if settings.DATABASES[DEFAULT_DB_ALIAS]['DATABASE_ENGINE'] == 'oracle': + if settings.DATABASES[DEFAULT_DB_ALIAS]['ENGINE'] == 'django.db.backends.oracle': c = connection.cursor() c.execute('CREATE TABLE ltext ("TEXT" NCLOB)') long_str = ''.join([unicode(x) for x in xrange(4000)]) @@ -79,7 +79,7 @@ __test__ = {'API_TESTS': """ # Unfortunately with sqlite3 the in-memory test database cannot be # closed, and so it cannot be re-opened during testing, and so we # sadly disable this test for now. -if settings.DATABASES[DEFAULT_DB_ALIAS]['DATABASE_ENGINE'] != 'sqlite3': +if settings.DATABASES[DEFAULT_DB_ALIAS]['ENGINE'] != 'django.db.backends.sqlite3': __test__['API_TESTS'] += """ >>> connection_created.connect(connection_created_test) >>> connection.close() # Ensure the connection is closed diff --git a/tests/regressiontests/datatypes/models.py b/tests/regressiontests/datatypes/models.py index 633253dd3b..f6cbc9f0f6 100644 --- a/tests/regressiontests/datatypes/models.py +++ b/tests/regressiontests/datatypes/models.py @@ -93,7 +93,7 @@ u'Outstanding' # Regression test for #8354: the MySQL backend should raise an error if given # a timezone-aware datetime object. -if settings.DATABASES[DEFAULT_DB_ALIAS]['DATABASE_ENGINE'] == 'mysql': +if settings.DATABASES[DEFAULT_DB_ALIAS]['ENGINE'] == 'django.db.backends.mysql': __test__['API_TESTS'] += """ >>> from django.utils import tzinfo >>> dt = datetime.datetime(2008, 8, 31, 16, 20, tzinfo=tzinfo.FixedOffset(0)) diff --git a/tests/regressiontests/delete_regress/models.py b/tests/regressiontests/delete_regress/models.py index ffb06b6c8a..ff561c9d20 100644 --- a/tests/regressiontests/delete_regress/models.py +++ b/tests/regressiontests/delete_regress/models.py @@ -8,18 +8,18 @@ class Book(models.Model): # Can't run this test under SQLite, because you can't # get two connections to an in-memory database. -if settings.DATABASES[DEFAULT_DB_ALIAS]['DATABASE_ENGINE'] != 'sqlite3': +if settings.DATABASES[DEFAULT_DB_ALIAS]['ENGINE'] != 'django.db.backends.sqlite3': class DeleteLockingTest(TransactionTestCase): def setUp(self): # Create a second connection to the database conn_settings = settings.DATABASES[DEFAULT_DB_ALIAS] self.conn2 = backend.DatabaseWrapper({ - 'DATABASE_HOST': conn_settings['DATABASE_HOST'], - 'DATABASE_NAME': conn_settings['DATABASE_NAME'], - 'DATABASE_OPTIONS': conn_settings['DATABASE_OPTIONS'], - 'DATABASE_PASSWORD': conn_settings['DATABASE_PASSWORD'], - 'DATABASE_PORT': conn_settings['DATABASE_PORT'], - 'DATABASE_USER': conn_settings['DATABASE_USER'], + 'HOST': conn_settings['HOST'], + 'NAME': conn_settings['NAME'], + 'OPTIONS': conn_settings['OPTIONS'], + 'PASSWORD': conn_settings['PASSWORD'], + 'PORT': conn_settings['PORT'], + 'USER': conn_settings['USER'], 'TIME_ZONE': settings.TIME_ZONE, }) diff --git a/tests/regressiontests/expressions_regress/models.py b/tests/regressiontests/expressions_regress/models.py index fe25ee9922..a517780323 100644 --- a/tests/regressiontests/expressions_regress/models.py +++ b/tests/regressiontests/expressions_regress/models.py @@ -121,7 +121,7 @@ Complex expressions of different connection types are possible. """} # Oracle doesn't support the Bitwise OR operator. -if settings.DATABASES[DEFAULT_DB_ALIAS]['DATABASE_ENGINE'] != 'oracle': +if settings.DATABASES[DEFAULT_DB_ALIAS]['ENGINE'] != 'django.db.backends.oracle': __test__['API_TESTS'] += """ >>> _ = Number.objects.filter(pk=n.pk).update(integer=42, float=15.5) diff --git a/tests/regressiontests/fixtures_regress/models.py b/tests/regressiontests/fixtures_regress/models.py index 09f12897d6..e5508185f5 100644 --- a/tests/regressiontests/fixtures_regress/models.py +++ b/tests/regressiontests/fixtures_regress/models.py @@ -35,7 +35,7 @@ class Stuff(models.Model): # Oracle doesn't distinguish between None and the empty string. # This hack makes the test case pass using Oracle. name = self.name - if (settings.DATABASES[DEFAULT_DB_ALIAS]['DATABASE_ENGINE'] == 'oracle' + if (settings.DATABASES[DEFAULT_DB_ALIAS]['ENGINE'] == 'django.db.backends.oracle' and name == u''): name = None return unicode(name) + u' is owned by ' + unicode(self.owner) diff --git a/tests/regressiontests/introspection/tests.py b/tests/regressiontests/introspection/tests.py index 1a2042992f..e11719e507 100644 --- a/tests/regressiontests/introspection/tests.py +++ b/tests/regressiontests/introspection/tests.py @@ -80,7 +80,7 @@ class IntrospectionTests(TestCase): ['IntegerField', 'CharField', 'CharField', 'CharField']) # Regression test for #9991 - 'real' types in postgres - if settings.DATABASES[DEFAULT_DB_ALIAS]['DATABASE_ENGINE'].startswith('postgresql'): + if settings.DATABASES[DEFAULT_DB_ALIAS]['ENGINE'].startswith('django.db.backends.postgresql'): def test_postgresql_real_type(self): cursor = connection.cursor() cursor.execute("CREATE TABLE django_ixn_real_test_table (number REAL);") diff --git a/tests/regressiontests/model_regress/models.py b/tests/regressiontests/model_regress/models.py index de7579dbe8..420f2c262c 100644 --- a/tests/regressiontests/model_regress/models.py +++ b/tests/regressiontests/model_regress/models.py @@ -149,7 +149,9 @@ datetime.datetime(2000, 1, 1, 6, 1, 1) """} -if settings.DATABASES[DEFAULT_DB_ALIAS]['DATABASE_ENGINE'] not in ("mysql", "oracle"): +if settings.DATABASES[DEFAULT_DB_ALIAS]['ENGINE'] not in ( + "django.db.backends.mysql", + "django.db.backends.oracle"): __test__["timezone-tests"] = """ # Saving an updating with timezone-aware datetime Python objects. Regression # test for #10443. diff --git a/tests/regressiontests/queries/models.py b/tests/regressiontests/queries/models.py index 56eaad2f61..aababffbab 100644 --- a/tests/regressiontests/queries/models.py +++ b/tests/regressiontests/queries/models.py @@ -1223,13 +1223,13 @@ FieldError: Infinite loop caused by ordering. # In Oracle, we expect a null CharField to return u'' instead of None. -if settings.DATABASES[DEFAULT_DB_ALIAS]['DATABASE_ENGINE'] == "oracle": +if settings.DATABASES[DEFAULT_DB_ALIAS]['ENGINE'] == "django.db.backends.oracle": __test__["API_TESTS"] = __test__["API_TESTS"].replace("", "u''") else: __test__["API_TESTS"] = __test__["API_TESTS"].replace("", "None") -if settings.DATABASES[DEFAULT_DB_ALIAS]['DATABASE_ENGINE'] == "mysql": +if settings.DATABASES[DEFAULT_DB_ALIAS]['ENGINE'] == "django.db.backends.mysql": __test__["API_TESTS"] += """ When grouping without specifying ordering, we add an explicit "ORDER BY NULL" portion in MySQL to prevent unnecessary sorting. diff --git a/tests/regressiontests/serializers_regress/tests.py b/tests/regressiontests/serializers_regress/tests.py index 94d082e56d..8cefb995f9 100644 --- a/tests/regressiontests/serializers_regress/tests.py +++ b/tests/regressiontests/serializers_regress/tests.py @@ -326,7 +326,7 @@ The end."""), # Because Oracle treats the empty string as NULL, Oracle is expected to fail # when field.empty_strings_allowed is True and the value is None; skip these # tests. -if settings.DATABASES[DEFAULT_DB_ALIAS]['DATABASE_ENGINE'] == 'oracle': +if settings.DATABASES[DEFAULT_DB_ALIAS]['ENGINE'] == 'django.db.backends.oracle': test_data = [data for data in test_data if not (data[0] == data_obj and data[2]._meta.get_field('data').empty_strings_allowed and @@ -335,7 +335,7 @@ if settings.DATABASES[DEFAULT_DB_ALIAS]['DATABASE_ENGINE'] == 'oracle': # Regression test for #8651 -- a FK to an object iwth PK of 0 # This won't work on MySQL since it won't let you create an object # with a primary key of 0, -if settings.DATABASES[DEFAULT_DB_ALIAS]['DATABASE_ENGINE'] != 'mysql': +if settings.DATABASES[DEFAULT_DB_ALIAS]['ENGINE'] != 'django.db.backends.mysql': test_data.extend([ (data_obj, 0, Anchor, "Anchor 0"), (fk_obj, 465, FKData, 0), diff --git a/tests/runtests.py b/tests/runtests.py index f556246c90..1408a0e0a3 100755 --- a/tests/runtests.py +++ b/tests/runtests.py @@ -89,7 +89,6 @@ def django_tests(verbosity, interactive, test_labels): from django.conf import settings old_installed_apps = settings.INSTALLED_APPS - old_test_database_name = settings.TEST_DATABASE_NAME old_root_urlconf = getattr(settings, "ROOT_URLCONF", "") old_template_dirs = settings.TEMPLATE_DIRS old_use_i18n = settings.USE_I18N