2010-01-18 12 views
5

Ho una dozzina circa di ricerche sui permessi sulle viste che assicurano che gli utenti abbiano le autorizzazioni giuste per fare qualcosa sul sistema (ad esempio assicuratevi che siano nel gruppo giusto, se possono modificare il loro profilo , se sono amministratori di gruppo, ecc.).Caching non vista restituisce

Un controllo potrebbe assomigliare a questo:

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): 
    # ... 

Questo è in realtà il codice dal tutorial Django (il mio è un po 'più brutta). A volte un controllo richiede molto database, sparando più query. Con molti utenti che accedono alle pagine con il controllo delle autorizzazioni, le cose possono diventare abbastanza lente.

La mia domanda è, posso (con il vostro aiuto) costruire un involucro (o sostituzione) per il decoratore user_passes_test che cerca la cache per una chiave 'TESTCACHE' + user.pk + 'testname' e se non esiste, viene eseguito il test e salva il risultato.

non ho mai scritto un decoratore prima, ma immagino che apparirebbe quasi identico al user_passes_test uno, basta passare il test come una stringa:

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

E come sempre, fatemi sapere se io' Sono pazzo o se Django lo fa già per me (quindi ho problemi altrove).

Edit: I decoratori standard possono essere trovate qui: http://code.djangoproject.com/browser/django/trunk/django/contrib/auth/decorators.py

penso che potrebbe essere più facile sostituzione user_passes_test di avvolgendolo ecco il punto di partenza. Naturalmente, se si sente che sono errati in questa affermazione, me lo faccia sapere:

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) 

risposta

1

potrebbe essere necessario per serializzare la funzione (che non sto facendo quando lo uso come la chiave per la cache) , ma qualcosa come questo dovrebbe funzionare:

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

Gli argomenti per la funzione di test dovrebbero anche essere parte della chiave anche per ovvi motivi. – Oli

+0

Certo, cercando di essere troppo intelligente con l'ultimo ... modificato per fare la presa e l'impostazione all'interno del decoratore. Funzionerebbe? – ara818

0

in primo luogo si può semplicemente scrivere:

from django.contrib.auth.decorators import permission_required 

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

in secondo luogo, se i permessi non cambiano nel tempo, si è liberi di memorizzare alcune informazioni nella sessione (L'ho trovato più comodo ent, che memorizzare in una cache di qualsiasi tipo), quando l'utente esegue il login.

Ma ricorda che se si modificano le autorizzazioni, l'utente deve disconnettersi e rientrare per lavorare con le nuove autorizzazioni.

+0

Penso che tu abbia perso il punto. Come ho già detto, i miei test sono leggermente più complessi di un semplice 'permission_required' e girano tutti su' user_passes_test'. "Come posso memorizzare in cache un decoratore?" potrebbe essere stato un titolo più accurato. Questo è molto di più su come si fa il caching. – Oli