Django使用INNER JOIN时原始查询与ORM查询结果重复如何解决?
问题原因
- 原生SQL查询逻辑问题:你通过
Projekt.objects.raw()执行的关联查询,拼接了一对多关系的项目表和用户资料表,INNER JOIN 会为每一组「项目+关联用户」生成一条独立记录,因此一个项目关联多少个用户,就会返回多少条重复的项目数据,和你预期的单条项目记录不符。同时你的SQL字段包含了用户维度的属性,返回结果本身就是用户粒度的,自然条数等于项目下的用户数量。 - ORM查询逻辑错误:你编写的
Profile.objects.filter(projekt=profile.projekt)本质是查询指定项目下的所有用户资料,返回结果条数天然等于该项目的用户数,和你要查询项目对象的需求不匹配。
解决方法
分不同需求场景给出方案:
场景1:仅需获取当前用户所属的单个项目信息
直接通过外键关联取值即可,无需额外过滤查询:
profile = Profile.objects.get(user=request.user) # 直接取Profile关联的Projekt外键对象即可,不会产生重复 projekt = profile.projekt
场景2:需要获取项目列表,同时关联查询每个项目下的用户数据
使用Django ORM的prefetch_related预加载关联的用户资料,不会产生JOIN导致的重复记录:
# 预加载每个项目关联的所有Profile数据 projekt_list = Projekt.objects.all().prefetch_related('profile_set') # 遍历项目不会重复,单个项目下可单独取关联用户 for projekt in projekt_list: print(f"项目名:{projekt.projekt}") # 该项目下的所有用户资料 for profile in projekt.profile_set.all(): print(f"关联用户:{profile.user.last_name} {profile.user.first_name}")
场景3:必须使用原生SQL查询,需要对结果去重
PostgreSQL环境可使用DISTINCT ON按项目ID去重:
SELECT DISTINCT ON (stressz_projekt.id) projekt_id, stressz_projekt.projekt, last_name, first_name, stressz_profile.id, stressz_profile.user_id, auth_user.id FROM stressz_profile INNER JOIN stressz_projekt ON stressz_projekt.id = stressz_profile.projekt_id INNER JOIN auth_user ON auth_user.id = stressz_profile.user_id
MySQL环境可使用GROUP BY按项目维度聚合:
SELECT projekt_id, stressz_projekt.projekt FROM stressz_profile INNER JOIN stressz_projekt ON stressz_projekt.id = stressz_profile.projekt_id INNER JOIN auth_user ON auth_user.id = stressz_profile.user_id GROUP BY stressz_projekt.id, stressz_projekt.projekt
内容的提问来源于stack exchange,提问作者RlM
相关产品推荐
相关产品推荐

