web/lib/django/db/backends/postgresql_psycopg2/base.py
changeset 0 0d40e90630ef
child 29 cc9b7e14412b
equal deleted inserted replaced
-1:000000000000 0:0d40e90630ef
       
     1 """
       
     2 PostgreSQL database backend for Django.
       
     3 
       
     4 Requires psycopg 2: http://initd.org/projects/psycopg2
       
     5 """
       
     6 
       
     7 from django.conf import settings
       
     8 from django.db.backends import *
       
     9 from django.db.backends.signals import connection_created
       
    10 from django.db.backends.postgresql.operations import DatabaseOperations as PostgresqlDatabaseOperations
       
    11 from django.db.backends.postgresql.client import DatabaseClient
       
    12 from django.db.backends.postgresql.creation import DatabaseCreation
       
    13 from django.db.backends.postgresql.version import get_version
       
    14 from django.db.backends.postgresql_psycopg2.introspection import DatabaseIntrospection
       
    15 from django.utils.safestring import SafeUnicode, SafeString
       
    16 
       
    17 try:
       
    18     import psycopg2 as Database
       
    19     import psycopg2.extensions
       
    20 except ImportError, e:
       
    21     from django.core.exceptions import ImproperlyConfigured
       
    22     raise ImproperlyConfigured("Error loading psycopg2 module: %s" % e)
       
    23 
       
    24 DatabaseError = Database.DatabaseError
       
    25 IntegrityError = Database.IntegrityError
       
    26 
       
    27 psycopg2.extensions.register_type(psycopg2.extensions.UNICODE)
       
    28 psycopg2.extensions.register_adapter(SafeString, psycopg2.extensions.QuotedString)
       
    29 psycopg2.extensions.register_adapter(SafeUnicode, psycopg2.extensions.QuotedString)
       
    30 
       
    31 class DatabaseFeatures(BaseDatabaseFeatures):
       
    32     needs_datetime_string_cast = False
       
    33     can_return_id_from_insert = False
       
    34 
       
    35 class DatabaseOperations(PostgresqlDatabaseOperations):
       
    36     def last_executed_query(self, cursor, sql, params):
       
    37         # With psycopg2, cursor objects have a "query" attribute that is the
       
    38         # exact query sent to the database. See docs here:
       
    39         # http://www.initd.org/tracker/psycopg/wiki/psycopg2_documentation#postgresql-status-message-and-executed-query
       
    40         return cursor.query
       
    41 
       
    42     def return_insert_id(self):
       
    43         return "RETURNING %s", ()
       
    44 
       
    45 class DatabaseWrapper(BaseDatabaseWrapper):
       
    46     operators = {
       
    47         'exact': '= %s',
       
    48         'iexact': '= UPPER(%s)',
       
    49         'contains': 'LIKE %s',
       
    50         'icontains': 'LIKE UPPER(%s)',
       
    51         'regex': '~ %s',
       
    52         'iregex': '~* %s',
       
    53         'gt': '> %s',
       
    54         'gte': '>= %s',
       
    55         'lt': '< %s',
       
    56         'lte': '<= %s',
       
    57         'startswith': 'LIKE %s',
       
    58         'endswith': 'LIKE %s',
       
    59         'istartswith': 'LIKE UPPER(%s)',
       
    60         'iendswith': 'LIKE UPPER(%s)',
       
    61     }
       
    62 
       
    63     def __init__(self, *args, **kwargs):
       
    64         super(DatabaseWrapper, self).__init__(*args, **kwargs)
       
    65 
       
    66         self.features = DatabaseFeatures()
       
    67         autocommit = self.settings_dict["DATABASE_OPTIONS"].get('autocommit', False)
       
    68         self.features.uses_autocommit = autocommit
       
    69         self._set_isolation_level(int(not autocommit))
       
    70         self.ops = DatabaseOperations()
       
    71         self.client = DatabaseClient(self)
       
    72         self.creation = DatabaseCreation(self)
       
    73         self.introspection = DatabaseIntrospection(self)
       
    74         self.validation = BaseDatabaseValidation()
       
    75 
       
    76     def _cursor(self):
       
    77         set_tz = False
       
    78         settings_dict = self.settings_dict
       
    79         if self.connection is None:
       
    80             set_tz = True
       
    81             if settings_dict['DATABASE_NAME'] == '':
       
    82                 from django.core.exceptions import ImproperlyConfigured
       
    83                 raise ImproperlyConfigured("You need to specify DATABASE_NAME in your Django settings file.")
       
    84             conn_params = {
       
    85                 'database': settings_dict['DATABASE_NAME'],
       
    86             }
       
    87             conn_params.update(settings_dict['DATABASE_OPTIONS'])
       
    88             if 'autocommit' in conn_params:
       
    89                 del conn_params['autocommit']
       
    90             if settings_dict['DATABASE_USER']:
       
    91                 conn_params['user'] = settings_dict['DATABASE_USER']
       
    92             if settings_dict['DATABASE_PASSWORD']:
       
    93                 conn_params['password'] = settings_dict['DATABASE_PASSWORD']
       
    94             if settings_dict['DATABASE_HOST']:
       
    95                 conn_params['host'] = settings_dict['DATABASE_HOST']
       
    96             if settings_dict['DATABASE_PORT']:
       
    97                 conn_params['port'] = settings_dict['DATABASE_PORT']
       
    98             self.connection = Database.connect(**conn_params)
       
    99             self.connection.set_client_encoding('UTF8')
       
   100             self.connection.set_isolation_level(self.isolation_level)
       
   101             connection_created.send(sender=self.__class__)
       
   102         cursor = self.connection.cursor()
       
   103         cursor.tzinfo_factory = None
       
   104         if set_tz:
       
   105             cursor.execute("SET TIME ZONE %s", [settings_dict['TIME_ZONE']])
       
   106             if not hasattr(self, '_version'):
       
   107                 self.__class__._version = get_version(cursor)
       
   108             if self._version[0:2] < (8, 0):
       
   109                 # No savepoint support for earlier version of PostgreSQL.
       
   110                 self.features.uses_savepoints = False
       
   111             if self.features.uses_autocommit:
       
   112                 if self._version[0:2] < (8, 2):
       
   113                     # FIXME: Needs extra code to do reliable model insert
       
   114                     # handling, so we forbid it for now.
       
   115                     from django.core.exceptions import ImproperlyConfigured
       
   116                     raise ImproperlyConfigured("You cannot use autocommit=True with PostgreSQL prior to 8.2 at the moment.")
       
   117                 else:
       
   118                     # FIXME: Eventually we're enable this by default for
       
   119                     # versions that support it, but, right now, that's hard to
       
   120                     # do without breaking other things (#10509).
       
   121                     self.features.can_return_id_from_insert = True
       
   122         return cursor
       
   123 
       
   124     def _enter_transaction_management(self, managed):
       
   125         """
       
   126         Switch the isolation level when needing transaction support, so that
       
   127         the same transaction is visible across all the queries.
       
   128         """
       
   129         if self.features.uses_autocommit and managed and not self.isolation_level:
       
   130             self._set_isolation_level(1)
       
   131 
       
   132     def _leave_transaction_management(self, managed):
       
   133         """
       
   134         If the normal operating mode is "autocommit", switch back to that when
       
   135         leaving transaction management.
       
   136         """
       
   137         if self.features.uses_autocommit and not managed and self.isolation_level:
       
   138             self._set_isolation_level(0)
       
   139 
       
   140     def _set_isolation_level(self, level):
       
   141         """
       
   142         Do all the related feature configurations for changing isolation
       
   143         levels. This doesn't touch the uses_autocommit feature, since that
       
   144         controls the movement *between* isolation levels.
       
   145         """
       
   146         assert level in (0, 1)
       
   147         try:
       
   148             if self.connection is not None:
       
   149                 self.connection.set_isolation_level(level)
       
   150         finally:
       
   151             self.isolation_level = level
       
   152             self.features.uses_savepoints = bool(level)
       
   153