Django QuerySet exclude多数据:筛选不在薪资记录中的员工
嘿,我来帮你搞定这个问题!先把你的数据库结构理清楚,再看看代码出了什么问题,最后给你正确的实现方式。
你的数据库结构
periode表(周期表)
| id | from | to |
|---|---|---|
| 1 | 2018-04-12 | 2018-05-11 |
| 2 | 2018-05-12 | 2018-06-11 |
foo表(员工表)
| id | name |
|---|---|
| 1 | John |
| 2 | Doe |
| 3 | Trodi |
| 4 | son |
| 5 | Alex |
bar表(薪资记录表)
| id | employee_id | periode_id |
|---|---|---|
| 1 | 1 | 1 |
| 2 | 2 | 1 |
| 3 | 1 | 2 |
| 4 | 3 | 1 |
你的问题
你想筛选出在periode_id=1的薪资记录里没有出现的员工,但你写的代码执行失败了:
queryset=Bar.objects.all().filter(periode_id=1) result=Foo.objects.exclude(id=queryset)
问题出在哪?
这段代码的问题很明显:queryset是一堆Bar对象的集合,而你试图把整个集合直接赋值给id进行比较——Django完全不知道怎么把一个对象集合和单个员工ID匹配,类型不匹配肯定会报错。
我们需要先从bar表里提取出有薪资记录的员工ID列表,再用这个列表去排除对应的员工。
正确的实现方式
方式1:直观易懂的写法(适合小数据量)
先把目标周期内有薪资记录的员工ID提取出来,再排除这些ID的员工:
# 提取periode_id=1的薪资记录对应的所有员工ID,得到一个纯整数列表 employee_ids_with_salary = Bar.objects.filter(periode_id=1).values_list('employee_id', flat=True) # 排除这些ID,得到没有薪资记录的员工 result = Foo.objects.exclude(id__in=employee_ids_with_salary)
这里values_list('employee_id', flat=True)会返回[1,2,3]这样的列表,刚好可以和id__in配合使用,告诉Django“排除ID在这个列表里的员工”。
方式2:性能更优的子查询(适合大数据量)
如果你的数据量比较大,用子查询可以减少一次数据库查询,直接在数据库层面完成筛选:
from django.db.models import Subquery # 构建子查询,获取目标周期内有薪资记录的员工ID salary_employee_subquery = Bar.objects.filter(periode_id=1).values('employee_id') # 用Subquery把子查询结果传入exclude条件 result = Foo.objects.exclude(id__in=Subquery(salary_employee_subquery))
验证结果
根据你的数据库数据,periode_id=1的薪资记录里有员工1、2、3,所以最终result会包含id为4(son)和5(Alex)的员工,完全符合你的需求。
内容的提问来源于stack exchange,提问作者Budi Gunawan
相关产品推荐
相关产品推荐

