在 Django ORM 中加入子查询 table

Join with Subquery table in Django ORM

假设我有一个名为 Book 的模型和另一个名为 Reaction 的模型,它具有指向 Book[= 的外键36=] 和一个名为 outcome 的字符串字段。数据库中有大量书籍和反应行。我想使用 Django ORM 查询数据库,结果如下 SQL:

SELECT b.*, r.n_like, r.n_dislike
FROM book b
JOIN (
  SELECT
    book_id,
    COALESCE(SUM(CASE WHEN outcome='like' THEN 1 ELSE 0 END), 0) n_like,
    COALESCE(SUM(CASE WHEN outcome='dislike' THEN 1 ELSE 0 END), 0) n_dislike
  FROM reaction
  GROUP BY book_id) r ON b.id=r.book_id;

我该怎么做?

请注意,此查询 returns 仅包含至少有一种反应及其对应的 likedislike 数量的图书反应。

我知道如何在 Django 中使用 CaseWhenSumCoalesce。我也知道如何编写在 SELECT 子句中生成这些注释的查询(我尝试过这种查询,但速度很慢)。我的问题仅仅是关于使用 Django 模型加入和选择子查询。子查询是这样的:

reactions_query = Subquery(
  Reaction.objects
  .values('book_id')
  .annotate(n_like=Coalesce(Sum(Case(When(outcome='like', then=1), default=0, output_field=IntegerField())), 0))
  .annotate(n_dislike=Coalesce(Sum(Case(When(outcome='dislike', then=1), default=0, output_field=IntegerField())), 0))
  .values('book_id', 'n_like', 'n_dislike')
)

Book.objects.filter(...) <-- how?

编辑:这些不是我的实际模型。我简化了它们。无论如何,这就是它们的样子:

class Book(models.Model):
    name = models.CharField(max_length=100)
    pub_date = models.CharField(max_length=100)
    about = models.TextField()
    
class Reaction(models.Model):
    LIKE = 'like'
    DISLIKE = 'dislike'
    OUTCOME_CHOICES = ((LIKE, ':)'), (DISLIKE, ':('))

    book = models.ForeignKey(Book, on_delete=models.CASCADE)
    outcome = models.CharField(max_length=20, choices=OUTCOME_OPTIONS, null=True)

您可以使用:

from django.db.models import <strong>Count, Q, Value</strong>
from django.db.models.functions import Coalesce

Book.objects.filter(
    <strong>reaction__isnull=False</strong>
).annotate(
    n_like=Coalesce(Count('reaction', filter=Q(outcome='like')), Value(0)),
    n_dislike=Coalesce(Count('reaction', filter=Q(outcome='dislike')), Value(0))
)

.filter(<b>reaction__isnull=False</b>) 将阻止包含 Books 而没有任何反应。因此,这将创建一个带有 INNER JOIN.

的查询