This does not work:
from django.db import connection
list_of_values = [1, 2, 3]
with connection.cursor() as cursor:
cursor.execute("""
SELECT *
FROM my_model_table
WHERE some_value IN %s
""", [
tuple(list_of_values),
])
results = cursor.fetchall()
It will give you:
django.db.utils.ProgrammingError: syntax error at or near "'(1,2,3)'" LINE 4: WHERE id IN '(1,2,3)'
It used to work with psycopg v2. Now instead, you have to use the ANY operator. See "You cannot use IN %s with a tuple"
This will work:
from django.db import connection
list_of_values = [1, 2, 3]
with connection.cursor() as cursor:
cursor.execute(
"""
SELECT *
FROM my_model_table
WHERE some_value = ANY(%s)
""",
[
list_of_values,
],
)
results = cursor.fetchall()
Note the ANY(%s) and instead of a list that has a tuple, it's a list that has a list.
What about list of strings
Consider...
from django.db import connection
-list_of_values = [1, 2, 3]
+list_of_values = ['foo', 'bar', 'fiz']
with connection.cursor() as cursor:
cursor.execute(
"""
SELECT *
FROM my_model_table
WHERE some_value = ANY(%s)
""",
[
list_of_values,
],
)
results = cursor.fetchall()
That will result in:
django.db.utils.DataError: invalid input syntax for type integer: "foo"
LINE 4: WHERE some_value = ANY('{foo,bar,fiz}')
My solution was to rewrite the SQL string itself and treat each value as a parameter each. In other words, the SQL string, before being sent to cursor.execute(...) will contain something like this:
AND (
some_value = % OR
some_value = % OR
some_value = % OR
some_value = % OR
-- ...etc...
some_value = %
)
This will work and is safe:
from django.db import connection
list_of_values = ["foo", "bar", "fiz"]
with connection.cursor() as cursor:
cursor.execute(
f"""
SELECT *
FROM my_model_table
WHERE ({" OR ".join(["some_value = %s" for _ in list_of_values])})
""",
list_of_values,
)
results = cursor.fetchall()