Joh*_*etz 5 django django-models django-queryset
假设我有以下 Django 模型:
class Team(models.Model):
name = models.CharField(max_length=255)
created_at = models.DateTimeField(auto_now_add=True)
Run Code Online (Sandbox Code Playgroud)
我想编写一个查询来获取每个团队名称的最新 N 条记录。
如果 N=1,查询非常简单(假设我使用 postgres,因为它是唯一支持的数据库distinct(*fields)):
Team.objects.order_by("name", "-created_at").distinct("name")
Run Code Online (Sandbox Code Playgroud)
如果 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=Subquery(top_3_per_team_name.values("id"))
)
Run Code Online (Sandbox Code Playgroud)
尽管这可能有点慢,所以请确保您已设置索引。
另请注意,理想情况下这可以通过使用Window..[Django-doc]函数使用DenseRank..[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
Run Code Online (Sandbox Code Playgroud)
有了上面的内容,你就得到:
NotSupportedError: Window is disallowed in the filter clause.
Run Code Online (Sandbox Code Playgroud)
但有计划在 Django 4.2 上支持这一点,因此理论上,一旦发布,上述内容就应该可以工作。
| 归档时间: |
|
| 查看次数: |
450 次 |
| 最近记录: |