How to join three many-to-many models with a double-join condition
I want to execute this query of three models/tables:
-- get all items that don't have a status for this member
SELECT i.*
FROM
mock_item i
LEFT JOIN mock_itemstatusmember ism ON i.id = ism.item_id AND ism.member_id = 2
WHERE
ism.id IS NULL
Here are how my models look:
from django.db import models
# think status as a status
class Member(models.Model):
id = models.AutoField(primary_key=True)
name = models.CharField(max_length=255)
class Status(models.Model):
id = models.AutoField(primary_key=True)
name = models.CharField(max_length=255)
no = models.SmallIntegerField()
class Item(models.Model):
id = models.AutoField(primary_key=True)
name = models.CharField(max_length=255)
status = models.ManyToManyField(Status, through='ItemStatusMember')
member = models.ManyToManyField(Member, through='ItemStatusMember')
class ItemStatusMember(models.Model):
"""
Table that keeps job statuss information for a user.
Tides Items with Members with Statuss
"""
id = models.AutoField(primary_key=True)
member = models.ForeignKey(Member)
status = models.ForeignKey(Status)
item = models.ForeignKey(Item)
And their database sample data:
mysql> select * from mock_member;
+----+--------+
| id | name |
+----+--------+
| 1 | Stefan |
| 2 | Alex |
| 3 | Diana |
+----+-------开发者_如何学编程-+
3 rows in set (0.00 sec)
mysql> select * from mock_status;
+----+---------+----+
| id | name | no |
+----+---------+----+
| 1 | Pending | 1 |
| 2 | Success | 2 |
+----+---------+----+
2 rows in set (0.00 sec)
mysql> select * from mock_item;
+----+----------------+
| id | name |
+----+----------------+
| 1 | My first item |
| 2 | My second item |
| 3 | My third item |
+----+----------------+
3 rows in set (0.00 sec)
mysql> select * from mock_itemstatusmember;
+----+-----------+-----------+---------+
| id | status_id | member_id | item_id |
+----+-----------+-----------+---------+
| 1 | 1 | 1 | 1 |
| 2 | 2 | 1 | 2 |
| 3 | 1 | 2 | 1 |
+----+-----------+-----------+---------+
3 rows in set (0.00 sec)
I need this, with the ORM, and NOT with the raw SQL query facility from the ORM to get all items that don't have a status for this member.
The SQL query at the beginning of the question does this, so it's important to have the
AND ism.member_id = 2
condition as a second condition to the left-join part, instead of moving into where
, which I know how to do.
from django.db.models import Q
Item.objects.filter(~Q(member__id=2))
精彩评论