2013-06-03 3 views
5

Из-за некоторых ограничений в проекте, над которым я работаю, мне пришлось заменить класс QuerySet Django на пользовательский. Объекты QuerySet могут иметь свои методы прикованным (например, QuerySet().filter(...).exclude(...) и т. Д.), Поэтому в моей реализации каждый метод просто возвращает self. Поэтому мой класс выглядит следующим образом:Python - Цепочные методы: возврат `self` против возврата нового клонированного объекта

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

Таким образом, я подражал поведению QuerySet Django.

Однако, глядя на код Django, я заметил, что вместо того, чтобы возвращать self, методы QuerySet возвращают клонированный объект при каждом вызове. Похоже, что этот (Удалены ненужные вещи):

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 

Так в основном, каждый раз, когда вызывается метод, QuerySet клонирует себя, создавать новый объект и вернуть его.

Мой вопрос: ПОЧЕМУ? Я ошибаюсь?
Мой страх в том, что так, как я это делаю, что-то может сломаться, иначе я не могу объяснить, почему команда 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 делает это так, чтобы базовый запрос можно было хранить и повторно использовать, не наследуя изменения от будущего «дочернего» запроса, например, ваш exclude() на вашем filter(). Я предполагаю, что кто-то попытался сохранить запросы позже, и понял, что не работает хорошо, не копируя.

Я клонировал репортер django и сделал быстрый git log на django/db/models/query.py, ища фразу clone.

Патч, который вносит эти изменения здесь:

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

+0

Спасибо @jpaugh! Похоже, вы прибили первоначальное использование этого метода. – user1102018

Смежные вопросы