summaryrefslogtreecommitdiff
path: root/django/db/backends
diff options
context:
space:
mode:
authorRussell Keith-Magee <russell@keith-magee.com>2009-12-22 15:18:51 +0000
committerRussell Keith-Magee <russell@keith-magee.com>2009-12-22 15:18:51 +0000
commitff60c5f9de3e8690d1e86f3e9e3f7248a15397c8 (patch)
treea4cb0ebdd55fcaf8c8855231b6ad3e1a7bf45bee /django/db/backends
parent7ef212af149540aa2da577a960d0d87029fd1514 (diff)
Fixed #1142 -- Added multiple database support.
This monster of a patch is the result of Alex Gaynor's 2009 Google Summer of Code project. Congratulations to Alex for a job well done. Big thanks also go to: * Justin Bronn for keeping GIS in line with the changes, * Karen Tracey and Jani Tiainen for their help testing Oracle support * Brett Hoerner, Jon Loyens, and Craig Kimmerer for their feedback. * Malcolm Treddinick for his guidance during the GSoC submission process. * Simon Willison for driving the original design process * Cal Henderson for complaining about ponies he wanted. ... and everyone else too numerous to mention that helped to bring this feature into fruition. git-svn-id: http://code.djangoproject.com/svn/django/trunk@11952 bcc190cf-cafb-0310-a4f2-bffc1f526a37
Diffstat (limited to 'django/db/backends')
-rw-r--r--django/db/backends/__init__.py60
-rw-r--r--django/db/backends/creation.py34
-rw-r--r--django/db/backends/dummy/base.py4
-rw-r--r--django/db/backends/mysql/base.py28
-rw-r--r--django/db/backends/mysql/client.py12
-rw-r--r--django/db/backends/mysql/creation.py18
-rw-r--r--django/db/backends/mysql/validation.py4
-rw-r--r--django/db/backends/oracle/base.py76
-rw-r--r--django/db/backends/oracle/compiler.py66
-rw-r--r--django/db/backends/oracle/creation.py129
-rw-r--r--django/db/backends/oracle/query.py150
-rw-r--r--django/db/backends/postgresql/base.py30
-rw-r--r--django/db/backends/postgresql/client.py14
-rw-r--r--django/db/backends/postgresql/creation.py7
-rw-r--r--django/db/backends/postgresql/operations.py7
-rw-r--r--django/db/backends/postgresql_psycopg2/base.py32
-rw-r--r--django/db/backends/sqlite3/base.py16
-rw-r--r--django/db/backends/sqlite3/client.py2
-rw-r--r--django/db/backends/sqlite3/creation.py11
19 files changed, 324 insertions, 376 deletions
diff --git a/django/db/backends/__init__.py b/django/db/backends/__init__.py
index 9a1fe30925..bf3e9db15a 100644
--- a/django/db/backends/__init__.py
+++ b/django/db/backends/__init__.py
@@ -1,37 +1,31 @@
-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
-try:
- set
-except NameError:
- # Python 2.3 compat
- from sets import Set as set
-
-try:
- import decimal
-except ImportError:
- # Python 2.3 fallback
- from django.utils import _decimal as decimal
+import decimal
+from threading import local
+from django.db import DEFAULT_DB_ALIAS
from django.db.backends import util
from django.utils import datetime_safe
+from django.utils.importlib import import_module
class BaseDatabaseWrapper(local):
"""
Represents a database connection.
"""
ops = None
- def __init__(self, settings_dict):
+
+ 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
+ self.alias = alias
+
+ def __eq__(self, other):
+ return self.settings_dict == other.settings_dict
+
+ def __ne__(self, other):
+ return not self == other
def _commit(self):
if self.connection is not None:
@@ -91,7 +85,6 @@ class BaseDatabaseFeatures(object):
# True if django.db.backend.utils.typecast_timestamp is used on values
# returned from dates() calls.
needs_datetime_string_cast = True
- uses_custom_query_class = False
empty_fetchmany_value = []
update_can_self_select = True
interprets_empty_strings_as_nulls = False
@@ -109,6 +102,11 @@ class BaseDatabaseOperations(object):
a backend performs ordering or calculates the ID of a recently-inserted
row.
"""
+ compiler_module = "django.db.models.sql.compiler"
+
+ def __init__(self):
+ self._cache = {}
+
def autoinc_sql(self, table, column):
"""
Returns any SQL needed to support auto-incrementing primary keys, or
@@ -271,14 +269,17 @@ class BaseDatabaseOperations(object):
"""
pass
- def query_class(self, DefaultQueryClass):
+ def compiler(self, compiler_name):
"""
- Given the default Query class, returns a custom Query class
- to use for this backend. Returns None if a custom Query isn't used.
- See also BaseDatabaseFeatures.uses_custom_query_class, which regulates
- whether this method is called at all.
+ Returns the SQLCompiler class corresponding to the given name,
+ in the namespace corresponding to the `compiler_module` attribute
+ on this backend.
"""
- return None
+ if compiler_name not in self._cache:
+ self._cache[compiler_name] = getattr(
+ import_module(self.compiler_module), compiler_name
+ )
+ return self._cache[compiler_name]
def quote_name(self, name):
"""
@@ -565,6 +566,9 @@ class BaseDatabaseValidation(object):
"""
This class encapsualtes all backend-specific model validation.
"""
+ def __init__(self, connection):
+ self.connection = connection
+
def validate_field(self, errors, opts, f):
"By default, there is no backend-specific validation"
pass
diff --git a/django/db/backends/creation.py b/django/db/backends/creation.py
index 43f47048e0..46e243aaf8 100644
--- a/django/db/backends/creation.py
+++ b/django/db/backends/creation.py
@@ -47,7 +47,7 @@ class BaseDatabaseCreation(object):
pending_references = {}
qn = self.connection.ops.quote_name
for f in opts.local_fields:
- col_type = f.db_type()
+ col_type = f.db_type(connection=self.connection)
tablespace = f.db_tablespace or opts.db_tablespace
if col_type is None:
# Skip ManyToManyFields, because they're not represented as
@@ -75,7 +75,7 @@ class BaseDatabaseCreation(object):
table_output.append(' '.join(field_output))
if opts.order_with_respect_to:
table_output.append(style.SQL_FIELD(qn('_order')) + ' ' + \
- style.SQL_COLTYPE(models.IntegerField().db_type()))
+ style.SQL_COLTYPE(models.IntegerField().db_type(connection=self.connection)))
for field_constraints in opts.unique_together:
table_output.append(style.SQL_KEYWORD('UNIQUE') + ' (%s)' % \
", ".join([style.SQL_FIELD(qn(opts.get_field(f).column)) for f in field_constraints]))
@@ -173,7 +173,7 @@ class BaseDatabaseCreation(object):
style.SQL_TABLE(qn(f.m2m_db_table())) + ' (']
table_output.append(' %s %s %s%s,' %
(style.SQL_FIELD(qn('id')),
- style.SQL_COLTYPE(models.AutoField(primary_key=True).db_type()),
+ style.SQL_COLTYPE(models.AutoField(primary_key=True).db_type(connection=self.connection)),
style.SQL_KEYWORD('NOT NULL PRIMARY KEY'),
tablespace_sql))
@@ -217,14 +217,14 @@ class BaseDatabaseCreation(object):
table_output = [
' %s %s %s %s (%s)%s,' %
(style.SQL_FIELD(qn(field.m2m_column_name())),
- style.SQL_COLTYPE(models.ForeignKey(model).db_type()),
+ style.SQL_COLTYPE(models.ForeignKey(model).db_type(connection=self.connection)),
style.SQL_KEYWORD('NOT NULL REFERENCES'),
style.SQL_TABLE(qn(opts.db_table)),
style.SQL_FIELD(qn(opts.pk.column)),
self.connection.ops.deferrable_sql()),
' %s %s %s %s (%s)%s,' %
(style.SQL_FIELD(qn(field.m2m_reverse_name())),
- style.SQL_COLTYPE(models.ForeignKey(field.rel.to).db_type()),
+ style.SQL_COLTYPE(models.ForeignKey(field.rel.to).db_type(connection=self.connection)),
style.SQL_KEYWORD('NOT NULL REFERENCES'),
style.SQL_TABLE(qn(field.rel.to._meta.db_table)),
style.SQL_FIELD(qn(field.rel.to._meta.pk.column)),
@@ -322,18 +322,16 @@ class BaseDatabaseCreation(object):
database already exists. Returns the name of the test database created.
"""
if verbosity >= 1:
- print "Creating test database..."
+ print "Creating test database '%s'..." % self.connection.alias
test_database_name = self._create_test_db(verbosity, autoclobber)
self.connection.close()
- settings.DATABASE_NAME = test_database_name
- self.connection.settings_dict["DATABASE_NAME"] = test_database_name
+ self.connection.settings_dict["NAME"] = test_database_name
can_rollback = self._rollback_works()
- settings.DATABASE_SUPPORTS_TRANSACTIONS = can_rollback
- self.connection.settings_dict["DATABASE_SUPPORTS_TRANSACTIONS"] = can_rollback
+ self.connection.settings_dict["SUPPORTS_TRANSACTIONS"] = can_rollback
- call_command('syncdb', verbosity=verbosity, interactive=False)
+ call_command('syncdb', verbosity=verbosity, interactive=False, database=self.connection.alias)
if settings.CACHE_BACKEND.startswith('db://'):
from django.core.cache import parse_backend_uri
@@ -350,10 +348,10 @@ class BaseDatabaseCreation(object):
"Internal implementation - creates the test db tables."
suffix = self.sql_table_creation_suffix()
- if settings.TEST_DATABASE_NAME:
- test_database_name = settings.TEST_DATABASE_NAME
+ if self.connection.settings_dict['TEST_NAME']:
+ test_database_name = self.connection.settings_dict['TEST_NAME']
else:
- test_database_name = TEST_DATABASE_PREFIX + settings.DATABASE_NAME
+ test_database_name = TEST_DATABASE_PREFIX + self.connection.settings_dict['NAME']
qn = self.connection.ops.quote_name
@@ -403,11 +401,10 @@ class BaseDatabaseCreation(object):
database already exists. Returns the name of the test database created.
"""
if verbosity >= 1:
- print "Destroying test database..."
+ print "Destroying test database '%s'..." % self.connection.alias
self.connection.close()
- test_database_name = settings.DATABASE_NAME
- settings.DATABASE_NAME = old_database_name
- self.connection.settings_dict["DATABASE_NAME"] = old_database_name
+ test_database_name = self.connection.settings_dict['NAME']
+ self.connection.settings_dict['NAME'] = old_database_name
self._destroy_test_db(test_database_name, verbosity)
@@ -436,4 +433,3 @@ class BaseDatabaseCreation(object):
def sql_table_creation_suffix(self):
"SQL to append to the end of the test table creation statements"
return ''
-
diff --git a/django/db/backends/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 f71e5cd99b..5c6abce8aa 100644
--- a/django/db/backends/mysql/base.py
+++ b/django/db/backends/mysql/base.py
@@ -242,7 +242,7 @@ class DatabaseWrapper(BaseDatabaseWrapper):
self.client = DatabaseClient(self)
self.creation = DatabaseCreation(self)
self.introspection = DatabaseIntrospection(self)
- self.validation = DatabaseValidation()
+ self.validation = DatabaseValidation(self)
def _valid_connection(self):
if self.connection is not None:
@@ -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 063ba4c712..8b026a908d 100644
--- a/django/db/backends/mysql/creation.py
+++ b/django/db/backends/mysql/creation.py
@@ -1,4 +1,3 @@
-from django.conf import settings
from django.db.backends.creation import BaseDatabaseCreation
class DatabaseCreation(BaseDatabaseCreation):
@@ -32,29 +31,29 @@ class DatabaseCreation(BaseDatabaseCreation):
def sql_table_creation_suffix(self):
suffix = []
- if settings.TEST_DATABASE_CHARSET:
- suffix.append('CHARACTER SET %s' % settings.TEST_DATABASE_CHARSET)
- if settings.TEST_DATABASE_COLLATION:
- suffix.append('COLLATE %s' % settings.TEST_DATABASE_COLLATION)
+ if self.connection.settings_dict['TEST_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):
"All inline references are pending under MySQL"
return [], True
-
+
def sql_for_inline_many_to_many_references(self, model, field, style):
from django.db import models
opts = model._meta
qn = self.connection.ops.quote_name
-
+
table_output = [
' %s %s %s,' %
(style.SQL_FIELD(qn(field.m2m_column_name())),
- style.SQL_COLTYPE(models.ForeignKey(model).db_type()),
+ style.SQL_COLTYPE(models.ForeignKey(model).db_type(connection=self.connection)),
style.SQL_KEYWORD('NOT NULL')),
' %s %s %s,' %
(style.SQL_FIELD(qn(field.m2m_reverse_name())),
- style.SQL_COLTYPE(models.ForeignKey(field.rel.to).db_type()),
+ style.SQL_COLTYPE(models.ForeignKey(field.rel.to).db_type(connection=self.connection)),
style.SQL_KEYWORD('NOT NULL'))
]
deferred = [
@@ -64,4 +63,3 @@ class DatabaseCreation(BaseDatabaseCreation):
field.rel.to._meta.db_table, field.rel.to._meta.pk.column)
]
return table_output, deferred
- \ No newline at end of file
diff --git a/django/db/backends/mysql/validation.py b/django/db/backends/mysql/validation.py
index 0b3d4ad0bd..197f91310e 100644
--- a/django/db/backends/mysql/validation.py
+++ b/django/db/backends/mysql/validation.py
@@ -11,8 +11,7 @@ class DatabaseValidation(BaseDatabaseValidation):
characters if they have a unique index on them.
"""
from django.db import models
- from django.db import connection
- db_version = connection.get_server_version()
+ db_version = self.connection.get_server_version()
varchar_fields = (models.CharField, models.CommaSeparatedIntegerField,
models.SlugField)
if isinstance(f, varchar_fields) and f.max_length > 255:
@@ -25,4 +24,3 @@ class DatabaseValidation(BaseDatabaseValidation):
if msg:
errors.add(opts, msg % {'name': f.name, 'cls': f.__class__.__name__, 'version': '.'.join([str(n) for n in db_version[:3]])})
-
diff --git a/django/db/backends/oracle/base.py b/django/db/backends/oracle/base.py
index c4155e2c9a..cc85685e5b 100644
--- a/django/db/backends/oracle/base.py
+++ b/django/db/backends/oracle/base.py
@@ -26,7 +26,6 @@ except ImportError, e:
from django.db.backends import *
from django.db.backends.signals import connection_created
-from django.db.backends.oracle import query
from django.db.backends.oracle.client import DatabaseClient
from django.db.backends.oracle.creation import DatabaseCreation
from django.db.backends.oracle.introspection import DatabaseIntrospection
@@ -47,13 +46,13 @@ else:
class DatabaseFeatures(BaseDatabaseFeatures):
empty_fetchmany_value = ()
needs_datetime_string_cast = False
- uses_custom_query_class = True
interprets_empty_strings_as_nulls = True
uses_savepoints = True
can_return_id_from_insert = True
class DatabaseOperations(BaseDatabaseOperations):
+ compiler_module = "django.db.backends.oracle.compiler"
def autoinc_sql(self, table, column):
# To simulate auto-incrementing primary keys in Oracle, we have to
@@ -102,6 +101,54 @@ WHEN (new.%(col_name)s IS NULL)
sql = "TRUNC(%s, '%s')" % (field_name, lookup_type)
return sql
+ def convert_values(self, value, field):
+ if isinstance(value, Database.LOB):
+ value = value.read()
+ if field and field.get_internal_type() == 'TextField':
+ value = force_unicode(value)
+
+ # Oracle stores empty strings as null. We need to undo this in
+ # order to adhere to the Django convention of using the empty
+ # string instead of null, but only if the field accepts the
+ # empty string.
+ if value is None and field and field.empty_strings_allowed:
+ value = u''
+ # Convert 1 or 0 to True or False
+ elif value in (1, 0) and field and field.get_internal_type() in ('BooleanField', 'NullBooleanField'):
+ value = bool(value)
+ # Force floats to the correct type
+ elif value is not None and field and field.get_internal_type() == 'FloatField':
+ value = float(value)
+ # Convert floats to decimals
+ elif value is not None and field and field.get_internal_type() == 'DecimalField':
+ value = util.typecast_decimal(field.format_number(value))
+ # cx_Oracle always returns datetime.datetime objects for
+ # DATE and TIMESTAMP columns, but Django wants to see a
+ # python datetime.date, .time, or .datetime. We use the type
+ # of the Field to determine which to cast to, but it's not
+ # always available.
+ # As a workaround, we cast to date if all the time-related
+ # values are 0, or to time if the date is 1/1/1900.
+ # This could be cleaned a bit by adding a method to the Field
+ # classes to normalize values from the database (the to_python
+ # method is used for validation and isn't what we want here).
+ elif isinstance(value, Database.Timestamp):
+ # In Python 2.3, the cx_Oracle driver returns its own
+ # Timestamp object that we must convert to a datetime class.
+ if not isinstance(value, datetime.datetime):
+ value = datetime.datetime(value.year, value.month,
+ value.day, value.hour, value.minute, value.second,
+ value.fsecond)
+ if field and field.get_internal_type() == 'DateTimeField':
+ pass
+ elif field and field.get_internal_type() == 'DateField':
+ value = value.date()
+ elif field and field.get_internal_type() == 'TimeField' or (value.year == 1900 and value.month == value.day == 1):
+ value = value.time()
+ elif value.hour == value.minute == value.second == value.microsecond == 0:
+ value = value.date()
+ return value
+
def datetime_cast_sql(self):
return "TO_TIMESTAMP(%s, 'YYYY-MM-DD HH24:MI:SS.FF')"
@@ -141,9 +188,6 @@ WHEN (new.%(col_name)s IS NULL)
return u''
return force_unicode(value.read())
- def query_class(self, DefaultQueryClass):
- return query.query_class(DefaultQueryClass, Database)
-
def quote_name(self, name):
# SQL92 requires delimited (quoted) names to be case-sensitive. When
# not quoted, Oracle has case-insensitive behavior for identifiers, but
@@ -291,29 +335,29 @@ class DatabaseWrapper(BaseDatabaseWrapper):
self.client = DatabaseClient(self)
self.creation = DatabaseCreation(self)
self.introspection = DatabaseIntrospection(self)
- self.validation = BaseDatabaseValidation()
+ self.validation = BaseDatabaseValidation(self)
def _valid_connection(self):
return self.connection is not None
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/compiler.py b/django/db/backends/oracle/compiler.py
new file mode 100644
index 0000000000..cc1541ff3f
--- /dev/null
+++ b/django/db/backends/oracle/compiler.py
@@ -0,0 +1,66 @@
+from django.db.models.sql import compiler
+
+
+class SQLCompiler(compiler.SQLCompiler):
+ def resolve_columns(self, row, fields=()):
+ # If this query has limit/offset information, then we expect the
+ # first column to be an extra "_RN" column that we need to throw
+ # away.
+ if self.query.high_mark is not None or self.query.low_mark:
+ rn_offset = 1
+ else:
+ rn_offset = 0
+ index_start = rn_offset + len(self.query.extra_select.keys())
+ values = [self.query.convert_values(v, None, connection=self.connection)
+ for v in row[rn_offset:index_start]]
+ for value, field in map(None, row[index_start:], fields):
+ values.append(self.query.convert_values(value, field, connection=self.connection))
+ return tuple(values)
+
+ def as_sql(self, with_limits=True, with_col_aliases=False):
+ """
+ Creates the SQL for this query. Returns the SQL string and list
+ of parameters. This is overriden from the original Query class
+ to handle the additional SQL Oracle requires to emulate LIMIT
+ and OFFSET.
+
+ If 'with_limits' is False, any limit/offset information is not
+ included in the query.
+ """
+
+ # The `do_offset` flag indicates whether we need to construct
+ # the SQL needed to use limit/offset with Oracle.
+ do_offset = with_limits and (self.query.high_mark is not None
+ or self.query.low_mark)
+ if not do_offset:
+ sql, params = super(SQLCompiler, self).as_sql(with_limits=False,
+ with_col_aliases=with_col_aliases)
+ else:
+ sql, params = super(SQLCompiler, self).as_sql(with_limits=False,
+ with_col_aliases=True)
+
+ # Wrap the base query in an outer SELECT * with boundaries on
+ # the "_RN" column. This is the canonical way to emulate LIMIT
+ # and OFFSET on Oracle.
+ high_where = ''
+ if self.query.high_mark is not None:
+ high_where = 'WHERE ROWNUM <= %d' % (self.query.high_mark,)
+ sql = 'SELECT * FROM (SELECT ROWNUM AS "_RN", "_SUB".* FROM (%s) "_SUB" %s) WHERE "_RN" > %d' % (sql, high_where, self.query.low_mark)
+
+ return sql, params
+
+
+class SQLInsertCompiler(compiler.SQLInsertCompiler, SQLCompiler):
+ pass
+
+class SQLDeleteCompiler(compiler.SQLDeleteCompiler, SQLCompiler):
+ pass
+
+class SQLUpdateCompiler(compiler.SQLUpdateCompiler, SQLCompiler):
+ pass
+
+class SQLAggregateCompiler(compiler.SQLAggregateCompiler, SQLCompiler):
+ pass
+
+class SQLDateCompiler(compiler.SQLDateCompiler, SQLCompiler):
+ pass
diff --git a/django/db/backends/oracle/creation.py b/django/db/backends/oracle/creation.py
index 86d84ca5a6..e6e242b9f7 100644
--- a/django/db/backends/oracle/creation.py
+++ b/django/db/backends/oracle/creation.py
@@ -1,5 +1,4 @@
import sys, time
-from django.conf import settings
from django.core import management
from django.db.backends.creation import BaseDatabaseCreation
@@ -43,25 +42,25 @@ class DatabaseCreation(BaseDatabaseCreation):
remember = {}
def _create_test_db(self, verbosity=1, autoclobber=False):
- TEST_DATABASE_NAME = self._test_database_name(settings)
- TEST_DATABASE_USER = self._test_database_user(settings)
- TEST_DATABASE_PASSWD = self._test_database_passwd(settings)
- TEST_DATABASE_TBLSPACE = self._test_database_tblspace(settings)
- TEST_DATABASE_TBLSPACE_TMP = self._test_database_tblspace_tmp(settings)
+ TEST_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'] = settings.DATABASE_USER
- self.remember['passwd'] = settings.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(settings):
+ if self._test_database_create():
if verbosity >= 1:
print 'Creating test database...'
try:
@@ -69,7 +68,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:
@@ -85,7 +84,7 @@ class DatabaseCreation(BaseDatabaseCreation):
print "Tests cancelled."
sys.exit(1)
- if self._test_user_create(settings):
+ if self._test_user_create():
if verbosity >= 1:
print "Creating test user..."
try:
@@ -93,7 +92,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:
@@ -109,43 +108,43 @@ class DatabaseCreation(BaseDatabaseCreation):
print "Tests cancelled."
sys.exit(1)
- settings.TEST_DATABASE_USER = settings.DATABASE_USER = self.connection.settings_dict["DATABASE_USER"] = TEST_DATABASE_USER
- settings.DATABASE_PASSWORD = self.connection.settings_dict["DATABASE_PASSWORD"] = TEST_DATABASE_PASSWD
+ self.connection.settings_dict['TEST_USER'] = self.connection.settings_dict["USER"] = TEST_USER
+ self.connection.settings_dict["PASSWORD"] = TEST_PASSWD
- return settings.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(settings)
- TEST_DATABASE_USER = self._test_database_user(settings)
- TEST_DATABASE_PASSWD = self._test_database_passwd(settings)
- TEST_DATABASE_TBLSPACE = self._test_database_tblspace(settings)
- TEST_DATABASE_TBLSPACE_TMP = self._test_database_tblspace_tmp(settings)
+ TEST_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()
- settings.DATABASE_USER = self.connection.settings_dict["DATABASE_USER"] = self.remember['user']
- settings.DATABASE_PASSWORD = self.connection.settings_dict["DATABASE_PASSWORD"] = self.remember['passwd']
+ self.connection.settings_dict["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'] = settings.DATABASE_USER
- self.remember['passwd'] = settings.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.
- if self._test_user_create(settings):
+ if self._test_user_create():
if verbosity >= 1:
print 'Destroying test user...'
self._destroy_test_user(cursor, parameters, verbosity)
- if self._test_database_create(settings):
+ if self._test_database_create():
if verbosity >= 1:
print 'Destroying test database tables...'
self._execute_test_db_destruction(cursor, parameters, verbosity)
@@ -208,82 +207,82 @@ class DatabaseCreation(BaseDatabaseCreation):
sys.stderr.write("Failed (%s)\n" % (err))
raise
- def _test_database_name(self, settings):
- name = TEST_DATABASE_PREFIX + settings.DATABASE_NAME
+ def _test_database_name(self):
+ name = TEST_DATABASE_PREFIX + self.connection.settings_dict['NAME']
try:
- if settings.TEST_DATABASE_NAME:
- name = settings.TEST_DATABASE_NAME
+ if self.connection.settings_dict['TEST_NAME']:
+ name = self.connection.settings_dict['TEST_NAME']
except AttributeError:
pass
except:
raise
return name
- def _test_database_create(self, settings):
+ def _test_database_create(self):
name = True
try:
- if settings.TEST_DATABASE_CREATE:
+ if self.connection.settings_dict['TEST_CREATE']:
name = True
else:
name = False
- except AttributeError:
+ except KeyError:
pass
except:
raise
return name
- def _test_user_create(self, settings):
+ def _test_user_create(self):
name = True
try:
- if settings.TEST_USER_CREATE:
+ if self.connection.settings_dict['TEST_USER_CREATE']:
name = True
else:
name = False
- except AttributeError:
+ except KeyError:
pass
except:
raise
return name
- def _test_database_user(self, settings):
- name = TEST_DATABASE_PREFIX + settings.DATABASE_USER
+ def _test_database_user(self):
+ name = TEST_DATABASE_PREFIX + self.connection.settings_dict['USER']
try:
- if settings.TEST_DATABASE_USER:
- name = settings.TEST_DATABASE_USER
- except AttributeError:
+ if self.connection.settings_dict['TEST_USER']:
+ name = self.connection.settings_dict['TEST_USER']
+ except KeyError:
pass
except:
raise
return name
- def _test_database_passwd(self, settings):
+ def _test_database_passwd(self):
name = PASSWORD
try:
- if settings.TEST_DATABASE_PASSWD:
- name = settings.TEST_DATABASE_PASSWD
- except AttributeError:
+ if self.connection.settings_dict['TEST_PASSWD']:
+ name = self.connection.settings_dict['TEST_PASSWD']
+ except KeyError:
pass
except:
raise
return name
- def _test_database_tblspace(self, settings):
- name = TEST_DATABASE_PREFIX + settings.DATABASE_NAME
+ def _test_database_tblspace(self):
+ name = TEST_DATABASE_PREFIX + self.connection.settings_dict['NAME']
try:
- if settings.TEST_DATABASE_TBLSPACE:
- name = settings.TEST_DATABASE_TBLSPACE
- except AttributeError:
+ if self.connection.settings_dict['TEST_TBLSPACE']:
+ name = self.connection.settings_dict['TEST_TBLSPACE']
+ except KeyError:
pass
except:
raise
return name
- def _test_database_tblspace_tmp(self, settings):
- name = TEST_DATABASE_PREFIX + settings.DATABASE_NAME + '_temp'
+ def _test_database_tblspace_tmp(self):
+ name = TEST_DATABASE_PREFIX + self.connection.settings_dict['NAME'] + '_temp'
try:
- if settings.TEST_DATABASE_TBLSPACE_TMP:
- name = settings.TEST_DATABASE_TBLSPACE_TMP
- except AttributeError:
+ if self.connection.settings_dict['TEST_TBLSPACE_TMP']:
+ name = self.connection.settings_dict['TEST_TBLSPACE_TMP']
+ except KeyError:
pass
except:
raise
diff --git a/django/db/backends/oracle/query.py b/django/db/backends/oracle/query.py
deleted file mode 100644
index 7be9533e34..0000000000
--- a/django/db/backends/oracle/query.py
+++ /dev/null
@@ -1,150 +0,0 @@
-"""
-Custom Query class for Oracle.
-Derives from: django.db.models.sql.query.Query
-"""
-
-import datetime
-
-from django.db.backends import util
-from django.utils.encoding import force_unicode
-
-# Cache. Maps default query class to new Oracle query class.
-_classes = {}
-
-def query_class(QueryClass, Database):
- """
- Returns a custom django.db.models.sql.query.Query subclass that is
- appropriate for Oracle.
-
- The 'Database' module (cx_Oracle) is passed in here so that all the setup
- required to import it only needs to be done by the calling module.
- """
- global _classes
- try:
- return _classes[QueryClass]
- except KeyError:
- pass
-
- class OracleQuery(QueryClass):
- def __reduce__(self):
- """
- Enable pickling for this class (normal pickling handling doesn't
- work as Python can only pickle module-level classes by default).
- """
- if hasattr(QueryClass, '__getstate__'):
- assert hasattr(QueryClass, '__setstate__')
- data = self.__getstate__()
- else:
- data = self.__dict__
- return (unpickle_query_class, (QueryClass,), data)
-
- def resolve_columns(self, row, fields=()):
- # If this query has limit/offset information, then we expect the
- # first column to be an extra "_RN" column that we need to throw
- # away.
- if self.high_mark is not None or self.low_mark:
- rn_offset = 1
- else:
- rn_offset = 0
- index_start = rn_offset + len(self.extra_select.keys())
- values = [self.convert_values(v, None)
- for v in row[rn_offset:index_start]]
- for value, field in map(None, row[index_start:], fields):
- values.append(self.convert_values(value, field))
- return tuple(values)
-
- def convert_values(self, value, field):
- if isinstance(value, Database.LOB):
- value = value.read()
- if field and field.get_internal_type() == 'TextField':
- value = force_unicode(value)
-
- # Oracle stores empty strings as null. We need to undo this in
- # order to adhere to the Django convention of using the empty
- # string instead of null, but only if the field accepts the
- # empty string.
- if value is None and field and field.empty_strings_allowed:
- value = u''
- # Convert 1 or 0 to True or False
- elif value in (1, 0) and field and field.get_internal_type() in ('BooleanField', 'NullBooleanField'):
- value = bool(value)
- # Force floats to the correct type
- elif value is not None and field and field.get_internal_type() == 'FloatField':
- value = float(value)
- # Convert floats to decimals
- elif value is not None and field and field.get_internal_type() == 'DecimalField':
- value = util.typecast_decimal(field.format_number(value))
- # cx_Oracle always returns datetime.datetime objects for
- # DATE and TIMESTAMP columns, but Django wants to see a
- # python datetime.date, .time, or .datetime. We use the type
- # of the Field to determine which to cast to, but it's not
- # always available.
- # As a workaround, we cast to date if all the time-related
- # values are 0, or to time if the date is 1/1/1900.
- # This could be cleaned a bit by adding a method to the Field
- # classes to normalize values from the database (the to_python
- # method is used for validation and isn't what we want here).
- elif isinstance(value, Database.Timestamp):
- # In Python 2.3, the cx_Oracle driver returns its own
- # Timestamp object that we must convert to a datetime class.
- if not isinstance(value, datetime.datetime):
- value = datetime.datetime(value.year, value.month,
- value.day, value.hour, value.minute, value.second,
- value.fsecond)
- if field and field.get_internal_type() == 'DateTimeField':
- pass
- elif field and field.get_internal_type() == 'DateField':
- value = value.date()
- elif field and field.get_internal_type() == 'TimeField' or (value.year == 1900 and value.month == value.day == 1):
- value = value.time()
- elif value.hour == value.minute == value.second == value.microsecond == 0:
- value = value.date()
- return value
-
- def as_sql(self, with_limits=True, with_col_aliases=False):
- """
- Creates the SQL for this query. Returns the SQL string and list
- of parameters. This is overriden from the original Query class
- to handle the additional SQL Oracle requires to emulate LIMIT
- and OFFSET.
-
- If 'with_limits' is False, any limit/offset information is not
- included in the query.
- """
-
- # The `do_offset` flag indicates whether we need to construct
- # the SQL needed to use limit/offset with Oracle.
- do_offset = with_limits and (self.high_mark is not None
- or self.low_mark)
- if not do_offset:
- sql, params = super(OracleQuery, self).as_sql(with_limits=False,
- with_col_aliases=with_col_aliases)
- else:
- sql, params = super(OracleQuery, self).as_sql(with_limits=False,
- with_col_aliases=True)
-
- # Wrap the base query in an outer SELECT * with boundaries on
- # the "_RN" column. This is the canonical way to emulate LIMIT
- # and OFFSET on Oracle.
- high_where = ''
- if self.high_mark is not None:
- high_where = 'WHERE ROWNUM <= %d' % (self.high_mark,)
- sql = 'SELECT * FROM (SELECT ROWNUM AS "_RN", "_SUB".* FROM (%s) "_SUB" %s) WHERE "_RN" > %d' % (sql, high_where, self.low_mark)
-
- return sql, params
-
- _classes[QueryClass] = OracleQuery
- return OracleQuery
-
-def unpickle_query_class(QueryClass):
- """
- Utility function, called by Python's unpickling machinery, that handles
- unpickling of Oracle Query subclasses.
- """
- # XXX: Would be nice to not have any dependency on cx_Oracle here. Since
- # modules can't be pickled, we need a way to know to load the right module.
- import cx_Oracle
-
- klass = query_class(QueryClass, cx_Oracle)
- return klass.__new__(klass)
-unpickle_query_class.__safe_for_unpickling__ = True
diff --git a/django/db/backends/postgresql/base.py b/django/db/backends/postgresql/base.py
index 19d5ea74d8..119df9f171 100644
--- a/django/db/backends/postgresql/base.py
+++ b/django/db/backends/postgresql/base.py
@@ -90,30 +90,30 @@ class DatabaseWrapper(BaseDatabaseWrapper):
super(DatabaseWrapper, self).__init__(*args, **kwargs)
self.features = DatabaseFeatures()
- self.ops = DatabaseOperations()
+ self.ops = DatabaseOperations(self)
self.client = DatabaseClient(self)
self.creation = DatabaseCreation(self)
self.introspection = DatabaseIntrospection(self)
- self.validation = BaseDatabaseValidation()
+ self.validation = BaseDatabaseValidation(self)
def _cursor(self):
set_tz = False
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 be7f49482b..af26d0b78f 100644
--- a/django/db/backends/postgresql/creation.py
+++ b/django/db/backends/postgresql/creation.py
@@ -1,4 +1,3 @@
-from django.conf import settings
from django.db.backends.creation import BaseDatabaseCreation
class DatabaseCreation(BaseDatabaseCreation):
@@ -31,9 +30,9 @@ class DatabaseCreation(BaseDatabaseCreation):
}
def sql_table_creation_suffix(self):
- assert settings.TEST_DATABASE_COLLATION is None, "PostgreSQL does not support collation setting at database creation time."
- if settings.TEST_DATABASE_CHARSET:
- return "WITH ENCODING '%s'" % settings.TEST_DATABASE_CHARSET
+ assert self.connection.settings_dict['TEST_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 ''
def sql_indexes_for_field(self, model, f, style):
diff --git a/django/db/backends/postgresql/operations.py b/django/db/backends/postgresql/operations.py
index 331156ee11..f51743646d 100644
--- a/django/db/backends/postgresql/operations.py
+++ b/django/db/backends/postgresql/operations.py
@@ -6,14 +6,15 @@ from django.db.backends import BaseDatabaseOperations
# used by both the 'postgresql' and 'postgresql_psycopg2' backends.
class DatabaseOperations(BaseDatabaseOperations):
- def __init__(self):
+ def __init__(self, connection):
+ super(DatabaseOperations, self).__init__()
self._postgres_version = None
+ self.connection = connection
def _get_postgres_version(self):
if self._postgres_version is None:
- from django.db import connection
from django.db.backends.postgresql.version import get_version
- cursor = connection.cursor()
+ cursor = self.connection.cursor()
self._postgres_version = get_version(cursor)
return self._postgres_version
postgres_version = property(_get_postgres_version)
diff --git a/django/db/backends/postgresql_psycopg2/base.py b/django/db/backends/postgresql_psycopg2/base.py
index d4ad3da646..fcd84cd290 100644
--- a/django/db/backends/postgresql_psycopg2/base.py
+++ b/django/db/backends/postgresql_psycopg2/base.py
@@ -4,7 +4,6 @@ PostgreSQL database backend for Django.
Requires psycopg 2: http://initd.org/projects/psycopg2
"""
-from django.conf import settings
from django.db.backends import *
from django.db.backends.signals import connection_created
from django.db.backends.postgresql.operations import DatabaseOperations as PostgresqlDatabaseOperations
@@ -64,37 +63,37 @@ 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.ops = DatabaseOperations(self)
self.client = DatabaseClient(self)
self.creation = DatabaseCreation(self)
self.introspection = DatabaseIntrospection(self)
- self.validation = BaseDatabaseValidation()
+ self.validation = BaseDatabaseValidation(self)
def _cursor(self):
set_tz = False
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)
@@ -150,4 +149,3 @@ class DatabaseWrapper(BaseDatabaseWrapper):
finally:
self.isolation_level = level
self.features.uses_savepoints = bool(level)
-
diff --git a/django/db/backends/sqlite3/base.py b/django/db/backends/sqlite3/base.py
index f9be87d00a..6f78cf2a4a 100644
--- a/django/db/backends/sqlite3/base.py
+++ b/django/db/backends/sqlite3/base.py
@@ -29,10 +29,6 @@ except ImportError, exc:
module = 'either pysqlite2 or sqlite3 modules (tried in that order)'
raise ImproperlyConfigured, "Error loading %s: %s" % (module, exc)
-try:
- import decimal
-except ImportError:
- from django.utils import _decimal as decimal # for Python 2.3
DatabaseError = Database.DatabaseError
IntegrityError = Database.IntegrityError
@@ -154,19 +150,19 @@ class DatabaseWrapper(BaseDatabaseWrapper):
self.client = DatabaseClient(self)
self.creation = DatabaseCreation(self)
self.introspection = DatabaseIntrospection(self)
- self.validation = BaseDatabaseValidation()
+ self.validation = BaseDatabaseValidation(self)
def _cursor(self):
if self.connection is None:
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 +175,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 fb27d22cf3..03897078a2 100644
--- a/django/db/backends/sqlite3/creation.py
+++ b/django/db/backends/sqlite3/creation.py
@@ -1,6 +1,5 @@
import os
import sys
-from django.conf import settings
from django.db.backends.creation import BaseDatabaseCreation
class DatabaseCreation(BaseDatabaseCreation):
@@ -30,7 +29,7 @@ class DatabaseCreation(BaseDatabaseCreation):
'TextField': 'text',
'TimeField': 'time',
}
-
+
def sql_for_pending_references(self, model, style, pending_references):
"SQLite3 doesn't support constraints"
return []
@@ -38,10 +37,10 @@ class DatabaseCreation(BaseDatabaseCreation):
def sql_remove_table_constraints(self, model, references_to_delete, style):
"SQLite3 doesn't support constraints"
return []
-
+
def _create_test_db(self, verbosity, autoclobber):
- if settings.TEST_DATABASE_NAME and settings.TEST_DATABASE_NAME != ":memory:":
- test_database_name = settings.TEST_DATABASE_NAME
+ test_database_name = self.connection.settings_dict['TEST_NAME']
+ if test_database_name and test_database_name != ":memory:":
# Erase the old test database
if verbosity >= 1:
print "Destroying old test database..."
@@ -64,7 +63,7 @@ class DatabaseCreation(BaseDatabaseCreation):
else:
test_database_name = ":memory:"
return test_database_name
-
+
def _destroy_test_db(self, test_database_name, verbosity):
if test_database_name and test_database_name != ":memory:":
# Remove the SQLite database file