2010-01-18 10 views
5

Tengo alrededor de una docena de búsquedas de permisos que aseguran que los usuarios tengan los permisos adecuados para hacer algo en el sistema (es decir, asegurarse de que estén en el grupo correcto, si pueden editar su perfil , si son administradores de grupo, etc.).Almacenamiento en caché de devoluciones no vistas

Un cheque podría tener este aspecto:

from django.contrib.auth.decorators import user_passes_test 

test_canvote = lambda u: u.has_perm('polls.can_vote') 

@user_passes_test(test_canvote) 
def my_view(request): 
    # ... 

Esto es en realidad el código del tutorial de Django (el mío es un poco más feo). A veces, un control requiere mucha base de datos y genera múltiples consultas. Con muchos usuarios accediendo a páginas marcadas con permiso, las cosas pueden volverse bastante lentas rápidamente.

Mi pregunta es, ¿puedo (con su ayuda) construir un contenedor (o reemplazo) para el decorador user_passes_test que busca en el caché una clave 'TESTCACHE' + user.pk + 'testname' y si no existe, ejecuta la prueba y guarda su resultado.

nunca he escrito un decorador antes, pero me imagino que sería casi idéntica a la user_passes_test uno, sólo pasar la prueba como una cadena:

@cached_user_passes_test('test_canvote') 
def my_view(request): 
    # ... 

Y como siempre, quiero saber si yo estoy loco o si Django ya hace esto por mí (entonces tengo problemas en otro lado).

Editar: Los decoradores estándar se pueden encontrar aquí: http://code.djangoproject.com/browser/django/trunk/django/contrib/auth/decorators.py

yo creo que puede ser más fácil la sustitución de user_passes_test envolviéndolo Así que aquí está el punto de partida. Por supuesto, si usted siente que soy incorrecto en esa declaración, que me haga saber:

try: 
    from functools import update_wrapper, wraps 
except ImportError: 
    from django.utils.functional import update_wrapper, wraps # Python 2.3, 2.4 fallback. 

from django.contrib.auth import REDIRECT_FIELD_NAME 
from django.http import HttpResponseRedirect 
from django.utils.http import urlquote 
from django.utils.decorators import auto_adapt_to_methods 

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. 
    """ 
    if not login_url: 
     from django.conf import settings 
     login_url = settings.LOGIN_URL 

    def decorator(view_func): 
     def _wrapped_view(request, *args, **kwargs): 
      if test_func(request.user): 
       return view_func(request, *args, **kwargs) 
      path = urlquote(request.get_full_path()) 
      tup = login_url, redirect_field_name, path 
      return HttpResponseRedirect('%s?%s=%s' % tup) 
     return wraps(view_func)(_wrapped_view) 
    return auto_adapt_to_methods(decorator) 

Respuesta

1

que pueda necesitar para serializar la función (que no estoy haciendo cuando lo uso como la clave de la memoria caché) , pero algo como esto debería funcionar:

from django.core.cache import cache 

def cached_user_passes_test(test_func, login_url=None, redirect_field_name=REDIRECT_FIELD_NAME): 
    if not login_url: 
     from django.conf import settings 
     login_url = settings.LOGIN_URL 

    def decorator(view_func): 
     def _wrapped_view(request, *args, **kwargs): 
      key = str(test_func) + str(request.user) 
      cached_test_result = cache.get(key) 
      if cached_test_result != None: 
       test_result = cached_test_result 
      else: 
       test_result = test_func(request.user) 
       cache.set(key, test_result, 60)  

      if test_result: 
       return view_func(request, *args, **kwargs) 
      path = urlquote(request.get_full_path()) 
      tup = login_url, redirect_field_name, path 
      return HttpResponseRedirect('%s?%s=%s' % tup) 
     return wraps(view_func)(_wrapped_view) 
    return auto_adapt_to_methods(decorator) 
+0

Los argumentos para la función de prueba también deberían ser parte de la clave por razones obvias. – Oli

+0

Por supuesto, tratando de ser demasiado inteligente con el último ... editado para hacer la obtención y la configuración dentro del decorador. ¿Esto funcionaría? – ara818

0

en primer lugar, simplemente puede escribir:

from django.contrib.auth.decorators import permission_required 

@permission_required('polls.can_vote') 
def my_view(request): 
    # ... 

en segundo lugar, si los permisos no cambian en el tiempo, usted es libre para almacenar alguna información en la sesión (Lo encontré más conveniente ent, que almacenar en un caché de cualquier tipo), cuando el usuario inicia sesión.

Pero recuerde que si cambia los permisos, el usuario tiene que cerrar la sesión y volver a trabajar con los nuevos permisos.

+0

Creo que te has perdido el punto. Como dije, mis pruebas son un poco más complejas que un simple 'permission_required' y todas giran alrededor de' user_passes_test'. "¿Cómo puedo guardar en caché un decorador?" podría haber sido un título más preciso. Esto es mucho más acerca de cómo se hace el almacenamiento en caché. – Oli

Cuestiones relacionadas