web/lib/django/db/backends/postgresql_psycopg2/base.py
changeset 29 cc9b7e14412b
parent 0 0d40e90630ef
equal deleted inserted replaced
28:b758351d191f 29:cc9b7e14412b
     2 PostgreSQL database backend for Django.
     2 PostgreSQL database backend for Django.
     3 
     3 
     4 Requires psycopg 2: http://initd.org/projects/psycopg2
     4 Requires psycopg 2: http://initd.org/projects/psycopg2
     5 """
     5 """
     6 
     6 
     7 from django.conf import settings
     7 import sys
       
     8 
       
     9 from django.db import utils
     8 from django.db.backends import *
    10 from django.db.backends import *
     9 from django.db.backends.signals import connection_created
    11 from django.db.backends.signals import connection_created
    10 from django.db.backends.postgresql.operations import DatabaseOperations as PostgresqlDatabaseOperations
    12 from django.db.backends.postgresql.operations import DatabaseOperations as PostgresqlDatabaseOperations
    11 from django.db.backends.postgresql.client import DatabaseClient
    13 from django.db.backends.postgresql.client import DatabaseClient
    12 from django.db.backends.postgresql.creation import DatabaseCreation
    14 from django.db.backends.postgresql.creation import DatabaseCreation
    25 IntegrityError = Database.IntegrityError
    27 IntegrityError = Database.IntegrityError
    26 
    28 
    27 psycopg2.extensions.register_type(psycopg2.extensions.UNICODE)
    29 psycopg2.extensions.register_type(psycopg2.extensions.UNICODE)
    28 psycopg2.extensions.register_adapter(SafeString, psycopg2.extensions.QuotedString)
    30 psycopg2.extensions.register_adapter(SafeString, psycopg2.extensions.QuotedString)
    29 psycopg2.extensions.register_adapter(SafeUnicode, psycopg2.extensions.QuotedString)
    31 psycopg2.extensions.register_adapter(SafeUnicode, psycopg2.extensions.QuotedString)
       
    32 
       
    33 class CursorWrapper(object):
       
    34     """
       
    35     A thin wrapper around psycopg2's normal cursor class so that we can catch
       
    36     particular exception instances and reraise them with the right types.
       
    37     """
       
    38 
       
    39     def __init__(self, cursor):
       
    40         self.cursor = cursor
       
    41 
       
    42     def execute(self, query, args=None):
       
    43         try:
       
    44             return self.cursor.execute(query, args)
       
    45         except Database.IntegrityError, e:
       
    46             raise utils.IntegrityError, utils.IntegrityError(*tuple(e)), sys.exc_info()[2]
       
    47         except Database.DatabaseError, e:
       
    48             raise utils.DatabaseError, utils.DatabaseError(*tuple(e)), sys.exc_info()[2]
       
    49 
       
    50     def executemany(self, query, args):
       
    51         try:
       
    52             return self.cursor.executemany(query, args)
       
    53         except Database.IntegrityError, e:
       
    54             raise utils.IntegrityError, utils.IntegrityError(*tuple(e)), sys.exc_info()[2]
       
    55         except Database.DatabaseError, e:
       
    56             raise utils.DatabaseError, utils.DatabaseError(*tuple(e)), sys.exc_info()[2]
       
    57 
       
    58     def __getattr__(self, attr):
       
    59         if attr in self.__dict__:
       
    60             return self.__dict__[attr]
       
    61         else:
       
    62             return getattr(self.cursor, attr)
       
    63 
       
    64     def __iter__(self):
       
    65         return iter(self.cursor)
    30 
    66 
    31 class DatabaseFeatures(BaseDatabaseFeatures):
    67 class DatabaseFeatures(BaseDatabaseFeatures):
    32     needs_datetime_string_cast = False
    68     needs_datetime_string_cast = False
    33     can_return_id_from_insert = False
    69     can_return_id_from_insert = False
    34 
    70 
    62 
    98 
    63     def __init__(self, *args, **kwargs):
    99     def __init__(self, *args, **kwargs):
    64         super(DatabaseWrapper, self).__init__(*args, **kwargs)
   100         super(DatabaseWrapper, self).__init__(*args, **kwargs)
    65 
   101 
    66         self.features = DatabaseFeatures()
   102         self.features = DatabaseFeatures()
    67         autocommit = self.settings_dict["DATABASE_OPTIONS"].get('autocommit', False)
   103         autocommit = self.settings_dict["OPTIONS"].get('autocommit', False)
    68         self.features.uses_autocommit = autocommit
   104         self.features.uses_autocommit = autocommit
    69         self._set_isolation_level(int(not autocommit))
   105         self._set_isolation_level(int(not autocommit))
    70         self.ops = DatabaseOperations()
   106         self.ops = DatabaseOperations(self)
    71         self.client = DatabaseClient(self)
   107         self.client = DatabaseClient(self)
    72         self.creation = DatabaseCreation(self)
   108         self.creation = DatabaseCreation(self)
    73         self.introspection = DatabaseIntrospection(self)
   109         self.introspection = DatabaseIntrospection(self)
    74         self.validation = BaseDatabaseValidation()
   110         self.validation = BaseDatabaseValidation(self)
    75 
   111 
    76     def _cursor(self):
   112     def _cursor(self):
       
   113         new_connection = False
    77         set_tz = False
   114         set_tz = False
    78         settings_dict = self.settings_dict
   115         settings_dict = self.settings_dict
    79         if self.connection is None:
   116         if self.connection is None:
    80             set_tz = True
   117             new_connection = True
    81             if settings_dict['DATABASE_NAME'] == '':
   118             set_tz = settings_dict.get('TIME_ZONE')
       
   119             if settings_dict['NAME'] == '':
    82                 from django.core.exceptions import ImproperlyConfigured
   120                 from django.core.exceptions import ImproperlyConfigured
    83                 raise ImproperlyConfigured("You need to specify DATABASE_NAME in your Django settings file.")
   121                 raise ImproperlyConfigured("You need to specify NAME in your Django settings file.")
    84             conn_params = {
   122             conn_params = {
    85                 'database': settings_dict['DATABASE_NAME'],
   123                 'database': settings_dict['NAME'],
    86             }
   124             }
    87             conn_params.update(settings_dict['DATABASE_OPTIONS'])
   125             conn_params.update(settings_dict['OPTIONS'])
    88             if 'autocommit' in conn_params:
   126             if 'autocommit' in conn_params:
    89                 del conn_params['autocommit']
   127                 del conn_params['autocommit']
    90             if settings_dict['DATABASE_USER']:
   128             if settings_dict['USER']:
    91                 conn_params['user'] = settings_dict['DATABASE_USER']
   129                 conn_params['user'] = settings_dict['USER']
    92             if settings_dict['DATABASE_PASSWORD']:
   130             if settings_dict['PASSWORD']:
    93                 conn_params['password'] = settings_dict['DATABASE_PASSWORD']
   131                 conn_params['password'] = settings_dict['PASSWORD']
    94             if settings_dict['DATABASE_HOST']:
   132             if settings_dict['HOST']:
    95                 conn_params['host'] = settings_dict['DATABASE_HOST']
   133                 conn_params['host'] = settings_dict['HOST']
    96             if settings_dict['DATABASE_PORT']:
   134             if settings_dict['PORT']:
    97                 conn_params['port'] = settings_dict['DATABASE_PORT']
   135                 conn_params['port'] = settings_dict['PORT']
    98             self.connection = Database.connect(**conn_params)
   136             self.connection = Database.connect(**conn_params)
    99             self.connection.set_client_encoding('UTF8')
   137             self.connection.set_client_encoding('UTF8')
   100             self.connection.set_isolation_level(self.isolation_level)
   138             self.connection.set_isolation_level(self.isolation_level)
   101             connection_created.send(sender=self.__class__)
   139             connection_created.send(sender=self.__class__)
   102         cursor = self.connection.cursor()
   140         cursor = self.connection.cursor()
   103         cursor.tzinfo_factory = None
   141         cursor.tzinfo_factory = None
   104         if set_tz:
   142         if new_connection:
   105             cursor.execute("SET TIME ZONE %s", [settings_dict['TIME_ZONE']])
   143             if set_tz:
       
   144                 cursor.execute("SET TIME ZONE %s", [settings_dict['TIME_ZONE']])
   106             if not hasattr(self, '_version'):
   145             if not hasattr(self, '_version'):
   107                 self.__class__._version = get_version(cursor)
   146                 self.__class__._version = get_version(cursor)
   108             if self._version[0:2] < (8, 0):
   147             if self._version[0:2] < (8, 0):
   109                 # No savepoint support for earlier version of PostgreSQL.
   148                 # No savepoint support for earlier version of PostgreSQL.
   110                 self.features.uses_savepoints = False
   149                 self.features.uses_savepoints = False
   117                 else:
   156                 else:
   118                     # FIXME: Eventually we're enable this by default for
   157                     # FIXME: Eventually we're enable this by default for
   119                     # versions that support it, but, right now, that's hard to
   158                     # versions that support it, but, right now, that's hard to
   120                     # do without breaking other things (#10509).
   159                     # do without breaking other things (#10509).
   121                     self.features.can_return_id_from_insert = True
   160                     self.features.can_return_id_from_insert = True
   122         return cursor
   161         return CursorWrapper(cursor)
   123 
   162 
   124     def _enter_transaction_management(self, managed):
   163     def _enter_transaction_management(self, managed):
   125         """
   164         """
   126         Switch the isolation level when needing transaction support, so that
   165         Switch the isolation level when needing transaction support, so that
   127         the same transaction is visible across all the queries.
   166         the same transaction is visible across all the queries.
   148             if self.connection is not None:
   187             if self.connection is not None:
   149                 self.connection.set_isolation_level(level)
   188                 self.connection.set_isolation_level(level)
   150         finally:
   189         finally:
   151             self.isolation_level = level
   190             self.isolation_level = level
   152             self.features.uses_savepoints = bool(level)
   191             self.features.uses_savepoints = bool(level)
   153