2015-06-05 66 views
2

我想寫一次過濾器並在任何地方重複使用,我該怎麼做?在Django中重複使用過濾器()queryset

例如:有一個模型Student與標誌field。我想寫一個過濾器讓非研究生(flag=0)。但是在許多視圖和功能中,我們需要列出非研究生名單,而且我很懶,不想一次次地在這些視圖和函數中編寫過濾器,因爲這會使維護源代碼變得很困難。

我可以在模型學生中使用meta嗎?我沒有找到任何過濾器相關元選項。或者我可以編寫一個函數來過濾學生模型?在我看來,模型中的函數只能在一個Student對象而不是列表中工作。

回答

3

可以使用自定義的經理讓事情變得乾燥,增強可讀性(明確指定的過濾器總是比拖着一個複雜的過濾器更好)

class GraduateManager(models.Manager): 
    def get_queryset(self): 
     return super(GraduateManager, self).get_queryset().filter(graduated=True) 

class UndergraduateManager(models.Manager): 
    def get_queryset(self): 
     return super(Undergraduate, self).get_queryset().filter(graduated=False) 

class Student(models.Model): 
    graduated = BooleanField() 

    graduates = GraduateManager() 
    undergraduates = UndergraduateManager() 

要使用它,你就會得到一個正常的查詢集,你可以操縱根據需要

Student.graduates.all(), or .filter(), or .count() etc 

參考https://docs.djangoproject.com/en/1.8/topics/db/managers/#modifying-initial-manager-querysets

+0

你的答案解決了我的問題。謝謝。 – JordanChina

2

使用自定義查詢集和QuerySet.as_manager()是最好的解決辦法現在。 Dabapps的Jamie Matthews在其博客文章Building a higher-level query API: the right way to use Django's ORM中詳細討論了可重複使用的過濾器。

「直接在視圖中使用Django的低級別的ORM查詢方法(通常情況下)的反模式」
- 傑米·馬修斯

的Django得到了.as_manager() method對於之前的博客文章是寫但是QuerySet。

我會使用的東西現在這個樣子(基於currently accepted answer):

class StudentQuerySet(models.query.QuerySet): 
    def graduate(self): 
     return self.filter(graduated=True) 

    def undergraduate(self): 
     return self.filter(graduated=False) 

class Student(models.Model): 
    graduated = BooleanField() 

    objects = StudentQuerySet.as_manager() 

在其他更復雜的情況下,這是很有用,能夠在自定義查詢來定義複雜的過濾器設置,因爲過濾器當這樣實施時可以鏈接。

如果您希望在其他模型中讓相關經理使用此功能(例如,如果您有其他型號參考學生模型並且使用otherinstance.student_set.all()),請參閱Django: Using managers for related object access。總之,這樣做:

class Student(models.Model): 
    graduated = BooleanField() 

    objects = StudentQuerySet.as_manager() 
    objects.use_for_related_fields = True