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

Django中order_by('datetime')不生效,distinct与排序冲突问题求助

解决Django中按多字段去重后按其他字段排序的冲突问题

需要从Chat模型中获取按phone_number和agent字段去重的记录(每个组合取最新datetime的那条),并最终按datetime降序排序,但直接使用distinct和排序会触发PostgreSQL的SELECT DISTINCT ON expressions must match initial ORDER BY expressions错误,且原有代码的结果排序不符合预期。

模型定义:

class Chat(m.Model):
    agent = m.ForeignKey(
        Agent, on_delete=m.DO_NOTHING, null=False)
    phone_number = m.CharField(max_length=100)
    datetime = DateTimeUTCField(default=datetime.now)

方案1:子查询+注解过滤(推荐)

利用Subquery获取每个(phone_number, agent)组的最新datetime,再过滤出对应记录并排序:

from django.db.models import Subquery, OuterRef, F

# 子查询:获取当前组的最新datetime
latest_datetime_sub = Chat.objects.filter(
    phone_number=OuterRef('phone_number'),
    agent=OuterRef('agent')
).order_by('-datetime').values('datetime')[:1]

# 注解最新时间,过滤出匹配的记录,再按datetime排序
chats = Chat.objects.annotate(
    latest_dt=Subquery(latest_datetime_sub)
).filter(datetime=F('latest_dt')).order_by('-datetime')

for chat in chats:
    print(chat.datetime)

方案2:分组获取最新记录ID后过滤

先通过分组聚合得到每个组最新记录的ID,再根据ID查询并排序:

from django.db.models import Max

# 分组获取每个(phone_number, agent)组的最新记录ID
latest_chat_ids = Chat.objects.values('phone_number', 'agent').annotate(
    max_datetime=Max('datetime')
).values_list('id', flat=True)

# 过滤ID并按datetime降序排序
chats = Chat.objects.filter(id__in=latest_chat_ids).order_by('-datetime')

为什么原有代码不生效?

PostgreSQL的DISTINCT ON语法要求初始ORDER BY的前几个字段必须完全匹配DISTINCT ON的字段,所以无法在distinct后直接添加其他排序规则。原有代码order_by('phone_number', 'agent', '-datetime').distinct('phone_number', 'agent')虽然能拿到每个组的最新记录,但结果集的排序是按phone_number和agent来的,不是按datetime,因此输出不符合预期。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.30 02:05:07