Due to some restrictions in a project I'm working on, I had to replace Django's QuerySet class with a custom one.
QuerySet objects can have their methods chained (eg QuerySet().filter(...).exclude(...)
and so on), so in my implementation, every method simply returns self
. So my class looks like this:
class MyQuerySet:
...
def filter(self, *args, **kwargs):
# Do some stuff and then:
return self
This way I imitated Django's QuerySet behaviour.
However, looking at the Django code, I noticed that instead of returning self
, QuerySet's methods return a cloned object every time they are called. It looks like this (removed unnecessary stuff):
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
So basically, every time a method is called, QuerySet will clone itself, instantiate a new object and return it.
My question is: WHY? Is my way wrong?
My fear is that the way I do it, something might break, otherwise I can't explain why Django team did what it did.
Django does this so that the base query can be kept around and reused, without inheriting changes from a future "child" query, like your exclude()
on your filter()
. I'm guessing somebody tried storing queries for later, and realized that didn't work well without copying.
I cloned the django repo and did a quick git log
on django/db/models/query.py
, searching for the phrase clone
.
The patch that introduces this change is here:
https://github.com/django/django/commit/d4a3a4b
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With