Django消息框架和login_required

rof*_*fle 21 django

我正在使用Django Message Framework向用户以及@login_required我的一个视图上的装饰器显示消息.因此,如果用户在未登录的情况下尝试访问某个视图,他们就会被踢到登录页面.我如何向登录页面添加错误消息"为了做...你必须登录".我不能像往常一样在视图中添加它,因为未登录的用户永远不会到达那里.

Lva*_*Ree 17

我花了一段时间才弄清楚这样做的好方法,但我认为我有一个实现,基于Daniel Roseman的回答

我做的第一件事是创建一个装饰器,当用户没有登录时设置消息,就像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, #fixed by removing ()
        message=message,
    )
    if function:
        return actual_decorator(function)
    return actual_decorator        
Run Code Online (Sandbox Code Playgroud)

通过此实现,您现在可以注释您的视图方法,如下所示:

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
Run Code Online (Sandbox Code Playgroud)

现在首先设置消息,然后执行重定向.

但实际上我并不想在任何地方添加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)
Run Code Online (Sandbox Code Playgroud)

我花了一段时间来弄清楚最后一行; 但是lambda要救了!

现在你可以用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)
Run Code Online (Sandbox Code Playgroud)

这让我打电话:

# 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
Run Code Online (Sandbox Code Playgroud)


Dan*_*man 13

没有任何明显的方法.我唯一想到的是编写自己的装饰器版本,在重定向之前将消息放入会话,然后获取登录模板以显示会话中的消息.

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