diff options
| author | Russell Keith-Magee <russell@keith-magee.com> | 2009-12-22 15:18:51 +0000 |
|---|---|---|
| committer | Russell Keith-Magee <russell@keith-magee.com> | 2009-12-22 15:18:51 +0000 |
| commit | ff60c5f9de3e8690d1e86f3e9e3f7248a15397c8 (patch) | |
| tree | a4cb0ebdd55fcaf8c8855231b6ad3e1a7bf45bee /django/db/backends | |
| parent | 7ef212af149540aa2da577a960d0d87029fd1514 (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__.py | 60 | ||||
| -rw-r--r-- | django/db/backends/creation.py | 34 | ||||
| -rw-r--r-- | django/db/backends/dummy/base.py | 4 | ||||
| -rw-r--r-- | django/db/backends/mysql/base.py | 28 | ||||
| -rw-r--r-- | django/db/backends/mysql/client.py | 12 | ||||
| -rw-r--r-- | django/db/backends/mysql/creation.py | 18 | ||||
| -rw-r--r-- | django/db/backends/mysql/validation.py | 4 | ||||
| -rw-r--r-- | django/db/backends/oracle/base.py | 76 | ||||
| -rw-r--r-- | django/db/backends/oracle/compiler.py | 66 | ||||
| -rw-r--r-- | django/db/backends/oracle/creation.py | 129 | ||||
| -rw-r--r-- | django/db/backends/oracle/query.py | 150 | ||||
| -rw-r--r-- | django/db/backends/postgresql/base.py | 30 | ||||
| -rw-r--r-- | django/db/backends/postgresql/client.py | 14 | ||||
| -rw-r--r-- | django/db/backends/postgresql/creation.py | 7 | ||||
| -rw-r--r-- | django/db/backends/postgresql/operations.py | 7 | ||||
| -rw-r--r-- | django/db/backends/postgresql_psycopg2/base.py | 32 | ||||
| -rw-r--r-- | django/db/backends/sqlite3/base.py | 16 | ||||
| -rw-r--r-- | django/db/backends/sqlite3/client.py | 2 | ||||
| -rw-r--r-- | django/db/backends/sqlite3/creation.py | 11 |
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 |
