如何在通过相关字段过滤时从自定义管理器查询集应用注释和过滤器?这里有一些代码来证明我的意思。
经理和模特
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并确保此行为重复无处不在访问此模型(除非明确指示不这样做)。
答案 0 :(得分:3)
如何运行嵌套查询(或两个查询,以防你的后端是MySQL;性能)。
第一个获取相关OtherModel
个对象的pk。
第二个过滤获取的pks上的Model
个对象。
other_model_pks = OtherModel.objects.filter(some_flag=...).values_list('pk', flat=True)
my_model = MyModel.objects.filter(other_model__in=other_model_pks)
# use (...__in=list(other_model_pks)) for MySQL to avoid a nested query.
答案 1 :(得分:2)
我不认为你想要的是什么。
1)我认为你错过了解注释的作用。
为QuerySet中的每个项生成聚合
生成汇总值的第二种方法是生成一个 QuerySet中每个对象的独立摘要。例如,如果你 正在检索书籍列表,您可能想知道有多少作者 为每本书做出了贡献。每本书都有多对多的关系 与作者;我们想要总结每本书的这种关系 在QuerySet中。
可以使用 annotate()子句生成每个对象的摘要。 当指定 annotate()子句时, QuerySet 中的每个对象 将使用指定的值进行注释。
这些注释的语法与用于注释的语法相同 aggregate()子句。 annotate()的每个参数都描述了一个聚合 这是要计算的。
所以当你说:
MyModel.objects.annotate(other_model__some_flag=Value(True, output_field=BooleanField()))
您不是some_flag
的注释other_model
即你没有:mymodel.other_model.some_flag
您正在other_model__some_flag
注释mymodel
即你将拥有:mymodel.other_model__some_flag
2)我不确定SQL
对您有多熟悉,但为了保持MyModel.objects.filter(other_model__some_flag=True)
可能,即在执行JOINS
时保留注释,{ {1}}必须ORM
超过JOIN
,例如:
subquery
这将是超级慢的,我并不感到惊讶他们没有这样做。
请勿对您的字段进行注释,但请将其添加为模型中的常规字段。
答案 2 :(得分:1)
简化的答案是模型对字段集合具有权威性,而管理者对模型集合具有权威性。在你努力使它干涸的时候,你做了WET,因为你改变了经理的场地收集。
为了解决这个问题,你必须教会模型有关查找的信息,并且需要使用Lookup API进行修复。
现在我假设您实际上没有使用固定值进行注释,因此如果该注释实际上可以简化为字段,那么您可能只是完成它,因为最终它需要映射到数据库表示。