Django Left Join с фильтром на модели «многие ко многим»

У меня есть 3 модели (модель по умолчанию для пользователя, Project, пользовательская модель m2m ClickedUsers), и я хочу выполнить левое соединение с фильтром в ORM для моделей ClickedUsers и Project. Я пробовал решения для переполнения стека, но когда я печатал эти запросы, я видел, что они выполняли внутреннее соединение.

Вот мои модели:

class Project(models.Model):
        …
    clicked_users = models.ManyToManyField(User,through='ClickedUsers',blank=True)


class ClickedUsers(models.Model):
    user = models.ForeignKey(User,on_delete=models.CASCADE)
    project = models.ForeignKey(Project,on_delete=models.CASCADE)
    status = models.IntegerField(default=0)

И запрос, который я хочу выполнить:

select * from project LEFT JOIN clickedusers ON project.id = clickedusers.project_id WHERE clickedusers.user_id = 1;

Как я могу сделать этот запрос с Django Orm?

Всего 2 ответа


LEFT JOIN не даст вам других результатов от INNER JOIN в этом запросе

SELECT *
FROM table_1
JOIN table_2 on table_2.table_1_id = table_1.id
WHERE table_2.field = some_value;

Поскольку у вас есть поле из table_2 в предложении where, вы можете получить результаты из table_1 только тогда, когда в table_2 есть запись. LEFT JOIN говорит, что нужно получить записи из таблицы_1, даже если в таблице_2 нет записей, удовлетворяющих критериям объединения.

Причина, по которой вы не получаете запрос от ORM, который вам нужен, состоит в том, что ORM распознает, что он может использовать INNER JOIN вместо LEFT JOIN без изменения результатов.


Посмотрите на обратные отношения и related_name .

Project.objects.filter(clicked_users__id=1)

Или вы используете сквозную модель:

Project.objects.filter(clickedusers_set__user_id=1)

Изменить: я пропустил * от select * from . Если вам нужны все поля, то вам нужно использовать:

ClickedUser.objects.filter(
    user_id=1,
).select_related('project')

Есть идеи?

10000