How to use a list/tuple/array in Django with a raw SQL cursor

How to use a list/tuple/array in Django with a raw SQL cursor

Articles

Title: How to use a list/tuple/array in Django with a raw SQL cursor - Peterbe.com

URL Source: http://www.peterbe.com/plog/how-to-use-a-listtuplearray-in-django-with-a-raw-sql-cursor

Markdown Content: 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, in psycopg v3, 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 a 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() ```