![](/img/trans.png)
[英]Django: Filter on related model's field not being equal to a specific value
[英]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_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
時保留注釋, 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.