diff --git a/django/db/backends/__init__.py b/django/db/backends/__init__.py index e69de29bb2d..91ad9a3d393 100644 --- a/django/db/backends/__init__.py +++ b/django/db/backends/__init__.py @@ -0,0 +1,36 @@ +try: + # Only exists in Python 2.4+ + from threading import local +except ImportError: + # Import copy of _thread_local.py from Python 2.4 + from django.utils._threading_local import local + +class BaseDatabaseWrapper(local): + def __init__(self, **kwargs): + self.connection = None + self.queries = [] + self.options = kwargs + + def _commit(self): + if self.connection is not None: + return self.connection.commit() + + def _rollback(self): + if self.connection is not None: + return self.connection.rollback() + + def close(self): + if self.connection is not None: + self.connection.close() + self.connection = None + + def cursor(self): + from django.conf import settings + cursor = self._cursor(settings) + if settings.DEBUG: + return self.make_debug_cursor(cursor) + return cursor + + def make_debug_cursor(self, cursor): + from django.db.backends import util + return util.CursorDebugWrapper(cursor, self) diff --git a/django/db/backends/ado_mssql/base.py b/django/db/backends/ado_mssql/base.py index 0deb6aae64c..27b796ce569 100644 --- a/django/db/backends/ado_mssql/base.py +++ b/django/db/backends/ado_mssql/base.py @@ -4,7 +4,7 @@ ADO MSSQL database backend for Django. Requires adodbapi 2.0.1: http://adodbapi.sourceforge.net/ """ -from django.db.backends import util +from django.db.backends import BaseDatabaseWrapper, util try: import adodbapi as Database except ImportError, e: @@ -48,46 +48,18 @@ def variantToPython(variant, adType): return res Database.convertVariantToPython = variantToPython -try: - # Only exists in Python 2.4+ - from threading import local -except ImportError: - # Import copy of _thread_local.py from Python 2.4 - from django.utils._threading_local import local - -class DatabaseWrapper(local): - def __init__(self, **kwargs): - self.connection = None - self.queries = [] - - def cursor(self): - from django.conf import settings +class DatabaseWrapper(BaseDatabaseWrapper): + def _cursor(self, settings): if self.connection is None: if settings.DATABASE_NAME == '' or settings.DATABASE_USER == '': from django.core.exceptions import ImproperlyConfigured - raise ImproperlyConfigured, "You need to specify both DATABASE_NAME and DATABASE_USER in your Django settings file." + raise ImproperlyConfigured("You need to specify both DATABASE_NAME and DATABASE_USER in your Django settings file.") if not settings.DATABASE_HOST: settings.DATABASE_HOST = "127.0.0.1" # TODO: Handle DATABASE_PORT. conn_string = "PROVIDER=SQLOLEDB;DATA SOURCE=%s;UID=%s;PWD=%s;DATABASE=%s" % (settings.DATABASE_HOST, settings.DATABASE_USER, settings.DATABASE_PASSWORD, settings.DATABASE_NAME) self.connection = Database.connect(conn_string) - cursor = self.connection.cursor() - if settings.DEBUG: - return util.CursorDebugWrapper(cursor, self) - return cursor - - def _commit(self): - if self.connection is not None: - return self.connection.commit() - - def _rollback(self): - if self.connection is not None: - return self.connection.rollback() - - def close(self): - if self.connection is not None: - self.connection.close() - self.connection = None + return self.connection.cursor() allows_group_by_ordinal = True allows_unique_and_pk = True diff --git a/django/db/backends/mysql/base.py b/django/db/backends/mysql/base.py index 25ae2fa84fe..22c819e3b76 100644 --- a/django/db/backends/mysql/base.py +++ b/django/db/backends/mysql/base.py @@ -4,7 +4,7 @@ MySQL database backend for Django. Requires MySQLdb: http://sourceforge.net/projects/mysql-python """ -from django.db.backends import util +from django.db.backends import BaseDatabaseWrapper, util try: import MySQLdb as Database except ImportError, e: @@ -53,19 +53,10 @@ server_version_re = re.compile(r'(\d{1,2})\.(\d{1,2})\.(\d{1,2})') # standard util.CursorDebugWrapper can be used. Also, using sql_mode # TRADITIONAL will automatically cause most warnings to be treated as errors. -try: - # Only exists in Python 2.4+ - from threading import local -except ImportError: - # Import copy of _thread_local.py from Python 2.4 - from django.utils._threading_local import local - -class DatabaseWrapper(local): +class DatabaseWrapper(BaseDatabaseWrapper): def __init__(self, **kwargs): - self.connection = None - self.queries = [] + super(DatabaseWrapper, self).__init__(**kwargs) self.server_version = None - self.options = kwargs def _valid_connection(self): if self.connection is not None: @@ -77,8 +68,7 @@ class DatabaseWrapper(local): self.connection = None return False - def cursor(self): - from django.conf import settings + def _cursor(self, settings): from warnings import filterwarnings if not self._valid_connection(): kwargs = { @@ -100,29 +90,16 @@ class DatabaseWrapper(local): kwargs['port'] = int(settings.DATABASE_PORT) kwargs.update(self.options) self.connection = Database.connect(**kwargs) - cursor = self.connection.cursor() - else: - cursor = self.connection.cursor() + cursor = self.connection.cursor() if settings.DEBUG: filterwarnings("error", category=Database.Warning) - return util.CursorDebugWrapper(cursor, self) return cursor - def _commit(self): - if self.connection is not None: - self.connection.commit() - def _rollback(self): - if self.connection is not None: - try: - self.connection.rollback() - except Database.NotSupportedError: - pass - - def close(self): - if self.connection is not None: - self.connection.close() - self.connection = None + try: + BaseDatabaseWrapper._rollback(self) + except Database.NotSupportedError: + pass def get_server_version(self): if not self.server_version: diff --git a/django/db/backends/mysql_old/base.py b/django/db/backends/mysql_old/base.py index 0116af53ea9..9abc1bf1293 100644 --- a/django/db/backends/mysql_old/base.py +++ b/django/db/backends/mysql_old/base.py @@ -4,7 +4,7 @@ MySQL database backend for Django. Requires MySQLdb: http://sourceforge.net/projects/mysql-python """ -from django.db.backends import util +from django.db.backends import BaseDatabaseWrapper, util from django.utils.encoding import force_unicode try: import MySQLdb as Database @@ -63,19 +63,10 @@ class MysqlDebugWrapper: else: return getattr(self.cursor, attr) -try: - # Only exists in Python 2.4+ - from threading import local -except ImportError: - # Import copy of _thread_local.py from Python 2.4 - from django.utils._threading_local import local - -class DatabaseWrapper(local): +class DatabaseWrapper(BaseDatabaseWrapper): def __init__(self, **kwargs): - self.connection = None - self.queries = [] + super(DatabaseWrapper, self).__init__(**kwargs) self.server_version = None - self.options = kwargs def _valid_connection(self): if self.connection is not None: @@ -87,8 +78,7 @@ class DatabaseWrapper(local): self.connection = None return False - def cursor(self): - from django.conf import settings + def _cursor(self, settings): if not self._valid_connection(): kwargs = { # Note: use_unicode intentonally not set to work around some @@ -119,25 +109,16 @@ class DatabaseWrapper(local): self.connection.set_character_set('utf8') else: cursor = self.connection.cursor() - if settings.DEBUG: - return util.CursorDebugWrapper(MysqlDebugWrapper(cursor), self) return cursor - def _commit(self): - if self.connection is not None: - self.connection.commit() + def make_debug_cursor(self, cursor): + return BaseDatabaseWrapper.make_debug_cursor(self, MysqlDebugWrapper(cursor)) def _rollback(self): - if self.connection is not None: - try: - self.connection.rollback() - except Database.NotSupportedError: - pass - - def close(self): - if self.connection is not None: - self.connection.close() - self.connection = None + try: + BaseDatabaseWrapper._rollback(self) + except Database.NotSupportedError: + pass def get_server_version(self): if not self.server_version: diff --git a/django/db/backends/oracle/base.py b/django/db/backends/oracle/base.py index ecf97b62ad3..fbbe11eb2d6 100644 --- a/django/db/backends/oracle/base.py +++ b/django/db/backends/oracle/base.py @@ -4,8 +4,7 @@ Oracle database backend for Django. Requires cx_Oracle: http://www.python.net/crew/atuining/cx_Oracle/ """ -from django.conf import settings -from django.db.backends import util +from django.db.backends import BaseDatabaseWrapper, util from django.utils.datastructures import SortedDict from django.utils.encoding import smart_str, force_unicode import datetime @@ -19,27 +18,14 @@ except ImportError, e: from django.core.exceptions import ImproperlyConfigured raise ImproperlyConfigured, "Error loading cx_Oracle module: %s" % e - DatabaseError = Database.Error IntegrityError = Database.IntegrityError -try: - # Only exists in Python 2.4+ - from threading import local -except ImportError: - # Import copy of _thread_local.py from Python 2.4 - from django.utils._threading_local import local - -class DatabaseWrapper(local): - def __init__(self, **kwargs): - self.connection = None - self.queries = [] - self.options = kwargs - +class DatabaseWrapper(BaseDatabaseWrapper): def _valid_connection(self): return self.connection is not None - def cursor(self): + def _cursor(self, settings): if not self._valid_connection(): if len(settings.DATABASE_HOST.strip()) == 0: settings.DATABASE_HOST = 'localhost' @@ -55,23 +41,8 @@ class DatabaseWrapper(local): # Set oracle date to ansi date format. cursor.execute("ALTER SESSION SET NLS_DATE_FORMAT = 'YYYY-MM-DD'") cursor.execute("ALTER SESSION SET NLS_TIMESTAMP_FORMAT = 'YYYY-MM-DD HH24:MI:SS.FF'") - if settings.DEBUG: - return util.CursorDebugWrapper(cursor, self) return cursor - def _commit(self): - if self.connection is not None: - return self.connection.commit() - - def _rollback(self): - if self.connection is not None: - return self.connection.rollback() - - def close(self): - if self.connection is not None: - self.connection.close() - self.connection = None - allows_group_by_ordinal = False allows_unique_and_pk = False # Suppress UNIQUE/PK for Oracle (ORA-02259) autoindexes_primary_keys = True diff --git a/django/db/backends/postgresql/base.py b/django/db/backends/postgresql/base.py index 9d0967fa2ba..0238ce8c571 100644 --- a/django/db/backends/postgresql/base.py +++ b/django/db/backends/postgresql/base.py @@ -5,7 +5,7 @@ Requires psycopg 1: http://initd.org/projects/psycopg1 """ from django.utils.encoding import smart_str, smart_unicode -from django.db.backends import util +from django.db.backends import BaseDatabaseWrapper, util try: import psycopg as Database except ImportError, e: @@ -15,13 +15,6 @@ except ImportError, e: DatabaseError = Database.DatabaseError IntegrityError = Database.IntegrityError -try: - # Only exists in Python 2.4+ - from threading import local -except ImportError: - # Import copy of _thread_local.py from Python 2.4 - from django.utils._threading_local import local - class UnicodeCursorWrapper(object): """ A thin wrapper around psycopg cursors that allows them to accept Unicode @@ -64,14 +57,8 @@ class UnicodeCursorWrapper(object): postgres_version = None -class DatabaseWrapper(local): - def __init__(self, **kwargs): - self.connection = None - self.queries = [] - self.options = kwargs - - def cursor(self): - from django.conf import settings +class DatabaseWrapper(BaseDatabaseWrapper): + def _cursor(self, settings): set_tz = False if self.connection is None: set_tz = True @@ -98,23 +85,8 @@ class DatabaseWrapper(local): if not postgres_version: cursor.execute("SELECT version()") postgres_version = [int(val) for val in cursor.fetchone()[0].split()[1].split('.')] - if settings.DEBUG: - return util.CursorDebugWrapper(cursor, self) return cursor - def _commit(self): - if self.connection is not None: - return self.connection.commit() - - def _rollback(self): - if self.connection is not None: - return self.connection.rollback() - - def close(self): - if self.connection is not None: - self.connection.close() - self.connection = None - allows_group_by_ordinal = True allows_unique_and_pk = True autoindexes_primary_keys = True diff --git a/django/db/backends/postgresql_psycopg2/base.py b/django/db/backends/postgresql_psycopg2/base.py index c0ecbf80e91..dcf9f017597 100644 --- a/django/db/backends/postgresql_psycopg2/base.py +++ b/django/db/backends/postgresql_psycopg2/base.py @@ -4,7 +4,7 @@ PostgreSQL database backend for Django. Requires psycopg 2: http://initd.org/projects/psycopg2 """ -from django.db.backends import util +from django.db.backends import BaseDatabaseWrapper, util try: import psycopg2 as Database import psycopg2.extensions @@ -15,25 +15,12 @@ except ImportError, e: DatabaseError = Database.DatabaseError IntegrityError = Database.IntegrityError -try: - # Only exists in Python 2.4+ - from threading import local -except ImportError: - # Import copy of _thread_local.py from Python 2.4 - from django.utils._threading_local import local - psycopg2.extensions.register_type(psycopg2.extensions.UNICODE) postgres_version = None -class DatabaseWrapper(local): - def __init__(self, **kwargs): - self.connection = None - self.queries = [] - self.options = kwargs - - def cursor(self): - from django.conf import settings +class DatabaseWrapper(BaseDatabaseWrapper): + def _cursor(self, settings): set_tz = False if self.connection is None: set_tz = True @@ -60,23 +47,8 @@ class DatabaseWrapper(local): if not postgres_version: cursor.execute("SELECT version()") postgres_version = [int(val) for val in cursor.fetchone()[0].split()[1].split('.')] - if settings.DEBUG: - return util.CursorDebugWrapper(cursor, self) return cursor - def _commit(self): - if self.connection is not None: - return self.connection.commit() - - def _rollback(self): - if self.connection is not None: - return self.connection.rollback() - - def close(self): - if self.connection is not None: - self.connection.close() - self.connection = None - allows_group_by_ordinal = True allows_unique_and_pk = True autoindexes_primary_keys = True diff --git a/django/db/backends/sqlite3/base.py b/django/db/backends/sqlite3/base.py index a0b1341b537..9f4df08f071 100644 --- a/django/db/backends/sqlite3/base.py +++ b/django/db/backends/sqlite3/base.py @@ -2,7 +2,7 @@ SQLite3 backend for django. Requires pysqlite2 (http://pysqlite.org/). """ -from django.db.backends import util +from django.db.backends import BaseDatabaseWrapper, util try: try: from sqlite3 import dbapi2 as Database @@ -34,21 +34,8 @@ Database.register_converter("TIMESTAMP", util.typecast_timestamp) Database.register_converter("decimal", util.typecast_decimal) Database.register_adapter(decimal.Decimal, util.rev_typecast_decimal) -try: - # Only exists in Python 2.4+ - from threading import local -except ImportError: - # Import copy of _thread_local.py from Python 2.4 - from django.utils._threading_local import local - -class DatabaseWrapper(local): - def __init__(self, **kwargs): - self.connection = None - self.queries = [] - self.options = kwargs - - def cursor(self): - from django.conf import settings +class DatabaseWrapper(BaseDatabaseWrapper): + def _cursor(self, settings): if self.connection is None: kwargs = { 'database': settings.DATABASE_NAME, @@ -60,28 +47,15 @@ class DatabaseWrapper(local): self.connection.create_function("django_extract", 2, _sqlite_extract) self.connection.create_function("django_date_trunc", 2, _sqlite_date_trunc) self.connection.create_function("regexp", 2, _sqlite_regexp) - cursor = self.connection.cursor(factory=SQLiteCursorWrapper) - if settings.DEBUG: - return util.CursorDebugWrapper(cursor, self) - else: - return cursor - - def _commit(self): - if self.connection is not None: - self.connection.commit() - - def _rollback(self): - if self.connection is not None: - self.connection.rollback() + return self.connection.cursor(factory=SQLiteCursorWrapper) def close(self): from django.conf import settings # If database is in memory, closing the connection destroys the - # database. To prevent accidental data loss, ignore close requests on + # database. To prevent accidental data loss, ignore close requests on # an in-memory db. - if self.connection is not None and settings.DATABASE_NAME != ":memory:": - self.connection.close() - self.connection = None + if settings.DATABASE_NAME != ":memory:": + BaseDatabaseWrapper.close(self) class SQLiteCursorWrapper(Database.Cursor): """