I have a custom QuerySet object that has several methods to chain filtering. First, the setup for context.
from django.db.models import Manager, Model
from django.db.models.query import QuerySet
class MyQuerySet(QuerySet):
def some_filter(self, foo):
return self.filter(some__chain__of__relationships__foo=foo)
class MyModelManager(Manager):
def get_query_set(self):
return MyQuerySet(self.model, using=self._db)
class MyModel(Model):
objects = MyModelManager()
Use Case:
qs = MyModel.objects.get_query_set()
qs = qs.filter_by_name(name).filter_by_color(color).filter_by_date(date)
I have a situation where I need to return an empty queryset of my object, not Django's EmptyQuerySet.
def filter_by_color(self, color):
if color.is_active:
return self.filter(some__chain__of__relationships__color=color)
return self.empty()
How would I define .empty()
? I can't use .none()
because the .filter_by_date(date)
will throw an error because an EmptyQuerySet has no .filter_by_date()
method. I'm currently using the hack where=['1=0']
def empty(self):
return self.extra(where=['1=0'])
Or...:
def empty(self):
return self.filter(pk=0)
I would much prefer to do this in a non-hack way.
What is the Pythonic way return an empty queryset of my custom QuerySet object?
If you're using Django <= 1.5, you can subclass both the EmptyQuerySet
class and your own custom queryset class. Just override none()
to return your custom class:
class MyQuerySet(QuerySet):
def none(self):
# prevent circular import
from . import MyEmptyQuerySet
return self._clone(klass=MyEmptyQuerySet)
class MyEmptyQuerySet(EmptyQuerySet, MyQuerySet):
pass
In Django 1.6, the class of your queryset is still the same if you call none()
, but through use of metaclasses and overriding __instancecheck__
, calling isinstance(qs.none(), EmptyQuerySet)
will still return True
. So in Django 1.6, there is no need for custom classes or anything, your new methods on your custom queryset class are still available on an empty queryset.
qs = qs.filter_by_name(name).filter_by_color(color)
qs = qs.filter_by_date(date) if isinstance(qs, MyQuerySet) else qs
That's the simplest thing I can see right now. Or filter by color at the end of the chain.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.