预取软删除模型多对多关联对象时如何避免重复?
问题解决:去除
enabled_accounts中的重复有效账户 问题原因
当用户与同一个账户之间存在多条UserAccount记录(一条已删除、一条未删除)时,原查询的子过滤逻辑虽然能筛选出该有效账户,但Django在处理多对多关联的prefetch_related时,会因关联表中存在多条记录(即使部分已被过滤),导致同一个账户被重复添加到enabled_accounts列表中。
解决方案
方案一:给账户查询集添加去重
直接在原查询逻辑的基础上,给Account查询集添加distinct(),确保每个账户仅被返回一次:
class UserQuerySet(models.QuerySet): def prefetch_accounts_for_api(self, request): accounts_qs = Account.objects.all() user_account_qs = UserAccount.objects.filter( user=request.user, account_id=OuterRef('pk'), deleted__isnull=True )[:1] # 添加distinct()去重,避免同一个账户被多次匹配 accounts_qs = accounts_qs.filter( useraccount=user_account_qs ).distinct() return self.prefetch_related(Prefetch( 'accounts', queryset=accounts_qs, to_attr='enabled_accounts' ))
方案二:从有效关联记录出发构建查询集
换一种更直观的方式:先筛选出当前用户未删除的UserAccount记录,提取去重后的账户ID,再基于这些ID获取账户列表,从根源避免重复:
class UserQuerySet(models.QuerySet): def prefetch_accounts_for_api(self, request): # 获取当前用户所有未删除的关联账户ID并去重 valid_account_ids = UserAccount.objects.filter( user=request.user, deleted__isnull=True ).values_list('account_id', flat=True).distinct() # 基于去重后的ID筛选账户 accounts_qs = Account.objects.filter(id__in=valid_account_ids) return self.prefetch_related(Prefetch( 'accounts', queryset=accounts_qs, to_attr='enabled_accounts' ))
两种方案都能确保enabled_accounts中仅保留每个有效账户的唯一实例,方案二更直接易懂,推荐使用。
内容的提问来源于stack exchange,提问作者Apyff
相关产品推荐
相关产品推荐

