2010-04-27 75 views
18

我使用Django的消息框架展现给用户的消息,以及在@login_required装饰上的我的意见之一。因此,如果用户尝试访问某个视图而未登录,则会被踢到登录页面。我将如何去添加一条错误消息到登录页面说:“为了做...你必须登录”。我不能像通常那样在视图中添加它,因为未登录的用户永远不会到达那里。Django的消息框架和login_required

回答

13

这里没有任何明显的方法。唯一值得关注的是编写自己的修饰器版本,在重定向之前将消息放入会话中,然后获取登录模板以显示会话中的消息。

您需要使用django.contrib.auth.decorators中的代码,特别是user_passes_test函数 - 添加消息的位必须在return HttpResponseRedirect之前执行。

13

我花了一段时间才能找出这样做的一个很好的方式,但我认为我有一个实施的基础上,丹尼尔·罗斯曼

第一件事答案我所做的就是创建一个装饰,设置消息时没有登录的用户,酷似login_required。

所以我写了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 

使用这种实现,你现在可以标注您的视图的方法是这样的:

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 

现在首先该消息将被设置,然后重定向将执行。

不过,我其实不想到处添加login_required_message装饰。只有一个装饰者会更好。因此,让他们链(简单地将其添加到login_required_message后您的decorator.py文件):

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) 

我花了一段时间才能找出这个最后一行;但拉姆达的救援!几乎有:

现在你可以只用login_required_message_and_redirect代替两个装饰!因为实际上我想在任何地方使用这个新login_required_message法,我添加了一个猴子补丁login_required,它是到处被使用(再次添加到decorators.py文件的底部)!

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

,让我打电话:

# 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