模型
這裏是我們的基本模型設置。基於ManyToMany關係過濾Django QuerySet
一個列表有很多項目,並且一個項目可以在許多列表中。對於給定的項目,如果其列表中的的任何是好的(即,list.bad == False
),那麼項目是好的。如果一個項目沒有出現在好列表中,那麼它是不好。
我們有一個自定義的項目查詢集,一個只返回好項目的方法和一個只返回壞項目的方法。
class Item(models.Model):
objects = ItemQuerySet.as_manager()
name = models.CharField(max_length=255, unique=True)
class List(models.Model):
name = models.CharField(max_length=255, unique=True)
bad = models.BooleanField(default=True)
items = models.ManyToManyField(Item, related_name='lists')
class ItemQuerySet(models.QuerySet):
def bad(self):
return self.exclude(lists__bad=False)
def good(self):
return self.filter(lists__bad=False)
場景
下面是我們遇到麻煩的場景的例子:一個壞的名單,一個良好的名單,以及兩個項目。
BadList: GoodList:
- Item1 - Item1
- Item2
由於項目1至少出現在一個良好的名單,就應該拿出在Item.objects.good()
,而不是在Item.objects.bad()
。
由於Item2沒有出現在任何好的列表中,它應該出現在Item.objects.bad()
中,而不是在Item.objects.good()
中出現。
我們可以設置情景就像這樣:
# Create the two lists.
>>> goodlist = List.objects.create(name='goodlist', bad=False)
>>> badlist = List.objects.create(name='badlist', bad=True)
# Create the two items.
>>> item1 = Item.objects.create(name='item1')
>>> item2 = Item.objects.create(name='item2')
# Item1 goes in both lists
>>> goodlist.items.add(item1)
>>> badlist.items.add(item1)
# Item2 only in badlist
>>> badlist.items.add(item2)
而且,事實上,Item.objects.good()
和Item.objects.bad()
工作,因爲我們預計:
>>> Item.objects.bad() # This returns what we want! Good!
<QuerySet [<Item: item2>]>
>>> Item.objects.good() # This returns what we want! Good!
<QuerySet [<Item: item1>]>
的問題
感謝您與我的軸承。這是我們自定義的QuerySet出錯的地方。如果我們訪問good()
和bad()
自定義的QuerySet方法到單個List的Items,我們會得到不正確的結果。
>>> badlist.items.bad() # WRONG! We want to ONLY see item2 here!
<QuerySet [<Item: item1>, <Item: item2>]
>>> badlist.items.good() # WRONG! We want to see item1 here!
<QuerySet []>
好像,當我們做badlist.items.bad()
,查詢只有考慮badlist
在確定的項目是壞的,而不是考慮所有列出了貨品,但我很困惑,爲什麼情況就是這樣。
我的想法是,在ItemQuerySet.bad
方法中,我想要的東西像self.exclude(any__lists__bad=False)
而不是隻是self.exclude(lists__bad=False)
。但當然any__
關鍵字實際上並不存在,我不確定如何在Django QuerySet中正確表達該邏輯。看起來使用Q
對象可能是前進的方向,但我仍然不確定如何用Q
對象表示這樣的查詢。
在我們的實際數據庫中,少於100個列表,但數百萬個項目。因此,出於性能方面的原因,使用一個查詢而不是屬性或多個查詢來完成這項工作是理想的。
乾杯!
感謝您的回答!這確實可以正常工作,但是我擔心其他使用該代碼的人會嘗試使用'badlist.items.good()'路由,但不知道更好。我想避免讓人們被這樣誤導。 此外,我打算在原始帖子中提到這一點:在我們的實際數據庫中,少於100個列表,但數百萬個項目。因此,出於性能方面的原因,使用一個查詢而不是屬性或多個查詢來完成這項工作是理想的。 –
啊,知道了。我認爲你可以使用queryset註釋來做到這一點。我使用我認爲應該可以工作的解決方案編輯了我的答案。否則,爲了提高性能,我只需將不良/好列添加到Item並更新它,這使得查詢變得更簡單 – Brobin