|
1 """ |
|
2 PostgreSQL database backend for Django. |
|
3 |
|
4 Requires psycopg 2: http://initd.org/projects/psycopg2 |
|
5 """ |
|
6 |
|
7 from django.db.backends import BaseDatabaseWrapper, BaseDatabaseFeatures |
|
8 from django.db.backends.postgresql.operations import DatabaseOperations as PostgresqlDatabaseOperations |
|
9 from django.utils.safestring import SafeUnicode |
|
10 try: |
|
11 import psycopg2 as Database |
|
12 import psycopg2.extensions |
|
13 except ImportError, e: |
|
14 from django.core.exceptions import ImproperlyConfigured |
|
15 raise ImproperlyConfigured("Error loading psycopg2 module: %s" % e) |
|
16 |
|
17 DatabaseError = Database.DatabaseError |
|
18 IntegrityError = Database.IntegrityError |
|
19 |
|
20 psycopg2.extensions.register_type(psycopg2.extensions.UNICODE) |
|
21 psycopg2.extensions.register_adapter(SafeUnicode, psycopg2.extensions.QuotedString) |
|
22 |
|
23 class DatabaseFeatures(BaseDatabaseFeatures): |
|
24 needs_datetime_string_cast = False |
|
25 |
|
26 class DatabaseOperations(PostgresqlDatabaseOperations): |
|
27 def last_executed_query(self, cursor, sql, params): |
|
28 # With psycopg2, cursor objects have a "query" attribute that is the |
|
29 # exact query sent to the database. See docs here: |
|
30 # http://www.initd.org/tracker/psycopg/wiki/psycopg2_documentation#postgresql-status-message-and-executed-query |
|
31 return cursor.query |
|
32 |
|
33 class DatabaseWrapper(BaseDatabaseWrapper): |
|
34 features = DatabaseFeatures() |
|
35 ops = DatabaseOperations() |
|
36 operators = { |
|
37 'exact': '= %s', |
|
38 'iexact': 'ILIKE %s', |
|
39 'contains': 'LIKE %s', |
|
40 'icontains': 'ILIKE %s', |
|
41 'regex': '~ %s', |
|
42 'iregex': '~* %s', |
|
43 'gt': '> %s', |
|
44 'gte': '>= %s', |
|
45 'lt': '< %s', |
|
46 'lte': '<= %s', |
|
47 'startswith': 'LIKE %s', |
|
48 'endswith': 'LIKE %s', |
|
49 'istartswith': 'ILIKE %s', |
|
50 'iendswith': 'ILIKE %s', |
|
51 } |
|
52 |
|
53 def _cursor(self, settings): |
|
54 set_tz = False |
|
55 if self.connection is None: |
|
56 set_tz = True |
|
57 if settings.DATABASE_NAME == '': |
|
58 from django.core.exceptions import ImproperlyConfigured |
|
59 raise ImproperlyConfigured("You need to specify DATABASE_NAME in your Django settings file.") |
|
60 conn_string = "dbname=%s" % settings.DATABASE_NAME |
|
61 if settings.DATABASE_USER: |
|
62 conn_string = "user=%s %s" % (settings.DATABASE_USER, conn_string) |
|
63 if settings.DATABASE_PASSWORD: |
|
64 conn_string += " password='%s'" % settings.DATABASE_PASSWORD |
|
65 if settings.DATABASE_HOST: |
|
66 conn_string += " host=%s" % settings.DATABASE_HOST |
|
67 if settings.DATABASE_PORT: |
|
68 conn_string += " port=%s" % settings.DATABASE_PORT |
|
69 self.connection = Database.connect(conn_string, **self.options) |
|
70 self.connection.set_isolation_level(1) # make transactions transparent to all cursors |
|
71 self.connection.set_client_encoding('UTF8') |
|
72 cursor = self.connection.cursor() |
|
73 cursor.tzinfo_factory = None |
|
74 if set_tz: |
|
75 cursor.execute("SET TIME ZONE %s", [settings.TIME_ZONE]) |
|
76 return cursor |