implement callables directly

This commit is contained in:
Laura Klünder 2019-12-10 15:49:06 +01:00
parent 127673f3b0
commit 154f04d4c2

View file

@ -19,13 +19,10 @@ class BaseWrapper:
Base Class for all wrappers. Saves wrapped objects along with the changeset. Base Class for all wrappers. Saves wrapped objects along with the changeset.
getattr, setattr and delattr will be forwarded to the object, exceptions are specified in _not_wrapped. getattr, setattr and delattr will be forwarded to the object, exceptions are specified in _not_wrapped.
If the value of an attribute is a model, model instance, manager or queryset, it will be wrapped, to. If the value of an attribute is a model, model instance, manager or queryset, it will be wrapped, to.
Callables will only be returned be getattr when they are inside _allowed_callables. Callables will only be passed through for models. Implement other passthroughs yourself.
Callables in _wrapped_callables will be returned wrapped, so that their self if the wrapping instance.
""" """
_not_wrapped = frozenset(('_changeset', '_obj', '_created_pks', '_result', '_extra', '_result_cache', _not_wrapped = frozenset(('_changeset', '_obj', '_created_pks', '_result', '_extra', '_result_cache',
'_affected_by_changeset')) '_affected_by_changeset'))
_allowed_callables = frozenset()
_wrapped_callables = frozenset()
def __init__(self, changeset, obj): def __init__(self, changeset, obj):
self._changeset = changeset self._changeset = changeset
@ -84,14 +81,7 @@ class BaseWrapper:
value = self._wrap_instance(value) value = self._wrap_instance(value)
elif isinstance(value, type) and issubclass(value, Exception): elif isinstance(value, type) and issubclass(value, Exception):
pass pass
elif callable(value) and name not in self._allowed_callables: elif callable(value):
if name in self._wrapped_callables:
func = getattr(self._obj.__class__, name)
@wraps(func)
def wrapper(*args, **kwargs):
return func(self, *args, **kwargs)
return wrapper
if isinstance(self, (ModelInstanceWrapper, ModelWrapper)) and not hasattr(models.Model, name): if isinstance(self, (ModelInstanceWrapper, ModelWrapper)) and not hasattr(models.Model, name):
return value return value
raise TypeError('Can not call %s.%s wrapped!' % (type(self), name)) raise TypeError('Can not call %s.%s wrapped!' % (type(self), name))
@ -195,9 +185,6 @@ class ModelInstanceWrapper(BaseWrapper):
Updates updated values on existing objects on init. Updates updated values on existing objects on init.
Can be compared to other wrapped or non-wrapped model instances. Can be compared to other wrapped or non-wrapped model instances.
""" """
_allowed_callables = frozenset(('full_clean', '_perform_unique_checks', '_perform_date_checks'))
_wrapped_callables = frozenset(('validate_unique', '_get_pk_val'))
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs) super().__init__(*args, **kwargs)
self._affected_by_changeset = False self._affected_by_changeset = False
@ -269,6 +256,21 @@ class ModelInstanceWrapper(BaseWrapper):
unique_checks, date_checks = self._obj.__class__._get_unique_checks(self, exclude=exclude) unique_checks, date_checks = self._obj.__class__._get_unique_checks(self, exclude=exclude)
return [(self._wrap_model(model), unique) for model, unique in unique_checks], date_checks return [(self._wrap_model(model), unique) for model, unique in unique_checks], date_checks
def full_clean(self, *args, **kwargs):
return self._obj.full_clean(*args, **kwargs)
def _perform_unique_checks(self, *args, **kwargs):
return self._obj._perform_unique_checks(*args, **kwargs)
def _perform_date_checks(self, *args, **kwargs):
return self._obj._perform_date_checks(*args, **kwargs)
def validate_unique(self, *args, **kwargs):
return self._obj.__class__.validate_unique(self, *args, **kwargs)
def _get_pk_val(self, *args, **kwargs):
return self._obj.__class__._get_pk_val(self, *args, **kwargs)
def save(self): def save(self):
""" """
Create changes in changeset instead of saving. Create changes in changeset instead of saving.
@ -300,8 +302,6 @@ class BaseQueryWrapper(BaseWrapper):
Keeps track of which created objects the current filtering still applies to. Keeps track of which created objects the current filtering still applies to.
When evaluated, just does everything as if the queryset was applied to the databse. When evaluated, just does everything as if the queryset was applied to the databse.
""" """
_allowed_callables = frozenset(('_add_hints', 'get_prefetch_queryset', '_apply_rel_filters'))
def __init__(self, changeset, obj, created_pks=None, extra=()): def __init__(self, changeset, obj, created_pks=None, extra=()):
super().__init__(changeset, obj) super().__init__(changeset, obj)
if created_pks is None: if created_pks is None:
@ -775,6 +775,15 @@ class BaseQueryWrapper(BaseWrapper):
""" """
return self._wrap_queryset(self._obj._next_is_sticky()) return self._wrap_queryset(self._obj._next_is_sticky())
def _add_hints(self, *args, **kwargs):
return self._obj._add_hints(*args, **kwargs)
def get_prefetch_queryset(self, *args, **kwargs):
return self._obj.get_prefetch_queryset(*args, **kwargs)
def _apply_rel_filters(self, *args, **kwargs):
return self._obj._apply_rel_filters(*args, **kwargs)
def create(self, *args, **kwargs): def create(self, *args, **kwargs):
obj = self.model(*args, **kwargs) obj = self.model(*args, **kwargs)
obj.save() obj.save()