Do not rely on dicts.merge to change target
Also make dicts.merge actually not touch target. This is much cleaner
than modifying in place, especially since we assign the result of the
dicts.merge call to target most of the time anyway.
Patch by: Sverre Rabbelier
"""PostgreSQL database backend for Django.Requires psycopg 2: http://initd.org/projects/psycopg2"""from django.db.backends import *from django.db.backends.postgresql.operations import DatabaseOperations as PostgresqlDatabaseOperationsfrom django.db.backends.postgresql.client import DatabaseClientfrom django.db.backends.postgresql.creation import DatabaseCreationfrom django.db.backends.postgresql.version import get_versionfrom django.db.backends.postgresql_psycopg2.introspection import DatabaseIntrospectionfrom django.utils.safestring import SafeUnicode, SafeStringtry: import psycopg2 as Database import psycopg2.extensionsexcept ImportError, e: from django.core.exceptions import ImproperlyConfigured raise ImproperlyConfigured("Error loading psycopg2 module: %s" % e)DatabaseError = Database.DatabaseErrorIntegrityError = Database.IntegrityErrorpsycopg2.extensions.register_type(psycopg2.extensions.UNICODE)psycopg2.extensions.register_adapter(SafeString, psycopg2.extensions.QuotedString)psycopg2.extensions.register_adapter(SafeUnicode, psycopg2.extensions.QuotedString)class DatabaseFeatures(BaseDatabaseFeatures): needs_datetime_string_cast = False uses_savepoints = Trueclass DatabaseOperations(PostgresqlDatabaseOperations): def last_executed_query(self, cursor, sql, params): # With psycopg2, cursor objects have a "query" attribute that is the # exact query sent to the database. See docs here: # http://www.initd.org/tracker/psycopg/wiki/psycopg2_documentation#postgresql-status-message-and-executed-query return cursor.queryclass DatabaseWrapper(BaseDatabaseWrapper): operators = { 'exact': '= %s', 'iexact': '= UPPER(%s)', 'contains': 'LIKE %s', 'icontains': 'LIKE UPPER(%s)', 'regex': '~ %s', 'iregex': '~* %s', 'gt': '> %s', 'gte': '>= %s', 'lt': '< %s', 'lte': '<= %s', 'startswith': 'LIKE %s', 'endswith': 'LIKE %s', 'istartswith': 'LIKE UPPER(%s)', 'iendswith': 'LIKE UPPER(%s)', } def __init__(self, *args, **kwargs): super(DatabaseWrapper, self).__init__(*args, **kwargs) self.features = DatabaseFeatures() self.ops = DatabaseOperations() self.client = DatabaseClient() self.creation = DatabaseCreation(self) self.introspection = DatabaseIntrospection(self) self.validation = BaseDatabaseValidation() def _cursor(self, settings): set_tz = False if self.connection is None: set_tz = True if settings.DATABASE_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.DATABASE_NAME if settings.DATABASE_USER: conn_string = "user=%s %s" % (settings.DATABASE_USER, conn_string) if settings.DATABASE_PASSWORD: conn_string += " password='%s'" % settings.DATABASE_PASSWORD if settings.DATABASE_HOST: conn_string += " host=%s" % settings.DATABASE_HOST if settings.DATABASE_PORT: conn_string += " port=%s" % settings.DATABASE_PORT self.connection = Database.connect(conn_string, **self.options) self.connection.set_isolation_level(1) # make transactions transparent to all cursors self.connection.set_client_encoding('UTF8') cursor = self.connection.cursor() cursor.tzinfo_factory = None if set_tz: cursor.execute("SET TIME ZONE %s", [settings.TIME_ZONE]) if not hasattr(self, '_version'): self.__class__._version = get_version(cursor) if self._version < (8, 0): # No savepoint support for earlier version of PostgreSQL. self.features.uses_savepoints = False return cursor