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

Django:如何通过关联模型字段对QuerySet按用户ID去重

按关联模型字段对QuerySet去重的简便实现

问题回顾

你有如下模型结构:

class User(models.Model):
    group = models.ForeignKey('Group')
    # 其他字段...
class Address(models.Model):
    user = models.ForeignKey('User')
    # 其他字段...

执行addresses = Address.objects.filter(user__group__id=1).order_by('-id')得到Address的QuerySet后,希望按User ID去重,每个用户仅保留最新的Address记录,但受限于需要保留Address全字段和关联关系,无法直接用annotate或普通distinct,目前用循环遍历的方式实现,想找更简便的方法。


更简洁的ORM解决方案

这确实是Django开发中很常见的需求,不用手动循环的话,有两种更优雅的实现方式,取决于你使用的数据库:

方法一:PostgreSQL专属——distinct()指定字段

如果你用的是PostgreSQL数据库,Django支持给distinct()传入字段参数,结合排序逻辑就能实现需求:

addresses = Address.objects.filter(user__group__id=1)\
    .order_by('user__id', '-id')\
    .distinct('user__id')

逻辑说明:

  1. 先按user__id分组排序,确保同一用户的地址排在一起
  2. 再在每个用户组内按-id(ID降序,最新的地址在前)排序
  3. 最后用distinct('user__id')保留每个用户组的第一条记录,也就是该用户的最新地址

这种写法完全用ORM实现,不需要额外的Python循环,性能也更好。

方法二:跨数据库兼容——子查询筛选最新ID

如果你的项目用的是MySQL等不支持distinct指定字段的数据库,可以用子查询先找出每个用户的最新Address ID,再根据ID筛选:

from django.db.models import Subquery, OuterRef

# 子查询:获取当前用户的最新Address的ID
latest_address_subquery = Address.objects.filter(user=OuterRef('user'))\
    .order_by('-id')\
    .values('id')[:1]

# 筛选出符合条件的最新地址
addresses = Address.objects.filter(
    user__group__id=1,
    id__in=Subquery(latest_address_subquery)
).order_by('-id')

逻辑说明:

  1. 子查询会针对每个User,找到其ID最大的Address(也就是最新的那条)
  2. 主查询只保留ID在子查询结果里的Address记录,自然就实现了按用户去重且保留最新地址的效果

这种方法兼容性拉满,几乎支持所有Django兼容的数据库,同时也能完整保留Address的所有字段和与User的关联关系。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.29 08:20:21