当我尝试将未执行的查询字符串传递给原始查询时,使用Django recommends的 params 参数将其用作子查询时,我收到错误:< / p>
from apps.bikeshare.models import Station
qs = Station.objects.filter(...)
subquery_string = qs.values('id').order_by().query
raw = Station.objects.raw('SELECT * FROM bikeshare_station WHERE id IN (%s)', [subquery_string])
查询打印正确的SQL(省略WHERE
子句):
<RawQuerySet: SELECT * FROM bikeshare_station WHERE id IN (SELECT "bikeshare_station"."id" FROM "bikeshare_station" WHERE ...)>
但是,执行原始查询(raw[0]
)会出错:
Traceback (most recent call last):
File "/home/gbrown/Envs/bikeshare-dev/lib/python3.5/site-packages/IPython/core/interactiveshell.py", line 2847, in run_code
exec(code_obj, self.user_global_ns, self.user_ns)
File "<ipython-input-4-6eada3e31b4e>", line 1, in <module>
raw[0]
File "/home/gbrown/Envs/bikeshare-dev/lib/python3.5/site-packages/django/db/models/query.py", line 1329, in __getitem__
return list(self)[k]
File "/home/gbrown/Envs/bikeshare-dev/lib/python3.5/site-packages/django/db/models/query.py", line 1299, in __iter__
query = iter(self.query)
File "/home/gbrown/Envs/bikeshare-dev/lib/python3.5/site-packages/django/db/models/sql/query.py", line 93, in __iter__
self._execute_query()
File "/home/gbrown/Envs/bikeshare-dev/lib/python3.5/site-packages/django/db/models/sql/query.py", line 127, in _execute_query
self.cursor.execute(self.sql, params)
File "/home/gbrown/Envs/bikeshare-dev/lib/python3.5/site-packages/django/db/backends/utils.py", line 100, in execute
return super().execute(sql, params)
File "/home/gbrown/Envs/bikeshare-dev/lib/python3.5/site-packages/django/db/backends/utils.py", line 68, in execute
return self._execute_with_wrappers(sql, params, many=False, executor=self._execute)
File "/home/gbrown/Envs/bikeshare-dev/lib/python3.5/site-packages/django/db/backends/utils.py", line 77, in _execute_with_wrappers
return executor(sql, params, many, context)
File "/home/gbrown/Envs/bikeshare-dev/lib/python3.5/site-packages/django/db/backends/utils.py", line 85, in _execute
return self.cursor.execute(sql, params)
File "/home/gbrown/Envs/bikeshare-dev/lib/python3.5/site-packages/django/db/utils.py", line 89, in __exit__
raise dj_exc_value.with_traceback(traceback) from exc_value
File "/home/gbrown/Envs/bikeshare-dev/lib/python3.5/site-packages/django/db/backends/utils.py", line 85, in _execute
return self.cursor.execute(sql, params)
django.db.utils.ProgrammingError: can't adapt type 'Query'
我知道这很危险,因为它是SQL注入。但是,我想支持这一点,创建一个QuerySet方法(恰好需要原始查询),该方法可以在查询集链的末尾使用,其中筛选的查询集作为子查询传递给原始查询。
params 参数是否可以降低任何风险,即使错误没有发生?或者我只是允许风险并使用基本的python字符串格式?
答案 0 :(得分:0)
我刚刚发布我的方法无论如何都无法正常工作,因为query
方法没有返回有效的SQL,即
qs = Station.objects.filter(name='Albert Gate, Hyde Park').values('id').order_by()
print(qs.query)
[out] SELECT "bikeshare_station"."id" FROM "bikeshare_station" WHERE "bikeshare_station"."name" = Albert Gate, Hyde Park
爆炸,因为没有引用名称字符串。
正如Jon Clements在评论中指出的那样,唯一的方法是执行查询并传入可以实现的ID列表:
qs = Station.objects.filter(name='Albert Gate, Hyde Park')
ids = list(qs.values_list('id', flat=True))
然后,您可以将id列表传递给原始查询而不是字符串。