Django 在 BooleanField 上注释
Posted
技术标签:
【中文标题】Django 在 BooleanField 上注释【英文标题】:Django annotate on BooleanField 【发布时间】:2013-02-28 16:40:10 【问题描述】:我有以下型号:
class Foo(models.Model):
pass
class Bar(models.Model):
foo = models.ForeignKey(Foo)
is_successful = models.BooleanField()
如果与foo
对象关联的所有bar
对象都具有is_successful
作为True
,我想获取所有带有注释的foo
对象
到目前为止,我的查询集是:
foos = Foo.objects.all().annotate(all_successful=Min('bar__is_successful'))
all_successful
注解的思想是,如果所有is_successful
行的最小值为1,那么它们都必须是True
(假设0
是False
并且1
是@ 987654334@)。所以知道我可以像这样使用查询集:
foo = foos[0]
if foo.all_successful == 1:
print 'All bars are successful'
else:
print 'Not all bars are successful'
这在 sqlite 中效果很好,但在 PostgreSQL 中失败了,因为 PostgreSQL 无法在布尔列上执行 MIN
聚合。我猜这在 sqlite 中有效,因为 sqlite 将布尔值视为整数,因此它可以执行聚合。
我的问题是如何在不将我的 is_successful
字段转换为 IntegerField
的情况下使这个查询集在 PostgreSQL 中工作?
感谢
【问题讨论】:
【参考方案1】:我知道这是一个老问题,但我最近遇到了这个问题。 Django v1.8 现在内置了对 case/when 的支持,因此您可以使用 ORM 而不是使用自定义 SQL。
https://docs.djangoproject.com/en/1.8/ref/models/conditional-expressions/#case
Foo.objects.annotate(
all_successful=Case(
When(bar__is_successful=False, then=False),
When(bar__is_successful=True, then=True),
default=False,
output_field=BooleanField()
))
我还没有尝试过,但在最近的一个项目中,类似的方法对我有用。
【讨论】:
这是现在最好的方法,好点!感谢您的贡献! 您的语法比实际文档更容易理解,谢谢!缺少代码块中的最终)
。另外,请在 Case()
调用中添加最后一个 kwarg output_field=BooleanField()
。
所做的更改。 :)【参考方案2】:
对于 DJANGO 获得annotation
我认为您可以简单地使用Extra
foos = Foo.objects.extra(select='all_successful': 'CASE WHEN COUNT(b.foo) > 0 THEN 0 ELSE 1 END FROM yourapp_bar as b WHERE b.is_successful = false and b.foo = yourapp_foo.id' )
如果您的系统正在运行 Django 1.8+,请关注 Dav3xor answer。
【讨论】:
这太棒了。我一直在寻找一种在 Django 中使用 SQL“CASE WHEN”的好方法,结果成功了。【参考方案3】:受到https://docs.djangoproject.com/en/dev/topics/db/managers/ 的启发,我建议对 Bar 类使用自定义管理器而不是注释
class BarManager(models.Manager):
def get_all_successful_foos_ids(self):
from django.db import connection
cursor = connection.cursor()
cursor.execute("""
SELECT foo, COUNT(*)
FROM yourapp_bar
GROUP BY 1
WHERE is_successful = true""") # <-- you have to write the correct table name here
result_list = []
for row in cursor.fetchall():
if row[1] > 0:
result_list.append(row[0])
return result_list
class Bar(models.Model):
foo = models.ForeignKey(Foo)
is_successful = models.BooleanField()
objects = BarManager() # here I'm changing the default manager
然后,在您的代码中:
foos = foo.objects.filter(id__in=Bar.objects.get_all_successful_foos_ids())
【讨论】:
感谢这个想法,但这不是我想要的,因为你的建议只是过滤查询集,而我正在寻找如何注释我的 foo 模型。 我写了另一个答案,用一种更简单的方法应该给你预期的注释(我没有时间测试它,但它应该让你朝着正确的方向前进,我希望)以上是关于Django 在 BooleanField 上注释的主要内容,如果未能解决你的问题,请参考以下文章
Django Booleanfield Checkbox 和 Label 分两行显示
如何在 Django 上将 True 设置为 BooleanField 的默认值?