【问题标题】:Django ORM query join unrelated tables on two fieldsDjango ORM 查询在两个字段上连接不相关的表
【发布时间】:2020-07-15 07:52:22
【问题描述】:

问题

我正在编写一个程序,在该程序中记录在不同医疗场所对患者进行的治疗。每次治疗都是针对特定身体部位进行的,每个医疗场所都可以定义自己的方式来命名这些身体部位。

我的模型如下所示:

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 天前(治疗模型创建了我没有创建的日期时间字段 显示在这里)

到目前为止我尝试过的解决方案

我可以在使用子查询时检索带注释的 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 在这里发布的答案确实很有帮助,但不能完全满足我的需要。我知道我通过 medical_place 字段在 LocalProcedure 和 Treatment 对象之间建立了关系,但这意味着查询将有另一个完全不必要的连接子句...

对于那些想在没有 ForeignKey 的情况下向模型引入关系的方法的人 - 有一种叫做 ForeignObject 的东西,可用于使用任何字段在两个对象之间创建关系。

【问题讨论】:

    标签: python django postgresql


    【解决方案1】:

    这可能会简单得多:

    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 的过滤器来计算。

    【讨论】:

    • 谢谢,我会尽快尝试。正如我所看到的,您使用medical_place 表作为这两个表的共同点。如果我想在 LocalProcedure 类中省略它怎么办?你还能为我提供这样的解决方案吗?非常感谢您的帮助。
    • 我不认为没有medical_place 会起作用,我的意思是如果没有关系,那么 Count 将不起作用。
    猜你喜欢
    • 2012-10-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多