2013-06-03 100 views
5

由於我正在處理的項目中存在一些限制,我不得不用自定義項替換Django的QuerySet類。 QuerySet對象可以鏈接它們的方法(例如,QuerySet().filter(...).exclude(...)等),所以在我的實現中,每個方法只返回self。所以我的班級看起來是這樣的:Python - 鏈接方法:返回`self` vs返回一個新的克隆對象

class MyQuerySet: 
    ... 
    def filter(self, *args, **kwargs): 
     # Do some stuff and then: 
     return self 

這樣我模仿了Django的QuerySet行爲。

但是,看着Django代碼,我注意到QuerySet的方法不是返回self,而是每次調用時都會返回一個克隆的對象。它看起來像這樣(去除不必要的東西):

class QuerySet(...): 
    ... 
    def filter(self, *args, **kwargs): 
     clone = self._clone() 
     # Do some stuff and then 
     return clone 

    def _clone(self,...): 
     klass = self.__class__ 
     obj = klass(...) 
     return obj 

所以基本上,每一個方法被調用時,查詢集將克隆自己,實例化一個新的對象,並將其返回。

我的問題是:爲什麼?我的方式錯了嗎?
我的恐懼是,我這樣做的方式可能會破壞,否則我無法解釋Django團隊爲什麼會這麼做。

+5

返回一個克隆的對象是指原來的對象保證不變性(你改變的克隆,而不是原來的對象)。不過,這只是我的觀察。 –

+0

@RobertHarvey - 看起來非常有效,看看這裏的解釋:https://docs.djangoproject.com/en/1.0/ref/models/querysets/#all – karthikr

+1

我在看'git blame'輸出的那個文件,我看到'self._clone()'來自多個提交。無論什麼原因,這種設計現在一直在實施。 https://github.com/django/django/blame/master/django/db/models/query.py – jpaugh

回答

2

Django會這樣做,以便基本查詢可以保留和重用,而不會繼承未來「子」查詢的更改,例如filter()上的您的exclude()。我猜有些人以後嘗試存儲查詢,並意識到如果不復制,效果不佳。

我克隆了django回購,並在django/db/models/query.py上做了一個快速git log,搜索短語clone

,介紹這一變化的補丁是在這裏:

https://github.com/django/django/commit/d4a3a4b

+0

謝謝@jpaugh!它看起來像你確定了這種方法的最初使用。 – user1102018