2013-06-03 9 views
5

A causa di alcune restrizioni in un progetto su cui sto lavorando, ho dovuto sostituire la classe QuerySet di Django con una personalizzata. Gli oggetti QuerySet possono avere i loro metodi concatenati (ad esempio QuerySet().filter(...).exclude(...) e così via), quindi nella mia implementazione, ogni metodo restituisce semplicemente self. Quindi la mia classe ha questo aspetto:Python - Metodi concatenamento: restituire `self` e restituire un nuovo oggetto clonato

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

In questo modo ho imitato il comportamento di QuerySet di Django.

Tuttavia, guardando il codice Django, ho notato che invece di tornare self, i metodi di set di query restituiscono un oggetto clonato ogni volta che vengono chiamati. Sembra che questo (cose inutili rimosso):

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 

Quindi, in pratica, ogni volta che un metodo viene chiamato, QuerySet sarà clonare se stessa, un'istanza di un nuovo oggetto e restituirlo.

La mia domanda è: PERCHÉ? La mia strada è sbagliata?
La mia paura è che il modo in cui lo faccio, qualcosa potrebbe rompersi, altrimenti non posso spiegare perché il team Django ha fatto quello che ha fatto.

+5

Restituzione di un oggetto clonato significa che l'oggetto originale è garantita immutabilità (Stai cambiando il clone, non l'oggetto originale). Questa è solo un'osservazione da parte mia, però. –

+0

@RobertHarvey - Sembra molto valido, guardando la spiegazione qui: https://docs.djangoproject.com/en/1.0/ref/models/querysets/#all – karthikr

+1

Sto guardando l'output di 'git blame' per quel file e vedo 'self._clone()' proveniente da diversi commit. Qualunque sia la ragione, questo progetto è stato implementato in modo coerente per un po 'di tempo. https://github.com/django/django/blame/master/django/db/models/query.py – jpaugh

risposta

2

Django esegue questa operazione in modo che la query di base possa essere mantenuta e riutilizzata, senza ereditare le modifiche da una futura query "figlio", ad esempio exclude() su filter(). Immagino che qualcuno abbia provato a memorizzare le query per dopo, e ha capito che non funzionava bene senza copiare.

Ho clonato il repository django e ho fatto un rapido git log su django/db/models/query.py, cercando la frase clone.

La patch che introduce questo cambiamento è qui:

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

+0

Grazie a @jpaugh! Sembra che tu abbia inchiodato l'uso iniziale di questo metodo. – user1102018

Problemi correlati