Django ORM методы фильтрации запросов запуск множественного фильтра дублирует джойнты
Я пытаюсь запустить фильтры, использующие методы в двух отдельных атрибутах.
В ICD10Filter:
class Icd10Filter(filters.FilterSet):
# New Filters for DOS Range
dosFrom = filters.DateFilter(method='filter_by_dos_from', lookup_expr='gte')
dosTo = filters.DateFilter(method='filter_by_dos_to', lookup_expr='lte')
def filter_by_dos_from(self, queryset, name, value):
return queryset.filter(
base_icd__chart_review_dos__dos_from__gte=value
)
def filter_by_dos_to(self, queryset, name, value):
return queryset.filter(
base_icd__chart_review_dos__dos_to__lte=value
)
Фильтр ICD10 упоминается в модели ChartReviewDx:
class ChartReviewDx(models.Model):
chart_review_dos = models.ForeignKey(
ChartReviewDos, on_delete=models.SET_NULL, null=True, related_name="diagnosis_details"
)
diagnosis_code = models.CharField(max_length=1024, null=True, blank=True)
diagnosis_description = models.CharField(max_length=1024, null=True, blank=True)
icd10 = models.ForeignKey("risk_adjustment.Icd10", on_delete=models.SET_NULL, null=True)
base_icd = models.ForeignKey(
"risk_adjustment.Icd10", on_delete=models.SET_NULL, null=True, blank=True, related_name="base_icd"
)
и ChartReviewDx ссылается на модель ChartReviewDOS:
class ChartReviewDos(models.Model):
chart = models.ForeignKey(Chart, on_delete=models.SET_NULL, null=True, blank=True, related_name="diagnosis")
dos_from = models.DateField()
dos_to = models.DateField()
Я хочу получить коды МКБ10 только для определенного диапазона DOS.
Желаемый запрос:
SELECT
distinct id,
code,
description
FROM
risk_adjustment_icd10
INNER JOIN healthcare_data_chart_review_dx ON (
id = healthcare_data_chart_review_dx.base_icd_id
)
INNER JOIN healthcare_data_chart_review_dos ON (
healthcare_data_chart_review_dx.chart_review_dos_id = healthcare_data_chart_review_dos.id
)
WHERE
(
valid = 1
AND healthcare_data_chart_review_dos.dos_from >= '2023-08-19'
AND healthcare_data_chart_review_dos.dos_to <= '2023-08-19'
)
ORDER BY
code ASC
Когда я запускаю фильтр только для одного из полей, запрос работает нормально.
Но запуск фильтров по обоим полям дает избыточные JOINS и, следовательно, неточные результаты:
Запрос, который формируется после применения обоих фильтров:
SELECT
DISTINCT id,
code,
description
FROM
risk_adjustment_icd10
INNER JOIN healthcare_data_chart_review_dx ON (
id = healthcare_data_chart_review_dx.base_icd_id
)
INNER JOIN healthcare_data_chart_review_dos ON (
healthcare_data_chart_review_dx.chart_review_dos_id = healthcare_data_chart_review_dos.id
)
INNER JOIN healthcare_data_chart_review_dx T4 ON (
id = T4.base_icd_id
)
INNER JOIN healthcare_data_chart_review_dos T5 ON (
T4.chart_review_dos_id = T5.id
)
WHERE
(
valid = 1
AND healthcare_data_chart_review_dos.dos_from >= '2023-08-19'
AND T5.dos_to <= '2023-08-19'
)
ORDER BY
code asc
Как удалить эти лишние соединения?
Если вы присоединяетесь к моделям, есть огромная разница между:
queryset.filter(
base_icd__chart_review_dos__dos_from__gte=value
).filter(
base_icd__chart_review_dos__dos_to__lte=value
)
и:
queryset.filter(
base_icd__chart_review_dos__dos_from__gte=value,
base_icd__chart_review_dos__dos_to__lte=value,
)
В форме запрашивается запись, в которой есть связанная review_dos
, для которой from
больше или равно value
, и связанная review_dos
, , возможно, другая , для которой to
меньше или равно value
. Для последнего эта review_dos
запись должна быть одной и той же.
Если вы используете same .filter(…)
[Django-doc], то JOINы будут повторно использоваться в пунктах этого .filter(…)
, тогда как отдельные вызовы .filter(…)
будут генерировать разные джойны.
Таким образом, это не ошибка, оба случая допустимы, в зависимости от того, что вы хотите, вы используете один из сценариев.
Таким образом, вам, вероятно, следует сделать третий метод фильтрации, в котором вы используете тот же .filter(…)
.