PageRenderTime 49ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 0ms

/django/db/backends/postgresql/base.py

https://bitbucket.org/taxilian/racecontrol5
Python | 179 lines | 164 code | 5 blank | 10 comment | 4 complexity | c1e55b343141baa5ced4d35c6cf388f6 MD5 | raw file
Possible License(s): BSD-3-Clause
  1. """
  2. PostgreSQL database backend for Django.
  3. Requires psycopg 1: http://initd.org/projects/psycopg1
  4. """
  5. import sys
  6. from django.db import utils
  7. from django.db.backends import *
  8. from django.db.backends.signals import connection_created
  9. from django.db.backends.postgresql.client import DatabaseClient
  10. from django.db.backends.postgresql.creation import DatabaseCreation
  11. from django.db.backends.postgresql.introspection import DatabaseIntrospection
  12. from django.db.backends.postgresql.operations import DatabaseOperations
  13. from django.db.backends.postgresql.version import get_version
  14. from django.utils.encoding import smart_str, smart_unicode
  15. try:
  16. import psycopg as Database
  17. except ImportError, e:
  18. from django.core.exceptions import ImproperlyConfigured
  19. raise ImproperlyConfigured("Error loading psycopg module: %s" % e)
  20. DatabaseError = Database.DatabaseError
  21. IntegrityError = Database.IntegrityError
  22. class UnicodeCursorWrapper(object):
  23. """
  24. A thin wrapper around psycopg cursors that allows them to accept Unicode
  25. strings as params.
  26. This is necessary because psycopg doesn't apply any DB quoting to
  27. parameters that are Unicode strings. If a param is Unicode, this will
  28. convert it to a bytestring using database client's encoding before passing
  29. it to psycopg.
  30. All results retrieved from the database are converted into Unicode strings
  31. before being returned to the caller.
  32. """
  33. def __init__(self, cursor, charset):
  34. self.cursor = cursor
  35. self.charset = charset
  36. def format_params(self, params):
  37. if isinstance(params, dict):
  38. result = {}
  39. charset = self.charset
  40. for key, value in params.items():
  41. result[smart_str(key, charset)] = smart_str(value, charset)
  42. return result
  43. else:
  44. return tuple([smart_str(p, self.charset, True) for p in params])
  45. def execute(self, sql, params=()):
  46. try:
  47. return self.cursor.execute(smart_str(sql, self.charset), self.format_params(params))
  48. except Database.IntegrityError, e:
  49. raise utils.IntegrityError, utils.IntegrityError(*tuple(e)), sys.exc_info()[2]
  50. except Database.DatabaseError, e:
  51. raise utils.DatabaseError, utils.DatabaseError(*tuple(e)), sys.exc_info()[2]
  52. def executemany(self, sql, param_list):
  53. try:
  54. new_param_list = [self.format_params(params) for params in param_list]
  55. return self.cursor.executemany(sql, new_param_list)
  56. except Database.IntegrityError, e:
  57. raise utils.IntegrityError, utils.IntegrityError(*tuple(e)), sys.exc_info()[2]
  58. except Database.DatabaseError, e:
  59. raise utils.DatabaseError, utils.DatabaseError(*tuple(e)), sys.exc_info()[2]
  60. def __getattr__(self, attr):
  61. if attr in self.__dict__:
  62. return self.__dict__[attr]
  63. else:
  64. return getattr(self.cursor, attr)
  65. def __iter__(self):
  66. return iter(self.cursor.fetchall())
  67. class DatabaseFeatures(BaseDatabaseFeatures):
  68. uses_savepoints = True
  69. class DatabaseWrapper(BaseDatabaseWrapper):
  70. operators = {
  71. 'exact': '= %s',
  72. 'iexact': '= UPPER(%s)',
  73. 'contains': 'LIKE %s',
  74. 'icontains': 'LIKE UPPER(%s)',
  75. 'regex': '~ %s',
  76. 'iregex': '~* %s',
  77. 'gt': '> %s',
  78. 'gte': '>= %s',
  79. 'lt': '< %s',
  80. 'lte': '<= %s',
  81. 'startswith': 'LIKE %s',
  82. 'endswith': 'LIKE %s',
  83. 'istartswith': 'LIKE UPPER(%s)',
  84. 'iendswith': 'LIKE UPPER(%s)',
  85. }
  86. def __init__(self, *args, **kwargs):
  87. super(DatabaseWrapper, self).__init__(*args, **kwargs)
  88. import warnings
  89. warnings.warn(
  90. 'The "postgresql" backend has been deprecated. Use "postgresql_psycopg2" instead.',
  91. PendingDeprecationWarning
  92. )
  93. self.features = DatabaseFeatures()
  94. self.ops = DatabaseOperations(self)
  95. self.client = DatabaseClient(self)
  96. self.creation = DatabaseCreation(self)
  97. self.introspection = DatabaseIntrospection(self)
  98. self.validation = BaseDatabaseValidation(self)
  99. def _cursor(self):
  100. new_connection = False
  101. set_tz = False
  102. settings_dict = self.settings_dict
  103. if self.connection is None:
  104. new_connection = True
  105. set_tz = settings_dict.get('TIME_ZONE')
  106. if settings_dict['NAME'] == '':
  107. from django.core.exceptions import ImproperlyConfigured
  108. raise ImproperlyConfigured("You need to specify NAME in your Django settings file.")
  109. conn_string = "dbname=%s" % settings_dict['NAME']
  110. if settings_dict['USER']:
  111. conn_string = "user=%s %s" % (settings_dict['USER'], conn_string)
  112. if settings_dict['PASSWORD']:
  113. conn_string += " password='%s'" % settings_dict['PASSWORD']
  114. if settings_dict['HOST']:
  115. conn_string += " host=%s" % settings_dict['HOST']
  116. if settings_dict['PORT']:
  117. conn_string += " port=%s" % settings_dict['PORT']
  118. self.connection = Database.connect(conn_string, **settings_dict['OPTIONS'])
  119. # make transactions transparent to all cursors
  120. self.connection.set_isolation_level(1)
  121. connection_created.send(sender=self.__class__, connection=self)
  122. cursor = self.connection.cursor()
  123. if new_connection:
  124. if set_tz:
  125. cursor.execute("SET TIME ZONE %s", [settings_dict['TIME_ZONE']])
  126. if not hasattr(self, '_version'):
  127. self.__class__._version = get_version(cursor)
  128. if self._version[0:2] < (8, 0):
  129. # No savepoint support for earlier version of PostgreSQL.
  130. self.features.uses_savepoints = False
  131. cursor.execute("SET client_encoding to 'UNICODE'")
  132. return UnicodeCursorWrapper(cursor, 'utf-8')
  133. def _commit(self):
  134. if self.connection is not None:
  135. try:
  136. return self.connection.commit()
  137. except Database.IntegrityError, e:
  138. raise utils.IntegrityError, utils.IntegrityError(*tuple(e)), sys.exc_info()[2]
  139. def typecast_string(s):
  140. """
  141. Cast all returned strings to unicode strings.
  142. """
  143. if not s and not isinstance(s, str):
  144. return s
  145. return smart_unicode(s)
  146. # Register these custom typecasts, because Django expects dates/times to be
  147. # in Python's native (standard-library) datetime/time format, whereas psycopg
  148. # use mx.DateTime by default.
  149. try:
  150. Database.register_type(Database.new_type((1082,), "DATE", util.typecast_date))
  151. except AttributeError:
  152. raise Exception("You appear to be using psycopg version 2. Set your DATABASES.ENGINE to 'postgresql_psycopg2' instead of 'postgresql'.")
  153. Database.register_type(Database.new_type((1083,1266), "TIME", util.typecast_time))
  154. Database.register_type(Database.new_type((1114,1184), "TIMESTAMP", util.typecast_timestamp))
  155. Database.register_type(Database.new_type((16,), "BOOLEAN", util.typecast_boolean))
  156. Database.register_type(Database.new_type((1700,), "NUMERIC", util.typecast_decimal))
  157. Database.register_type(Database.new_type(Database.types[1043].values, 'STRING', typecast_string))