Sql Django-具有预取对象的多个注释

Sql Django-具有预取对象的多个注释,sql,django,orm,annotations,Sql,Django,Orm,Annotations,我有一个带有两个m2m字段的模型测试:foo和bar 我试图对这些相关字段的条件计数进行注释,即对满足特定条件的相关对象进行计数。在queryset之外检索此信息不是一个选项,因为我需要使用带注释的字段对结果进行排序 我尝试了以下方法: 一,。使用预取对象 这不起作用,因为多个总和批注上存在此错误: 三,。使用RawSQL 我被困在这里,因为这会检索所有行的总和,而我找不到添加类似WHERE test.id=的内容的方法 有没有办法从自定义SQL中获得正确的单行?还是其他解决方法?我不确定是否可

我有一个带有两个m2m字段的模型测试:foo和bar

我试图对这些相关字段的条件计数进行注释,即对满足特定条件的相关对象进行计数。在queryset之外检索此信息不是一个选项,因为我需要使用带注释的字段对结果进行排序

我尝试了以下方法:

一,。使用预取对象

这不起作用,因为多个总和批注上存在此错误:

三,。使用RawSQL

我被困在这里,因为这会检索所有行的总和,而我找不到添加类似WHERE test.id=的内容的方法


有没有办法从自定义SQL中获得正确的单行?还是其他解决方法?

我不确定是否可以使用Django ORM实现这一点,因为这是一个8年前的错误,但在RawSQL上使用HAVING应该可以。你试过这样的东西吗

sql = """SELECT SUM(CASE WHEN app_foo.<condition> 
      THEN 1 ELSE 0 END) FROM app_test 
      LEFT OUTER JOIN app_foo 
      ON (app_test.id = app_foo.test_id) 
      GROUP BY app_test.id 
      HAVING app_test.id = <ID of the object the annotation corresponds to>"""

T

我对您的SQL进行了更改。您不使用从获取应用程序测试。您以前见过SQL子查询吗

sql = """
  SELECT SUM(CASE WHEN app_foo.<condition> THEN 1 ELSE 0 END) 
  FROM app_foo 
  WHERE app_test.id = app_foo.id  # app_test comes from outside the sub query.

  """
result = test.objects.annotate(n_foo=RawSQL(sql, []))
运行的实际查询将类似于

SELECT app_test.*, (
  SELECT SUM(CASE WHEN app_foo.<condition> THEN 1 ELSE 0 END) 
  FROM app_foo 
  WHERE app_test.id = app_foo.id  ) AS n_foo
FROM app_test
Django中的Count函数现在有一个过滤器参数,应该是您正在寻找的参数

在这种情况下:

result = test.objects.annotate(n_foo=Count('foo_set', filter=Q(<some condition>)), n_bar=Count('bar_set', filter=Q(<some condition)))
应该给出预期的结果。

django.db.models.F在RawSQL中不可用,因此我无法在SQL字符串中包含对象的属性。
sql = """
  SELECT SUM(CASE WHEN app_foo.<condition> THEN 1 ELSE 0 END) 
  FROM app_foo 
  WHERE app_test.id = app_foo.id  # app_test comes from outside the sub query.

  """
result = test.objects.annotate(n_foo=RawSQL(sql, []))
SELECT app_test.*, (
  SELECT SUM(CASE WHEN app_foo.<condition> THEN 1 ELSE 0 END) 
  FROM app_foo 
  WHERE app_test.id = app_foo.id  ) AS n_foo
FROM app_test
result = test.objects.annotate(n_foo=Count('foo_set', filter=Q(<some condition>)), n_bar=Count('bar_set', filter=Q(<some condition)))