繁体   English   中英

Django使用相关模型的自定义管理器过滤相关字段

[英]Django filter related field using related model's custom manager

在通过相关字段进行过滤时,如何从自定义管理器查询集应用注释和过滤器? 这里有一些代码来证明我的意思。

经理和模特

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并确保访问此模型的任何地方重复此行为(除非明确指示不)。

如何运行嵌套查询(或两个查询,以防您的后端是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)我认为你错过了解注释的作用。

为QuerySet中的每个项生成聚合

生成汇总值的第二种方法是为QuerySet中的每个对象生成独立摘要。 例如,如果您要检索书籍列表,您可能想知道有多少作者为每本书做出了贡献。 每本书都与作者有多对多的关系; 我们想要总结QuerySet中每本书的这种关系。

可以使用annotate()子句生成每对象摘要。 指定annotate()子句时, QuerySet中的每个对象都将使用指定的值进行批注。

这些注释的语法与用于aggregate()子句的语法相同。 annotate()的每个参数都描述了要计算的聚合。

所以当你说:

MyModel.objects.annotate(other_model__some_flag=Value(True, output_field=BooleanField()))

你是不是注释some_flagother_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时保留注释, ORM必须在subquery进行JOIN , 就像是:

INNER JOIN 
(
    SELECT other_model.id, /* more fields,*/ 1 as some_flag
    FROM other_model
) as sub on mymodel.other_model_id = sub.id

这将是超级慢,我并不惊讶他们没有这样做。

可能解决方案

不要注释您的字段,而是将其添加为模型中的常规字段。

简化的答案是模型对字段集合具有权威性,而管理者对模型集合具有权威性。 在你努力使它干涸的时候,你做了WET,因为你改变了经理的字段集。

为了解决这个问题,你必须教会模型有关查找的信息,并且需要使用Lookup API来完成

现在我假设您实际上没有使用固定值进行注释,因此如果该注释实际上可以简化为字段,那么您可能只是将其完成,因为最终它需要映射到数据库表示。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM