【发布时间】:2017-11-17 09:32:06
【问题描述】:
通过相关字段进行过滤时,如何应用自定义管理器查询集中的注释和过滤器?这里有一些代码来说明我的意思。
经理和模型
from django.db.models import Value, BooleanField
class OtherModelManager(Manager):
def get_queryset(self):
return super(OtherModelManager, self).get_queryset().annotate(
some_flag=Value(True, output_field=BooleanField())
).filter(
disabled=False
)
class MyModel(Model):
other_model = ForeignKey(OtherModel)
class OtherModel(Model):
disabled = BooleanField()
objects = OtherModelManager()
正在尝试使用管理器过滤相关字段
# This should only give me MyModel objects with related
# OtherModel objects that have the some_flag annotation
# set to True and disabled=False
my_model = MyModel.objects.filter(some_flag=True)
如果你尝试上面的代码,你会得到以下错误:
TypeError: Related Field got invalid lookup: some_flag
为了进一步澄清,基本上相同的问题被报告为一个错误,没有回应如何实际实现这一点:https://code.djangoproject.com/ticket/26393。
我知道这可以通过直接在 MyModel 过滤器中使用来自管理器的过滤器和注释来实现,但关键是要保持此 DRY 并确保此行为在任何地方重复 em> 访问此模型(除非明确指示不要访问)。
【问题讨论】:
-
=True在任意名称“some_flag”之后是什么意思?写一个示例如何手动获得正确的结果,因为我在最新的 Django 中得到了错误AttributeError: 'bool' object has no attribute 'resolve_expression',原因是简单的值True。不清楚你想要什么? (顺便说一句,似乎在上面的链接中它与您无关,并且原始发布者接受它不是错误报告的错误,而只是误解。) -
这是一个人为的例子来演示这个问题;不管我是否已更新注释以使其现在可以正常工作。您要求的示例很明显,只需将代码从管理器移至查询
MyModel.objects.annotate(other_model__some_flag=Value(True, output_field=BooleanField())).filter(other_model__some_flag=True, other_model__disabled=False)。该链接是完全相同的问题,它被报告为一个错误,因为作者认为相关的 Django 功能可以解决它,但它没有。没有发布关于如何解决问题的回复。 -
不,我想看看你声称的代码对你来说是正确的,但它还不够干,我希望我能干。您的“明显”示例肯定是不正确的,因为它在内部编译为
SELECT app_mymodel.id,... , True AS "other_model__some_flag" FROM ...SQL 可以通过any_queryset.query.get_compiler('default').as_sql()轻松验证。也许解释清楚,例如通过 SQL 你想得到什么。是的,简化的示例很有用,但经过验证的示例通过简化没有其他不相关的错误,例如在def get_queryset之后丢失的return。 -
很高兴您解释了您的努力,但您还应该使用您确信自己知道的术语来解释问题,以便有可能获得相关答案。 (它似乎还不是 Django ORM 术语。) 1)注释通常是某些组的某个字段(或逐个字段的表达式)的计数或求和、最小值、最大值或平均值。与常量 True 无关。 2)如果顺序不相关,通常在注释之前过滤比在注释之后更好。没有更多信息就无法决定。 V
-
@hynekcer 很抱歉让您失望,但您混淆了注释和聚合。注解的常见工作负载是在行级别添加计算字段(例如
amount=F('price')+F('quantity')(简化)。正如您所说的聚合,适用于一组行。
标签: python django django-models django-orm