【问题标题】:Django prefetch_related - filter with or-clause from different tablesDjango prefetch_related - 使用来自不同表的 or 子句进行过滤
【发布时间】:2016-09-16 07:32:42
【问题描述】:

我有一个简单关系的模型

class Tasks(models.Model):
   initiator = models.ForeignKey(User, on_delete = models.CASCADE)

class TaskResponsiblePeople(models.Model):
    task = models.ForeignKey('Tasks')
    auth_user = models.ForeignKey(User)

我需要编写一个类似的 SQL 查询,如下所示:

select a.initiator, b.auth_user 
from Tasks a
inner join TaskResponsiblePeople b
on TaskResponsiblePeople.task_id = task.id 
where Tasks.initiator = 'value A' OR TaskResponsiblePeople.auth_user = 'value B'

问题是 OR 语句处理两个不同的表,我不知道正确的 Django 语法来模仿上述原始 SQL 查询。请帮帮我!

更新 1

根据下面的答案,我使用以下代码:

people = TaskResponsiblePeople.objects.filter(Q(task__initiator = request.user.id)|Q(auth_user = request.user.id)).select_related('auth_user')
print people.query
# The result of the print copy-pasted from console
# SELECT * FROM `task_responsible_people` 
# LEFT OUTER JOIN `tasks` ON (`task_responsible_people`.`task_id` = `tasks`.`id`)
# LEFT OUTER JOIN `auth_user` T4 
# ON (`task_responsible_people`.`auth_user_id` = T4.`id`) 
# WHERE (`tasks`.`initiator_id` = 7 OR    
# 'task_responsible_people`.`auth_user_id` = 7)

tasks = Tasks.objects.prefetch_related(
              Prefetch('task_responsible_people', queryset=people, to_attr='people'))

但是,在最终结果集中,我仍然可以看到发起者和 auth_user 都不等于 request.user 的记录(在这种情况下等于 7) 我避免使用“.values”,因为可能需要将查询集序列化并将其转换为 json。

【问题讨论】:

  • 而且,您是否希望在结果查询集中同时拥有 TasksTaskResponsiblePeople
  • 是的,完全正确。我已经编辑了上面的问题以反映这一点。
  • 看看我的回答。它应该生成正确的查询。

标签: django prefetch


【解决方案1】:

如果您只想要那些特定的列,我认为您可以这样做:

from django.db.models import Q

qs = Tasks.objects.filter(Q(initiator=userA) | Q(taskresponsiblepeople__auth_user=userB))\
          .values('initiator', 'taskresponsiblepeople__auth_user')

要检查生成的查询,您可以查看:

print(qs.query)

我的数据库中没有模型,但它应该会生成类似于以下的查询:

SELECT "tasks"."initiator_id", "taskresponsiblepeople"."auth_user_id" 
    FROM "tasks" LEFT OUTER JOIN "taskresponsiblepeople" 
    ON ( "tasks"."id" = "taskresponsiblepeople"."tasks_id" ) 
    WHERE  ("tasks"."initiator_id" = userA_id 
            OR "taskresponsiblepeople"."auth_user_id" = userB_id))

【讨论】:

  • 好吧!您正在随着时间的推移修改问题的范围,而您发布的 SQL 查询的范围更小。如果你看我上面的第一条评论,我特别问你是否想要对象本身?
  • 我只想通过filter、select_related或者prefetch_related的组合来获取查询,不使用values。
  • 太棒了。我刚刚删除了你答案中的值部分,得到了我想要的。
  • tasks = Tasks.objects.filter(Q(initiator=request.user) | Q(task_responsible_people__auth_user=request.user)).prefetch_related('task_responsible_people').all()
猜你喜欢
  • 1970-01-01
  • 2012-12-04
  • 2021-10-16
  • 1970-01-01
  • 2012-06-10
  • 1970-01-01
  • 2013-09-25
  • 2015-08-23
  • 2019-02-08
相关资源
最近更新 更多