Передача списков или кортежей в качестве аргументов в django raw sql
У меня есть список и вы хотите пройти через django raw sql.
Вот мой список
region = ['US','CA','UK']
Я вставляю часть raw sql здесь.
results = MMCode.objects.raw('select assigner, assignee from mm_code where date between %s and %s and country_code in %s',[fromdate,todate,region])
Теперь он дает следующую ошибку, когда я выполняю ее в оболочке python django
Traceback (most recent call last):
File "<console>", line 1, in <module>
File "/usr/local/lib/python2.6/dist-packages/django/db/models/query.py", line 1412, in __iter__
query = iter(self.query)
File "/usr/local/lib/python2.6/dist-packages/django/db/models/sql/query.py", line 73, in __iter__
self._execute_query()
File "/usr/local/lib/python2.6/dist-packages/django/db/models/sql/query.py", line 87, in _execute_query
self.cursor.execute(self.sql, self.params)
File "/usr/local/lib/python2.6/dist-packages/django/db/backends/util.py", line 15, in execute
return self.cursor.execute(sql, params)
File "/usr/local/lib/python2.6/dist-packages/django/db/backends/mysql/base.py", line 86, in execute
return self.cursor.execute(query, args)
File "/usr/lib/pymodules/python2.6/MySQLdb/cursors.py", line 166, in execute
self.errorhandler(self, exc, value)
File "/usr/lib/pymodules/python2.6/MySQLdb/connections.py", line 35, in defaulterrorhandler
raise errorclass, errorvalue
DatabaseError: (1064, "You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ')' at line 1")
Я тоже пробовал пропустить кортеж, но это бесполезно. Может кто-то мне помочь.
Спасибо
Викрам
Ответы
Ответ 1
По крайней мере для PostgreSQL параметр list/tuple преобразуется в массив в SQL, например.
ARRAY['US', 'CA', 'UK']
Когда это вставляется в данный запрос, это приводит к недействительному SQL -
SELECT assigner, assignee FROM mm_code
WHERE date BETWEEN '2014-02-01' AND '2014-02-05'
AND country_code IN ARRAY['US', 'CA', 'UK']
Однако предложение 'in' в SQL логически эквивалентно -
SELECT assigner, assignee FROM mm_code
WHERE date BETWEEN %s AND %s
AND country_code = ANY(%s)
... и когда этот запрос заполняется параметрами, результирующий SQL действителен и работает -
SELECT assigner, assignee FROM mm_code
WHERE date BETWEEN '2014-02-01' AND '2014-02-05'
AND country_code = ANY(ARRAY['US', 'CA', 'UK'])
Я не уверен, что это работает в других базах данных, и независимо от того, изменяет ли он, как планируется этот запрос.
Ответ 2
Приведение списка в кортеж работает в Postgres, хотя тот же код выходит из строя под sqlite3 с DatabaseError: near "?": syntax error
, поэтому кажется, что это зависит от файла. Ваша строка кода будет выглядеть следующим образом:
results = MMCode.objects.raw('select assigner, assignee from mm_code where date between %s and %s and country_code in %s',[fromdate,todate,tuple(region)])
Я тестировал это на чистом проекте Django 1.5.1 со следующими параметрами в bar/models.py:
from django.db import models
class MMCode(models.Model):
assigner = models.CharField(max_length=100)
assignee = models.CharField(max_length=100)
date = models.DateField()
country_code = models.CharField(max_length=2)
то в оболочке:
>>> from datetime import date
>>> from bar.models import MMCode
>>>
>>> regions = ['US', 'CA', 'UK']
>>> fromdate = date.today()
>>> todate = date.today()
>>>
>>> results = MMCode.objects.raw('select id, assigner, assignee from bar_mmcode where date between %s and %s and country_code in %s',[fromdate,todate,tuple(regions)])
>>> list(results)
[]
(обратите внимание, что строка запроса немного изменилась здесь, чтобы использовать имя таблицы по умолчанию, созданную Django, и включить столбец id
в выходном файле, чтобы ORM не жаловался)
Ответ 3
Это не отличное решение, потому что вы должны убедиться, что ваши "региональные" значения правильно экранированы для SQL. Тем не менее, это единственное, что я мог бы получить для работы с Sqlite:
sql = ('select assigner, assignee from mm_code '
'where date between %%s and %%s and country_code in %s' % (tuple(region),))
results = MMCode.objects.raw(sql, [fromdate,todate])
Ответ 4
Сегодня я столкнулся с этой проблемой. Django изменился (теперь у нас есть RawSQL()
и друзья!), Но общее решение остается тем же.
Согласно fooobar.com/questions/79880/..., общая идея состоит в том, чтобы явно добавить те же самые числа заполнителей в вашу строку SQL, поскольку в вашем массиве region
есть элементы.
Тогда ваш код будет выглядеть так:
sql = 'select assigner, assignee from mm_code where date between %s and %s and country_code in ({0})'\
.format(','.join([%s] * len(region)))
results = MMCode.objects.raw(sql, [fromdate,todate] + region)
Ваша строка sql сначала станет ... between %s and %s and country_code in (%s, %s, %s) ...
, и ваши параметры будут эффективными [fromdate, todate, 'US', 'CA', 'UK']
. Таким образом, вы позволяете бэкэнд базы данных правильно убежать и потенциально кодировать каждый из кодов стран.
Ответ 5
привет у меня есть два пути к файлам в строковом формате, и мне нужно передать это как параметр, как я могу это сделать. но когда я прохожу, как сказано выше, это не работает для DJANGO, последняя версия может помочь мне, пожалуйста, как это сделать. если это возможно, пожалуйста, сделайте это быстро
Ответ 6
Ну, я не против raw sql, но вы можете использовать:
MMCode.objects.filter(country_code__in=region, date__range=[fromdate,todate])
надеюсь, что это поможет.