Skip to content

Commit bf9cc99

Browse files
committed
Support both psqlextra and PostGis backends at the same time
[#181799346]
1 parent 9aecb3d commit bf9cc99

File tree

5 files changed

+40
-33
lines changed

5 files changed

+40
-33
lines changed

psqlextra/backend/base.py

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,20 @@ class DatabaseWrapper(base_impl.backend()):
2222
introspection_class = PostgresIntrospection
2323
ops_class = PostgresOperations
2424

25-
def prepare_database(self):
25+
def __init__(self, *args, **kwargs):
26+
super().__init__(*args, **kwargs)
27+
if not isinstance(self.ops, PostgresOperations):
28+
# PostGis replaces the ops object instead of setting the ops_class attribute
29+
if self.ops.compiler_module != 'django.db.models.sql.compiler':
30+
raise NotImplementedError(
31+
f'''The Django ops object has been replaced by {self.ops} and a custom compiler module {self.ops.compiler_module} has been set.
32+
Replacing both at the same time is incompatible with psqlextra. '''
33+
)
34+
self.ops._compiler_cache = None
35+
self.ops.compiler_module = 'psqlextra.compiler'
36+
37+
38+
def prepare_database(self):
2639
"""Ran to prepare the configured database.
2740
2841
This is where we enable the `hstore` extension if it wasn't

psqlextra/backend/base_impl.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import importlib
2+
import os
23

34
from django.conf import settings
45
from django.core.exceptions import ImproperlyConfigured
@@ -23,7 +24,7 @@ def backend():
2324
base_class_name = getattr(
2425
settings,
2526
"POSTGRES_EXTRA_DB_BACKEND_BASE",
26-
"django.db.backends.postgresql",
27+
os.environ.get("POSTGRES_EXTRA_DB_BACKEND_BASE") or "django.db.backends.postgresql",
2728
)
2829

2930
base_class_module = importlib.import_module(base_class_name + ".base")

psqlextra/backend/operations.py

Lines changed: 11 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
1+
from importlib import import_module
2+
13
from psqlextra.compiler import (
2-
PostgresAggregateCompiler,
3-
PostgresCompiler,
4-
PostgresDeleteCompiler,
5-
PostgresInsertCompiler,
6-
PostgresUpdateCompiler,
4+
SQLAggregateCompiler,
5+
SQLCompiler,
6+
SQLDeleteCompiler,
7+
SQLInsertCompiler,
8+
SQLUpdateCompiler,
79
)
810

911
from . import base_impl
@@ -12,14 +14,6 @@
1214
class PostgresOperations(base_impl.operations()):
1315
"""Simple operations specific to PostgreSQL."""
1416

15-
compiler_map = {
16-
"SQLCompiler": PostgresCompiler,
17-
"SQLInsertCompiler": PostgresInsertCompiler,
18-
"SQLUpdateCompiler": PostgresUpdateCompiler,
19-
"SQLDeleteCompiler": PostgresDeleteCompiler,
20-
"SQLAggregateCompiler": PostgresAggregateCompiler,
21-
}
22-
2317
def __init__(self, *args, **kwargs):
2418
super().__init__(*args, **kwargs)
2519

@@ -28,9 +22,8 @@ def __init__(self, *args, **kwargs):
2822
def compiler(self, compiler_name: str):
2923
"""Gets the SQL compiler with the specified name."""
3024

31-
postgres_compiler = self.compiler_map.get(compiler_name)
32-
if postgres_compiler:
33-
return postgres_compiler
25+
if self._cache is None:
26+
self._cache = import_module('psqlextra.compiler')
3427

35-
# Let Django try to find the compiler. Better run without caller comment than break
36-
return super().compiler(compiler_name)
28+
# Let any parent module try to find the compiler as fallback. Better run without caller comment than break
29+
return getattr(self._cache, compiler_name, super().compiler(compiler_name))

psqlextra/compiler.py

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,11 @@
1212
from django.db.models import Expression, Model, Q
1313
from django.db.models.fields.related import RelatedField
1414
from django.db.models.sql.compiler import (
15-
SQLAggregateCompiler,
16-
SQLCompiler,
17-
SQLDeleteCompiler,
18-
SQLInsertCompiler,
19-
SQLUpdateCompiler,
15+
SQLAggregateCompiler as DjangoSQLAggregateCompiler,
16+
SQLCompiler as DjangoSQLCompiler,
17+
SQLDeleteCompiler as DjangoSQLDeleteCompiler,
18+
SQLInsertCompiler as DjangoSQLInsertCompiler,
19+
SQLUpdateCompiler as DjangoSQLUpdateCompiler,
2020
)
2121
from django.db.utils import ProgrammingError
2222

@@ -77,25 +77,25 @@ def append_caller_to_sql(sql):
7777
return sql
7878

7979

80-
class PostgresCompiler(SQLCompiler):
80+
class SQLCompiler(DjangoSQLCompiler):
8181
def as_sql(self, *args, **kwargs):
8282
sql, params = super().as_sql(*args, **kwargs)
8383
return append_caller_to_sql(sql), params
8484

8585

86-
class PostgresDeleteCompiler(SQLDeleteCompiler):
86+
class SQLDeleteCompiler(DjangoSQLDeleteCompiler):
8787
def as_sql(self, *args, **kwargs):
8888
sql, params = super().as_sql(*args, **kwargs)
8989
return append_caller_to_sql(sql), params
9090

9191

92-
class PostgresAggregateCompiler(SQLAggregateCompiler):
92+
class SQLAggregateCompiler(DjangoSQLAggregateCompiler):
9393
def as_sql(self, *args, **kwargs):
9494
sql, params = super().as_sql(*args, **kwargs)
9595
return append_caller_to_sql(sql), params
9696

9797

98-
class PostgresUpdateCompiler(SQLUpdateCompiler):
98+
class SQLUpdateCompiler(DjangoSQLUpdateCompiler):
9999
"""Compiler for SQL UPDATE statements that allows us to use expressions
100100
inside HStore values.
101101
@@ -152,7 +152,7 @@ def _does_dict_contain_expression(data: dict) -> bool:
152152
return False
153153

154154

155-
class PostgresInsertCompiler(SQLInsertCompiler):
155+
class SQLInsertCompiler(DjangoSQLInsertCompiler):
156156
"""Compiler for SQL INSERT statements."""
157157

158158
def as_sql(self, *args, **kwargs):
@@ -165,7 +165,7 @@ def as_sql(self, *args, **kwargs):
165165
return queries
166166

167167

168-
class PostgresInsertOnConflictCompiler(SQLInsertCompiler):
168+
class PostgresInsertOnConflictCompiler(DjangoSQLInsertCompiler):
169169
"""Compiler for SQL INSERT statements."""
170170

171171
def __init__(self, *args, **kwargs):
@@ -407,7 +407,7 @@ def _format_field_value(self, field_name) -> str:
407407
if isinstance(field, RelatedField) and isinstance(value, Model):
408408
value = value.pk
409409

410-
return SQLInsertCompiler.prepare_value(
410+
return DjangoSQLInsertCompiler.prepare_value(
411411
self,
412412
field,
413413
# Note: this deliberately doesn't use `pre_save_val` as we don't

psqlextra/sql.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
from django.db.models import sql
99
from django.db.models.constants import LOOKUP_SEP
1010

11-
from .compiler import PostgresInsertOnConflictCompiler, PostgresUpdateCompiler
11+
from .compiler import PostgresInsertOnConflictCompiler, SQLUpdateCompiler as PostgresUpdateCompiler
1212
from .expressions import HStoreColumn
1313
from .fields import HStoreField
1414
from .types import ConflictAction

0 commit comments

Comments
 (0)