Как использовать список в необработанном 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
будет работать как надо.