Django get query from queryset. Возвращение недопустимых параметров
Когда я пытаюсь получить запрос из django queryset, он возвращает параметры без кавычек, что делает его недопустимым для выполнения
У меня есть код django следующего содержания:
qs = Sample.objects.filter(data_date__range=[start_date, end_date])
Когда я пытаюсь получить запрос, чтобы я мог запросить его с помощью pyodbc (я обнаружил, что запрос django занимает 5 секунд, а pyodbc - <1 для 50k+ строк), я пытаюсь получить запрос следующим образом:
str(qs.query)
Однако, для параметров, которые он возвращает без кавычек, например, запрос возвращается следующим образом
SELECT * FROM [sample] WHERE [data_date]
BETWEEN 2019-01-01 00:00:00 AND 2022-01-01 00:00:00
Как видно, кавычки отсутствуют в двух переменных datetime, поэтому, когда я пытаюсь выполнить запрос, используя pd.read_sql_query(query, conn)
, я получаю ошибку, указывающую на эти параметры. И дело не только в параметре даты, если я пытаюсь фильтровать, используя что-либо еще, я получаю ту же проблему.
Ошибка при запросе без кавычек
Execution failed on sql 'SELECT * FROM [sample] WHERE [sample].[data_date] BETWEEN 2019-01-01 00:00:00 AND 2022-01-01 00:00:00': ('42000', "[42000] [Microsoft][ODBC Driver 17 for SQL Server][SQL Server]Incorrect syntax near '00'. (102) (SQLExecDirectW)")
Мне интересно, есть ли другой способ генерировать запрос из django queryset, чтобы я мог запустить его с помощью pyodbc или чего-либо еще для получения более быстрого результата.
Я использую Django 3.2
и sql-server
Обновление:
Индексы на БД
...
[sample_data_date] (Non-unique, Non-clustered)
AK (Unique, Non-clustered)
PK (clustered)
...
После долгих поисков я нашел ответ на свой собственный вопрос.
Размещаю здесь, чтобы другим не пришлось искать столько же, сколько искал я.
Оказалось, что queryset.query
не возвращает правильный SQL. Нам нужно использовать .sql_with_params()
, чтобы получить запрос и параметры отдельно.
Конечный код выглядел примерно так:
qs = Sample.objects.filter(data_date__range=[start_date, end_date])
query, params = qs.query.sql_with_params()
# pyodbc uses "?" vs django returns "%s" as placeholder
query = query.replace("%s", "?")
df = pd.read_sql(query, pyodbc_conn, params=params)
Запрос с использованием pyodbc занял <1 секунду по сравнению с использованием Django ORM, занявшим 5 секунд для 56000 строк x 5 столбцов.
Большая помощь от этого билета Django.