Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

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
Russell Keith-Magee authored April 02, 2011
0  backends/postgresql/__init__.py b/django/db/backends/postgresql/__init__.py
No changes.
183  django/db/backends/postgresql/base.py
... ...
@@ -1,183 +0,0 @@
1  
-"""
2  
-PostgreSQL database backend for Django.
3  
-
4  
-Requires psycopg 1: http://initd.org/projects/psycopg1
5  
-"""
6  
-
7  
-import sys
8  
-
9  
-from django.db import utils
10  
-from django.db.backends import *
11  
-from django.db.backends.signals import connection_created
12  
-from django.db.backends.postgresql.client import DatabaseClient
13  
-from django.db.backends.postgresql.creation import DatabaseCreation
14  
-from django.db.backends.postgresql.introspection import DatabaseIntrospection
15  
-from django.db.backends.postgresql.operations import DatabaseOperations
16  
-from django.db.backends.postgresql.version import get_version
17  
-from django.utils.encoding import smart_str, smart_unicode
18  
-
19  
-try:
20  
-    import psycopg as Database
21  
-except ImportError, e:
22  
-    from django.core.exceptions import ImproperlyConfigured
23  
-    raise ImproperlyConfigured("Error loading psycopg module: %s" % e)
24  
-
25  
-DatabaseError = Database.DatabaseError
26  
-IntegrityError = Database.IntegrityError
27  
-
28  
-class UnicodeCursorWrapper(object):
29  
-    """
30  
-    A thin wrapper around psycopg cursors that allows them to accept Unicode
31  
-    strings as params.
32  
-
33  
-    This is necessary because psycopg doesn't apply any DB quoting to
34  
-    parameters that are Unicode strings. If a param is Unicode, this will
35  
-    convert it to a bytestring using database client's encoding before passing
36  
-    it to psycopg.
37  
-
38  
-    All results retrieved from the database are converted into Unicode strings
39  
-    before being returned to the caller.
40  
-    """
41  
-    def __init__(self, cursor, charset):
42  
-        self.cursor = cursor
43  
-        self.charset = charset
44  
-
45  
-    def format_params(self, params):
46  
-        if isinstance(params, dict):
47  
-            result = {}
48  
-            charset = self.charset
49  
-            for key, value in params.items():
50  
-                result[smart_str(key, charset)] = smart_str(value, charset)
51  
-            return result
52  
-        else:
53  
-            return tuple([smart_str(p, self.charset, True) for p in params])
54  
-
55  
-    def execute(self, sql, params=()):
56  
-        try:
57  
-            return self.cursor.execute(smart_str(sql, self.charset), self.format_params(params))
58  
-        except Database.IntegrityError, e:
59  
-            raise utils.IntegrityError, utils.IntegrityError(*tuple(e)), sys.exc_info()[2]
60  
-        except Database.DatabaseError, e:
61  
-            raise utils.DatabaseError, utils.DatabaseError(*tuple(e)), sys.exc_info()[2]
62  
-
63  
-    def executemany(self, sql, param_list):
64  
-        try:
65  
-            new_param_list = [self.format_params(params) for params in param_list]
66  
-            return self.cursor.executemany(sql, new_param_list)
67  
-        except Database.IntegrityError, e:
68  
-            raise utils.IntegrityError, utils.IntegrityError(*tuple(e)), sys.exc_info()[2]
69  
-        except Database.DatabaseError, e:
70  
-            raise utils.DatabaseError, utils.DatabaseError(*tuple(e)), sys.exc_info()[2]
71  
-
72  
-    def __getattr__(self, attr):
73  
-        if attr in self.__dict__:
74  
-            return self.__dict__[attr]
75  
-        else:
76  
-            return getattr(self.cursor, attr)
77  
-
78  
-    def __iter__(self):
79  
-        return iter(self.cursor.fetchall())
80  
-
81  
-class DatabaseFeatures(BaseDatabaseFeatures):
82  
-    uses_savepoints = True
83  
-    requires_rollback_on_dirty_transaction = True
84  
-    has_real_datatype = True
85  
-    can_defer_constraint_checks = True
86  
-
87  
-class DatabaseWrapper(BaseDatabaseWrapper):
88  
-    vendor = 'postgresql'
89  
-    operators = {
90  
-        'exact': '= %s',
91  
-        'iexact': '= UPPER(%s)',
92  
-        'contains': 'LIKE %s',
93  
-        'icontains': 'LIKE UPPER(%s)',
94  
-        'regex': '~ %s',
95  
-        'iregex': '~* %s',
96  
-        'gt': '> %s',
97  
-        'gte': '>= %s',
98  
-        'lt': '< %s',
99  
-        'lte': '<= %s',
100  
-        'startswith': 'LIKE %s',
101  
-        'endswith': 'LIKE %s',
102  
-        'istartswith': 'LIKE UPPER(%s)',
103  
-        'iendswith': 'LIKE UPPER(%s)',
104  
-    }
105  
-
106  
-    def __init__(self, *args, **kwargs):
107  
-        super(DatabaseWrapper, self).__init__(*args, **kwargs)
108  
-
109  
-        import warnings
110  
-        warnings.warn(
111  
-            'The "postgresql" backend has been deprecated. Use "postgresql_psycopg2" instead.',
112  
-            DeprecationWarning
113  
-        )
114  
-
115  
-        self.features = DatabaseFeatures(self)
116  
-        self.ops = DatabaseOperations(self)
117  
-        self.client = DatabaseClient(self)
118  
-        self.creation = DatabaseCreation(self)
119  
-        self.introspection = DatabaseIntrospection(self)
120  
-        self.validation = BaseDatabaseValidation(self)
121  
-
122  
-    def _cursor(self):
123  
-        new_connection = False
124  
-        set_tz = False
125  
-        settings_dict = self.settings_dict
126  
-        if self.connection is None:
127  
-            new_connection = True
128  
-            set_tz = settings_dict.get('TIME_ZONE')
129  
-            if settings_dict['NAME'] == '':
130  
-                from django.core.exceptions import ImproperlyConfigured
131  
-                raise ImproperlyConfigured("You need to specify NAME in your Django settings file.")
132  
-            conn_string = "dbname=%s" % settings_dict['NAME']
133  
-            if settings_dict['USER']:
134  
-                conn_string = "user=%s %s" % (settings_dict['USER'], conn_string)
135  
-            if settings_dict['PASSWORD']:
136  
-                conn_string += " password='%s'" % settings_dict['PASSWORD']
137  
-            if settings_dict['HOST']:
138  
-                conn_string += " host=%s" % settings_dict['HOST']
139  
-            if settings_dict['PORT']:
140  
-                conn_string += " port=%s" % settings_dict['PORT']
141  
-            self.connection = Database.connect(conn_string, **settings_dict['OPTIONS'])
142  
-            # make transactions transparent to all cursors
143  
-            self.connection.set_isolation_level(1)
144  
-            connection_created.send(sender=self.__class__, connection=self)
145  
-        cursor = self.connection.cursor()
146  
-        if new_connection:
147  
-            if set_tz:
148  
-                cursor.execute("SET TIME ZONE %s", [settings_dict['TIME_ZONE']])
149  
-            if not hasattr(self, '_version'):
150  
-                self.__class__._version = get_version(cursor)
151  
-            if self._version[0:2] < (8, 0):
152  
-                # No savepoint support for earlier version of PostgreSQL.
153  
-                self.features.uses_savepoints = False
154  
-            cursor.execute("SET client_encoding to 'UNICODE'")
155  
-        return UnicodeCursorWrapper(cursor, 'utf-8')
156  
-
157  
-    def _commit(self):
158  
-        if self.connection is not None:
159  
-            try:
160  
-                return self.connection.commit()
161  
-            except Database.IntegrityError, e:
162  
-                raise utils.IntegrityError, utils.IntegrityError(*tuple(e)), sys.exc_info()[2]
163  
-
164  
-def typecast_string(s):
165  
-    """
166  
-    Cast all returned strings to unicode strings.
167  
-    """
168  
-    if not s and not isinstance(s, str):
169  
-        return s
170  
-    return smart_unicode(s)
171  
-
172  
-# Register these custom typecasts, because Django expects dates/times to be
173  
-# in Python's native (standard-library) datetime/time format, whereas psycopg
174  
-# use mx.DateTime by default.
175  
-try:
176  
-    Database.register_type(Database.new_type((1082,), "DATE", util.typecast_date))
177  
-except AttributeError:
178  
-    raise Exception("You appear to be using psycopg version 2. Set your DATABASES.ENGINE to 'postgresql_psycopg2' instead of 'postgresql'.")
179  
-Database.register_type(Database.new_type((1083,1266), "TIME", util.typecast_time))
180  
-Database.register_type(Database.new_type((1114,1184), "TIMESTAMP", util.typecast_timestamp))
181  
-Database.register_type(Database.new_type((16,), "BOOLEAN", util.typecast_boolean))
182  
-Database.register_type(Database.new_type((1700,), "NUMERIC", util.typecast_decimal))
183  
-Database.register_type(Database.new_type(Database.types[1043].values, 'STRING', typecast_string))
88  django/db/backends/postgresql/introspection.py
... ...
@@ -1,88 +0,0 @@
1  
-from django.db.backends import BaseDatabaseIntrospection
2  
-
3  
-class DatabaseIntrospection(BaseDatabaseIntrospection):
4  
-    # Maps type codes to Django Field types.
5  
-    data_types_reverse = {
6  
-        16: 'BooleanField',
7  
-        20: 'BigIntegerField',
8  
-        21: 'SmallIntegerField',
9  
-        23: 'IntegerField',
10  
-        25: 'TextField',
11  
-        700: 'FloatField',
12  
-        701: 'FloatField',
13  
-        869: 'IPAddressField',
14  
-        1043: 'CharField',
15  
-        1082: 'DateField',
16  
-        1083: 'TimeField',
17  
-        1114: 'DateTimeField',
18  
-        1184: 'DateTimeField',
19  
-        1266: 'TimeField',
20  
-        1700: 'DecimalField',
21  
-    }
22  
-        
23  
-    def get_table_list(self, cursor):
24  
-        "Returns a list of table names in the current database."
25  
-        cursor.execute("""
26  
-            SELECT c.relname
27  
-            FROM pg_catalog.pg_class c
28  
-            LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace
29  
-            WHERE c.relkind IN ('r', 'v', '')
30  
-                AND n.nspname NOT IN ('pg_catalog', 'pg_toast')
31  
-                AND pg_catalog.pg_table_is_visible(c.oid)""")
32  
-        return [row[0] for row in cursor.fetchall()]
33  
-
34  
-    def get_table_description(self, cursor, table_name):
35  
-        "Returns a description of the table, with the DB-API cursor.description interface."
36  
-        cursor.execute("SELECT * FROM %s LIMIT 1" % self.connection.ops.quote_name(table_name))
37  
-        return cursor.description
38  
-
39  
-    def get_relations(self, cursor, table_name):
40  
-        """
41  
-        Returns a dictionary of {field_index: (field_index_other_table, other_table)}
42  
-        representing all relationships to the given table. Indexes are 0-based.
43  
-        """
44  
-        cursor.execute("""
45  
-            SELECT con.conkey, con.confkey, c2.relname
46  
-            FROM pg_constraint con, pg_class c1, pg_class c2
47  
-            WHERE c1.oid = con.conrelid
48  
-                AND c2.oid = con.confrelid
49  
-                AND c1.relname = %s
50  
-                AND con.contype = 'f'""", [table_name])
51  
-        relations = {}
52  
-        for row in cursor.fetchall():
53  
-            try:
54  
-                # row[0] and row[1] are like "{2}", so strip the curly braces.
55  
-                relations[int(row[0][1:-1]) - 1] = (int(row[1][1:-1]) - 1, row[2])
56  
-            except ValueError:
57  
-                continue
58  
-        return relations
59  
-
60  
-    def get_indexes(self, cursor, table_name):
61  
-        """
62  
-        Returns a dictionary of fieldname -> infodict for the given table,
63  
-        where each infodict is in the format:
64  
-            {'primary_key': boolean representing whether it's the primary key,
65  
-             'unique': boolean representing whether it's a unique index}
66  
-        """
67  
-        # This query retrieves each index on the given table, including the
68  
-        # first associated field name
69  
-        cursor.execute("""
70  
-            SELECT attr.attname, idx.indkey, idx.indisunique, idx.indisprimary
71  
-            FROM pg_catalog.pg_class c, pg_catalog.pg_class c2,
72  
-                pg_catalog.pg_index idx, pg_catalog.pg_attribute attr
73  
-            WHERE c.oid = idx.indrelid
74  
-                AND idx.indexrelid = c2.oid
75  
-                AND attr.attrelid = c.oid
76  
-                AND attr.attnum = idx.indkey[0]
77  
-                AND c.relname = %s""", [table_name])
78  
-        indexes = {}
79  
-        for row in cursor.fetchall():
80  
-            # row[1] (idx.indkey) is stored in the DB as an array. It comes out as
81  
-            # a string of space-separated integers. This designates the field
82  
-            # indexes (1-based) of the fields that have indexes on the table.
83  
-            # Here, we skip any indexes across multiple fields.
84  
-            if ' ' in row[1]:
85  
-                continue
86  
-            indexes[row[0]] = {'primary_key': row[3], 'unique': row[2]}
87  
-        return indexes
88  
-
18  django/db/backends/postgresql_psycopg2/base.py
@@ -9,10 +9,10 @@
9 9
 from django.db import utils
10 10
 from django.db.backends import *
11 11
 from django.db.backends.signals import connection_created
12  
-from django.db.backends.postgresql.operations import DatabaseOperations as PostgresqlDatabaseOperations
13  
-from django.db.backends.postgresql.client import DatabaseClient
14  
-from django.db.backends.postgresql.creation import DatabaseCreation
15  
-from django.db.backends.postgresql.version import get_version
  12
+from django.db.backends.postgresql_psycopg2.operations import DatabaseOperations
  13
+from django.db.backends.postgresql_psycopg2.client import DatabaseClient
  14
+from django.db.backends.postgresql_psycopg2.creation import DatabaseCreation
  15
+from django.db.backends.postgresql_psycopg2.version import get_version
16 16
 from django.db.backends.postgresql_psycopg2.introspection import DatabaseIntrospection
17 17
 from django.utils.safestring import SafeUnicode, SafeString
18 18
 
@@ -71,16 +71,6 @@ class DatabaseFeatures(BaseDatabaseFeatures):
71 71
     has_real_datatype = True
72 72
     can_defer_constraint_checks = True
73 73
 
74  
-class DatabaseOperations(PostgresqlDatabaseOperations):
75  
-    def last_executed_query(self, cursor, sql, params):
76  
-        # With psycopg2, cursor objects have a "query" attribute that is the
77  
-        # exact query sent to the database. See docs here:
78  
-        # http://www.initd.org/tracker/psycopg/wiki/psycopg2_documentation#postgresql-status-message-and-executed-query
79  
-        return cursor.query
80  
-
81  
-    def return_insert_id(self):
82  
-        return "RETURNING %s", ()
83  
-
84 74
 class DatabaseWrapper(BaseDatabaseWrapper):
85 75
     vendor = 'postgresql'
86 76
     operators = {
0  django/db/backends/postgresql/client.py → django/db/backends/postgresql_psycopg2/client.py
File renamed without changes
1  django/db/backends/postgresql/creation.py → django/db/backends/postgresql_psycopg2/creation.py
... ...
@@ -1,6 +1,7 @@
1 1
 from django.db.backends.creation import BaseDatabaseCreation
2 2
 from django.db.backends.util import truncate_name
3 3
 
  4
+
4 5
 class DatabaseCreation(BaseDatabaseCreation):
5 6
     # This dictionary maps Field objects to their associated PostgreSQL column
6 7
     # types, as strings. Column-type strings can contain format strings; they'll
68  django/db/backends/postgresql_psycopg2/introspection.py
... ...
@@ -1,6 +1,41 @@
1  
-from django.db.backends.postgresql.introspection import DatabaseIntrospection as PostgresDatabaseIntrospection
  1
+from django.db.backends import BaseDatabaseIntrospection
2 2
 
3  
-class DatabaseIntrospection(PostgresDatabaseIntrospection):
  3
+
  4
+class DatabaseIntrospection(BaseDatabaseIntrospection):
  5
+    # Maps type codes to Django Field types.
  6
+    data_types_reverse = {
  7
+        16: 'BooleanField',
  8
+        20: 'BigIntegerField',
  9
+        21: 'SmallIntegerField',
  10
+        23: 'IntegerField',
  11
+        25: 'TextField',
  12
+        700: 'FloatField',
  13
+        701: 'FloatField',
  14
+        869: 'IPAddressField',
  15
+        1043: 'CharField',
  16
+        1082: 'DateField',
  17
+        1083: 'TimeField',
  18
+        1114: 'DateTimeField',
  19
+        1184: 'DateTimeField',
  20
+        1266: 'TimeField',
  21
+        1700: 'DecimalField',
  22
+    }
  23
+        
  24
+    def get_table_list(self, cursor):
  25
+        "Returns a list of table names in the current database."
  26
+        cursor.execute("""
  27
+            SELECT c.relname
  28
+            FROM pg_catalog.pg_class c
  29
+            LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace
  30
+            WHERE c.relkind IN ('r', 'v', '')
  31
+                AND n.nspname NOT IN ('pg_catalog', 'pg_toast')
  32
+                AND pg_catalog.pg_table_is_visible(c.oid)""")
  33
+        return [row[0] for row in cursor.fetchall()]
  34
+
  35
+    def get_table_description(self, cursor, table_name):
  36
+        "Returns a description of the table, with the DB-API cursor.description interface."
  37
+        cursor.execute("SELECT * FROM %s LIMIT 1" % self.connection.ops.quote_name(table_name))
  38
+        return cursor.description
4 39
 
5 40
     def get_relations(self, cursor, table_name):
6 41
         """
@@ -19,3 +54,32 @@ def get_relations(self, cursor, table_name):
19 54
             # row[0] and row[1] are single-item lists, so grab the single item.
20 55
             relations[row[0][0] - 1] = (row[1][0] - 1, row[2])
21 56
         return relations
  57
+
  58
+    def get_indexes(self, cursor, table_name):
  59
+        """
  60
+        Returns a dictionary of fieldname -> infodict for the given table,
  61
+        where each infodict is in the format:
  62
+            {'primary_key': boolean representing whether it's the primary key,
  63
+             'unique': boolean representing whether it's a unique index}
  64
+        """
  65
+        # This query retrieves each index on the given table, including the
  66
+        # first associated field name
  67
+        cursor.execute("""
  68
+            SELECT attr.attname, idx.indkey, idx.indisunique, idx.indisprimary
  69
+            FROM pg_catalog.pg_class c, pg_catalog.pg_class c2,
  70
+                pg_catalog.pg_index idx, pg_catalog.pg_attribute attr
  71
+            WHERE c.oid = idx.indrelid
  72
+                AND idx.indexrelid = c2.oid
  73
+                AND attr.attrelid = c.oid
  74
+                AND attr.attnum = idx.indkey[0]
  75
+                AND c.relname = %s""", [table_name])
  76
+        indexes = {}
  77
+        for row in cursor.fetchall():
  78
+            # row[1] (idx.indkey) is stored in the DB as an array. It comes out as
  79
+            # a string of space-separated integers. This designates the field
  80
+            # indexes (1-based) of the fields that have indexes on the table.
  81
+            # Here, we skip any indexes across multiple fields.
  82
+            if ' ' in row[1]:
  83
+                continue
  84
+            indexes[row[0]] = {'primary_key': row[3], 'unique': row[2]}
  85
+        return indexes
13  django/db/backends/postgresql/operations.py → django/db/backends/postgresql_psycopg2/operations.py
@@ -2,8 +2,6 @@
2 2
 
3 3
 from django.db.backends import BaseDatabaseOperations
4 4
 
5  
-# This DatabaseOperations class lives in here instead of base.py because it's
6  
-# used by both the 'postgresql' and 'postgresql_psycopg2' backends.
7 5
 
8 6
 class DatabaseOperations(BaseDatabaseOperations):
9 7
     def __init__(self, connection):
@@ -13,7 +11,7 @@ def __init__(self, connection):
13 11
 
14 12
     def _get_postgres_version(self):
15 13
         if self._postgres_version is None:
16  
-            from django.db.backends.postgresql.version import get_version
  14
+            from django.db.backends.postgresql_psycopg2.version import get_version
17 15
             cursor = self.connection.cursor()
18 16
             self._postgres_version = get_version(cursor)
19 17
         return self._postgres_version
@@ -203,3 +201,12 @@ def max_name_length(self):
203 201
         """
204 202
 
205 203
         return 63
  204
+
  205
+    def last_executed_query(self, cursor, sql, params):
  206
+        # With psycopg2, cursor objects have a "query" attribute that is the
  207
+        # exact query sent to the database. See docs here:
  208
+        # http://www.initd.org/tracker/psycopg/wiki/psycopg2_documentation#postgresql-status-message-and-executed-query
  209
+        return cursor.query
  210
+
  211
+    def return_insert_id(self):
  212
+        return "RETURNING %s", ()
1  django/db/backends/postgresql/version.py → django/db/backends/postgresql_psycopg2/version.py
@@ -12,6 +12,7 @@
12 12
 #   PostgreSQL 8.4beta1
13 13
 VERSION_RE = re.compile(r'\S+ (\d+)\.(\d+)\.?(\d+)?')
14 14
 
  15
+
15 16
 def _parse_version(text):
16 17
     "Internal parsing method. Factored out for testing purposes."
17 18
     major, major2, minor = VERSION_RE.search(text).groups()

0 notes on commit 8911754

Please sign in to comment.
Something went wrong with that request. Please try again.