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
相关产品推荐
相关产品推荐

