Подтвердить что ты не робот

Структура сообщений Django и login_required

Я использую Django Message Framework, чтобы показывать сообщения пользователям, а также декоратору @login_required на одном из моих представлений. Поэтому, если пользователь пытается получить доступ к определенному виду без входа в систему, он попадает на страницу входа в систему. Как я могу добавить сообщение об ошибке на страницу входа, в которой говорится: "Чтобы... вы должны войти в систему". Я не могу добавить его в представление, как обычно, потому что пользователь без входа никогда не доберется туда.

4b9b3361

Ответ 1

Нет никакого очевидного пути. Единственное, что приходит на ум, это написать свою собственную версию декоратора, которая отправляет сообщение в сеанс перед перенаправлением, а затем получает шаблон входа для отображения сообщения из сеанса.

Вам нужно будет использовать код в django.contrib.auth.decorators, в частности функцию user_passes_test - бит для добавления сообщения должен пройти до return HttpResponseRedirect.

Ответ 2

Мне потребовалось некоторое время, чтобы найти хороший способ сделать это, но я думаю, что у меня есть реализация, основанная на ответе Даниэля Роузмана

Первым делом я создал декоратор, который устанавливает сообщения, когда пользователь не вошел в систему, точно так же, как 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        

С помощью этой реализации вы можете теперь аннотировать ваши методы представления следующим образом:

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 везде. Было бы намного приятнее иметь только одного декоратора. Итак, давайте разберем их (просто добавьте это в ваш файл decorator.py после 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)

Мне понадобилось время, чтобы выяснить эту последнюю строку; но лямбда на помощь!

Теперь вы можете заменить два декоратора только login_required_message_and_redirect: Почти здесь! Поскольку на самом деле я хочу использовать этот новый метод login_required_message везде, я добавляю monkey-patch для 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