跨多值查詢
跨越 ManyToManyField 或反查 ForeignKey (例如從 Blog 到 Entry )時,對多個屬性進行過濾會產生這樣的問題:是否要求每個屬性都在同一個相關對象中重合。
filter()
先看filter(),通過一個例子看:
from datetime import datefrom django.db import modelsclass Blog(models.Model):name = models.CharField(max_length=100)tagline = models.TextField()def __str__(self):return self.nameclass Entry(models.Model):blog = models.ForeignKey(Blog, on_delete=models.CASCADE)headline = models.CharField(max_length=255)body_text = models.TextField()pub_date = models.DateField()# 其他字段省略...def __str__(self):return self.headline
假設Entry模型對應的表數據如下
# 要選擇所有包含 2008 年至少一個標題中有 "Lennon" 的條目的博客(滿足兩個條件的同一條目)
>>> Blog.objects.filter(entry__headline__contains="Lennon", entry__pub_date__year=2008)
<QuerySet [<Blog: Beatles Blog>]>
# 要執行一個更為寬松的查詢,選擇任何只在標題中帶有 "Lennon" 的條目和 2008 年的條目的博客
>>> Blog.objects.filter(entry__headline__contains="Lennon").filter(entry__pub_date__year=2008)
<QuerySet [<Blog: Beatles Blog>, <Blog: Beatles Blog>, <Blog: Pop Music Blog]>
這個結果看起來有點怪,官方文檔的解釋是由于第二個(更寬松的)查詢鏈接了多個過濾器,它對主模型進行了多次連接,可能會產生重復的結果。
下面是其他網友的解釋,可以參考
如果使用多個filter函數,單個函數接收單個條件,采用鏈式調用的方式來查詢,則先過濾第一個查詢條件,其返回的是QuerySet對象,注意:由于是跨關聯關系查詢,我們時刻要清除自己檢索的是什么,這里我們檢索的是Blog對象,而不是Entry對象,所以第一個過濾器返回的QuerySet內包含的也是Blog對象,而不是Entry對象。然后在此QuerySet基礎上繼續跨關聯關系查詢第二個過濾條件,如果返回的Blog對象關聯的Entry對象中有滿足過濾器條件的Entry,則將該Blog對象添加到返回的Queryset中
https://www.cnblogs.com/fu-9/p/14645330.html
exclude()
一次 exclude() 調用的條件并不需要指向同一項目。
還是用上面entry的數據。
例如,以下查詢會排除那些 【關聯條目標題包含"Lennon" 的博客】和【發布于 2008 年的博客】,查詢結果是空:
>>> Blog.objects.exclude(
... entry__headline__contains="Lennon",
... entry__pub_date__year=2008,)
<QuerySet []>
如果要排除【關聯條目標題包含"Lennon"且發布于2008年的博客】,查詢結果是id為2的blog。
>>> Blog.objects.exclude(
... entry__in=Entry.objects.filter(
... headline__contains="Lennon",
... pub_date__year=2008,
... ),
... )
<QuerySet [<Blog: Pop Music Blog>]>