Django ORM-запрос объединяет несвязанные таблицы в двух полях - PullRequest
0 голосов
/ 03 апреля 2020

Проблема

Я пишу программу, в которой регистрирую процедуры, проводимые для пациентов в различных медицинских учреждениях. Каждое лечение проводится на определенной части тела, и каждое медицинское место может определять свой собственный способ именования этих частей тела.

Мои модели выглядят так:

class Treatment(Model):
    medical_place = ForeignKey(to=MedicalPlace, on_delete=PROTECT, related_name='treatments')
    body_part = CharField(max_length=64, choices=BodyPart.choices(), db_index=True)
    ... (some other fields) ...

class LocalProcedure(ProcedureBase):
    medical_place = ForeignKey(to=MedicalPlace, on_delete=PROTECT, related_name='procedures')
    identifier = CharField(verbose_name=_('Procedure number'), max_length=64, blank=False, null=False)
    description = CharField(verbose_name=_('Procedure description'), max_length=256, blank=True, null=False)
    body_part = CharField(max_length=64, choices=BodyPart.choices(), blank=False, db_index=True)

    class Meta:
        unique_together = (('body_part', 'medical_place', 'identifier'),)

Мне нужно получить список объектов "LocalProcedure" с аннотацией:

  • количество связанных обработок
  • количество связанных обработок, выполненных до X дней go (модель обработок создала поле даты и времени, которое я здесь не показывал)

Решения, которые я пробовал до сих пор

Я могу получить аннотированный список LocalProcedures при использовании подзапросов:

    related_treatments = Treatment.objects.filter(
        body_part=OuterRef('body_part'),
        medical_places=OuterRef('medical_place'),
    ).values(
        f'body_part',
    )
    LocalProcedure.objects.annotate(
        treatments_count = Subquery(related_treatments.annotate(count=Count('pk')).values('count'),
        treatments_count = Subquery(related_treatments.filter(created__gt=now()).annotate(count=Count('pk')).values('count'),
    )

, но это решение действительно выполняет подзапросы, в то время как объединение этих двух таблиц (при написании необработанного запроса) происходит намного быстрее.

Любая помощь приветствуется.

Частично работающее решение (в конце отмечен как принятый)

Ответ, размещенный здесь @ruddra, был действительно полезным, но не полностью удовлетворяет мою потребность. Я знаю, что у меня есть связь между LocalProcedure и объектом Treatment через поле medical_place, но это означает, что в запросе будет другое, совершенно ненужное предложение соединения ...

Что касается людей, которые ищут способ ввести отношения в их модели без ForeignKey - есть то, что называется ForeignObject и может использоваться для создания отношений между двумя объектами с использованием любых полей.

1 Ответ

1 голос
/ 03 апреля 2020

Вероятно, это было бы намного проще:

from django.db.models import Count, F, Q

LocalProcedure.objects.annotate(
    treatments_count=Count(
        'medical_places__treatments',
        filter=Q(body_part=F('body_part'))
    ),
    treatments_count_x=Count(
        'medical_places__treatments',
        filter=Q(body_part=F('body_part'))|Q(created_gt=now())
    )
)

Здесь я просто считаю с фильтром на основе conditional expression.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...