2010-04-27 16 views
18

Sto utilizzando il Django Message Framework per mostrare messaggi agli utenti e il decoratore @login_required su una delle mie viste. Quindi, se un utente tenta di accedere a una determinata vista senza essere loggato, viene preso a calci alla pagina di accesso. Come vorrei aggiungere un messaggio di errore alla pagina di accesso che dice "Per poter fare ... devi essere loggato". Non riesco ad aggiungerlo alla vista come faresti normalmente perché l'utente che non ha effettuato l'accesso non ci arriverebbe mai.Django message framework e login_required

risposta

13

Non c'è alcun modo ovvio. L'unica cosa che mi viene in mente è scrivere la tua versione del decoratore che mette un messaggio nella sessione prima di reindirizzare, quindi ottenere il modello di login per visualizzare il messaggio dalla sessione.

È necessario utilizzare il codice in django.contrib.auth.decorators, in particolare la funzione user_passes_test - il bit per aggiungere il messaggio dovrebbe andare prima dello return HttpResponseRedirect.

13

Mi c'è voluto un po 'per capire un bel modo di fare questo, ma penso che Ho un'implementazione, basata sulla risposta di Daniel Roseman

Per prima cosa ho creato un decoratore che imposta i messaggi quando un utente non ha effettuato l'accesso, esattamente come login_required.

Così ho scritto login_required_message:

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

from django.utils.decorators import available_attrs 

from django.contrib import messages 

default_message = "Please log in, in order to see the requested page." 

def user_passes_test(test_func, message=default_message): 
    """ 
    Decorator for views that checks that the user passes the given test, 
    setting a message in case of no success. 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 not test_func(request.user): 
       messages.error(request, message) 
      return view_func(request, *args, **kwargs) 
     return _wrapped_view 
    return decorator 

def login_required_message(function=None, message=default_message): 
    """ 
    Decorator for views that checks that the user is logged in, redirecting 
    to the log-in page if necessary. 
    """ 
    actual_decorator = user_passes_test(
     lambda u: u.is_authenticated(), 
     message=message, 
    ) 
    if function: 
     return actual_decorator(function) 
    return actual_decorator 

Con questa implementazione è ora possibile annotare i vostri metodi vista in questo modo:

from decorators import login_required_message 
from django.contrib.auth.decorators import login_required 

@login_required_message(message="You should be logged in, in order to see the index!") 
@login_required 
def index(request): 
    pass 

Ora prima sarà impostato il messaggio, quindi verrà eseguita l'reindirizzamento .

Tuttavia, in realtà non desidero aggiungere il decoratore login_required_message ovunque. Sarebbe molto più bello avere un solo decoratore. Quindi, consente loro catena (semplicemente aggiungere questo al file decorator.py dopo login_required_message):

from django.contrib.auth import REDIRECT_FIELD_NAME 
from django.contrib.auth.decorators import login_required 

def login_required_message_and_redirect(function=None, redirect_field_name=REDIRECT_FIELD_NAME, login_url=None, message=default_message): 

    if function: 
     return login_required_message(
      login_required(function, redirect_field_name, login_url), 
      message 
     ) 

    return lambda deferred_function: login_required_message_and_redirect(deferred_function, redirect_field_name, login_url, message) 

Mi c'è voluto un po 'per capire questa ultima riga; ma Lambda è in soccorso!

Ora è possibile sostituire i due decoratori con solo login_required_message_and_redirect: quasi lì! Dal momento che in realtà voglio usare questo nuovo metodo login_required_message ovunque, aggiungo una patch di scimmia per login_required e viene usato ovunque (di nuovo aggiunta alla fine del file decorators.py)!

from django.contrib.auth import decorators 
setattr(decorators, 'login_required', login_required_message_and_redirect) 

che mi permette di chiamare:

# a message will appear, since login_required is monkey patched 
@login_required 
def logout(request): 
    pass 

# or customize the message per view 
@login_required(message="You should be logged in message! Available after monkey patch") 
def index(request): 
    pass 
Problemi correlati