Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Deprecated the psycopg-based postgresql database backend.

git-svn-id: http://code.djangoproject.com/svn/django/trunk@15980 bcc190cf-cafb-0310-a4f2-bffc1f526a37
  • Loading branch information...
commit 89117545557f8ccfccfa9addd086a160501104b3 1 parent f9972bc
@freakboy3742 freakboy3742 authored
View
0  django/db/backends/postgresql/__init__.py
No changes.
View
183 django/db/backends/postgresql/base.py
@@ -1,183 +0,0 @@
-"""
-PostgreSQL database backend for Django.
-
-Requires psycopg 1: http://initd.org/projects/psycopg1
-"""
-
-import sys
-
-from django.db import utils
-from django.db.backends import *
-from django.db.backends.signals import connection_created
-from django.db.backends.postgresql.client import DatabaseClient
-from django.db.backends.postgresql.creation import DatabaseCreation
-from django.db.backends.postgresql.introspection import DatabaseIntrospection
-from django.db.backends.postgresql.operations import DatabaseOperations
-from django.db.backends.postgresql.version import get_version
-from django.utils.encoding import smart_str, smart_unicode
-
-try:
- import psycopg as Database
-except ImportError, e:
- from django.core.exceptions import ImproperlyConfigured
- raise ImproperlyConfigured("Error loading psycopg module: %s" % e)
-
-DatabaseError = Database.DatabaseError
-IntegrityError = Database.IntegrityError
-
-class UnicodeCursorWrapper(object):
- """
- A thin wrapper around psycopg cursors that allows them to accept Unicode
- strings as params.
-
- This is necessary because psycopg doesn't apply any DB quoting to
- parameters that are Unicode strings. If a param is Unicode, this will
- convert it to a bytestring using database client's encoding before passing
- it to psycopg.
-
- All results retrieved from the database are converted into Unicode strings
- before being returned to the caller.
- """
- def __init__(self, cursor, charset):
- self.cursor = cursor
- self.charset = charset
-
- def format_params(self, params):
- if isinstance(params, dict):
- result = {}
- charset = self.charset
- for key, value in params.items():
- result[smart_str(key, charset)] = smart_str(value, charset)
- return result
- else:
- return tuple([smart_str(p, self.charset, True) for p in params])
-
- def execute(self, sql, params=()):
- try:
- return self.cursor.execute(smart_str(sql, self.charset), self.format_params(params))
- except Database.IntegrityError, e:
- raise utils.IntegrityError, utils.IntegrityError(*tuple(e)), sys.exc_info()[2]
- except Database.DatabaseError, e:
- raise utils.DatabaseError, utils.DatabaseError(*tuple(e)), sys.exc_info()[2]
-
- def executemany(self, sql, param_list):
- try:
- new_param_list = [self.format_params(params) for params in param_list]
- return self.cursor.executemany(sql, new_param_list)
- except Database.IntegrityError, e:
- raise utils.IntegrityError, utils.IntegrityError(*tuple(e)), sys.exc_info()[2]
- except Database.DatabaseError, e:
- raise utils.DatabaseError, utils.DatabaseError(*tuple(e)), sys.exc_info()[2]
-
- def __getattr__(self, attr):
- if attr in self.__dict__:
- return self.__dict__[attr]
- else:
- return getattr(self.cursor, attr)
-
- def __iter__(self):
- return iter(self.cursor.fetchall())
-
-class DatabaseFeatures(BaseDatabaseFeatures):
- uses_savepoints = True
- requires_rollback_on_dirty_transaction = True
- has_real_datatype = True
- can_defer_constraint_checks = True
-
-class DatabaseWrapper(BaseDatabaseWrapper):
- vendor = 'postgresql'
- 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)
-
- import warnings
- warnings.warn(
- 'The "postgresql" backend has been deprecated. Use "postgresql_psycopg2" instead.',
- DeprecationWarning
- )
-
- self.features = DatabaseFeatures(self)
- self.ops = DatabaseOperations(self)
- self.client = DatabaseClient(self)
- self.creation = DatabaseCreation(self)
- self.introspection = DatabaseIntrospection(self)
- self.validation = BaseDatabaseValidation(self)
-
- def _cursor(self):
- new_connection = False
- set_tz = False
- settings_dict = self.settings_dict
- if self.connection is None:
- new_connection = True
- set_tz = settings_dict.get('TIME_ZONE')
- if settings_dict['NAME'] == '':
- from django.core.exceptions import ImproperlyConfigured
- 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'])
- # make transactions transparent to all cursors
- self.connection.set_isolation_level(1)
- connection_created.send(sender=self.__class__, connection=self)
- cursor = self.connection.cursor()
- if new_connection:
- if set_tz:
- cursor.execute("SET TIME ZONE %s", [settings_dict['TIME_ZONE']])
- if not hasattr(self, '_version'):
- self.__class__._version = get_version(cursor)
- if self._version[0:2] < (8, 0):
- # No savepoint support for earlier version of PostgreSQL.
- self.features.uses_savepoints = False
- cursor.execute("SET client_encoding to 'UNICODE'")
- return UnicodeCursorWrapper(cursor, 'utf-8')
-
- def _commit(self):
- if self.connection is not None:
- try:
- return self.connection.commit()
- except Database.IntegrityError, e:
- raise utils.IntegrityError, utils.IntegrityError(*tuple(e)), sys.exc_info()[2]
-
-def typecast_string(s):
- """
- Cast all returned strings to unicode strings.
- """
- if not s and not isinstance(s, str):
- return s
- return smart_unicode(s)
-
-# Register these custom typecasts, because Django expects dates/times to be
-# in Python's native (standard-library) datetime/time format, whereas psycopg
-# use mx.DateTime by default.
-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 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))
-Database.register_type(Database.new_type((1700,), "NUMERIC", util.typecast_decimal))
-Database.register_type(Database.new_type(Database.types[1043].values, 'STRING', typecast_string))
View
88 django/db/backends/postgresql/introspection.py
@@ -1,88 +0,0 @@
-from django.db.backends import BaseDatabaseIntrospection
-
-class DatabaseIntrospection(BaseDatabaseIntrospection):
- # Maps type codes to Django Field types.
- data_types_reverse = {
- 16: 'BooleanField',
- 20: 'BigIntegerField',
- 21: 'SmallIntegerField',
- 23: 'IntegerField',
- 25: 'TextField',
- 700: 'FloatField',
- 701: 'FloatField',
- 869: 'IPAddressField',
- 1043: 'CharField',
- 1082: 'DateField',
- 1083: 'TimeField',
- 1114: 'DateTimeField',
- 1184: 'DateTimeField',
- 1266: 'TimeField',
- 1700: 'DecimalField',
- }
-
- def get_table_list(self, cursor):
- "Returns a list of table names in the current database."
- cursor.execute("""
- SELECT c.relname
- FROM pg_catalog.pg_class c
- LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace
- WHERE c.relkind IN ('r', 'v', '')
- AND n.nspname NOT IN ('pg_catalog', 'pg_toast')
- AND pg_catalog.pg_table_is_visible(c.oid)""")
- return [row[0] for row in cursor.fetchall()]
-
- def get_table_description(self, cursor, table_name):
- "Returns a description of the table, with the DB-API cursor.description interface."
- cursor.execute("SELECT * FROM %s LIMIT 1" % self.connection.ops.quote_name(table_name))
- return cursor.description
-
- def get_relations(self, cursor, table_name):
- """
- Returns a dictionary of {field_index: (field_index_other_table, other_table)}
- representing all relationships to the given table. Indexes are 0-based.
- """
- cursor.execute("""
- SELECT con.conkey, con.confkey, c2.relname
- FROM pg_constraint con, pg_class c1, pg_class c2
- WHERE c1.oid = con.conrelid
- AND c2.oid = con.confrelid
- AND c1.relname = %s
- AND con.contype = 'f'""", [table_name])
- relations = {}
- for row in cursor.fetchall():
- try:
- # row[0] and row[1] are like "{2}", so strip the curly braces.
- relations[int(row[0][1:-1]) - 1] = (int(row[1][1:-1]) - 1, row[2])
- except ValueError:
- continue
- return relations
-
- def get_indexes(self, cursor, table_name):
- """
- Returns a dictionary of fieldname -> infodict for the given table,
- where each infodict is in the format:
- {'primary_key': boolean representing whether it's the primary key,
- 'unique': boolean representing whether it's a unique index}
- """
- # This query retrieves each index on the given table, including the
- # first associated field name
- cursor.execute("""
- SELECT attr.attname, idx.indkey, idx.indisunique, idx.indisprimary
- FROM pg_catalog.pg_class c, pg_catalog.pg_class c2,
- pg_catalog.pg_index idx, pg_catalog.pg_attribute attr
- WHERE c.oid = idx.indrelid
- AND idx.indexrelid = c2.oid
- AND attr.attrelid = c.oid
- AND attr.attnum = idx.indkey[0]
- AND c.relname = %s""", [table_name])
- indexes = {}
- for row in cursor.fetchall():
- # row[1] (idx.indkey) is stored in the DB as an array. It comes out as
- # a string of space-separated integers. This designates the field
- # indexes (1-based) of the fields that have indexes on the table.
- # Here, we skip any indexes across multiple fields.
- if ' ' in row[1]:
- continue
- indexes[row[0]] = {'primary_key': row[3], 'unique': row[2]}
- return indexes
-
View
18 django/db/backends/postgresql_psycopg2/base.py
@@ -9,10 +9,10 @@
from django.db import utils
from django.db.backends import *
from django.db.backends.signals import connection_created
-from django.db.backends.postgresql.operations import DatabaseOperations as PostgresqlDatabaseOperations
-from django.db.backends.postgresql.client import DatabaseClient
-from django.db.backends.postgresql.creation import DatabaseCreation
-from django.db.backends.postgresql.version import get_version
+from django.db.backends.postgresql_psycopg2.operations import DatabaseOperations
+from django.db.backends.postgresql_psycopg2.client import DatabaseClient
+from django.db.backends.postgresql_psycopg2.creation import DatabaseCreation
+from django.db.backends.postgresql_psycopg2.version import get_version
from django.db.backends.postgresql_psycopg2.introspection import DatabaseIntrospection
from django.utils.safestring import SafeUnicode, SafeString
@@ -71,16 +71,6 @@ class DatabaseFeatures(BaseDatabaseFeatures):
has_real_datatype = True
can_defer_constraint_checks = True
-class 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.query
-
- def return_insert_id(self):
- return "RETURNING %s", ()
-
class DatabaseWrapper(BaseDatabaseWrapper):
vendor = 'postgresql'
operators = {
View
0  django/db/backends/postgresql/client.py → django/db/backends/postgresql_psycopg2/client.py
File renamed without changes
View
1  django/db/backends/postgresql/creation.py → django/db/backends/postgresql_psycopg2/creation.py
@@ -1,6 +1,7 @@
from django.db.backends.creation import BaseDatabaseCreation
from django.db.backends.util import truncate_name
+
class DatabaseCreation(BaseDatabaseCreation):
# This dictionary maps Field objects to their associated PostgreSQL column
# types, as strings. Column-type strings can contain format strings; they'll
View
68 django/db/backends/postgresql_psycopg2/introspection.py
@@ -1,6 +1,41 @@
-from django.db.backends.postgresql.introspection import DatabaseIntrospection as PostgresDatabaseIntrospection
+from django.db.backends import BaseDatabaseIntrospection
-class DatabaseIntrospection(PostgresDatabaseIntrospection):
+
+class DatabaseIntrospection(BaseDatabaseIntrospection):
+ # Maps type codes to Django Field types.
+ data_types_reverse = {
+ 16: 'BooleanField',
+ 20: 'BigIntegerField',
+ 21: 'SmallIntegerField',
+ 23: 'IntegerField',
+ 25: 'TextField',
+ 700: 'FloatField',
+ 701: 'FloatField',
+ 869: 'IPAddressField',
+ 1043: 'CharField',
+ 1082: 'DateField',
+ 1083: 'TimeField',
+ 1114: 'DateTimeField',
+ 1184: 'DateTimeField',
+ 1266: 'TimeField',
+ 1700: 'DecimalField',
+ }
+
+ def get_table_list(self, cursor):
+ "Returns a list of table names in the current database."
+ cursor.execute("""
+ SELECT c.relname
+ FROM pg_catalog.pg_class c
+ LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace
+ WHERE c.relkind IN ('r', 'v', '')
+ AND n.nspname NOT IN ('pg_catalog', 'pg_toast')
+ AND pg_catalog.pg_table_is_visible(c.oid)""")
+ return [row[0] for row in cursor.fetchall()]
+
+ def get_table_description(self, cursor, table_name):
+ "Returns a description of the table, with the DB-API cursor.description interface."
+ cursor.execute("SELECT * FROM %s LIMIT 1" % self.connection.ops.quote_name(table_name))
+ return cursor.description
def get_relations(self, cursor, table_name):
"""
@@ -19,3 +54,32 @@ def get_relations(self, cursor, table_name):
# row[0] and row[1] are single-item lists, so grab the single item.
relations[row[0][0] - 1] = (row[1][0] - 1, row[2])
return relations
+
+ def get_indexes(self, cursor, table_name):
+ """
+ Returns a dictionary of fieldname -> infodict for the given table,
+ where each infodict is in the format:
+ {'primary_key': boolean representing whether it's the primary key,
+ 'unique': boolean representing whether it's a unique index}
+ """
+ # This query retrieves each index on the given table, including the
+ # first associated field name
+ cursor.execute("""
+ SELECT attr.attname, idx.indkey, idx.indisunique, idx.indisprimary
+ FROM pg_catalog.pg_class c, pg_catalog.pg_class c2,
+ pg_catalog.pg_index idx, pg_catalog.pg_attribute attr
+ WHERE c.oid = idx.indrelid
+ AND idx.indexrelid = c2.oid
+ AND attr.attrelid = c.oid
+ AND attr.attnum = idx.indkey[0]
+ AND c.relname = %s""", [table_name])
+ indexes = {}
+ for row in cursor.fetchall():
+ # row[1] (idx.indkey) is stored in the DB as an array. It comes out as
+ # a string of space-separated integers. This designates the field
+ # indexes (1-based) of the fields that have indexes on the table.
+ # Here, we skip any indexes across multiple fields.
+ if ' ' in row[1]:
+ continue
+ indexes[row[0]] = {'primary_key': row[3], 'unique': row[2]}
+ return indexes
View
13 django/db/backends/postgresql/operations.py → django/db/backends/postgresql_psycopg2/operations.py
@@ -2,8 +2,6 @@
from django.db.backends import BaseDatabaseOperations
-# This DatabaseOperations class lives in here instead of base.py because it's
-# used by both the 'postgresql' and 'postgresql_psycopg2' backends.
class DatabaseOperations(BaseDatabaseOperations):
def __init__(self, connection):
@@ -13,7 +11,7 @@ def __init__(self, connection):
def _get_postgres_version(self):
if self._postgres_version is None:
- from django.db.backends.postgresql.version import get_version
+ from django.db.backends.postgresql_psycopg2.version import get_version
cursor = self.connection.cursor()
self._postgres_version = get_version(cursor)
return self._postgres_version
@@ -203,3 +201,12 @@ def max_name_length(self):
"""
return 63
+
+ 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.query
+
+ def return_insert_id(self):
+ return "RETURNING %s", ()
View
1  django/db/backends/postgresql/version.py → django/db/backends/postgresql_psycopg2/version.py
@@ -12,6 +12,7 @@
# PostgreSQL 8.4beta1
VERSION_RE = re.compile(r'\S+ (\d+)\.(\d+)\.?(\d+)?')
+
def _parse_version(text):
"Internal parsing method. Factored out for testing purposes."
major, major2, minor = VERSION_RE.search(text).groups()
Please sign in to comment.
Something went wrong with that request. Please try again.