【问题标题】:Django orm get latest for each groupDjango orm 为每个组获取最新信息
【发布时间】:2013-11-24 06:56:21
【问题描述】:

我正在将 Django 1.6 与 Mysql 一起使用。

我有这些模型:

class Student(models.Model):
     username = models.CharField(max_length=200, unique = True)

class Score(models.Model)
     student = models.ForeignKey(Student)
     date = models.DateTimeField()
     score = models.IntegerField()

我想获取每个学生的最新成绩记录。
我试过了:

Score.objects.values('student').annotate(latest_date=Max('date'))

和:

Score.objects.values('student__username').annotate(latest_date=Max('date'))

Django ORM - Get the latest record for the group 所述 但它没有帮助。

【问题讨论】:

    标签: python django django-queryset django-orm


    【解决方案1】:

    这是一个使用Greatest 和辅助annotate 的示例。我正面临annotate 返回重复记录(示例)的问题,但last_message_time Greatest 注释导致重复。

    qs = (
                Example.objects.filter(
                    Q(xyz=xyz)
                )
                .exclude(
                     Q(zzz=zzz)
                )
                # this annotation causes duplicate Examples in the qs
                # and distinct doesn't work, as expected
                # .distinct('id') 
                .annotate(
                    last_message_time=Greatest(
                        "comments__created",
                        "files__owner_files__created",
                    )
                )
                # so this second annotation selects the Max value of the various Greatest
                .annotate(
                    last_message_time=Max(
                        "last_message_time"
                    )
                )
                .order_by("-last_message_time")
        )
    
    

    参考:

    【讨论】:

      【解决方案2】:

      这应该适用于 Django 1.2+ 和 MySQL:

      Score.objects.annotate(
        max_date=Max('student__score__date')
      ).filter(
        date=F('max_date')
      )
      

      【讨论】:

      • 这需要很长时间才能运行!
      • @emisilva 我不相信这种数据结构和数据库后端有更有效的方法。如果您需要它更快 - 添加索引或重构数据结构。
      • 如果你有很多分数,这真的很慢。
      • 仅作记录:此解决方案生成 N^2 行并过滤它们(N=Score count),如果 N 大于数千,则无用。最好做一个 O(N) 查询并找到每个学生的max_date,然后发出另一个查询确实得到实际的Score 对象。或者如果您在 Postgres 上,请使用 @Rohan 的答案。
      【解决方案3】:

      如果你的数据库是支持distinct()的postgres,你可以试试

      Score.objects.order_by('student__username', '-date').distinct('student__username')
      

      【讨论】:

      • 不幸的是我正在使用 mysql
      • 您在尝试聚合此类查询时可能会遇到问题:NotImplementedError: aggregate() + distinct(fields) not implemented.
      • 重要的是不要在这个查询集上调用.update() 之类的东西。从 1.11 开始,这将默默地做错事。
      • 如果我在 order_by 前加上 filter_by 前缀,这是否也有效?
      • @NirIzr 是的,将过滤器放在order_by() 之前,它应该可以按预期工作。
      【解决方案4】:

      我相信这会给你学生和数据

      Score.objects.values('student').annotate(latest_date=Max('date'))
      

      如果您想要完整的 Score 记录,您似乎必须使用原始 SQL 查询:Filtering Django Query by the Record with the Maximum Column Value

      【讨论】:

        猜你喜欢
        • 2019-10-11
        • 1970-01-01
        • 1970-01-01
        • 2018-06-14
        • 2013-07-27
        • 1970-01-01
        • 2017-09-27
        • 1970-01-01
        相关资源
        最近更新 更多