在python django中使用OR条件LEFT JOIN

时间:2016-04-29 11:16:37

标签: python django join

我想要的只是用Python Django语法编写以下SQL查询。我研究了很多,但无法得到我想要的结果。你能帮我吗?

    SELECT * FROM thread
    LEFT JOIN user
    ON (thread.user1_id = user.id OR thread.user2_id = user.id)
    WHERE user.id = 9

我的模特:

 class Thread(models.Model):
        last_message = models.TextField(max_length=100)
        user1_id = models.IntegerField()
        user2_id = models.IntegerField()

1 个答案:

答案 0 :(得分:1)

在不使用某些原始SQL的情况下,无法使用Django ORM创建确切的查询。问题是连接条件中的OR。

但是,由于您没有从用户表中选择任何行,因此您可以创建具有相同结果的其他查询。

首先使用ForeignKeys定义模型。

from django.db import models
from django.contrib.auth.models import User

class Thread(models.Model):
    last_message = models.TextField(max_length=100)
    user1 = models.ForeignKey(User)
    user2 = models.ForeignKey(User)

    class Meta:
        db_table = 'thread'  # otherwise it will be: appname_thread

然后你可以预先形成查询。

from django.db.models import Q

threads = Thread.objects.filter(Q(user1__id=9) | Q(user2__id=9))

生成的SQL将是这样的:

SELECT * FROM thread
LEFT JOIN user AS user1
ON (thread.user1_id = user1.id)
LEFT JOIN user AS user2
ON (thread.user2_id = user2.id)
WHERE (user1.id = 9 OR user2.id = 9)

您可以通过完全避免加入来改善这一点。

# note the single underscore!
threads = Thread.objects.filter(Q(user1_id=9) | Q(user2_id=9))

生成以下SQL。

SELECT * FROM thread
WHERE (user1_id = 9 OR user2_id = 9)

如果您还需要在同一查询中获取用户实例,在这种情况下您确实需要加入,则有两种选择。

  1. 使用包含联接的第一个查询,然后在Python中选择基于id的正确用户。

    for thread in threads:
        if thread.user1.id == 9:
            user = thread.user1
        else:
            user = thread.user2
    
  2. 或使用原始SQL获取所需的确切查询。在这种情况下,您可以使用没有定义它们的ForeignKeys的模型。

    threads = Thread.objects.raw('''
               SELECT *, user.id AS user_id, user.name as user_name FROM thread
               LEFT JOIN user
               ON (thread.user1_id = user.id OR thread.user2_id = user.id)
               WHERE user.id = 9''')
    for thread in threads:
        # threads use the ORM
        thread.id
        # user fields are extra attributes
        thread.user_id
        thread.user_name