Reputation: 1909
I have a Django Model (MyModel) with a decorated method (my_method). I expect the decorators to perform some checks on my_method:
if the checks succeed, my_method should return a string;
if the checks do not succeed, my_method should return the failure messages returned by the decorators.
The logic is the following:
# models.py
class MyModel(models.Model):
@decorator1
@decorator2
def my_method(self, request, *args, **kwargs):
return u'The result that must be returned if all the checks performed by the decorator succeed'
# decorators.py
from functools import wraps
# decorator1 checks if certain conditions are met. If yes, it returns the decorated method (method_to_decorate); if not, it returns a tuple
def decorator1(method_to_decorate):
@wraps(method_to_decorate)
def wrapper1(self, request, *args, **kwargs):
if a_condition :
return method_to_decorate(self, request, *args, **kwargs)
else:
# we return a failure message
return ('failure', 'message')
return wrapper1
# in decorator2, we want to know if the check performed by decorator1 was successful
# in case of success, we perform decorator2's check
# in case of failure, decorator2 should simply pass the failure message returned by decorator1
def decorator2(method_to_decorate):
@wraps(method_to_decorate)
def wrapper2(self, request, *args, **kwargs):
# if the first decorator succeeded
if decorator1_s_test_was_successful:
# we check if the conditions of the second decorator are met
if decorator2_s_test_was_successful:
# we return the method
return method_to_decorate(self, request, *args, **kwargs)
else:
# we return a failure message
return ('another failure', 'message')
# if the first decorator did not succeed
else: # decorator1 returned a tuple : ('failure', 'message')
return the_failure_that_decorator1_returned
return wrapper2
So, if decorator1 returns a failure, I expect an_instance_of_my_model_instance.my_method(request) to return ('failure', 'message'). If decorator1 succeeded but not decorator2, I would expect ('another failure', 'message'). And if all the test were passed, u'The result that must be returned if all the checks performed by the decorator succeed'
I do not know how to check in decorator2 if decorator1's checks were successfully passed. I tried to do it by checking the type() of the method_to_decorate in decorator2, but it seems that type uses the original method itself, not its result as returned by decorator1 (as if decorators did not know about the operations performed by previous decorators).
Thank you in advance!
Upvotes: 1
Views: 6128
Reputation: 41950
The decorators will be called in the order you put them above the decorated method, and given your program structure, decorator2
doesn't get called if decorator1
fails, so there's no need to check if decorator1
was successful in decorator2
.
A slightly simpler example...
from functools import wraps
def decorator1(f):
@wraps(f)
def wrapper(a):
if a >= 1:
return f(a)
return 'failed in decorator 1'
return wrapper
def decorator2(f):
@wraps(f)
def wrapper(a):
if a >= 2:
return f(a)
return 'failed in decorator 2'
return wrapper
@decorator1
@decorator2
def my_func(a):
return 'success'
print my_func(0)
print my_func(1)
print my_func(2)
...which prints...
failed in decorator 1
failed in decorator 2
success
Upvotes: 6
Reputation: 1121864
You'll need to swap the @decorator1
and @decorator2
lines if you want decorator2
to check up on whatever decorator1
returned:
@decorator2
@decorator1
def my_method(self, request, *args, **kwargs):
return u'The result that must be returned if all the checks performed by the decorator succeed'
Now decorator2
will wrap whatever method decorator1
returned, and you can thus inspect what that method returns.
def decorator2(method_to_decorate):
@wraps(method_to_decorate)
def wrapper2(self, request, *args, **kwargs):
result = method_to_decorate(self, request, *args, **kwargs)
if isinstance(result, tuple) and result and result[0] == 'failure':
# decorator1 returned a failure
return result
else:
# decorator1 passed through the wrapped method call
if decorator2_s_test_was_successful:
return result
else:
return ('another failure', 'message')
return wrapper2
Upvotes: 5