Django 左加入如何

Django Left join how

我对 Django 还很陌生,一直坚持在 Django 中创建左连接。我尝试了很多,但其中 none 似乎有效:

我想翻译成 Django 的查询是:

select ssc.id
      ,mgz.Title
      ,tli.id
      ,tli.Time
  
from Subscription ssc

join Person prs
  on ssc.PersonID = prs.id
 and prs.id = 3

join Magazine mgz
  on mgz.id = ssc.MagazineID
 and mgz.from <= date.today()
 and mgz.until > date.today()

left join TimeLogedIn tli
  on tli.SubscriptionID = ssc.id
 and tli.DateOnline = date.today()

我使用的模型如下所示:

class Magazine(models.Model):
      Title = models.CharField(max_length=100L)    
      from = models.Datefield()
      until = models.Datefield()
      Persons = models.ManyToManyField(Person, through='Subscription')

class Person(models.Model): 
      user = models.OneToOneField(User, on_delete=models.CASCADE)
      Magazines = models.ManyToManyField(Magazine, through='Subscription')

class Subscription(models.Model):
      MagazineID = models.ForeignKey(Magazine,on_delete=models.CASCADE)
      PersonID = models.ForeignKey(Person,on_delete=models.CASCADE)

class TimeLogedIn(models.Model):
      SubscriptionID = models.ForeignKey('Subscription', on_delete=models.CASCADE)
      DateOnline = models.DateField()
      Time = models.DecimalField(max_digits=5, decimal_places=2)

就像我说的,尝试了很多但没有成功,现在我不知道如何在 Django ORM 中做到这一点,这可能吗?我已经创建了一个原始查询并且它工作正常,但是如何在 Django ORM 中创建它?

您可以使用字段 lookups lte and gt to filter your objects and then values() 方法。

也可以反向查询,空值使用Q objects

from django.db.models import Q

Subscription.objects.filter(
    PersonID_id=3,
    MagazineID__from__lte=date.today(), 
    MagazineID__until__gt=date.today()
 ).filter(
    Q(TimeLogedIn__DateOnline=date.today()) | Q(TimeLogedIn__DateOnline__isnull=True)
 ).values("id", "MagazineID__Title", "TimeLogedIn__id", "TimeLogedIn__Time")

或来自TimeLogedIn

TimeLogedIn.objects.filter(DateOnline=date.today()).filter(
    SubscriptionID__MagazineID__from__lte=date.today(), 
    SubscriptionID__MagazineID__util__gt=date.today()
).values(
    "SubscriptionID_id", "SubscriptionID__MagazineID__Title", "id", "Time"
)

Querysets 也有 query 属性,其中包含要执行的 sql 查询,您可以看到如下所示:

print(TimeLogedIn.objects.filter(...).values(...).query)

Note: Behind the scenes, Django appends "_id" to the field name to create its database column name. Therefore it should be subscription, instead of SubscriptionID.

您还可以使用 prefetch_related() and select_related() 来防止多次数据库命中:

SubscriptionID.objects.filter(...).prefetch_related("TimeLogedIn_set")
SubscriptionID.objects.filter(...).select_related("PersonID")