假设我有以下Django模型:

class Team(models.Model):
    name = models.CharField(max_length=255)
    created_at = models.DateTimeField(auto_now_add=True)

我想编写一个查询来获取每个团队名称的最新N个记录.

如果N=1,则查询非常简单(假设我使用的是postgres,因为它是唯一支持distinct(*fields)的数据库):

Team.objects.order_by("name", "-created_at").distinct("name")

如果N大于1(比方说3),那么它就变得棘手了.我如何用Django编写这个查询?

推荐答案

不知道怎么才能让每个团队都有重复的名字,因为你有unique=True个.但是,如果您计划删除它以支持非唯一名称,则可以使用如下所示的子查询:

top_3_per_team_name = Team.objects.filter(
    name=OuterRef("name")
).order_by("-created_at")[:3]

Team.objects.filter(
    id__in=top_3_per_team_name.values("id")
)

虽然这可能会有点慢,但请确保您已经设置了索引.

还要注意的是,理想情况下,这可以通过使用DenseRank..[Django-doc]Window..[Django-doc]个函数来解决,但不幸的是,最新的Django版本不能在Windows上过滤:

from django.db.models import F
from django.db.models.expressions import Window
from django.db.models.functions import DenseRank

Team.objects.annotate(
    rank=Window(
        expression=DenseRank(),
        partition_by=[F('name'),],
        order_by=F('created_at').desc()
    ),
).filter(rank__in=range(1,4)) # 4 is N + 1 if N = 3

有了以上几点,你就能得到:

NotSupportedError: Window is disallowed in the filter clause.

但在Django 4.2上有一个支持这一点的计划,所以从理论上讲,一旦发布,上面的功能应该会起作用.

Django相关问答推荐

查询在对象中使用django查询与一个包含句子

DRF中是否有有效的更新有序数据的算法?

使用序列化器获取Django ORM auth_user. id数据

为什么Docker compose没有这样的文件或目录?

Django:如何 Select 没有其他项目引用的项目?

在 Django 4.1 中提交表单之前显示数据

初始填充 Django 表单

EmailBackend 用于在 Django 中通过多个 SMTP 发送邮箱

如何获得用户权限?

如果上下文中缺少变量,如何使 Django 模板引发错误

Django Facebook Connect 应用推荐

Django 基于角色的视图?

Django - 无法为具有动态 upload_to 值的 ImageField 创建迁移

__init__() 得到了一个意外的关键字参数user

如何在不同的元素上添加注释?

Table doesn't exist表不存在

django python 日期时间设置为午夜

django.db.utils.OperationalError 无法连接到服务器

Django:如何从模板中识别调用视图?

判断列表 django 模板中是否存在