18π
No, you cannot pass request to user_passes_test
. To understand why and how it works, just head over to the source:
def user_passes_test(test_func, login_url=None, redirect_field_name=REDIRECT_FIELD_NAME):
"""
Decorator for views that checks that the user passes the given test,
redirecting to the log-in page if necessary. The test should be a callable
that takes the user object and returns True if the user passes.
"""
def decorator(view_func):
@wraps(view_func, assigned=available_attrs(view_func))
def _wrapped_view(request, *args, **kwargs):
if test_func(request.user):
return view_func(request, *args, **kwargs)
path = request.build_absolute_uri()
# If the login url is the same scheme and net location then just
# use the path as the "next" url.
login_scheme, login_netloc = urlparse.urlparse(login_url or
settings.LOGIN_URL)[:2]
current_scheme, current_netloc = urlparse.urlparse(path)[:2]
if ((not login_scheme or login_scheme == current_scheme) and
(not login_netloc or login_netloc == current_netloc)):
path = request.get_full_path()
from django.contrib.auth.views import redirect_to_login
return redirect_to_login(path, login_url, redirect_field_name)
return _wrapped_view
return decorator
This is the code behind the user_passes_test
decorator. As you can see, the test function passed to the decorator (in your case, lambda u: has_add_permission(u, "project")
) is passed just one argument, request.user
. Now, itβs of course possible to write your own decorator (even copying this code directly and just modifying it) to also pass the request
itself, but you canβt do it with the default user_passes_test
implementation.
12π
Note that Django 1.9 introduced UserPassesTestMixin
, which uses a method test_func
as test function. This means the request is available in self.request
. So you can do something like that:
class MyView(UserPassesTestMixin, View):
def test_func(self):
return has_add_permission(self.request.user, self.request)
This only works with class-based views however.
- [Django]-SyntaxError: Generator expression must be parenthezised / python manage.py migrate
- [Django]-Recommended place for a Django project to live on Linux
- [Django]-How to update an object from edit form in Django?
6π
I found editing user_passes_test
to have the decorated function operate on request
rather than request.user
not to be overly difficult. I have a short version in this blog post about a view decorator decorator, but for posterity, hereβs my full edited code:
def request_passes_test(test_func, login_url=None, redirect_field_name=REDIRECT_FIELD_NAME):
"""
Decorator for views that checks that the request passes the given test,
redirecting to the log-in page if necessary. The test should be a callable
that takes the request object and returns True if the request passes.
"""
def decorator(view_func):
@wraps(view_func, assigned=available_attrs(view_func))
def _wrapped_view(request, *args, **kwargs):
if test_func(request):
return view_func(request, *args, **kwargs)
path = request.build_absolute_uri()
# urlparse chokes on lazy objects in Python 3, force to str
resolved_login_url = force_str(
resolve_url(login_url or settings.LOGIN_URL))
# If the login url is the same scheme and net location then just
# use the path as the "next" url.
login_scheme, login_netloc = urlparse(resolved_login_url)[:2]
current_scheme, current_netloc = urlparse(path)[:2]
if ((not login_scheme or login_scheme == current_scheme) and
(not login_netloc or login_netloc == current_netloc)):
path = request.get_full_path()
from django.contrib.auth.views import redirect_to_login
return redirect_to_login(
path, resolved_login_url, redirect_field_name)
return _wrapped_view
return decorator
Pretty much the only thing I did was change if test_func(request.user):
to if test_func(request):
.
- [Django]-Django β use template tag and 'with'?
- [Django]-AttributeError: 'Manager' object has no attribute 'get_by_natural_key' error in Django?
- [Django]-How to add a cancel button to DeleteView in django