2013-03-25 113 views
8

我正在使用Django的内置用户模型,并有一个自定义的Foo对象与外键给用户。我在寻找,选择所有用户对象和所有符合一定的约束富的对象,像这样:Django左外连接过滤器

SELECT * from auth_user LEFT OUTER JOIN "foo" ON 
(auth_user.id = foo.id AND <other criteria here>) 

我应该如何在Django做到这一点?到目前为止,我已经试过:

User.objects.filter(foo__<criteria>) 

但产生类似这样的SQL:

SELECT * from auth_user LEFT OUTER JOIN "foo" ON 
(auth_user.id = foo.id) WHERE <other criteria here> 

,并只返回有符合标准的Foo对象的用户对象。或者,我可以选择所有用户对象并为每个用户运行一个查询,但效率会大大降低。

+0

其他标准是什么?这一切仍然与'Foo'模型有关吗? – Ngenator 2013-03-25 19:31:01

+0

是的。 Foo包含一对夫妇日期字段,我只从指定的日期范围中选择Foos。 – Phobophobia 2013-03-25 22:02:16

+0

'User.objects.filter(foo__ )'应该做什么? '用户'模型中'foo'不是字段。我从来没有能够生成具有'LEFT OUTER JOIN'的查询。 – user2233706 2013-08-16 04:05:21

回答

1

如果你想的Django获取所有的User对象和所有相关的用户对象的Foo对象,那么你会使用select_related()

User.objects.all().select_related('foo') 

但在这里,你不想所有Foo与用户对象相关的对象,您只需要它们的子集满足您的条件。我不知道如何告诉Django在单个查询集中执行此操作。但是你可以是做什么都分别选择并做在Python中加入:

# Map from user id to corresponding Foo satisfying <criteria>, if any. 
foos = {foo.user_id: foo for foo in 
     Foo.objects.filter(user__isnull = False, <criteria>)} 
for user in User.objects.all(): 
    foo = foos.get(user.id) 
    # ... 

(这并不做任何更多的数据库的工作还是比你LEFT OUTER JOIN将传输更多的数据,所以我想这是一个合理的方法)

+0

完美,谢谢:) – Phobophobia 2013-03-25 22:01:19

+1

请记住,我实际上并不知道您的模型是如何相关的,所以您可能需要稍微调整我提出的解决方案以满足您的需求。 – 2013-03-25 22:24:03

+0

您的解决方案运行以下查询:SELECT•••FROM“auth_user”WHERE“auth_user”。“id”= 对于每个符合条件的Foo的用户。据我所知,这与“{foo.user_id:foo”;用别的东西替换任何一个部分会导致查询不能运行。两个模型之间的唯一关系是Foo具有指向用户的ForeignKey。 – Phobophobia 2013-03-25 22:30:17

1

这是笨重,但是这应该这样做:

User.objects.raw('SELECT auth_user.* from auth_user LEFT OUTER JOIN ' 
       '"foo" ON (auth_user.id = foo.id AND ' 
       '<other criteria here>)') 

您可以将它们添加到选择左侧图示上返回的用户对象额外的属性。

0

为了得到一个LEFT OUTER JOIN你可以去:

User.objects.select_related('foo').filter(Q(foo__isnull=True) | Q(<other criteria here>)) 

Django使用foo__isnull=True引导它来生成LEFT OUTER JOIN。给foo__isnull=False生成一个INNER JOIN,因为它没有过滤器参数。