summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJason Pellerin <jpellerin@gmail.com>2006-06-28 18:35:43 +0000
committerJason Pellerin <jpellerin@gmail.com>2006-06-28 18:35:43 +0000
commitf19713f56f50fbe04290ca46ebe7b51f999e9d0f (patch)
tree9a96ab3869e7ae948636fcd0c575de29abb25126
parentda5b0586d359390e2102703707afae65befe7f6d (diff)
* Added connect() function and ConnectionInfo class to abstract
connection-establishment mechanics. * In backends, added required settings parameter to DatabaseWrapper(), so that connections can keep track of their settings. git-svn-id: http://code.djangoproject.com/svn/django/branches/multiple-db-support@3229 bcc190cf-cafb-0310-a4f2-bffc1f526a37
-rw-r--r--django/db/__init__.py169
-rw-r--r--django/db/backends/ado_mssql/base.py5
-rw-r--r--django/db/backends/mysql/base.py5
-rw-r--r--django/db/backends/oracle/base.py5
-rw-r--r--django/db/backends/postgresql/base.py5
-rw-r--r--django/db/backends/sqlite3/base.py5
6 files changed, 153 insertions, 41 deletions
diff --git a/django/db/__init__.py b/django/db/__init__.py
index f21ae6a727..f519b5bea9 100644
--- a/django/db/__init__.py
+++ b/django/db/__init__.py
@@ -1,5 +1,6 @@
-from django.conf import settings
+from django.conf import settings, UserSettingsHolder
from django.core import signals
+from django.core.exceptions import ImproperlyConfigured
from django.dispatch import dispatcher
__all__ = ('backend', 'connection', 'DatabaseError')
@@ -7,42 +8,148 @@ __all__ = ('backend', 'connection', 'DatabaseError')
if not settings.DATABASE_ENGINE:
settings.DATABASE_ENGINE = 'dummy'
-try:
- backend = __import__('django.db.backends.%s.base' % settings.DATABASE_ENGINE, '', '', [''])
-except ImportError, e:
- # The database backend wasn't found. Display a helpful error message
- # listing all possible database backends.
- from django.core.exceptions import ImproperlyConfigured
- import os
- backend_dir = os.path.join(__path__[0], 'backends')
- available_backends = [f for f in os.listdir(backend_dir) if not f.startswith('_') and not f.startswith('.') and not f.endswith('.py') and not f.endswith('.pyc')]
- available_backends.sort()
- if settings.DATABASE_ENGINE not in available_backends:
- raise ImproperlyConfigured, "%r isn't an available database backend. vailable options are: %s" % \
- (settings.DATABASE_ENGINE, ", ".join(map(repr, available_backends)))
- else:
- raise # If there's some other error, this must be an error in Django itself.
+def connect(settings):
+ """Connect to the database specified in settings. Returns a
+ ConnectionInfo on succes, raises ImproperlyConfigured if the
+ settings don't specify a valid database connection.
+ """
+ try:
+ backend = __import__('django.db.backends.%s.base' % settings.DATABASE_ENGINE, '', '', [''])
+ except ImportError, e:
+ # The database backend wasn't found. Display a helpful error message
+ # listing all possible database backends.
+ import os
+ backend_dir = os.path.join(__path__[0], 'backends')
+ available_backends = [f for f in os.listdir(backend_dir) if not f.startswith('_') and not f.startswith('.') and not f.endswith('.py') and not f.endswith('.pyc')]
+ available_backends.sort()
+ if settings.DATABASE_ENGINE not in available_backends:
+ raise ImproperlyConfigured, "%r isn't an available database backend. vailable options are: %s" % \
+ (settings.DATABASE_ENGINE, ", ".join(map(repr, available_backends)))
+ else:
+ raise # If there's some other error, this must be an error in Django itself.
-get_introspection_module = lambda: __import__('django.db.backends.%s.introspection' % settings.DATABASE_ENGINE, '', '', [''])
-get_creation_module = lambda: __import__('django.db.backends.%s.creation' % settings.DATABASE_ENGINE, '', '', [''])
-runshell = lambda: __import__('django.db.backends.%s.client' % settings.DATABASE_ENGINE, '', '', ['']).runshell()
+ info = ConnectionInfo(backend, settings)
-connection = backend.DatabaseWrapper()
-DatabaseError = backend.DatabaseError
+ # Register an event that closes the database connection
+ # when a Django request is finished.
+ dispatcher.connect(info.close, signal=signals.request_finished)
+
+ # Register an event that resets connection.queries
+ # when a Django request is started.
+ dispatcher.connect(info.reset_queries, signal=signals.request_started)
-# Register an event that closes the database connection
-# when a Django request is finished.
-dispatcher.connect(connection.close, signal=signals.request_finished)
+ return info
-# Register an event that resets connection.queries
-# when a Django request is started.
-def reset_queries():
- connection.queries = []
-dispatcher.connect(reset_queries, signal=signals.request_started)
+
+class ConnectionInfo(object):
+ """Encapsulates all information about a connection and the backend
+ to which it belongs. Provides methods for loading backend
+ creation, introspection, and shell modules, closing the
+ connection, and resetting the connection's query log.
+ """
+ def __init__(self, backend, settings):
+ self.backend = backend
+ self.settings = settings
+ self.connection = backend.DatabaseWrapper(settings)
+ self.DatabaseError = backend.DatabaseError
-# Register an event that rolls back the connection
+ def __repr__(self):
+ return "Connection: %r (ENGINE=%s NAME=%s)" \
+ % (self.connection,
+ self.connection.settings.DATABASE_ENGINE,
+ self.connection.settings.DATABASE_NAME)
+
+ def close(self):
+ """Close connection"""
+ self.connection.close()
+
+ def get_introspection_module(self):
+ return __import__('django.db.backends.%s.introspection' %
+ self.settings.DATABASE_ENGINE, '', '', [''])
+
+ def get_creation_module(self):
+ return __import__('django.db.backends.%s.creation' %
+ self.settings.DATABASE_ENGINE, '', '', [''])
+
+ def runshell(self):
+ __import__('django.db.backends.%s.client' %
+ self.settings.DATABASE_ENGINE, '', '', ['']).runshell()
+
+ def reset_queries(self):
+ """Reset log of queries executed by connection"""
+ self.connection.queries = []
+
+
+class LazyConnectionManager(object):
+ """Manages named connections lazily, instantiating them as
+ they are requested.
+ """
+ def __init__(self):
+ self._connections = {}
+
+ def __iter__(self):
+ return self._connections.keys()
+
+ def __getattr__(self, attr):
+ # use __dict__ to avoid getattr() loop
+ return getattr(self.__dict__['_connections'], attr)
+
+ def __getitem__(self, k):
+ try:
+ return self._connections[k]
+ except KeyError:
+ try:
+ return self.connect(k)
+ except KeyError:
+ raise ImproperlyConfigured, \
+ "No database connection '%s' has been configured" % k
+
+ def connect(self, name):
+ """Return the connection with this name in
+ settings.DATABASES. Creates the connection if it doesn't yet
+ exist. Reconnects if it does.
+ """
+ if name in self._connections:
+ self._connections[name].close()
+ try:
+ info = settings.DATABASES[name]
+ except KeyError:
+ raise ImproperlyConfigured, \
+ "No database connection '%s' has been configured" % name
+ except AttributeError:
+ raise ImproperlyConfigured, \
+ "No DATABASES in settings."
+
+ # In settings it's a dict, but connect() needs an object
+ # pass global settings so that the default connection settings
+ # can be defaults for the named connections
+ database = UserSettingsHolder(settings)
+ for k, v in info.items():
+ setattr(database, k, v)
+ self._connections[name] = connect(database)
+ return self._connections[name]
+
+
+# Backwards compatibility: establish the default connection and set the
+# default connection properties at module level
+connection_info = connect(settings)
+(connection, DatabaseError, backend, get_introspection_module,
+ get_creation_module, runshell) = (connection_info.connection,
+ connection_info.DatabaseError,
+ connection_info.backend,
+ connection_info.get_introspection_module,
+ connection_info.get_creation_module,
+ connection_info.runshell)
+
+# Create a manager for named connections
+connections = LazyConnectionManager()
+
+# Register an event that rolls back all connections
# when a Django request has an exception.
def _rollback_on_exception():
from django.db import transaction
transaction.rollback_unless_managed()
-dispatcher.connect(_rollback_on_exception, signal=signals.got_request_exception)
+dispatcher.connect(_rollback_on_exception,
+ signal=signals.got_request_exception)
+
+
diff --git a/django/db/backends/ado_mssql/base.py b/django/db/backends/ado_mssql/base.py
index afe2d19981..8844faf293 100644
--- a/django/db/backends/ado_mssql/base.py
+++ b/django/db/backends/ado_mssql/base.py
@@ -55,12 +55,13 @@ except ImportError:
from django.utils._threading_local import local
class DatabaseWrapper(local):
- def __init__(self):
+ def __init__(self, settings):
+ self.settings = settings
self.connection = None
self.queries = []
def cursor(self):
- from django.conf import settings
+ settings = self.settings
if self.connection is None:
if settings.DATABASE_NAME == '' or settings.DATABASE_USER == '':
from django.core.exceptions import ImproperlyConfigured
diff --git a/django/db/backends/mysql/base.py b/django/db/backends/mysql/base.py
index a522f24f2f..669a4fccf2 100644
--- a/django/db/backends/mysql/base.py
+++ b/django/db/backends/mysql/base.py
@@ -58,7 +58,8 @@ except ImportError:
from django.utils._threading_local import local
class DatabaseWrapper(local):
- def __init__(self):
+ def __init__(self, settings):
+ self.settings = settings
self.connection = None
self.queries = []
@@ -73,7 +74,7 @@ class DatabaseWrapper(local):
return False
def cursor(self):
- from django.conf import settings
+ settings = self.settings
if not self._valid_connection():
kwargs = {
'user': settings.DATABASE_USER,
diff --git a/django/db/backends/oracle/base.py b/django/db/backends/oracle/base.py
index 9943ac9610..3bbe174188 100644
--- a/django/db/backends/oracle/base.py
+++ b/django/db/backends/oracle/base.py
@@ -22,7 +22,8 @@ except ImportError:
from django.utils._threading_local import local
class DatabaseWrapper(local):
- def __init__(self):
+ def __init__(self, settings):
+ self.settings = settings
self.connection = None
self.queries = []
@@ -30,7 +31,7 @@ class DatabaseWrapper(local):
return self.connection is not None
def cursor(self):
- from django.conf import settings
+ settings = self.settings
if not self._valid_connection():
if len(settings.DATABASE_HOST.strip()) == 0:
settings.DATABASE_HOST = 'localhost'
diff --git a/django/db/backends/postgresql/base.py b/django/db/backends/postgresql/base.py
index 5355781e81..f9372bf1f8 100644
--- a/django/db/backends/postgresql/base.py
+++ b/django/db/backends/postgresql/base.py
@@ -21,12 +21,13 @@ except ImportError:
from django.utils._threading_local import local
class DatabaseWrapper(local):
- def __init__(self):
+ def __init__(self, settings):
+ self.settings = settings
self.connection = None
self.queries = []
def cursor(self):
- from django.conf import settings
+ settings = self.settings
if self.connection is None:
if settings.DATABASE_NAME == '':
from django.core.exceptions import ImproperlyConfigured
diff --git a/django/db/backends/sqlite3/base.py b/django/db/backends/sqlite3/base.py
index 68452e1363..b277526b5a 100644
--- a/django/db/backends/sqlite3/base.py
+++ b/django/db/backends/sqlite3/base.py
@@ -34,12 +34,13 @@ except ImportError:
from django.utils._threading_local import local
class DatabaseWrapper(local):
- def __init__(self):
+ def __init__(self, settings):
+ self.settings = settings
self.connection = None
self.queries = []
def cursor(self):
- from django.conf import settings
+ settings = self.settings
if self.connection is None:
self.connection = Database.connect(settings.DATABASE_NAME,
detect_types=Database.PARSE_DECLTYPES | Database.PARSE_COLNAMES)