Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to pass Django request object in user_passes_test decorator callable function

Tags:

I am using Django user_passes_test decorator to check the User Permission.

@user_passes_test(lambda u: has_add_permission(u, "project")) def create_project(request): ...... 

I am calling a callback function has_add_permission which takes two arguments User and a String. I would like to pass the request object along with it is that possible? Also, can anyone please tell me how are we able to access the User object inside the decorator directly.

like image 245
Raunak Agarwal Avatar asked Aug 08 '12 20:08

Raunak Agarwal


2 Answers

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.

like image 91
Chris Pratt Avatar answered Sep 18 '22 15:09

Chris Pratt


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.

like image 44
Antoine Pinsard Avatar answered Sep 20 '22 15:09

Antoine Pinsard