Python 带有布尔字段的Django查询注释

Python 带有布尔字段的Django查询注释,python,django,orm,django-queryset,Python,Django,Orm,Django Queryset,假设我有一个产品模型,其中产品在店面中,ProductImages表中有产品的图像,可以有零个或多个图像。下面是一个简化的示例: 类Productmodels。模型: 产品名称=型号。CharFieldmax\u长度=255 ... 类ProductImagemodels。模型: product=models.ForeignKeyProduct,相关_name='images' image\u file=models.CharFieldmax\u length=255 ... 当显示产品的搜索结

假设我有一个产品模型,其中产品在店面中,ProductImages表中有产品的图像,可以有零个或多个图像。下面是一个简化的示例:

类Productmodels。模型: 产品名称=型号。CharFieldmax\u长度=255 ... 类ProductImagemodels。模型: product=models.ForeignKeyProduct,相关_name='images' image\u file=models.CharFieldmax\u length=255 ... 当显示产品的搜索结果时,我想对具有相关图像的产品进行优先级排序。我可以轻松获得图像的数量:

从django.db.models导入计数 Product.objects.annotateimage\u count=count'images' 但那不是我真正想要的。我想用一个布尔字段注释它,have_images,指示产品是否有一个或多个图像,这样我就可以按此进行排序:

Product.objects.annotatehave_images=?????.order_by'-have_images','Product_name' 我该怎么做?谢谢

阅读有关

测试它是否有效

但order_by或Where Filter by此字段不适用于我Django 1.8 0o:

如果需要使用一些新的 通过“额外使用”包含的字段或表格使用“订购人” 参数,并按字符串序列传递。这些弦 应该是模型字段,与上的方法的正常顺序相同 查询集,其形式为表\u name.column\u name或 在“选择要附加的参数”中指定的列

FieldError:无法将关键字“has_images”解析到字段中

我发现它还开着


因此,如果您有像我这样的问题,您可以使用

如果性能重要,我的建议是将hasPictures布尔字段添加为editable=False

然后通过ProductImage或覆盖保存和删除方法保持正确的值

优点:

索引友好。 更好的性能。避免连接。 数据库不可知论。 编码它将提高你的django技能到一个新的水平。 我最终通过django 1.8的新功能找到了一种方法:

从django.db.models导入Case、When、Value、IntegerField q= 产品对象 滤器 .annotateimage_count=计数“图像” 注释 有图片=案例 当年龄计数=0时, 然后=值1, 默认值=0, 输出\字段=整数字段 .按“拥有图像”订购
这就是我最终发现从1.7升级到1.8的动机的原因。

当你必须用一些过滤器注释存在时,可以使用Sum注释。例如,如果图像中存在任何GIF,请使用以下注释:


这实际上会对它们进行计数,但任何pythonic if product.animated_images:的工作原理与布尔值相同。

使用条件表达式并将outputfield强制转换为BooleanField

Product.objects.annotate(image_count=Count('images')).annotate(has_image=Case(When(image_count=0, then=Value(False)), default=Value(True), output_field=BooleanField())).order_by('-has_image')

从Django 1.11开始,可以使用Exists。以下示例来自:

>>>从django.db.models导入存在,OuterRef >>>从日期时间导入时间增量 >>>从django.utils导入时区 >>>一天前=时区。现在-timedeltadays=1 >>>最近的注释=Comment.objects.filter ... post=OuterRef'pk', ... 创建时间=一天前, ... >>>Post.objects.annotaterecent\u comment=Existsrecent\u comments
谢谢你的回答。我确实发现了,没有额外的,绝对没有原始的。@BrettGmoser这就是为什么我喜欢stackoverflow:D总是学习新东西!也谢谢你和+1!也许你只需要过滤而不是排序?这个简单的答案帮助我过滤:我不接受几年前的答案,并且接受了这个答案。Django1.11在当时已经不是什么东西了,但肯定没有人应该再使用Django1.8了。
qs = qs.extra(order_by = ['-has_images'])

qs = qs.extra(where = ['has_images=1'])
Product.objects.filter(
).annotate(
    animated_images=Sum(
        Case(
             When(images__image_file__endswith='gif', then=Value(1)),
             default=Value(0),
             output_field=IntegerField()
        )
    )
)
Product.objects.annotate(image_count=Count('images')).annotate(has_image=Case(When(image_count=0, then=Value(False)), default=Value(True), output_field=BooleanField())).order_by('-has_image')