From bce55b1aa8ee6548aa8494683211cc16e47282ea Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Wed, 3 Jun 2009 01:58:33 +0000 Subject: [PATCH] [soc2009/multidb] Implemented a connections object that is responsible for tracking multiple database connections and lazily instantiating them. Also implemneted the DATABASES setting which replaces the various DATABASE_* settings git-svn-id: http://code.djangoproject.com/svn/django/branches/soc2009/multidb@10892 bcc190cf-cafb-0310-a4f2-bffc1f526a37 --- django/conf/global_settings.py | 3 + django/conf/project_template/settings.py | 17 +++-- .../management/commands/createcachetable.py | 13 +++- django/db/__init__.py | 58 +++++---------- django/db/utils.py | 55 ++++++++++++++ docs/howto/initial-data.txt | 4 +- docs/howto/legacy-databases.txt | 17 +++-- docs/internals/contributing.txt | 10 +-- docs/intro/tutorial01.txt | 53 ++++++------- docs/ref/databases.txt | 74 +++++++++++-------- docs/ref/settings.txt | 52 +++++++------ docs/topics/testing.txt | 10 +-- .../multiple_database/__init__.py | 0 .../multiple_database/models.py | 1 + .../multiple_database/tests.py | 17 +++++ 15 files changed, 232 insertions(+), 152 deletions(-) create mode 100644 django/db/utils.py create mode 100644 tests/regressiontests/multiple_database/__init__.py create mode 100644 tests/regressiontests/multiple_database/models.py create mode 100644 tests/regressiontests/multiple_database/tests.py diff --git a/django/conf/global_settings.py b/django/conf/global_settings.py index 99fc72e468..7867accab9 100644 --- a/django/conf/global_settings.py +++ b/django/conf/global_settings.py @@ -131,6 +131,9 @@ DATABASE_HOST = '' # Set to empty string for localhost. Not used wit DATABASE_PORT = '' # Set to empty string for default. Not used with sqlite3. DATABASE_OPTIONS = {} # Set to empty dictionary for default. +DATABASES = { +} + # Host for sending e-mail. EMAIL_HOST = 'localhost' diff --git a/django/conf/project_template/settings.py b/django/conf/project_template/settings.py index bbf005ddea..57fc6b5f0c 100644 --- a/django/conf/project_template/settings.py +++ b/django/conf/project_template/settings.py @@ -9,12 +9,17 @@ ADMINS = ( MANAGERS = ADMINS -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. +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. + } +} + # Local time zone for this installation. Choices can be found here: # http://en.wikipedia.org/wiki/List_of_tz_zones_by_name diff --git a/django/core/management/commands/createcachetable.py b/django/core/management/commands/createcachetable.py index 098bca793f..48fe791f39 100644 --- a/django/core/management/commands/createcachetable.py +++ b/django/core/management/commands/createcachetable.py @@ -1,14 +1,23 @@ +from optparse import make_option + from django.core.management.base import LabelCommand +from django.db import connections, transaction, models class Command(LabelCommand): help = "Creates the table needed to use the SQL cache backend." args = "" label = 'tablename' + options_list = LabelCommand.options_list + ( + make_option('--database', action='store', dest='database', + default='default', help='Selects what database to install the cache table to.'), + ) + requires_model_validation = False def handle_label(self, tablename, **options): - from django.db import connection, transaction, models + alias = options['alias'] + connection = connections[alias] fields = ( # "key" is a reserved word in MySQL, so use "cache_key" instead. models.CharField(name='cache_key', max_length=255, unique=True, primary_key=True), @@ -17,7 +26,7 @@ class Command(LabelCommand): ) table_output = [] index_output = [] - qn = connection.ops.quote_name + qn = connections.ops.quote_name for f in fields: field_output = [qn(f.name), f.db_type()] field_output.append("%sNULL" % (not f.null and "NOT " or "")) diff --git a/django/db/__init__.py b/django/db/__init__.py index 61c7a4fc74..fca992cd74 100644 --- a/django/db/__init__.py +++ b/django/db/__init__.py @@ -1,44 +1,25 @@ -import os from django.conf import settings from django.core import signals from django.core.exceptions import ImproperlyConfigured +from django.db.utils import ConnectionHandler, load_backend from django.utils.functional import curry -from django.utils.importlib import import_module __all__ = ('backend', 'connection', 'DatabaseError', 'IntegrityError') -if not settings.DATABASE_ENGINE: - settings.DATABASE_ENGINE = 'dummy' +if not settings.DATABASES or 'default' not in settings.DATABASES: + settings.DATABASES['default'] = { + '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, + } -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) - except ImportError, e: - # If the import failed, we might be looking for a database backend - # distributed external to Django. So we'll try that next. - try: - return import_module('.base', backend_name) - except ImportError, e_user: - # The database backend wasn't found. Display a helpful error message - # listing all possible (built-in) database backends. - backend_dir = os.path.join(__path__[0], 'backends') - try: - available_backends = [f for f in os.listdir(backend_dir) - if os.path.isdir(os.path.join(backend_dir, f)) - and not f.startswith('.')] - except EnvironmentError: - available_backends = [] - available_backends.sort() - if backend_name not in available_backends: - error_msg = "%r isn't an available database backend. Available options are: %s\nError was: %s" % \ - (backend_name, ", ".join(map(repr, available_backends)), e_user) - raise ImproperlyConfigured(error_msg) - else: - raise # If there's some other error, this must be an error in Django itself. +connections = ConnectionHandler(settings.DATABASES) -backend = load_backend(settings.DATABASE_ENGINE) # `connection`, `DatabaseError` and `IntegrityError` are convenient aliases # for backend bits. @@ -47,15 +28,10 @@ backend = load_backend(settings.DATABASE_ENGINE) # we manually create the dictionary from the settings, passing only the # settings that the database backends care about. Note that TIME_ZONE is used # by the PostgreSQL backends. -connection = backend.DatabaseWrapper({ - '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, -}) +# we load all these up for backwards compatibility, you should use +# connections['default'] instead. +connection = connections['default'] +backend = load_backend(settings.DATABASE_ENGINE) DatabaseError = backend.DatabaseError IntegrityError = backend.IntegrityError diff --git a/django/db/utils.py b/django/db/utils.py new file mode 100644 index 0000000000..b5e6f1e2a8 --- /dev/null +++ b/django/db/utils.py @@ -0,0 +1,55 @@ +import os + +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) + except ImportError, e: + # If the import failed, we might be looking for a database backend + # distributed external to Django. So we'll try that next. + try: + return import_module('.base', backend_name) + except ImportError, e_user: + # The database backend wasn't found. Display a helpful error message + # listing all possible (built-in) database backends. + backend_dir = os.path.join(__path__[0], 'backends') + try: + available_backends = [f for f in os.listdir(backend_dir) + if os.path.isdir(os.path.join(backend_dir, f)) + and not f.startswith('.')] + except EnvironmentError: + available_backends = [] + available_backends.sort() + if backend_name not in available_backends: + error_msg = "%r isn't an available database backend. Available options are: %s\nError was: %s" % \ + (backend_name, ", ".join(map(repr, available_backends)), e_user) + raise ImproperlyConfigured(error_msg) + else: + raise # If there's some other error, this must be an error in Django itself. + +class ConnectionHandler(object): + def __init__(self, databases): + self.databases = databases + self._connections = {} + + def check_connection(self, alias): + conn = self.databases[alias] + conn.setdefault('DATABASE_ENGINE', 'dummy') + conn.setdefault('DATABASE_OPTIONS', {}) + for setting in ('DATABASE_NAME', 'DATABASE_USER', 'DATABASE_PASSWORD', + 'DATABASE_HOST', 'DATABASE_PORT'): + conn.setdefault(setting, '') + + def __getitem__(self, alias): + if alias in self._connections: + return self._connections[alias] + + self.check_connection(alias) + db = self.databases[alias] + backend = load_backend(db['DATABASE_ENGINE']) + conn = backend.DatabaseWrapper(db) + self._connections[alias] = conn + return conn diff --git a/docs/howto/initial-data.txt b/docs/howto/initial-data.txt index d36329daa4..51a9c4742b 100644 --- a/docs/howto/initial-data.txt +++ b/docs/howto/initial-data.txt @@ -130,8 +130,8 @@ 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 :setting:`DATABASE_ENGINE` in your -settings file (e.g., ``postgresql``, ``mysql``). +lowercase and ```` is the value of ``DATABASE_ENGINE`` for the given +database being set up in your settings file (e.g., ``postgresql``, ``mysql``). Backend-specific SQL data is executed before non-backend-specific SQL data. For example, if your app contains the files ``sql/person.sql`` and diff --git a/docs/howto/legacy-databases.txt b/docs/howto/legacy-databases.txt index c4eb1d82c7..1f3cd7ae80 100644 --- a/docs/howto/legacy-databases.txt +++ b/docs/howto/legacy-databases.txt @@ -18,15 +18,16 @@ 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 these settings in your -:ref:`settings file `: +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:`DATABASE_NAME` - * :setting:`DATABASE_ENGINE` - * :setting:`DATABASE_USER` - * :setting:`DATABASE_PASSWORD` - * :setting:`DATABASE_HOST` - * :setting:`DATABASE_PORT` + * ``DATABASE_NAME`` + * ``DATABASE_ENGINE`` + * ``DATABASE_USER`` + * ``DATABASE_PASSWORD`` + * ``DATABASE_HOST`` + * ``DATABASE_PORT`` Auto-generate the models ======================== diff --git a/docs/internals/contributing.txt b/docs/internals/contributing.txt index 1f1161de43..7ec152ec43 100644 --- a/docs/internals/contributing.txt +++ b/docs/internals/contributing.txt @@ -752,20 +752,20 @@ To run the tests, ``cd`` to the ``tests/`` directory and type: ./runtests.py --settings=path.to.django.settings Yes, the unit tests need a settings module, but only for database connection -info, with the ``DATABASE_ENGINE`` setting. +info, with the ``DATABASES`` setting. If you're using the ``sqlite3`` database backend, no further settings are needed. A temporary database will be created in memory when running the tests. If you're using another backend: - * Your :setting:`DATABASE_USER` setting needs to specify an existing user account - for the database engine. + * Your the ``DATABASE_USER`` option for the ``'default'`` datbase setting + needs to specify an existing user account for the database engine. - * The :setting:`DATABASE_NAME` setting must be the name of an existing database to + * The ``DATABASE_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 + ``DATABASE_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``. diff --git a/docs/intro/tutorial01.txt b/docs/intro/tutorial01.txt index c0ad3dd8cf..ef65dae38d 100644 --- a/docs/intro/tutorial01.txt +++ b/docs/intro/tutorial01.txt @@ -42,13 +42,13 @@ code, then run the command ``django-admin.py startproject mysite``. This will create a ``mysite`` directory in your current directory. .. admonition:: Mac OS X permissions - + If you're using Mac OS X, you may see the message "permission denied" when you try to run ``django-admin.py startproject``. This is because, on Unix-based systems like OS X, a file must be marked as "executable" before it can be run as a program. To do this, open Terminal.app and navigate (using the ``cd`` command) to the directory where :ref:`django-admin.py - ` is installed, then run the command + ` is installed, then run the command ``chmod +x django-admin.py``. .. note:: @@ -90,14 +90,14 @@ These files are: * :file:`__init__.py`: An empty file that tells Python that this directory should be considered a Python package. (Read `more about packages`_ in the official Python docs if you're a Python beginner.) - + * :file:`manage.py`: A command-line utility that lets you interact with this Django project in various ways. You can read all the details about :file:`manage.py` in :ref:`ref-django-admin`. - + * :file:`settings.py`: Settings/configuration for this Django project. :ref:`topics-settings` will tell you all about how settings work. - + * :file:`urls.py`: The URL declarations for this Django project; a "table of contents" of your Django-powered site. You can read more about URLs in :ref:`topics-http-urls`. @@ -134,22 +134,22 @@ It worked! .. admonition:: Changing the port By default, the :djadmin:`runserver` command starts the development server - on the internal IP at port 8000. - + on the internal IP at port 8000. + If you want to change the server's port, pass it as a command-line argument. For instance, this command starts the server on port 8080: - + .. code-block:: bash python manage.py runserver 8080 - + If you want to change the server's IP, pass it along with the port. So to listen on all public IPs (useful if you want to show off your work on other computers), use: - + .. code-block:: bash - + python manage.py runserver 0.0.0.0:8000 Full docs for the development server can be found in the @@ -159,32 +159,33 @@ Database setup -------------- Now, edit :file:`settings.py`. It's a normal Python module with module-level -variables representing Django settings. Change these settings to match your -database's connection parameters: +variables representing Django settings. Change the following keys in the +:setting:`DATABASES` ``'default'`` item to match your databases connection +settings. - * :setting:`DATABASE_ENGINE` -- Either 'postgresql_psycopg2', 'mysql' or + * ``DATABASE_ENGINE`` -- Either 'postgresql_psycopg2', 'mysql' or 'sqlite3'. Other backends are :setting:`also available `. - - * :setting:`DATABASE_NAME` -- The name of your database. If you're using + + * ``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). - - When specifying the path, always use forward slashes, even on Windows + + When specifying the path, always use forward slashes, even on Windows (e.g. ``C:/homes/user/mysite/sqlite3.db``). - - * :setting:`DATABASE_USER` -- Your database username (not used for SQLite). - - * :setting:`DATABASE_PASSWORD` -- Your database password (not used for + + * ``DATABASE_USER`` -- Your database username (not used for SQLite). + + * ``DATABASE_PASSWORD`` -- Your database password (not used for SQLite). - - * :setting:`DATABASE_HOST` -- The host your database is on. Leave this as an + + * ``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). If you're new to databases, we recommend simply using SQLite (by setting -:setting:`DATABASE_ENGINE` to ``'sqlite3'``). SQLite is included as part of +``DATABASE_ENGINE`` to ``'sqlite3'``). SQLite is included as part of Python 2.5 and later, so you won't need to install anything else. .. note:: @@ -594,7 +595,7 @@ your models, not only for your own sanity when dealing with the interactive prompt, but also because objects' representations are used throughout Django's automatically-generated admin. -.. admonition:: Why :meth:`~django.db.models.Model.__unicode__` and not +.. admonition:: Why :meth:`~django.db.models.Model.__unicode__` and not :meth:`~django.db.models.Model.__str__`? If you're familiar with Python, you might be in the habit of adding diff --git a/docs/ref/databases.txt b/docs/ref/databases.txt index 76a4159235..adac7523b4 100644 --- a/docs/ref/databases.txt +++ b/docs/ref/databases.txt @@ -53,7 +53,7 @@ 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:`DATABASE_OPTIONS` setting:: +``DATABASE_OPTIONS`` part of your database in :setting:`DATABASES`:: DATABASE_OPTIONS = { "autocommit": True, @@ -69,9 +69,9 @@ objects are changed or none of them are. 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 :setting:`DATABASE_OPTIONS` - settings provides autocommit behavior at the database adapter level. It - commits after *every* operation. + operations. The feature enabled using the ``DATABASE_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,10 +234,10 @@ Refer to the :ref:`settings documentation `. Connection settings are used in this order: - 1. :setting:`DATABASE_OPTIONS`. - 2. :setting:`DATABASE_NAME`, :setting:`DATABASE_USER`, - :setting:`DATABASE_PASSWORD`, :setting:`DATABASE_HOST`, - :setting:`DATABASE_PORT` + 1. ``DATABASE_OPTIONS``. + 2. ``DATABASE_NAME``, ``DATABASE_USER``, + ``DATABASE_PASSWORD``, ``DATABASE_HOST``, + ``DATABASE_PORT`` 3. MySQL option files. In other words, if you set the name of the database in ``DATABASE_OPTIONS``, @@ -247,11 +247,16 @@ anything in a `MySQL option file`_. Here's a sample configuration which uses a MySQL option file:: # settings.py - DATABASE_ENGINE = "mysql" - DATABASE_OPTIONS = { - 'read_default_file': '/path/to/my.cnf', + DATABASES = { + 'default': { + 'DATABASE_ENGINE': "mysql", + 'DATABASE_OPTIONS': { + 'read_default_file': '/path/to/my.cnf', + }, + } } - + + # my.cnf [client] database = DATABASE_NAME @@ -445,10 +450,10 @@ If you're getting this error, you can solve it by: * Switching to another database backend. At a certain point SQLite becomes too "lite" for real-world applications, and these sorts of concurrency errors indicate you've reached that point. - - * Rewriting your code to reduce concurrency and ensure that database + + * Rewriting your code to reduce concurrency and ensure that database transactions are short-lived. - + * Increase the default timeout value by setting the ``timeout`` database option option:: @@ -457,7 +462,7 @@ If you're getting this error, you can solve it by: "timeout": 20, # ... } - + This will simply make SQLite wait a bit longer before throwing "database is locked" errors; it won't really do anything to solve them. @@ -501,25 +506,34 @@ Connecting to the database Your Django settings.py file should look something like this for Oracle:: - DATABASE_ENGINE = 'oracle' - DATABASE_NAME = 'xe' - DATABASE_USER = 'a_user' - DATABASE_PASSWORD = 'a_password' - DATABASE_HOST = '' - DATABASE_PORT = '' + DATABASES = { + 'default': { + 'DATABASE_ENGINE': 'oracle', + 'DATABASE_NAME': 'xe', + 'DATABASE_USER': 'a_user', + 'DATABASE_PASSWORD': 'a_password', + 'DATABASE_HOST': '', + 'DATABASE_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 -:setting:`DATABASE_HOST` and :setting:`DATABASE_PORT` like so:: +``DATABASE_HOST`` and ``DATABASE_PORT`` like so:: - DATABASE_ENGINE = 'oracle' - DATABASE_NAME = 'xe' - DATABASE_USER = 'a_user' - DATABASE_PASSWORD = 'a_password' - DATABASE_HOST = 'dbprod01ned.mycompany.com' - DATABASE_PORT = '1540' + DATABASES = { + 'default': { + 'DATABASE_ENGINE': 'oracle', + 'DATABASE_NAME': 'xe', + 'DATABASE_USER': 'a_user', + 'DATABASE_PASSWORD': 'a_password', + 'DATABASE_HOST': 'dbprod01ned.mycompany.com', + 'DATABASE_PORT': '1540', + } + } -You should supply both :setting:`DATABASE_HOST` and :setting:`DATABASE_PORT`, or leave both +You should supply both ``DATABASE_HOST`` and ``DATABASE_PORT``, or leave both as empty strings. Tablespace options diff --git a/docs/ref/settings.txt b/docs/ref/settings.txt index 0cca6fe05d..c3d00e74a4 100644 --- a/docs/ref/settings.txt +++ b/docs/ref/settings.txt @@ -144,10 +144,20 @@ Default: ``600`` The default number of seconds to cache a page when the caching middleware or ``cache_page()`` decorator is used. -.. setting:: DATABASE_ENGINE +.. setting:: DATABASES + +DATABASES +--------- + +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: DATABASE_ENGINE ---------------- +~~~~~~~~~~~~~~~ Default: ``''`` (Empty string) @@ -164,10 +174,8 @@ examples. .. versionadded:: 1.0 Support for external database backends is new in 1.0. -.. setting:: DATABASE_HOST - DATABASE_HOST -------------- +~~~~~~~~~~~~~ Default: ``''`` (Empty string) @@ -177,7 +185,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' + "DATABASE_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. @@ -187,50 +195,40 @@ 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. -.. setting:: DATABASE_NAME - DATABASE_NAME -------------- +~~~~~~~~~~~~~ Default: ``''`` (Empty string) 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 +file. When specifying the path, always use forward slashes, even on Windows (e.g. ``C:/homes/user/mysite/sqlite3.db``). -.. setting:: DATABASE_OPTIONS - DATABASE_OPTIONS ----------------- +~~~~~~~~~~~~~~~~ Default: ``{}`` (Empty dictionary) Extra parameters to use when connecting to the database. Consult backend module's document for available keywords. -.. setting:: DATABASE_PASSWORD - DATABASE_PASSWORD ------------------ +~~~~~~~~~~~~~~~~~ Default: ``''`` (Empty string) The password to use when connecting to the database. Not used with SQLite. -.. setting:: DATABASE_PORT - DATABASE_PORT -------------- +~~~~~~~~~~~~~ Default: ``''`` (Empty string) The port to use when connecting to the database. An empty string means the default port. Not used with SQLite. -.. setting:: DATABASE_USER - DATABASE_USER -------------- +~~~~~~~~~~~~~ Default: ``''`` (Empty string) @@ -251,7 +249,7 @@ See also ``DATETIME_FORMAT``, ``TIME_FORMAT``, ``YEAR_MONTH_FORMAT`` and ``MONTH_DAY_FORMAT``. .. setting:: DATETIME_FORMAT - + DATETIME_FORMAT --------------- @@ -519,14 +517,14 @@ system's standard umask. .. warning:: **Always prefix the mode with a 0.** - + If you're not familiar with file modes, please note that the leading ``0`` is very important: it indicates an octal number, which is the way that modes must be specified. If you try to use ``644``, you'll get totally incorrect behavior. - -.. _documentation for os.chmod: http://docs.python.org/lib/os-file-dir.html + +.. _documentation for os.chmod: http://docs.python.org/lib/os-file-dir.html .. setting:: FIXTURE_DIRS @@ -1153,7 +1151,7 @@ running in the correct environment. Django cannot reliably use alternate time zones in a Windows environment. If you're running Django on Windows, this variable must be set to match the system timezone. - + .. _See available choices: http://www.postgresql.org/docs/8.1/static/datetime-keywords.html#DATETIME-TIMEZONE-SET-TABLE .. setting:: URL_VALIDATOR_USER_AGENT diff --git a/docs/topics/testing.txt b/docs/topics/testing.txt index 0410049297..5db4897a59 100644 --- a/docs/topics/testing.txt +++ b/docs/topics/testing.txt @@ -139,8 +139,8 @@ In the case of model tests, note that the test runner takes care of creating its own test database. That is, any test that accesses a database -- by creating and saving model instances, for example -- will not affect your production database. However, the database is not refreshed between doctests, -so if your doctest requires a certain state you should consider flushin the -database or loading a fixture. (See the section on fixtures, below, for more +so if your doctest requires a certain state you should consider flushin the +database or loading a fixture. (See the section on fixtures, below, for more on this.) Note that to use this feature, the database user Django is connecting as must have ``CREATE DATABASE`` rights. @@ -284,7 +284,7 @@ Regardless of whether the tests pass or fail, the test database is destroyed when all the tests have been executed. By default this test database gets its name by prepending ``test_`` to the -value of the :setting:`DATABASE_NAME` setting. When using the SQLite database +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 the :setting:`TEST_DATABASE_NAME` @@ -292,9 +292,9 @@ setting. 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:`DATABASE_ENGINE`, :setting:`DATABASE_USER`, :setting:`DATABASE_HOST`, +``DATABASE_ENGINE``, ``DATABASE_USER``, ``DATABASE_HOST``, etc. The test database is created by the user specified by -:setting:`DATABASE_USER`, so you'll need to make sure that the given user +``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. .. versionadded:: 1.0 diff --git a/tests/regressiontests/multiple_database/__init__.py b/tests/regressiontests/multiple_database/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/regressiontests/multiple_database/models.py b/tests/regressiontests/multiple_database/models.py new file mode 100644 index 0000000000..8b13789179 --- /dev/null +++ b/tests/regressiontests/multiple_database/models.py @@ -0,0 +1 @@ + diff --git a/tests/regressiontests/multiple_database/tests.py b/tests/regressiontests/multiple_database/tests.py new file mode 100644 index 0000000000..a55a9c7123 --- /dev/null +++ b/tests/regressiontests/multiple_database/tests.py @@ -0,0 +1,17 @@ +from django.conf import settings +from django.db import connections +from django.test import TestCase + +class DatabaseSettingTestCase(TestCase): + def setUp(self): + settings.DATABASES['__test_db'] = { + 'DATABASE_ENGINE': 'sqlite3', + 'DATABASE_NAME': ':memory:', + } + + def tearDown(self): + del settings.DATABASES['__test_db'] + + def test_db_connection(self): + connections['default'].cursor() + connections['__test_db'].cursor()