Django中的连接附加条件
可以在Django的ORM中给连接语句添加额外的条件吗?
我在SQL中需要的是
'SELECT "post"."id", COUNT("watchlist"."id") FROM "post"
LEFT OUTER JOIN "watchlist"
ON ("post"."id" = "watchlist"."post_id" AND "watchlist"."user_id" = 1)
WHERE "post"."id" = 123 GROUP BY …
在Django中,大部分内容是
Post.objects.annotate(Count('watchinglist')).get(pk=123)
但是我该如何在Django的ORM中把AND "watchlist"."user_id" = …
这个条件加到JOIN的条件里呢?
如果把它加到过滤条件里,就无法获取没有关联的watchlist对象的Post对象了。
3 个回答
2
Post.objects.annotate(Count('watchinglist')).filter(pk=123).extra(where=['"watchlist"."user_id" = 1'])
祝你编码愉快。
9
简单来说:在某些情况下,是的。
当使用通用外键(GenericForeignKey)进行左连接(LEFT JOIN)时,Django会调用 GenericRelation.get_extra_restriction,这个方法会在连接条件中添加额外的限制,具体是“content_type_id”的限制。
对于“外键”(ForeignKey),这个方法也会被调用,但返回的结果是None。
如果你能合理安排代码,以便在特定时间获取正确的限制参数,你可以在这个地方添加额外的限制到连接条件中。
class UserForeignKey(models.ForeignKey):
def get_extra_restriction(self, where_class, alias, related_alias):
field = self.model._meta.get_field('user')
cond = where_class()
# Here is a hack to get custom condition parameters
value = SomeContextManager.get_needed_value()
lookup = field.get_lookup('exact')(field.get_col(related_alias), value)
cond.add(lookup, 'AND')
return cond
class WatchList(models.Model):
user = UserForeignKey(User)
24
在Django 2.0版本中,可以使用FilteredRelation。
Post.objects.annotate(
t=FilteredRelation(
'watchlist', condition=Q(watchlist__user_id=1)
).filter(t__field__in=...)