Django 对同一模型的多个外键排除过滤器
Django exclude filter on multiple foreign keys to the same model
我正在尝试根据多个字段的嵌套包含来过滤查询集。一个字段有效,但另一个字段无效
这是我的模型的简短版本:
class Shift(models.Model):
users = models.ManyToManyField(User, blank=True)
potential_users = models.ManyToManyField(User, blank=True, related_name='potential_users')
我想对其进行过滤,使用户不在用户和潜在用户属性中。我在查询集上使用这个排除函数:
queryset = Shift.objects.exclude(users__id__contains=self.request.user.id, potential_users__id__contains=self.request.user.id)
我也试过链接排除:
queryset = Shift.objects.exclude(users__id__contains=self.request.user.id).exclude(potential_users__id__contains=self.request.user.id)
当用户处于轮班的用户属性中时,我没有得到任何预期的班次。但是当用户处于潜在用户属性时,我确实得到了转变。
在潜在用户中
当用户处于 potential_users 时。我 运行 在创建查询集后在我的调试执行器中这样做:
self.request.user.id == queryset[0].potential_users.all()[0].id
我得到 True
这应该是不可能的,因为它在排除中。我怀疑它与引用相同外键模型的两个属性有关
在用户中
当我在 users
属性中对用户进行相同的过滤时,我得到了一个超出范围的索引,这很好,因为这意味着它没有检索到班次。这是预期的。这是支票我运行:
self.request.user.id == queryset[0].users.all()[0].id
查询
这是完整的查询集:
Shift.objects.annotate(amount_users=Count('users')).filter(show_on_market=True, amount_users__lt=F('amount_of_employees'), start__week=self.request.query_params['week'], start__year=self.request.query_params['year'], start__gt=datetime.datetime.now()).exclude(users__id__contains=self.request.user.id, potential_users__id__contains=self.request.user.id)
这是django 运行s
的查询
SELECT `shift_shift`.`id`, `shift_shift`.`title`, `shift_shift`.`start`, `shift_shift`.`end`, `shift_shift`.`amount_of_minutes`, `shift_shift`.`amount_of_employees`, `shift_shift`.`employment_agency_id`, `shift_shift`.`client_id`, `shift_shift`.`store_id`, `shift_shift`.`description`, `shift_shift`.`show_on_market`, `shift_shift`.`repeat_shift_id`, `shift_shift`.`is_repeat`, COUNT(`shift_shift_users`.`user_id`) AS `amount_users` FROM `shift_shift` LEFT OUTER JOIN `shift_shift_users` ON (`shift_shift`.`id` = `shift_shift_users`.`shift_id`) WHERE (`shift_shift`.`is_repeat` = False AND `shift_shift`.`show_on_market` = True AND `shift_shift`.`start` > 2019-02-11 14:54:28.462725 AND WEEK(`shift_shift`.`start`, 3) = 7 AND `shift_shift`.`start` BETWEEN 2019-01-01 00:00:00 AND 2019-12-31 23:59:59.999999 AND NOT (`shift_shift`.`id` IN (SELECT U1.`shift_id` FROM `shift_shift_users` U1 WHERE U1.`user_id` LIKE BINARY %df6c3f22-b3c2-40af-81c9-9a689083bd15%)) AND NOT (`shift_shift`.`id` IN (SELECT U1.`shift_id` FROM `shift_shift_potential_users` U1 WHERE U1.`user_id` LIKE BINARY %df6c3f22-b3c2-40af-81c9-9a689083bd15%))) GROUP BY `shift_shift`.`id`, `shift_shift`.`amount_of_employees` HAVING COUNT(`shift_shift_users`.`user_id`) < (`shift_shift`.`amount_of_employees`) ORDER BY `shift_shift`.`start` ASC
有谁知道我做错了什么。
如果我正确理解你的意图,那就是:
not (in users) and not (in potential users)
可以更改为:not (in users or in potential users)
,您应该使用排除 chaining 而不是单独调用,即:
queryset = Shift.objects.exclude(
users__id__contains=self.request.user.id,
).exclude(
potential_users__id__contains=self.request.user.id
)
您的问题的简单答案是:
from django.db.models import Q
user_id = self.request.user.id
queryset = Shift.objects.exclude(
Q(users__id__contains=user_id) | Q(potential_users__id__contains=user_id
)
试试这个:
from django.db.models import Q
queryset = Shift.objects.exclude(Q(users__id__in=[self.request.user.id]) & Q(potential_users__id__in=[self.request.user.id]))
- 仅将
__contains
用于字符串检查。尝试 __in=[Array]
语法来检查元素是否存在于多边。
- 使用 Q() 可以组合多个查询(
|
=OR,&
=AND)
- 您不应链接多个 filter()/exclude(),因为这样计算效率较低。
我正在尝试根据多个字段的嵌套包含来过滤查询集。一个字段有效,但另一个字段无效
这是我的模型的简短版本:
class Shift(models.Model):
users = models.ManyToManyField(User, blank=True)
potential_users = models.ManyToManyField(User, blank=True, related_name='potential_users')
我想对其进行过滤,使用户不在用户和潜在用户属性中。我在查询集上使用这个排除函数:
queryset = Shift.objects.exclude(users__id__contains=self.request.user.id, potential_users__id__contains=self.request.user.id)
我也试过链接排除:
queryset = Shift.objects.exclude(users__id__contains=self.request.user.id).exclude(potential_users__id__contains=self.request.user.id)
当用户处于轮班的用户属性中时,我没有得到任何预期的班次。但是当用户处于潜在用户属性时,我确实得到了转变。
在潜在用户中
当用户处于 potential_users 时。我 运行 在创建查询集后在我的调试执行器中这样做:
self.request.user.id == queryset[0].potential_users.all()[0].id
我得到 True
这应该是不可能的,因为它在排除中。我怀疑它与引用相同外键模型的两个属性有关
在用户中
当我在 users
属性中对用户进行相同的过滤时,我得到了一个超出范围的索引,这很好,因为这意味着它没有检索到班次。这是预期的。这是支票我运行:
self.request.user.id == queryset[0].users.all()[0].id
查询
这是完整的查询集:
Shift.objects.annotate(amount_users=Count('users')).filter(show_on_market=True, amount_users__lt=F('amount_of_employees'), start__week=self.request.query_params['week'], start__year=self.request.query_params['year'], start__gt=datetime.datetime.now()).exclude(users__id__contains=self.request.user.id, potential_users__id__contains=self.request.user.id)
这是django 运行s
的查询SELECT `shift_shift`.`id`, `shift_shift`.`title`, `shift_shift`.`start`, `shift_shift`.`end`, `shift_shift`.`amount_of_minutes`, `shift_shift`.`amount_of_employees`, `shift_shift`.`employment_agency_id`, `shift_shift`.`client_id`, `shift_shift`.`store_id`, `shift_shift`.`description`, `shift_shift`.`show_on_market`, `shift_shift`.`repeat_shift_id`, `shift_shift`.`is_repeat`, COUNT(`shift_shift_users`.`user_id`) AS `amount_users` FROM `shift_shift` LEFT OUTER JOIN `shift_shift_users` ON (`shift_shift`.`id` = `shift_shift_users`.`shift_id`) WHERE (`shift_shift`.`is_repeat` = False AND `shift_shift`.`show_on_market` = True AND `shift_shift`.`start` > 2019-02-11 14:54:28.462725 AND WEEK(`shift_shift`.`start`, 3) = 7 AND `shift_shift`.`start` BETWEEN 2019-01-01 00:00:00 AND 2019-12-31 23:59:59.999999 AND NOT (`shift_shift`.`id` IN (SELECT U1.`shift_id` FROM `shift_shift_users` U1 WHERE U1.`user_id` LIKE BINARY %df6c3f22-b3c2-40af-81c9-9a689083bd15%)) AND NOT (`shift_shift`.`id` IN (SELECT U1.`shift_id` FROM `shift_shift_potential_users` U1 WHERE U1.`user_id` LIKE BINARY %df6c3f22-b3c2-40af-81c9-9a689083bd15%))) GROUP BY `shift_shift`.`id`, `shift_shift`.`amount_of_employees` HAVING COUNT(`shift_shift_users`.`user_id`) < (`shift_shift`.`amount_of_employees`) ORDER BY `shift_shift`.`start` ASC
有谁知道我做错了什么。
如果我正确理解你的意图,那就是:
not (in users) and not (in potential users)
可以更改为:not (in users or in potential users)
,您应该使用排除 chaining 而不是单独调用,即:
queryset = Shift.objects.exclude(
users__id__contains=self.request.user.id,
).exclude(
potential_users__id__contains=self.request.user.id
)
您的问题的简单答案是:
from django.db.models import Q
user_id = self.request.user.id
queryset = Shift.objects.exclude(
Q(users__id__contains=user_id) | Q(potential_users__id__contains=user_id
)
试试这个:
from django.db.models import Q
queryset = Shift.objects.exclude(Q(users__id__in=[self.request.user.id]) & Q(potential_users__id__in=[self.request.user.id]))
- 仅将
__contains
用于字符串检查。尝试__in=[Array]
语法来检查元素是否存在于多边。 - 使用 Q() 可以组合多个查询(
|
=OR,&
=AND) - 您不应链接多个 filter()/exclude(),因为这样计算效率较低。