使用 JOIN 表达式和与 Django ORM 的通用关系翻译查询

Translating query with JOIN expressions and a generic relation to Django ORM

class Business(models.Model):
    manager = models.ForeignKey(User, on_delete=models.CASCADE)
    #...

class Event(models.Model):
    business = models.ForeignKey(Business, on_delete=models.CASCADE)

    text = models.TextField()
    when = models.DateTimeField()
    likes = GenericRelation('Like')

class Like(models.Model):
    person = models.ForeignKey(User, on_delete=models.CASCADE)

    content_type = models.ForeignKey(ContentType)
    object_id = models.PositiveIntegerField()
    content_object = GenericForeignKey('content_type', 'object_id')

    date = models.DateTimeField(auto_now=True)

所以我在models.py中有这个结构。下面是对重要模型的解释:
事件模型具有 "business" 字段,其中 link 指向某个业务对象,该对象还具有 "manager" 字段。此外,事件模型具有 "when" 字段,用于描述事件发生的日期。
另一方面,Like 模型有通用的外键字段,可以 link 到某个 Event 对象,还有 "person" 和 "date" 字段,描述谁给了 like 以及何时给了那个事件。

现在的目标是在用户页面上显示目标用户喜欢的所有活动,以及经理是该用户的所有活动。可以简单地用这个 SQL 命令来完成:

SELECT event.*
FROM event
INNER JOIN 
     business
     ON (event.business_id = business.id)
LEFT JOIN
    'like'
    ON (event.id = object_id AND content_type_id = 17)
WHERE ('like'.person_id = 1 OR business.manager_id = 1);

但现在结果必须排序,通过已经提到的 Like 中的 "date" 和 Event 模型中的 "when"。排序行为应该如下:如果 Event 对象派生自 Like 对象,那么它应该在那个 Like 对象中按 "date" 排序,在其他情况下它应该在 Event 中按 "when" 排序 - 这是事情发生变化的地方。因此,最终的原始查询如下所示:

SELECT event.*
FROM event
INNER JOIN
    business
    ON (event.business_id = business.id AND business.manager_id = 1)
LEFT JOIN
    'like'
    ON (event.id = object_id AND content_type_id = 17 AND person_id = 1)
ORDER BY COALESCE('like'.date, event.'when') DESC;

现在我必须将最后一个查询转换为 Django ORM,但我完全迷失了那部分。谁能帮我?提前致谢!

折腾了一天,终于解决了。虽然它不会从上面产生相同的查询并且不像它那样高效(因为它在查询事件上选择所有喜欢的东西),但它似乎是在 ORM 中这样做的唯一好方法:

from django.db.models import Case, When, F

Event.objects.filter( \
        Q(business__manager=person) | \
        Q(likes__person=person)) \
    .order_by( \
        Case( \
            When(likes__person=person, then=F('likes__date')), \
            default=F('when')) \
    .desc())

这是 SQL 它产生的结果:

SELECT event.*
FROM event
INNER JOIN
    business
    ON (event.business_id = business.id)
LEFT OUTER JOIN
    'like'
    ON (event.id = object_id AND content_type_id = 17)
WHERE (business.manager_id = 2 OR 'like'.person_id = 2)
ORDER BY CASE
    WHEN 'like'.person_id = 2 THEN 'like'.date
    ELSE event.'when'
END DESC;