24
24
get_related_populators ,
25
25
)
26
26
from django .utils .dateparse import parse_datetime
27
- from psycopg2 .extensions import QuotedString
28
27
29
28
logger = logging .getLogger (__name__ )
30
29
@@ -189,6 +188,19 @@ def _get_compiler_from_queryset(self, queryset: QuerysetWrapperType) -> Any:
189
188
190
189
return compiler
191
190
191
+ def _get_sanitized_sql_param (self , param : str ) -> str :
192
+ try :
193
+ from psycopg import sql
194
+
195
+ return sql .quote (param )
196
+ except ImportError :
197
+ try :
198
+ from psycopg2 .extensions import QuotedString
199
+
200
+ return QuotedString (param ).getquoted ().decode ("utf-8" )
201
+ except ImportError :
202
+ raise ImportError ("psycopg or psycopg2 not installed" )
203
+
192
204
def _get_django_sql_for_queryset (self , queryset : QuerysetWrapperType ) -> str :
193
205
"""
194
206
gets the sql that django would normally execute for the queryset, return empty string
@@ -212,7 +224,7 @@ def _get_django_sql_for_queryset(self, queryset: QuerysetWrapperType) -> str:
212
224
for param in params :
213
225
if isinstance (param , str ):
214
226
# this is to handle special char handling
215
- param = QuotedString ( param ). getquoted (). decode ( "utf-8" )
227
+ param = self . _get_sanitized_sql_param ( param )
216
228
elif isinstance (param , UUID ) or isinstance (param , datetime .datetime ):
217
229
param = f"'{ param } '"
218
230
elif isinstance (param , int ) or isinstance (param , float ):
@@ -419,7 +431,7 @@ def execute(self) -> list[list[Any]]:
419
431
raw_sql = f"""
420
432
SELECT
421
433
json_build_object(
422
- { ', ' .join ([f"'{ i } ', { sql } " for i , sql in enumerate (non_empty_django_sqls_for_querysets )])}
434
+ { ", " .join ([f"'{ i } ', { sql } " for i , sql in enumerate (non_empty_django_sqls_for_querysets )])}
423
435
)
424
436
"""
425
437
with connections ["default" ].cursor () as cursor :
0 commit comments