Как использовать список в необработанном SQL-запросе django, который использует `WHERE ... IN (...)`?

Как внедрить параметр списка в сырой запрос Django?

Получив список UUID, я хотел бы иметь возможность вводить их в () в WHERE ... IN (...) запрос.

list_of_uuids = [
  "<UUID_1>",
  "<UUID_2>
]

Вывод для SQL:

SELECT * 
FROM some_model_table 
WHERE some_model_table.uuid IN ( "<UUID_1>", "<UUID_2>" )

Итак, я попробовал сделать следующее, используя необработанные запросы django:

query_set = SomeModel.objects.raw("SELECT * FROM some_model_table where some_model_table.uuid IN %s", [list_of_uuids])

К сожалению, вышеописанное приведет к следующей ошибке:

django.db.utils.ProgrammingError: syntax error at or near "ARRAY":

LINE X: WHERE uuid IN ARRAY['00123...

Это означает, что список интерпретируется как массив и передается в SQL-запрос как массив, который нельзя использовать в запросе IN.

Заключение инжектированного массива в () также не работает:

LINE X: WHERE uuid IN (ARRAY['00123...
                                                     ^
HINT:  No operator matches the given name and argument types. You might need to add explicit type casts.

Примечание: Я знаю, что этот конкретный пример можно сделать с помощью Django ORM, но мой реальный запрос сложнее этого и должен быть сделан с помощью необработанных запросов, и содержит этот WHERE ... IN (...) синтаксис. Я просто убрал нерелевантный код из вопроса, чтобы его было легче разобрать. Для тех, кто хочет использовать ORM, вот код, который вам нужен:

query_set = SomeModel.objects.filter(uuid__in=list_of_uuids)

Я попробовал сам построить разделенный список строк UUID и внедрить его, к сожалению, он внедряется в формате WHERE uuid IN ('"some_uuid", "other_uuid"')

Вы могли бы использовать .format(...) в строке запроса перед передачей ее в Django ORM, но это открывает нам путь к SQL-инъекции.

Я также искал способ заставить SQL интерпретировать массив как входные данные для запроса WHERE IN, но мне не очень повезло.

Есть ли другой способ? Можно ли как-то разобрать массив, переданный в SQL, на допустимый синтаксис для запроса WHERE ... IN (...)?

Вы можете использовать ANY(%s), например, в вашем случае:

query_set = SomeModel.objects.raw("SELECT * FROM some_model_table where some_model_table.uuid = ANY(%s)", [list_of_uuids])

Я полагаю, что ваше поле uuid на самом деле не является полем UUID. Я думаю, что вместо этого это поле CharField.

Если вы измените тип uuid на UUIDField, то упомянутый вами подход ORM с фильтрацией __in будет работать как надо.

Вернуться на верх