Как получить подзапрос в предложении FROM в Django ORM
Я пытаюсь выразить следующий (Postgres) SQL-оператор с помощью Django ORM:
SELECT
v.id, v.min_salary, v.max_salary, v.min_weekly_hours, v.max_weekly_hours
p.min_start_date, p.max_end_date
FROM
vacancy v,
(
SELECT
id, vacancy_id, MIN(start_date) min_start_date, MAX(end_date) AS max_end_date
FROM vacancypublication
WHERE (active = True AND site_id = 1 AND start_date <= CURRENT_TIMESTAMP)
GROUP BY id, vacancy_id
) p
WHERE
p.vacancy_id = v.id AND
v.workflow_status = 'A'
ORDER BY p.min_start_date DESC;
Проблема в том, что я использую подзапрос в предложении FROM (также известный как "inline-view").
Я пытался использовать .extra(tables=['...'])
но Django добавляет к выражению кавычки, делая SQL недействительным.
Я бы предпочел не прибегать к .raw
запрос. Есть ли способ сделать это? Может быть, через повторно используемое приложение, если ядро API не предоставляет пути.
РЕДАКТИРОВАТЬ:
Это (на первый взгляд) эквивалентное утверждение, использующее соединение:
SELECT
v.id, v.code, v.min_salary, v.max_salary, v.min_weekly_hours, v.max_weekly_hours, v.application_email, v.application_url, v.available_positions,
MIN(CASE WHEN (p.active = True AND p.site_id = 1 AND p.start_date <= CURRENT_TIMESTAMP) THEN p.start_date ELSE NULL END) AS start_date,
MAX(CASE WHEN (p.active = True AND p.site_id = 1) THEN p.end_date ELSE NULL END) AS end_date
FROM base_vacancy v
LEFT OUTER JOIN
base_vacancypublication p ON v.id = p.vacancy_id
WHERE v.workflow_status = 'A'
GROUP BY v.id, v.code, v.min_salary, v.max_salary, v.min_weekly_hours, v.max_weekly_hours, v.application_email, v.application_url, v.available_positions
HAVING MIN(CASE WHEN (p.active = True AND p.site_id = 1 AND p.start_date <= CURRENT_TIMESTAMP) THEN p.start_date ELSE NULL END) IS NOT NULL
ORDER BY start_date DESC;
Это примерно в 3 раза медленнее, но можно написать это с помощью методов Django 1.9 ORM:
Vacancy.objects.annotate(
start_date=Min(
Case(
When(publication_set__is_active=True, publication_set__site_id=1, publication_set__start_date__lte=Now(), then='publication_set__start_date'),
default=None
)
),
end_date=Max(
Case(
When(publication_set__is_active=True, publication_set__site_id=1, then='publication_set__end_date'),
default=None
)
)
).filter(
start_date__isnull=False, status=Workflow.APPROVED
).order_by(
'-start_date'
)
1 ответ
Вы можете запустить запрос непосредственно от Postgres...
Будет вид:
con = mysql.connector.connect(....)
cur = con.cursor()
query = "SELECT v.id, v.min_salary, v.max_salary,v.min_weekly_hours, v.max_weekly_hours, p.min_start_date, p.max_end_date FROM vacancy v, (SELECT id, vacancy_id, MIN(start_date) min_start_date, MAX(end_date) AS max_end_date FROM vacancypublication WHERE active = True AND site_id = 1 AND start_date <= CURRENT_TIMESTAMP) GROUP BY id, vacancy_id) p WHERE p.vacancy_id = v.id AND v.workflow_status = 'A' ORDER BY p.min_start_date DESC;"
cur.execute(query)
rows = cur.fetchall()
for row in rows:
// DO YOUR STUFF.