1👍
✅
It is possible, and it came to me in the form of a decorator.
It’s a little bit obscure, I know, but we are in Python, and Python allow for a lil bit of darkness 😉
This one here searches the stack frames for an instance of HttpRequest
and if it finds it, it will inject it into the decorated function.
(If you are wondering, assertions are there to help you code defensively: a request object might not be found, or the function call could still fail in a template if extra arguments don’t have default values, etc.)
import inspect
from django.http import HttpRequest
from django.utils import six
def inject_request(func):
argspec = inspect.getargspec(func)
assert 'request' in argspec.args, \
"There must be a 'request' argument in the function."
index = argspec.args.index('request')
assert index in [0, 1], \
"The 'request' argument must be, at most, the second positional argument."
assert len(argspec.args) - len(argspec.defaults or []) == index, \
"All arguments after (and including) 'request' must have default values."
def wrapper(*args, **kwargs):
if (index < len(args) and args[index]) or kwargs.get('request', None):
return func(*args, **kwargs)
request = None
frame = inspect.currentframe().f_back
while frame and not request:
for v_name, v_object in six.iteritems(frame.f_locals):
if isinstance(v_object, HttpRequest):
request = v_object
break
frame = frame.f_back
if request:
kwargs.setdefault('request', request)
return func(*args, **kwargs)
return wrapper
In your models, you can do this:
class SomeModel(models.Model):
...
...
@inject_request
def allow_editing(self, request=None):
...
@inject_request
def allow_super_awkward_action(self, request=None):
...
And we’re back to happiness using the plain method call in templates:
{% if object.allow_super_awkward_action %}
place link to the action
{% endif %}
This will work!
Source:stackexchange.com