【问题标题】:Translating query with JOIN expressions and a generic relation to Django ORM使用 JOIN 表达式和与 Django ORM 的通用关系翻译查询
【发布时间】:2017-02-19 04:18:51
【问题描述】:
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 中有这个结构。以下是对重要模型的解释:
事件模型具有链接到某个业务对象的“业务”字段,该业务对象还具有“经理”字段。此外,事件模型具有“何时”字段,用于描述事件发生的日期。
另一方面,Like 模型具有通用外键字段,可以链接到某个 Event 对象,还有“person”和“date”字段,用于描述谁给了赞以及何时给了该事件。

现在的目标是在用户页面上显示目标用户所有喜欢的事件,以及经理是该用户的所有事件。可以用这个 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 中已经提到的“日期”和 Event 模型中的“时间”。排序行为应如下所示:如果 Event 对象派生自 Like 对象,则应按该 Like 对象中的“日期”排序,否则应按 Event 中的“时间”排序 - 这是事情发生变化的地方.因此,最终的原始查询如下所示:

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,但我完全迷失了这部分。谁能帮我?提前致谢!

【问题讨论】:

  • 这是我的尝试,但仍不接近上面的查询:Event.objects.filter(Q(pk__in=Like.objects.filter(person_id=1, content_type_id=17).prefetch_related('content_object').values_list('object_id', flat=True)) | Q(business__manager_id=1)).order_by(Coalesce('likes__date', 'when').desc())

标签: sql django orm django-queryset django-orm


【解决方案1】:

又折腾了一天,终于解决了。尽管它不会从上面生成相同的查询并且效率不高(因为它选择了查询事件上的所有喜欢),但它似乎是在 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;

【讨论】:

    猜你喜欢
    • 2010-12-29
    • 2014-06-13
    • 2018-12-01
    • 2021-07-26
    • 1970-01-01
    • 2021-10-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多