execute query commands always to get exceptions if they are not valid
This commit is contained in:
parent
c6247aca19
commit
8b8dd06660
1 changed files with 34 additions and 50 deletions
|
@ -7,11 +7,11 @@ from django.db import models
|
||||||
from django.db.models import Manager, Prefetch, Q
|
from django.db.models import Manager, Prefetch, Q
|
||||||
from django.db.models.fields.related_descriptors import ForwardManyToOneDescriptor, ManyToManyDescriptor
|
from django.db.models.fields.related_descriptors import ForwardManyToOneDescriptor, ManyToManyDescriptor
|
||||||
from django.db.models.query_utils import DeferredAttribute
|
from django.db.models.query_utils import DeferredAttribute
|
||||||
from django.utils.functional import cached_property
|
|
||||||
|
|
||||||
|
|
||||||
class BaseWrapper:
|
class BaseWrapper:
|
||||||
_not_wrapped = ('_changeset', '_author', '_obj', '_commands', '_wrap_instances', '_initial_values')
|
_not_wrapped = ('_changeset', '_author', '_obj', '_commands', '_with_commands_executed', '_wrap_instances',
|
||||||
|
'_initial_values')
|
||||||
_allowed_callables = ('', )
|
_allowed_callables = ('', )
|
||||||
|
|
||||||
def __init__(self, changeset, obj, author=None):
|
def __init__(self, changeset, obj, author=None):
|
||||||
|
@ -208,40 +208,24 @@ class ModelInstanceWrapper(BaseWrapper):
|
||||||
self._changeset.add_delete(self, author=author)
|
self._changeset.add_delete(self, author=author)
|
||||||
|
|
||||||
|
|
||||||
class ModifiesQueryDecorator:
|
def modifies_query(f):
|
||||||
def __init__(self, test_call=False):
|
|
||||||
self.test_call = test_call
|
|
||||||
|
|
||||||
def __call__(self, f):
|
|
||||||
@wraps(f)
|
@wraps(f)
|
||||||
def wrapper(qs, *args, execute=False, **kwargs):
|
def wrapper(self, *args, execute=False, **kwargs):
|
||||||
if execute:
|
if execute:
|
||||||
return f(qs, *args, **kwargs)
|
return f(self, *args, **kwargs)
|
||||||
if self.test_call:
|
qs = self._wrap_queryset(self.get_queryset(), add_command=(f.__name__, args, kwargs))
|
||||||
f(qs, *args, test_call=True, **kwargs)
|
qs.execute_commands()
|
||||||
return qs._wrap_queryset(qs.get_queryset(), add_command=(f.__name__, args, kwargs))
|
return qs
|
||||||
|
|
||||||
return wrapper
|
return wrapper
|
||||||
|
|
||||||
|
|
||||||
modifies_query = ModifiesQueryDecorator
|
def executes_query(f):
|
||||||
|
|
||||||
|
|
||||||
class ExecutesQueryDecorator:
|
|
||||||
def __init__(self, test_call=False):
|
|
||||||
self.test_call = test_call
|
|
||||||
|
|
||||||
def __call__(self, f):
|
|
||||||
@wraps(f)
|
@wraps(f)
|
||||||
def wrapper(qs, *args, **kwargs):
|
def wrapper(self, *args, **kwargs):
|
||||||
qs = qs.executed
|
return f(self._with_commands_executed, *args, **kwargs)
|
||||||
return f(qs, *args, **kwargs)
|
|
||||||
return wrapper
|
return wrapper
|
||||||
|
|
||||||
|
|
||||||
executes_query = ExecutesQueryDecorator
|
|
||||||
|
|
||||||
|
|
||||||
class BaseQueryWrapper(BaseWrapper):
|
class BaseQueryWrapper(BaseWrapper):
|
||||||
_allowed_callables = ('_add_hints', '_next_is_sticky', 'get_prefetch_queryset')
|
_allowed_callables = ('_add_hints', '_next_is_sticky', 'get_prefetch_queryset')
|
||||||
|
|
||||||
|
@ -249,17 +233,17 @@ class BaseQueryWrapper(BaseWrapper):
|
||||||
super().__init__(changeset, obj, author)
|
super().__init__(changeset, obj, author)
|
||||||
self._wrap_instances = wrap_instances
|
self._wrap_instances = wrap_instances
|
||||||
self._commands = commands
|
self._commands = commands
|
||||||
|
self._with_commands_executed = self
|
||||||
|
|
||||||
def get_queryset(self):
|
def get_queryset(self):
|
||||||
return self._obj
|
return self._obj
|
||||||
|
|
||||||
@cached_property
|
def execute_commands(self):
|
||||||
def executed(self):
|
|
||||||
result = self
|
result = self
|
||||||
for name, args, kwargs in self._commands:
|
for name, args, kwargs in self._commands:
|
||||||
result = getattr(result, name)(*args, execute=True, **kwargs)
|
result = getattr(result, name)(*args, execute=True, **kwargs)
|
||||||
result._commands = ()
|
result._commands = ()
|
||||||
return result
|
self._with_commands_executed = result
|
||||||
|
|
||||||
def _wrap_instance(self, instance):
|
def _wrap_instance(self, instance):
|
||||||
if self._wrap_instances:
|
if self._wrap_instances:
|
||||||
|
@ -274,19 +258,19 @@ class BaseQueryWrapper(BaseWrapper):
|
||||||
commands += (add_command, )
|
commands += (add_command, )
|
||||||
return QuerySetWrapper(self._changeset, queryset, self._author, commands, wrap_instances)
|
return QuerySetWrapper(self._changeset, queryset, self._author, commands, wrap_instances)
|
||||||
|
|
||||||
@modifies_query()
|
@modifies_query
|
||||||
def all(self):
|
def all(self):
|
||||||
return self._wrap_queryset(self.get_queryset().all())
|
return self._wrap_queryset(self.get_queryset().all())
|
||||||
|
|
||||||
@modifies_query()
|
@modifies_query
|
||||||
def none(self):
|
def none(self):
|
||||||
return self._wrap_queryset(self.get_queryset().none())
|
return self._wrap_queryset(self.get_queryset().none())
|
||||||
|
|
||||||
@modifies_query()
|
@modifies_query
|
||||||
def select_related(self, *args, **kwargs):
|
def select_related(self, *args, **kwargs):
|
||||||
return self._wrap_queryset(self.get_queryset().select_related(*args, **kwargs))
|
return self._wrap_queryset(self.get_queryset().select_related(*args, **kwargs))
|
||||||
|
|
||||||
@modifies_query()
|
@modifies_query
|
||||||
def prefetch_related(self, *lookups):
|
def prefetch_related(self, *lookups):
|
||||||
new_lookups = deque()
|
new_lookups = deque()
|
||||||
for lookup in lookups:
|
for lookup in lookups:
|
||||||
|
@ -301,7 +285,7 @@ class BaseQueryWrapper(BaseWrapper):
|
||||||
new_lookups.append(Prefetch(lookup, qs))
|
new_lookups.append(Prefetch(lookup, qs))
|
||||||
return self._wrap_queryset(self.get_queryset().prefetch_related(*new_lookups))
|
return self._wrap_queryset(self.get_queryset().prefetch_related(*new_lookups))
|
||||||
|
|
||||||
@executes_query()
|
@executes_query
|
||||||
def get(self, *args, **kwargs):
|
def get(self, *args, **kwargs):
|
||||||
results = tuple(self.filter(*args, **kwargs))
|
results = tuple(self.filter(*args, **kwargs))
|
||||||
if len(results) == 1:
|
if len(results) == 1:
|
||||||
|
@ -310,7 +294,7 @@ class BaseQueryWrapper(BaseWrapper):
|
||||||
raise self._obj.model.DoesNotExist
|
raise self._obj.model.DoesNotExist
|
||||||
raise self._obj.model.MultipleObjectsReturned
|
raise self._obj.model.MultipleObjectsReturned
|
||||||
|
|
||||||
@modifies_query()
|
@modifies_query
|
||||||
def order_by(self, *args):
|
def order_by(self, *args):
|
||||||
return self._wrap_queryset(self.get_queryset().order_by(*args))
|
return self._wrap_queryset(self.get_queryset().order_by(*args))
|
||||||
|
|
||||||
|
@ -426,42 +410,42 @@ class BaseQueryWrapper(BaseWrapper):
|
||||||
tuple(self._filter_kwarg(name, value) for name, value in kwargs.items())
|
tuple(self._filter_kwarg(name, value) for name, value in kwargs.items())
|
||||||
)
|
)
|
||||||
|
|
||||||
@modifies_query()
|
@modifies_query
|
||||||
def filter(self, *args, **kwargs):
|
def filter(self, *args, **kwargs):
|
||||||
return self._wrap_queryset(self.get_queryset().filter(*self._filter(*args, **kwargs)))
|
return self._wrap_queryset(self.get_queryset().filter(*self._filter(*args, **kwargs)))
|
||||||
|
|
||||||
@modifies_query()
|
@modifies_query
|
||||||
def exclude(self, *args, **kwargs):
|
def exclude(self, *args, **kwargs):
|
||||||
return self._wrap_queryset(self.get_queryset().exclude(*self._filter(*args, **kwargs)))
|
return self._wrap_queryset(self.get_queryset().exclude(*self._filter(*args, **kwargs)))
|
||||||
|
|
||||||
@executes_query()
|
@executes_query
|
||||||
def count(self):
|
def count(self):
|
||||||
return self.get_queryset().count()
|
return self.get_queryset().count()
|
||||||
|
|
||||||
@executes_query()
|
@executes_query
|
||||||
def values_list(self, *args, flat=False):
|
def values_list(self, *args, flat=False):
|
||||||
return self.get_queryset().values_list(*args, flat=flat)
|
return self.get_queryset().values_list(*args, flat=flat)
|
||||||
|
|
||||||
@executes_query()
|
@executes_query
|
||||||
def first(self):
|
def first(self):
|
||||||
first = self.get_queryset().first()
|
first = self.get_queryset().first()
|
||||||
if first is not None:
|
if first is not None:
|
||||||
first = self._wrap_instance(first)
|
first = self._wrap_instance(first)
|
||||||
return first
|
return first
|
||||||
|
|
||||||
@modifies_query()
|
@modifies_query
|
||||||
def using(self, alias):
|
def using(self, alias):
|
||||||
return self._wrap_queryset(self.get_queryset().using(alias))
|
return self._wrap_queryset(self.get_queryset().using(alias))
|
||||||
|
|
||||||
@executes_query()
|
@executes_query
|
||||||
def __iter__(self):
|
def __iter__(self):
|
||||||
return iter((self._wrap_instance(instance) for instance in self.get_queryset()))
|
return iter((self._wrap_instance(instance) for instance in self.get_queryset()))
|
||||||
|
|
||||||
@executes_query()
|
@executes_query
|
||||||
def iterator(self):
|
def iterator(self):
|
||||||
return iter((self._wrap_instance(instance) for instance in self.get_queryset().iterator()))
|
return iter((self._wrap_instance(instance) for instance in self.get_queryset().iterator()))
|
||||||
|
|
||||||
@executes_query()
|
@executes_query
|
||||||
def __len__(self):
|
def __len__(self):
|
||||||
return len(self.get_queryset())
|
return len(self.get_queryset())
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue