mirror of
https://github.com/django/django.git
synced 2025-09-26 12:09:19 +00:00
Fixed #19173 -- Made EmptyQuerySet a marker class only
The guarantee that no queries will be made when accessing results is done by new EmptyWhere class which is used for query.where and having. Thanks to Simon Charette for reviewing and valuable suggestions.
This commit is contained in:
parent
a843539af2
commit
a2396a4c8f
11 changed files with 96 additions and 177 deletions
|
@ -35,7 +35,6 @@ class QuerySet(object):
|
|||
"""
|
||||
def __init__(self, model=None, query=None, using=None):
|
||||
self.model = model
|
||||
# EmptyQuerySet instantiates QuerySet with model as None
|
||||
self._db = using
|
||||
self.query = query or sql.Query(self.model)
|
||||
self._result_cache = None
|
||||
|
@ -217,7 +216,9 @@ class QuerySet(object):
|
|||
def __and__(self, other):
|
||||
self._merge_sanity_check(other)
|
||||
if isinstance(other, EmptyQuerySet):
|
||||
return other._clone()
|
||||
return other
|
||||
if isinstance(self, EmptyQuerySet):
|
||||
return self
|
||||
combined = self._clone()
|
||||
combined._merge_known_related_objects(other)
|
||||
combined.query.combine(other.query, sql.AND)
|
||||
|
@ -225,9 +226,11 @@ class QuerySet(object):
|
|||
|
||||
def __or__(self, other):
|
||||
self._merge_sanity_check(other)
|
||||
combined = self._clone()
|
||||
if isinstance(self, EmptyQuerySet):
|
||||
return other
|
||||
if isinstance(other, EmptyQuerySet):
|
||||
return combined
|
||||
return self
|
||||
combined = self._clone()
|
||||
combined._merge_known_related_objects(other)
|
||||
combined.query.combine(other.query, sql.OR)
|
||||
return combined
|
||||
|
@ -632,7 +635,9 @@ class QuerySet(object):
|
|||
"""
|
||||
Returns an empty QuerySet.
|
||||
"""
|
||||
return self._clone(klass=EmptyQuerySet)
|
||||
clone = self._clone()
|
||||
clone.query.set_empty()
|
||||
return clone
|
||||
|
||||
##################################################################
|
||||
# PUBLIC METHODS THAT ALTER ATTRIBUTES AND RETURN A NEW QUERYSET #
|
||||
|
@ -981,6 +986,18 @@ class QuerySet(object):
|
|||
# empty" result.
|
||||
value_annotation = True
|
||||
|
||||
class InstanceCheckMeta(type):
|
||||
def __instancecheck__(self, instance):
|
||||
return instance.query.is_empty()
|
||||
|
||||
class EmptyQuerySet(six.with_metaclass(InstanceCheckMeta), object):
|
||||
"""
|
||||
Marker class usable for checking if a queryset is empty by .none():
|
||||
isinstance(qs.none(), EmptyQuerySet) -> True
|
||||
"""
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
raise TypeError("EmptyQuerySet can't be instantiated")
|
||||
|
||||
class ValuesQuerySet(QuerySet):
|
||||
def __init__(self, *args, **kwargs):
|
||||
|
@ -1180,138 +1197,6 @@ class DateQuerySet(QuerySet):
|
|||
return c
|
||||
|
||||
|
||||
class EmptyQuerySet(QuerySet):
|
||||
def __init__(self, model=None, query=None, using=None):
|
||||
super(EmptyQuerySet, self).__init__(model, query, using)
|
||||
self._result_cache = []
|
||||
|
||||
def __and__(self, other):
|
||||
return self._clone()
|
||||
|
||||
def __or__(self, other):
|
||||
return other._clone()
|
||||
|
||||
def count(self):
|
||||
return 0
|
||||
|
||||
def delete(self):
|
||||
pass
|
||||
|
||||
def _clone(self, klass=None, setup=False, **kwargs):
|
||||
c = super(EmptyQuerySet, self)._clone(klass, setup=setup, **kwargs)
|
||||
c._result_cache = []
|
||||
return c
|
||||
|
||||
def iterator(self):
|
||||
# This slightly odd construction is because we need an empty generator
|
||||
# (it raises StopIteration immediately).
|
||||
yield next(iter([]))
|
||||
|
||||
def all(self):
|
||||
"""
|
||||
Always returns EmptyQuerySet.
|
||||
"""
|
||||
return self
|
||||
|
||||
def filter(self, *args, **kwargs):
|
||||
"""
|
||||
Always returns EmptyQuerySet.
|
||||
"""
|
||||
return self
|
||||
|
||||
def exclude(self, *args, **kwargs):
|
||||
"""
|
||||
Always returns EmptyQuerySet.
|
||||
"""
|
||||
return self
|
||||
|
||||
def complex_filter(self, filter_obj):
|
||||
"""
|
||||
Always returns EmptyQuerySet.
|
||||
"""
|
||||
return self
|
||||
|
||||
def select_related(self, *fields, **kwargs):
|
||||
"""
|
||||
Always returns EmptyQuerySet.
|
||||
"""
|
||||
return self
|
||||
|
||||
def annotate(self, *args, **kwargs):
|
||||
"""
|
||||
Always returns EmptyQuerySet.
|
||||
"""
|
||||
return self
|
||||
|
||||
def order_by(self, *field_names):
|
||||
"""
|
||||
Always returns EmptyQuerySet.
|
||||
"""
|
||||
return self
|
||||
|
||||
def distinct(self, fields=None):
|
||||
"""
|
||||
Always returns EmptyQuerySet.
|
||||
"""
|
||||
return self
|
||||
|
||||
def extra(self, select=None, where=None, params=None, tables=None,
|
||||
order_by=None, select_params=None):
|
||||
"""
|
||||
Always returns EmptyQuerySet.
|
||||
"""
|
||||
assert self.query.can_filter(), \
|
||||
"Cannot change a query once a slice has been taken"
|
||||
return self
|
||||
|
||||
def reverse(self):
|
||||
"""
|
||||
Always returns EmptyQuerySet.
|
||||
"""
|
||||
return self
|
||||
|
||||
def defer(self, *fields):
|
||||
"""
|
||||
Always returns EmptyQuerySet.
|
||||
"""
|
||||
return self
|
||||
|
||||
def only(self, *fields):
|
||||
"""
|
||||
Always returns EmptyQuerySet.
|
||||
"""
|
||||
return self
|
||||
|
||||
def update(self, **kwargs):
|
||||
"""
|
||||
Don't update anything.
|
||||
"""
|
||||
return 0
|
||||
|
||||
def aggregate(self, *args, **kwargs):
|
||||
"""
|
||||
Return a dict mapping the aggregate names to None
|
||||
"""
|
||||
for arg in args:
|
||||
kwargs[arg.default_alias] = arg
|
||||
return dict([(key, None) for key in kwargs])
|
||||
|
||||
def values(self, *fields):
|
||||
"""
|
||||
Always returns EmptyQuerySet.
|
||||
"""
|
||||
return self
|
||||
|
||||
def values_list(self, *fields, **kwargs):
|
||||
"""
|
||||
Always returns EmptyQuerySet.
|
||||
"""
|
||||
return self
|
||||
|
||||
# EmptyQuerySet is always an empty result in where-clauses (and similar
|
||||
# situations).
|
||||
value_annotation = False
|
||||
|
||||
def get_klass_info(klass, max_depth=0, cur_depth=0, requested=None,
|
||||
only_load=None, from_parent=None):
|
||||
"""
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue