【问题标题】:Django ORM filter multiple fields using 'IN' statementDjango ORM 使用“IN”语句过滤多个字段
【发布时间】:2020-06-06 00:39:32
【问题描述】:

所以我在 Django 中有以下模型:

class MemberLoyalty(models.Model):
    date_time = models.DateField(primary_key=True)
    member = models.ForeignKey(Member, models.DO_NOTHING)
    loyalty_value = models.IntegerField()

我的目标是让所有元组按日期最近的成员分组。有很多方法可以做到这一点,其中一种是使用子查询,该查询由具有 max date_time 的成员分组,并使用其结果过滤 member_loyalty。该解决方案的工作sql如下:

SELECT 
    *
FROM
    member_loyalty
WHERE
    (date_time , member_id) IN (SELECT 
            max(date_time), member_id
        FROM
            member_loyalty
        GROUP BY member_id);

另一种方法是加入子查询。

我如何在 django 查询中翻译这个?我找不到使用 IN 过滤两个字段的方法,也找不到使用特定 ON 语句加入子查询的方法。

我试过了:

cls.objects.values('member_id', 'loyalty_value').annotate(latest_date=Max('date_time'))

但它开始按忠诚度值分组。

也尝试构建子查询,但找不到如何加入它或在过滤器上使用它:

subquery = cls.objects.values('member_id').annotate(max_date=Max('date_time'))

另外,我使用的是 Mysql,所以我不能使用 .distinct('param') 方法。

【问题讨论】:

    标签: sql django python-3.x django-orm


    【解决方案1】:

    这是一个典型的greatest-per-group 查询。 Stack-overflow 甚至有一个tag

    我相信使用最新版本的 Django 最有效的方法是通过window query。类似的东西应该可以解决问题。

        MemberLoyalty.objects.all().annotate(my_max=Window(
            expression=Max('date_time'),
            partition_by=F('member')
        )).filter(my_max=F('date_time'))
    

    更新:这实际上是行不通的,因为Window 注释不是filterable。我认为为了过滤窗口注释,您需要将其包装在Subquery 中,但使用Subquery,您实际上没有义务使用Window 函数,还有另一种方法可以做到这一点,这是我的下一个例子。

    如果 MySQL 或 Django 不支持窗口查询,那么 Subquery 就会发挥作用。

    MemberLoyalty.objects.filter(
        date_time=Subquery(
            (MemberLoyalty.objects
                .filter(member=OuterRef('member'))
                .values('member')
                .annotate(max_date=Max('date_time'))
                .values('max_date')[:1]
            )
        )
    )
    

    如果事件Subqueries 不可用(Django 1.11 之前),那么这也应该有效:

    MemberLoyalty.objects.annotate(
        max_date=Max('member__memberloyalty_set__date_time')
    ).filter(max_date=F('date_time'))
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-05-04
      • 2018-11-06
      • 1970-01-01
      • 2021-10-23
      • 2019-07-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多