Проблема
Попытка оптимизировать аналогичный запрос
Случай
Скажем, у меня есть модель тега вакансии, например:
class VacancyTag(models.Model):
TYPE_GENERAL = 1
TYPE_EDUCATION_LEVEL = 2
TYPE_LOCATION_CITY = 3
TYPE_LOCATION_PROVINCE = 4
TYPE_CONTRACT_TYPE = 5
TYPE_JOB_TYPE = 6
name = models.CharField(max_length=50)
tag_type = models.SmallIntegerField(choices=(
(TYPE_GENERAL, 'General'),
(TYPE_EDUCATION_LEVEL, 'Education Level'),
(TYPE_LOCATION_CITY, 'Location City'),
(TYPE_LOCATION_PROVINCE, 'Location Province'),
(TYPE_CONTRACT_TYPE, 'Contract Type'),
(TYPE_JOB_TYPE, 'Job Type'),
), default=TYPE_GENERAL, db_index=True)
В представлении я разбираю несколько типов записей тегов в контексте следующим образом:
context['tag_education'] = vacancy_services.get_vacancy_tag_by_type(VacancyTag.TYPE_EDUCATION_LEVEL)
context['tag_job_type'] = vacancy_services.get_vacancy_tag_by_type(VacancyTag.TYPE_JOB_TYPE)
context['tag_contract_type'] = vacancy_services.get_vacancy_tag_by_type(VacancyTag.TYPE_CONTRACT_TYPE)
Где vacancy_services.get_vacancy_tag_by_type
просто выполняю запрос следующим образом:
VacancyTag.objects.filter(tag_type=tag_type)
Используя Django Панель инструментов отладки, я заметил, что эти 3 контекста имеют похожий запрос, потому что он отличается только параметром фильтра tag_type
.
Обыскивал его несколько раз и нашел ответ, предлагающий запросить все теги типа I нужно, а затем обработать данные в представлении, поэтому я попробовал что-то вроде этого:
all_tags = vacancy_services.get_vacancy_tag_by_type_in([
VacancyTag.TYPE_EDUCATION_LEVEL,
VacancyTag.TYPE_JOB_TYPE,
VacancyTag.TYPE_CONTRACT_TYPE,
])
context['education_tags'] = [e for e in all_tags if e.tag_type == VacancyTag.TYPE_EDUCATION_LEVEL]
Где vacancy_services.get_vacancy_tag_by_type_in
просто:
VacancyTag.objects.filter(tag_type__in=tag_types)
Однако он не оптимизировал запрос как Я хочу. Приведенный выше код приводит к двум различным запросам.
(0.006) SELECT "app_vacancy_vacancytag"."id", "app_vacancy_vacancytag"."name", "app_vacancy_vacancytag"."slug", "app_vacancy_vacancytag"."tag_type" FROM "app_vacancy_vacancytag" WHERE ("app_vacancy_vacancytag"."is_show" = 1 AND "app_vacancy_vacancytag"."tag_type" IN (2, 6, 5)) ORDER BY "app_vacancy_vacancytag"."tag_type" DESC, "app_vacancy_vacancytag"."is_popular" DESC, "app_vacancy_vacancytag"."hit_count" ASC LIMIT 21; args=(True, 2, 6, 5)
(0.000) SELECT "app_vacancy_vacancytag"."id", "app_vacancy_vacancytag"."name", "app_vacancy_vacancytag"."slug", "app_vacancy_vacancytag"."tag_type" FROM "app_vacancy_vacancytag" WHERE ("app_vacancy_vacancytag"."is_show" = 1 AND "app_vacancy_vacancytag"."tag_type" IN (2, 6, 5) AND "app_vacancy_vacancytag"."tag_type" = 2) ORDER BY "app_vacancy_vacancytag"."tag_type" DESC, "app_vacancy_vacancytag"."is_popular" DESC, "app_vacancy_vacancytag"."hit_count" ASC LIMIT 21; args=(True, 2, 6, 5, 2)
То, что я хочу
Приведенный выше код должен выполнять только 1 запрос (следовательно, оптимизацию) с возможностью получения и фильтрации нескольких типов тегов
Что я сделал не так? Где я пропустил?