Django 使用 LEFT JOIN 而不是 INNER JOIN

Django use LEFT JOIN instead of INNER JOIN

我有两个模型:CommentsCommentFlags

class Comments(models.Model):
    content_type = models.ForeignKey(ContentType,
                                     verbose_name=_('content type'),
                                     related_name="content_type_set_for_%(class)s",
                                     on_delete=models.CASCADE)
    object_pk = models.CharField(_('object ID'), db_index=True, max_length=64)
    content_object = GenericForeignKey(ct_field="content_type", fk_field="object_pk")
    submit_date = models.DateTimeField(_('date/time submitted'), default=None, db_index=True)
    ...
    ...


class CommentFlags(models.Model):
    user = models.ForeignKey(settings.AUTH_USER_MODEL, related_name="comment_flags",
                             on_delete=models.CASCADE)
    comment = models.ForeignKey(Comment, related_name="flags", on_delete=models.CASCADE)
    flag = models.CharField(max_length=30, db_index=True)
    ...
    ...  

CommentFlags flag 可以有值:likedislike

问题陈述:我想得到所有 Comments 喜欢的数量 DESC 中排序 举止。

上述问题陈述的原始查询

SELECT 
    cmnts.*, coalesce(cmnt_flgs.num_like, 0) as num_like
FROM 
    comments cmnts
LEFT JOIN
(
    SELECT 
        comment_id, Count(comment_id) AS num_like 
    FROM 
        comment_flags 
    WHERE 
        flag='like' 
    GROUP BY comment_id 
) cmnt_flgs      
ON 
    cmnt_flgs.comment_id = cmnts.id 
ORDER BY 
    num_like DESC

我无法在 Django ORM Queryset 中转换上述查询。

到目前为止我尝试了什么...

>>> qs = (Comment.objects.filter(flags__flag='like').values('flags__comment_id')
                         .annotate(num_likes=Count('flags__comment_id')))

生成 不同的 查询。

>>> print(qs.query)
>>> SELECT "comment_flags"."comment_id",
       COUNT("comment_flags"."comment_id") AS "num_likes"
    FROM "comments"
    INNER JOIN "comment_flags"
    ON ("comments"."id" = "comment_flags"."comment_id")
    WHERE "comment_flags"."flag" = 'like'
    GROUP BY "comment_flags"."comment_id",
             "comments"."submit_date"
   ORDER BY "comments"."submit_date" ASC
   LIMIT 21

上面的 ORM 查询集的问题是,它使用 InnerJoin 而且我也不知道它是如何添加 submit_dategroupby 子句中。

能否建议我将上述原始查询转换为 Django ORM 查询集的方法?

您可以尝试在 Count 中使用 filter 参数:

qs = (Comment.objects.all()
      .annotate(num_likes=Count('flags__comment_id', filter=Q(flags__flag='like'))))

根据数据库后端,它可能会产生与您期望的略有不同的查询,但它应该具有相同的行为。