2012-08-08 21 views
16

Estoy usando Django user_passes_test decorator para comprobar el permiso del usuario.Cómo pasar el objeto de solicitud de Django en user_passes_test decorator invocable función

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

Estoy llamando a una función de devolución de has_add_permission que toma dos argumentos de 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?

+0

Tengo curiosidad, ¿cómo terminaste yendo sobre esto? ¿Escribiste tu propio decorador? – teewuane

+0

En lugar de usar decoradores, estoy buscando permisos dentro del código de vista. Me dio un mejor control sobre la lógica de vista. –

+0

Eso es lo que terminé haciendo también. ¡Gracias! – teewuane

Respuesta

12

No, no puede pasar la solicitud al user_passes_test. Para entender por qué y cómo funciona, sólo la cabeza hacia el 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 

Este es el código detrás de la user_passes_test decorador. Como puede ver, la función de prueba transferida al decorador (en su caso, lambda u: has_add_permission(u, "project")) se pasa solo un argumento, request.user. Ahora, es posible, naturalmente, para escribir su propio decorador (incluso copiar el código directamente y simplemente modificarlo) también para pasar el request sí mismo, pero no puede hacerlo con la user_passes_test implementación por defecto.

+0

Gracias Chris. Supongo que tengo que escribir un nuevo decorador o hacerlo dentro del código de vista. –

4

Encontré la edición user_passes_test para tener la función decorada operar en request en lugar de request.user para no ser demasiado difícil. Tengo una versión corta en this blog post sobre un decorador decorador de vista, pero para la posteridad, aquí está mi código editado completo:

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 

Prácticamente lo único que hice fue el cambio if test_func(request.user): a if test_func(request):.

7

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

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

Esto solo funciona con vistas basadas en clases.

Cuestiones relacionadas