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.

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