簡體   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