【问题标题】:Can a Django Queryset be created to do this complex query?可以创建一个 Django 查询集来执行这个复杂的查询吗?
【发布时间】:2015-12-14 16:58:53
【问题描述】:

假设我有以下 Django 类:

class MyModel(models.Model):
    a = models.IntegerField()
    created_ts = models.DateTimeField(default=datetime.utcnow, editable=False)

    def __str__(self):
        return "<%s %s>" % (
            self.__class__.__name__,
            "; ".join(
                [
                    "ID: %s" % self.pk,
                    "a: %s" % self.a,
                    "created_ts: %s" % self.created_ts,
                ]
            )
        )

我想为a 的每个不同值找到MyModel 和最新created_ts 的实例。我可以用一个 QuerySet 做到这一点吗?如果是这样,那 QuerySet 是什么?如果没有,获得该结果的最有效方法是什么?

最后,我想要 Integer/MyModel-Instance 对。答案应该大概是这样的:

{
    1: <MyModel ID: 1; a: 1; created_ts: 2004-11-08 06:01:00>,
    5: <MyModel ID: 2; a: 5; created_ts: 2004-11-05 08:01:32>,
    3: <MyModel ID: 3; a: 3; created_ts: 2004-11-04 11:01:42>,
    0: <MyModel ID: 4; a: 0; created_ts: 2004-11-03 06:12:10>,
}

【问题讨论】:

  • 你使用什么数据库后端? MySQL 不支持按字段区分(PostgreSQL 确实支持)。据我所知,不使用原始 SQL 就没有“直截了当”的方式来做你想做的事。
  • 后端是mysql。是的,它不支持“按字段区分”。解决方法是什么?如有必要,我宁愿执行多个查询而不是编写原始 SQL。

标签: python mysql django django-queryset


【解决方案1】:

您的问题与您之前的问题几乎完全相同:How to make Django Queryset that selects records with max value within a group

因此,我将使用我以前的proposed solution 的一部分来回答:

MyClass.objects.filter(
    created_ts__in=MyClass.objects.values(
        "a"
    ).annotate(
        created_ts=models.Max(
            "created_ts"
        )
    ).values_list("created_ts", flat=True)
)

请注意,这只需要一个 SQL 请求,您可以通过在查询前后打印 len(django.db.connection.queries) 看到。

但是,请注意,后一种解决方案仅在您的 created_ts 属性被保证是唯一的情况下才有效,这可能不是您的情况。

【讨论】:

    【解决方案2】:

    来自https://docs.djangoproject.com/en/1.8/ref/models/querysets/#queryset-api,由于查询集的结果是一个查询集,你应该能够像这样链接:

    MyModel.objects.order_by('created_ts').distinct('a')

    【讨论】:

      【解决方案3】:

      如果您在 Postgres 上,这将起作用。如果您使用的是 MySQL 或 sqlite,则无法使用。

      MyModel.objects.order_by('a', '-created_ts').distinct('a')
      

      编辑:哎呀,刚刚看到你在 MySQL 上。

      这会对你有所帮助

      from django.db.models import Count, Max
      MyModel.objects.values('a').annotate(count=Count("a"),latest_date=Max('created_ts'))
      

      表格中的数据

          a              created_ts
          -             -----------
          1 2015-09-08 20:05:51.144321+00:00
          1 2015-09-08 20:08:40.687936+00:00
          3 2015-09-08 20:08:58.472077+00:00
          2 2015-09-08 20:09:08.493748+00:00
          2 2015-09-08 20:10:20.906069+00:00
      

      输出

      [
          {'count': 2, 'latest_date': datetime.datetime(2015, 9, 8, 20, 8, 40, 687936, tzinfo=<UTC>), 'a': 1},
          {'count': 2, 'latest_date': datetime.datetime(2015, 9, 8, 20, 10, 20, 906069, tzinfo=<UTC>), 'a': 2},
          {'count': 1, 'latest_date': datetime.datetime(2015, 9, 8, 20, 8, 58, 472077, tzinfo=<UTC>), 'a': 3}
      ]
      

      【讨论】:

      • 有趣的是,这几乎是 stackoverflow.com/a/32466750/356528 的复制品
      • 我就是从那里得到它的。如果你在那里看,你会发现我用另一种方式做了一些工作,使用蛮力 python,直到我发现了这种方式。
      • 在您这样做时添加指向原始解决方案的链接是公平的。
      【解决方案4】:

      不是最直接的答案,但希望对您有所帮助:

      那么你可以使用raw queries

      MyModel.objects.raw("SELECT * FROM mymodel main INNER JOIN (SELECT max(created_ts) as max_ts, a FROM mymodel GROUP BY a) sub on main.a = sub.a  AND main.created_ts = sub.max_ts")
      

      我自己没有运行查询,所以它可能有语法错误,但你明白了。

      【讨论】:

        【解决方案5】:

        不确定如何使用单个查询集,但如果您可以不使用 raw 为代价进行更多查询,您可以这样做

        from django.db.models import Max
        max_ts_queryset = MyModel.objects.values('a').order_by('a').annotate(max_ts=Max('created_ts'))
        

        要获得 a 的每个值的最大 ts,然后用类似的东西循环它

        final_list = {}
        for obj in max_ts_queryset:
            final_list[obj['a']] = MyModel.objects.get(a=obj['a'], created_ts=obj['max_ts']
        
        return final_list
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2016-05-11
          • 1970-01-01
          • 1970-01-01
          • 2022-06-14
          • 2014-12-22
          相关资源
          最近更新 更多