template loginview login_required decorators custom python django django-views django-authentication

python - loginview - login_required django



Cómo pasar el objeto de solicitud de Django en la función invocable user_passes_test decorator (3)

No, no puedes pasar la solicitud a user_passes_test . Para entender por qué y cómo funciona, diríjase a la fuente :

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

Este es el código detrás del decorador user_passes_test . Como puede ver, la función de prueba pasó al decorador (en su caso, lambda u: has_add_permission(u, "project") ) se pasa solo un argumento, request.user . Ahora, por supuesto, es posible escribir su propio decorador (incluso copiando este código directamente y simplemente modificándolo) para pasar también la request , pero no puede hacerlo con la implementación user_passes_test predeterminada.

Estoy usando Django user_passes_test decorator para verificar el permiso del usuario.

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

Estoy llamando a una función de devolución de llamada has_add_permission que toma dos argumentos Usuario y una Cadena. Me gustaría pasar el objeto de solicitud junto con eso es posible? Además, ¿alguien puede decirme cómo podemos acceder directamente al objeto Usuario dentro del decorador?


Encontré la edición de user_passes_test para que la función decorada funcione a request lugar de request.user para que no sea demasiado difícil. Tengo una versión corta en este blog sobre decorador de decorador de vistas, pero para la posteridad, aquí está mi código completo editado:

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

Casi lo único que hice fue cambiar if test_func(request.user): to if test_func(request):


Tenga en cuenta que Django 1.9 introdujo UserPassesTestMixin , que usa un método test_func como función de prueba. Esto significa que la solicitud está disponible en self.request . Entonces puedes hacer algo como eso:

class MyView(UserPassesTestMixin, View): def test_func(self): return has_add_permission(self.request.user, self.request)

Sin embargo, esto solo funciona con vistas basadas en clases.