You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用Django ORM获取每个用户的最新关联Post记录?

解决Django中获取每个用户最新Post且无重复用户的问题

问题分析

你当前的查询方式存在两个核心问题:

  1. select_related仅适用于一对一/多对一关联,User到Post是一对多关系,用它无法正确过滤每个用户的单条Post,导致用户重复出现。
  2. distinct('id')会按用户ID去重,但数据库会返回匹配该用户的第一条记录,关联查询时排序优先级可能被干扰,导致拿到的是最早的Post而非最新的。

以下是两种无需循环遍历、直接通过Django ORM实现的高效方案:


方案一:使用子查询(Subquery)获取最新Post

利用Subquery和OuterRef,为每个用户单独查询其最新的Post记录,再将结果关联到User查询中:

from django.db.models import Subquery, OuterRef
from .models import User, Post

# 构造子查询:筛选当前用户的最新1条Post
latest_post_subquery = Post.objects.filter(user=OuterRef('pk')).order_by('-created')[:1]

# 查询用户并附加最新Post的字段
users_with_latest_post = User.objects.annotate(
    latest_post_title=Subquery(latest_post_subquery.values('title')),
    latest_post_created=Subquery(latest_post_subquery.values('created'))
).values_list('id', 'name', 'latest_post_title', 'latest_post_created')

这种方式会在数据库层面执行关联子查询,每个用户仅返回一条记录,且确保拿到的是最新的Post。


方案二:使用窗口函数(Django 2.0+)

通过RowNumber()窗口函数,按用户分组并按Post创建时间降序排序,筛选出每个用户的第一条(最新)Post记录,再关联用户信息:

from django.db.models import Window, F
from django.db.models.functions import RowNumber
from .models import Post

# 为每个Post添加分组排序的行号,行号为1的就是该用户的最新Post
ranked_posts = Post.objects.annotate(
    rank=Window(
        expression=RowNumber(),
        partition_by=F('user_id'),  # 按用户ID分组
        order_by=F('created').desc()  # 按创建时间降序排序
    )
).filter(rank=1)

# 直接获取包含用户信息的最新Post列表(无需单独查User表)
result = ranked_posts.values_list('user__id', 'user__name', 'title', 'created')

这种方案在数据量较大时性能更优,因为所有逻辑都在数据库层面完成,避免了多次查询。


注意事项

  • 确保你的Post模型Meta类中的ordering=['-created']配置正确,这会影响子查询和窗口函数的排序逻辑。
  • 如果使用MySQL数据库,窗口函数需要MySQL 8.0及以上版本支持;子查询方式兼容大多数主流数据库(PostgreSQL、MySQL、SQLite等)。

内容的提问来源于stack exchange,提问作者danic

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.11 16:35:20