Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

Moved postgresql backend DatabaseOperations class into a new module, …

…postgresql/operations.py, so that it can be imported by both the postgresql and postgresql_psycopg2 backends. Hence the two backends no longer have a duplicated DatabaseOperations class

git-svn-id: http://code.djangoproject.com/svn/django/trunk@5972 bcc190cf-cafb-0310-a4f2-bffc1f526a37
  • Loading branch information...
commit f4b397087cd0261ce1f8c35c2014e1121f5f0f5f 1 parent c2c3e93
Adrian Holovaty authored August 20, 2007
112  django/db/backends/postgresql/base.py
@@ -5,7 +5,8 @@
5 5
 """
6 6
 
7 7
 from django.utils.encoding import smart_str, smart_unicode
8  
-from django.db.backends import BaseDatabaseWrapper, BaseDatabaseOperations, util
  8
+from django.db.backends import BaseDatabaseWrapper, util
  9
+from django.db.backends.postgresql.operations import DatabaseOperations
9 10
 try:
10 11
     import psycopg as Database
11 12
 except ImportError, e:
@@ -55,110 +56,6 @@ def __getattr__(self, attr):
55 56
         else:
56 57
             return getattr(self.cursor, attr)
57 58
 
58  
-postgres_version = None
59  
-
60  
-class DatabaseOperations(BaseDatabaseOperations):
61  
-    def date_extract_sql(self, lookup_type, field_name):
62  
-        # http://www.postgresql.org/docs/8.0/static/functions-datetime.html#FUNCTIONS-DATETIME-EXTRACT
63  
-        return "EXTRACT('%s' FROM %s)" % (lookup_type, field_name)
64  
-
65  
-    def date_trunc_sql(self, lookup_type, field_name):
66  
-        # http://www.postgresql.org/docs/8.0/static/functions-datetime.html#FUNCTIONS-DATETIME-TRUNC
67  
-        return "DATE_TRUNC('%s', %s)" % (lookup_type, field_name)
68  
-
69  
-    def deferrable_sql(self):
70  
-        return " DEFERRABLE INITIALLY DEFERRED"
71  
-
72  
-    def last_insert_id(self, cursor, table_name, pk_name):
73  
-        cursor.execute("SELECT CURRVAL('\"%s_%s_seq\"')" % (table_name, pk_name))
74  
-        return cursor.fetchone()[0]
75  
-
76  
-    def quote_name(self, name):
77  
-        if name.startswith('"') and name.endswith('"'):
78  
-            return name # Quoting once is enough.
79  
-        return '"%s"' % name
80  
-
81  
-    def sql_flush(self, style, tables, sequences):
82  
-        if tables:
83  
-            if postgres_version[0] >= 8 and postgres_version[1] >= 1:
84  
-                # Postgres 8.1+ can do 'TRUNCATE x, y, z...;'. In fact, it *has to*
85  
-                # in order to be able to truncate tables referenced by a foreign
86  
-                # key in any other table. The result is a single SQL TRUNCATE
87  
-                # statement.
88  
-                sql = ['%s %s;' % \
89  
-                    (style.SQL_KEYWORD('TRUNCATE'),
90  
-                     style.SQL_FIELD(', '.join([self.quote_name(table) for table in tables]))
91  
-                )]
92  
-            else:
93  
-                # Older versions of Postgres can't do TRUNCATE in a single call, so
94  
-                # they must use a simple delete.
95  
-                sql = ['%s %s %s;' % \
96  
-                        (style.SQL_KEYWORD('DELETE'),
97  
-                         style.SQL_KEYWORD('FROM'),
98  
-                         style.SQL_FIELD(self.quote_name(table))
99  
-                         ) for table in tables]
100  
-
101  
-            # 'ALTER SEQUENCE sequence_name RESTART WITH 1;'... style SQL statements
102  
-            # to reset sequence indices
103  
-            for sequence_info in sequences:
104  
-                table_name = sequence_info['table']
105  
-                column_name = sequence_info['column']
106  
-                if column_name and len(column_name)>0:
107  
-                    # sequence name in this case will be <table>_<column>_seq
108  
-                    sql.append("%s %s %s %s %s %s;" % \
109  
-                        (style.SQL_KEYWORD('ALTER'),
110  
-                        style.SQL_KEYWORD('SEQUENCE'),
111  
-                        style.SQL_FIELD(self.quote_name('%s_%s_seq' % (table_name, column_name))),
112  
-                        style.SQL_KEYWORD('RESTART'),
113  
-                        style.SQL_KEYWORD('WITH'),
114  
-                        style.SQL_FIELD('1')
115  
-                        )
116  
-                    )
117  
-                else:
118  
-                    # sequence name in this case will be <table>_id_seq
119  
-                    sql.append("%s %s %s %s %s %s;" % \
120  
-                        (style.SQL_KEYWORD('ALTER'),
121  
-                         style.SQL_KEYWORD('SEQUENCE'),
122  
-                         style.SQL_FIELD(self.quote_name('%s_id_seq' % table_name)),
123  
-                         style.SQL_KEYWORD('RESTART'),
124  
-                         style.SQL_KEYWORD('WITH'),
125  
-                         style.SQL_FIELD('1')
126  
-                         )
127  
-                    )
128  
-            return sql
129  
-        else:
130  
-            return []
131  
-
132  
-    def sequence_reset_sql(self, style, model_list):
133  
-        from django.db import models
134  
-        output = []
135  
-        qn = self.quote_name
136  
-        for model in model_list:
137  
-            # Use `coalesce` to set the sequence for each model to the max pk value if there are records,
138  
-            # or 1 if there are none. Set the `is_called` property (the third argument to `setval`) to true
139  
-            # if there are records (as the max pk value is already in use), otherwise set it to false.
140  
-            for f in model._meta.fields:
141  
-                if isinstance(f, models.AutoField):
142  
-                    output.append("%s setval('%s', coalesce(max(%s), 1), max(%s) %s null) %s %s;" % \
143  
-                        (style.SQL_KEYWORD('SELECT'),
144  
-                        style.SQL_FIELD(qn('%s_%s_seq' % (model._meta.db_table, f.column))),
145  
-                        style.SQL_FIELD(qn(f.column)),
146  
-                        style.SQL_FIELD(qn(f.column)),
147  
-                        style.SQL_KEYWORD('IS NOT'),
148  
-                        style.SQL_KEYWORD('FROM'),
149  
-                        style.SQL_TABLE(qn(model._meta.db_table))))
150  
-                    break # Only one AutoField is allowed per model, so don't bother continuing.
151  
-            for f in model._meta.many_to_many:
152  
-                output.append("%s setval('%s', coalesce(max(%s), 1), max(%s) %s null) %s %s;" % \
153  
-                    (style.SQL_KEYWORD('SELECT'),
154  
-                    style.SQL_FIELD(qn('%s_id_seq' % f.m2m_db_table())),
155  
-                    style.SQL_FIELD(qn('id')),
156  
-                    style.SQL_FIELD(qn('id')),
157  
-                    style.SQL_KEYWORD('IS NOT'),
158  
-                    style.SQL_KEYWORD('FROM'),
159  
-                    style.SQL_TABLE(f.m2m_db_table())))
160  
-        return output
161  
-
162 59
 class DatabaseWrapper(BaseDatabaseWrapper):
163 60
     ops = DatabaseOperations()
164 61
 
@@ -185,10 +82,9 @@ def _cursor(self, settings):
185 82
             cursor.execute("SET TIME ZONE %s", [settings.TIME_ZONE])
186 83
         cursor.execute("SET client_encoding to 'UNICODE'")
187 84
         cursor = UnicodeCursorWrapper(cursor, 'utf-8')
188  
-        global postgres_version
189  
-        if not postgres_version:
  85
+        if self.ops.postgres_version is None:
190 86
             cursor.execute("SELECT version()")
191  
-            postgres_version = [int(val) for val in cursor.fetchone()[0].split()[1].split('.')]
  87
+            self.ops.postgres_version = [int(val) for val in cursor.fetchone()[0].split()[1].split('.')]
192 88
         return cursor
193 89
 
194 90
 allows_group_by_ordinal = True
109  django/db/backends/postgresql/operations.py
... ...
@@ -0,0 +1,109 @@
  1
+from django.db.backends import BaseDatabaseOperations
  2
+
  3
+# This DatabaseOperations class lives in here instead of base.py because it's
  4
+# used by both the 'postgresql' and 'postgresql_psycopg2' backends.
  5
+
  6
+class DatabaseOperations(BaseDatabaseOperations):
  7
+    def __init__(self, postgres_version=None):
  8
+        self.postgres_version = postgres_version
  9
+
  10
+    def date_extract_sql(self, lookup_type, field_name):
  11
+        # http://www.postgresql.org/docs/8.0/static/functions-datetime.html#FUNCTIONS-DATETIME-EXTRACT
  12
+        return "EXTRACT('%s' FROM %s)" % (lookup_type, field_name)
  13
+
  14
+    def date_trunc_sql(self, lookup_type, field_name):
  15
+        # http://www.postgresql.org/docs/8.0/static/functions-datetime.html#FUNCTIONS-DATETIME-TRUNC
  16
+        return "DATE_TRUNC('%s', %s)" % (lookup_type, field_name)
  17
+
  18
+    def deferrable_sql(self):
  19
+        return " DEFERRABLE INITIALLY DEFERRED"
  20
+
  21
+    def last_insert_id(self, cursor, table_name, pk_name):
  22
+        cursor.execute("SELECT CURRVAL('\"%s_%s_seq\"')" % (table_name, pk_name))
  23
+        return cursor.fetchone()[0]
  24
+
  25
+    def quote_name(self, name):
  26
+        if name.startswith('"') and name.endswith('"'):
  27
+            return name # Quoting once is enough.
  28
+        return '"%s"' % name
  29
+
  30
+    def sql_flush(self, style, tables, sequences):
  31
+        if tables:
  32
+            if self.postgres_version[0] >= 8 and self.postgres_version[1] >= 1:
  33
+                # Postgres 8.1+ can do 'TRUNCATE x, y, z...;'. In fact, it *has to*
  34
+                # in order to be able to truncate tables referenced by a foreign
  35
+                # key in any other table. The result is a single SQL TRUNCATE
  36
+                # statement.
  37
+                sql = ['%s %s;' % \
  38
+                    (style.SQL_KEYWORD('TRUNCATE'),
  39
+                     style.SQL_FIELD(', '.join([self.quote_name(table) for table in tables]))
  40
+                )]
  41
+            else:
  42
+                # Older versions of Postgres can't do TRUNCATE in a single call, so
  43
+                # they must use a simple delete.
  44
+                sql = ['%s %s %s;' % \
  45
+                        (style.SQL_KEYWORD('DELETE'),
  46
+                         style.SQL_KEYWORD('FROM'),
  47
+                         style.SQL_FIELD(self.quote_name(table))
  48
+                         ) for table in tables]
  49
+
  50
+            # 'ALTER SEQUENCE sequence_name RESTART WITH 1;'... style SQL statements
  51
+            # to reset sequence indices
  52
+            for sequence_info in sequences:
  53
+                table_name = sequence_info['table']
  54
+                column_name = sequence_info['column']
  55
+                if column_name and len(column_name)>0:
  56
+                    # sequence name in this case will be <table>_<column>_seq
  57
+                    sql.append("%s %s %s %s %s %s;" % \
  58
+                        (style.SQL_KEYWORD('ALTER'),
  59
+                        style.SQL_KEYWORD('SEQUENCE'),
  60
+                        style.SQL_FIELD(self.quote_name('%s_%s_seq' % (table_name, column_name))),
  61
+                        style.SQL_KEYWORD('RESTART'),
  62
+                        style.SQL_KEYWORD('WITH'),
  63
+                        style.SQL_FIELD('1')
  64
+                        )
  65
+                    )
  66
+                else:
  67
+                    # sequence name in this case will be <table>_id_seq
  68
+                    sql.append("%s %s %s %s %s %s;" % \
  69
+                        (style.SQL_KEYWORD('ALTER'),
  70
+                         style.SQL_KEYWORD('SEQUENCE'),
  71
+                         style.SQL_FIELD(self.quote_name('%s_id_seq' % table_name)),
  72
+                         style.SQL_KEYWORD('RESTART'),
  73
+                         style.SQL_KEYWORD('WITH'),
  74
+                         style.SQL_FIELD('1')
  75
+                         )
  76
+                    )
  77
+            return sql
  78
+        else:
  79
+            return []
  80
+
  81
+    def sequence_reset_sql(self, style, model_list):
  82
+        from django.db import models
  83
+        output = []
  84
+        qn = self.quote_name
  85
+        for model in model_list:
  86
+            # Use `coalesce` to set the sequence for each model to the max pk value if there are records,
  87
+            # or 1 if there are none. Set the `is_called` property (the third argument to `setval`) to true
  88
+            # if there are records (as the max pk value is already in use), otherwise set it to false.
  89
+            for f in model._meta.fields:
  90
+                if isinstance(f, models.AutoField):
  91
+                    output.append("%s setval('%s', coalesce(max(%s), 1), max(%s) %s null) %s %s;" % \
  92
+                        (style.SQL_KEYWORD('SELECT'),
  93
+                        style.SQL_FIELD(qn('%s_%s_seq' % (model._meta.db_table, f.column))),
  94
+                        style.SQL_FIELD(qn(f.column)),
  95
+                        style.SQL_FIELD(qn(f.column)),
  96
+                        style.SQL_KEYWORD('IS NOT'),
  97
+                        style.SQL_KEYWORD('FROM'),
  98
+                        style.SQL_TABLE(qn(model._meta.db_table))))
  99
+                    break # Only one AutoField is allowed per model, so don't bother continuing.
  100
+            for f in model._meta.many_to_many:
  101
+                output.append("%s setval('%s', coalesce(max(%s), 1), max(%s) %s null) %s %s;" % \
  102
+                    (style.SQL_KEYWORD('SELECT'),
  103
+                    style.SQL_FIELD(qn('%s_id_seq' % f.m2m_db_table())),
  104
+                    style.SQL_FIELD(qn('id')),
  105
+                    style.SQL_FIELD(qn('id')),
  106
+                    style.SQL_KEYWORD('IS NOT'),
  107
+                    style.SQL_KEYWORD('FROM'),
  108
+                    style.SQL_TABLE(f.m2m_db_table())))
  109
+        return output
113  django/db/backends/postgresql_psycopg2/base.py
@@ -4,7 +4,8 @@
4 4
 Requires psycopg 2: http://initd.org/projects/psycopg2
5 5
 """
6 6
 
7  
-from django.db.backends import BaseDatabaseWrapper, BaseDatabaseOperations, util
  7
+from django.db.backends import BaseDatabaseWrapper, util
  8
+from django.db.backends.postgresql.operations import DatabaseOperations
8 9
 try:
9 10
     import psycopg2 as Database
10 11
     import psycopg2.extensions
@@ -17,111 +18,6 @@
17 18
 
18 19
 psycopg2.extensions.register_type(psycopg2.extensions.UNICODE)
19 20
 
20  
-postgres_version = None
21  
-
22  
-class DatabaseOperations(BaseDatabaseOperations):
23  
-    def date_extract_sql(self, lookup_type, field_name):
24  
-        # http://www.postgresql.org/docs/8.0/static/functions-datetime.html#FUNCTIONS-DATETIME-EXTRACT
25  
-        return "EXTRACT('%s' FROM %s)" % (lookup_type, field_name)
26  
-
27  
-    def date_trunc_sql(self, lookup_type, field_name):
28  
-        # http://www.postgresql.org/docs/8.0/static/functions-datetime.html#FUNCTIONS-DATETIME-TRUNC
29  
-        return "DATE_TRUNC('%s', %s)" % (lookup_type, field_name)
30  
-
31  
-    def deferrable_sql(self):
32  
-        return " DEFERRABLE INITIALLY DEFERRED"
33  
-
34  
-    def last_insert_id(self, cursor, table_name, pk_name):
35  
-        cursor.execute("SELECT CURRVAL('\"%s_%s_seq\"')" % (table_name, pk_name))
36  
-        return cursor.fetchone()[0]
37  
-
38  
-    def quote_name(self, name):
39  
-        if name.startswith('"') and name.endswith('"'):
40  
-            return name # Quoting once is enough.
41  
-        return '"%s"' % name
42  
-
43  
-    def sql_flush(self, style, tables, sequences):
44  
-        qn = self.quote_name
45  
-        if tables:
46  
-            if postgres_version[0] >= 8 and postgres_version[1] >= 1:
47  
-                # Postgres 8.1+ can do 'TRUNCATE x, y, z...;'. In fact, it *has to*
48  
-                # in order to be able to truncate tables referenced by a foreign
49  
-                # key in any other table. The result is a single SQL TRUNCATE
50  
-                # statement.
51  
-                sql = ['%s %s;' % \
52  
-                    (style.SQL_KEYWORD('TRUNCATE'),
53  
-                     style.SQL_FIELD(', '.join([qn(table) for table in tables]))
54  
-                )]
55  
-            else:
56  
-                # Older versions of Postgres can't do TRUNCATE in a single call, so
57  
-                # they must use a simple delete.
58  
-                sql = ['%s %s %s;' % \
59  
-                        (style.SQL_KEYWORD('DELETE'),
60  
-                         style.SQL_KEYWORD('FROM'),
61  
-                         style.SQL_FIELD(qn(table))
62  
-                         ) for table in tables]
63  
-
64  
-            # 'ALTER SEQUENCE sequence_name RESTART WITH 1;'... style SQL statements
65  
-            # to reset sequence indices
66  
-            for sequence_info in sequences:
67  
-                table_name = sequence_info['table']
68  
-                column_name = sequence_info['column']
69  
-                if column_name and len(column_name)>0:
70  
-                    # sequence name in this case will be <table>_<column>_seq
71  
-                    sql.append("%s %s %s %s %s %s;" % \
72  
-                        (style.SQL_KEYWORD('ALTER'),
73  
-                        style.SQL_KEYWORD('SEQUENCE'),
74  
-                        style.SQL_FIELD(qn('%s_%s_seq' % (table_name, column_name))),
75  
-                        style.SQL_KEYWORD('RESTART'),
76  
-                        style.SQL_KEYWORD('WITH'),
77  
-                        style.SQL_FIELD('1')
78  
-                        )
79  
-                    )
80  
-                else:
81  
-                    # sequence name in this case will be <table>_id_seq
82  
-                    sql.append("%s %s %s %s %s %s;" % \
83  
-                        (style.SQL_KEYWORD('ALTER'),
84  
-                         style.SQL_KEYWORD('SEQUENCE'),
85  
-                         style.SQL_FIELD(qn('%s_id_seq' % table_name)),
86  
-                         style.SQL_KEYWORD('RESTART'),
87  
-                         style.SQL_KEYWORD('WITH'),
88  
-                         style.SQL_FIELD('1')
89  
-                         )
90  
-                    )
91  
-            return sql
92  
-        else:
93  
-            return []
94  
-
95  
-    def sequence_reset_sql(self, style, model_list):
96  
-        from django.db import models
97  
-        qn = self.quote_name
98  
-        output = []
99  
-        for model in model_list:
100  
-            # Use `coalesce` to set the sequence for each model to the max pk value if there are records,
101  
-            # or 1 if there are none. Set the `is_called` property (the third argument to `setval`) to true
102  
-            # if there are records (as the max pk value is already in use), otherwise set it to false.
103  
-            for f in model._meta.fields:
104  
-                if isinstance(f, models.AutoField):
105  
-                    output.append("%s setval('%s', coalesce(max(%s), 1), max(%s) %s null) %s %s;" % \
106  
-                        (style.SQL_KEYWORD('SELECT'),
107  
-                        style.SQL_FIELD(qn('%s_%s_seq' % (model._meta.db_table, f.column))),
108  
-                        style.SQL_FIELD(qn(f.column)),
109  
-                        style.SQL_FIELD(qn(f.column)),
110  
-                        style.SQL_KEYWORD('IS NOT'),
111  
-                        style.SQL_KEYWORD('FROM'),
112  
-                        style.SQL_TABLE(qn(model._meta.db_table))))
113  
-                    break # Only one AutoField is allowed per model, so don't bother continuing.
114  
-            for f in model._meta.many_to_many:
115  
-                output.append("%s setval('%s', coalesce(max(%s), 1), max(%s) %s null) %s %s;" % \
116  
-                    (style.SQL_KEYWORD('SELECT'),
117  
-                    style.SQL_FIELD(qn('%s_id_seq' % f.m2m_db_table())),
118  
-                    style.SQL_FIELD(qn('id')),
119  
-                    style.SQL_FIELD(qn('id')),
120  
-                    style.SQL_KEYWORD('IS NOT'),
121  
-                    style.SQL_KEYWORD('FROM'),
122  
-                    style.SQL_TABLE(f.m2m_db_table())))
123  
-        return output
124  
-
125 21
 class DatabaseWrapper(BaseDatabaseWrapper):
126 22
     ops = DatabaseOperations()
127 23
 
@@ -148,10 +44,9 @@ def _cursor(self, settings):
148 44
         cursor.tzinfo_factory = None
149 45
         if set_tz:
150 46
             cursor.execute("SET TIME ZONE %s", [settings.TIME_ZONE])
151  
-        global postgres_version
152  
-        if not postgres_version:
  47
+        if self.ops.postgres_version is None:
153 48
             cursor.execute("SELECT version()")
154  
-            postgres_version = [int(val) for val in cursor.fetchone()[0].split()[1].split('.')]
  49
+            self.ops.postgres_version = [int(val) for val in cursor.fetchone()[0].split()[1].split('.')]
155 50
         return cursor
156 51
 
157 52
 allows_group_by_ordinal = True

0 notes on commit f4b3970

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