【问题标题】:additional conditions on join in django [duplicate]加入django的附加条件[重复]
【发布时间】:2011-03-20 16:55:51
【问题描述】:

是否可以在 django ORM 创建的 join 语句中添加附加条件?

我在 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 条件中?

将其添加到过滤器无法获取关注列表中没有关联对象的 Post 对象。

【问题讨论】:

  • 很好的问题,不确定这将如何被视为标记问题的重复。这个问题是指向关系添加额外的过滤器,而不是简单地执行一个开始。
  • 对,这与另一个已标记为重复的问题不同。

标签: python django


【解决方案1】:
Post.objects.annotate(Count('watchinglist')).filter(pk=123).extra(where=['"watchlist"."user_id" = 1'])

快乐编码。

【讨论】:

  • 看起来它实际上和 filter() 做同样的事情。例如。将一个参数添加到 WHERE,而不是 ON,因此,如果没有监视列表对象,则提供空结果。
  • 但是,实际上,好主意。我错过了 Count 的“额外”参数。看起来那个有效。
  • ...也许不是。 “额外”似乎有一些不同的目的。
  • EXTRA 不会向 ON 语句添加任何内容,但它会添加到 WHERE,我使用它来修改 JOIN 结果,只需在条件中添加连接表的名称(T4,T5)。一点都不漂亮,但我觉得比使用自定义 SQL 要好。
【解决方案2】:

简短回答:在某些情况下 - 是的。

当使用 GenericForeignKey 构建 LEFT JOIN 时,Django 调用 GenericRelation.get_extra_restriction 为具有“content_type_id”限制的 ON 子句添加额外条件。

对于“ForeignKey”,这个方法也被调用,返回 None。

如果您设法组织代码以在特定时间获得适当的限制参数,您可以使用这个地方在 ON 子句中添加额外的限制。

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)

【讨论】:

  • 你救了我的命 :)
【解决方案3】:

在 Django v2.0 中使用FilteredRelation

Post.objects.annotate(
    t=FilteredRelation(
        'watchlist', condition=Q(watchlist__user_id=1)
).filter(t__field__in=...)

【讨论】:

  • 这是对较新版本 Django 问题的最佳直接答案。但不幸的是,FilteredRelation 不能跨多个关系工作,所以目前有点半生不熟。
  • 我同意@getup8,FilteredRelation是一个半生不熟的功能,你不能通过属性访问获得t的值,它只适用于valuesvalues_list
  • 请注意,如果关系查询结果为空,code.djangoproject.com/ticket/29810 我发现的唯一解决方法是使用更新的 django。
  • 我已经在 Django 3.2 中尝试过,并且可以很好地满足我的目的(一对多,而不是一些复杂的查询,我想使用 FilteredRelation 通过添加 AND 条件来加入,然后在WHERE 子句上添加过滤器)。似乎工作正常,到目前为止我认为最好的答案(不确定其他人提到的洞穴猫认为,也许这在所有情况下都不起作用)
猜你喜欢
  • 2023-04-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-10-16
相关资源
最近更新 更多