- PVSM.RU - https://www.pvsm.ru -
Каждый из нас не раз использовал декоратор login_required и скорее всего писал похожий декоратор(скажем для проверки пустая ли корзина). Давайте рассмотрим что делает данный декоратор:

Если посмотреть на это целиком то можно представить так:

Декоратор, который проверяет пришедший к нему запрос и в зависимости от результата отдает либо view, либо другую функцию — назовем декоратором проверки.
Так как схема одна и та же, мы можем написать «заготовку» для декоратора:
def check_decorator(view=None,
condition_func = lambda request, *args, **kwargs: True,
false_func = lambda request, *args, **kwargs: HttpResponse()):
'''
Checks by :function:condition_func, if true go to :function: view,
else go to :function:false_func
:param condition_func: Should return Boolean value
:type condition_func: function
:param false_func: Should return object of :class:`http.HttpResponse'
:return: :class:`http.HttpResponse`
'''
def decorator(view):
@wraps(view)
def wrapper(request, *args, **kwargs):
if not condition_func(request, *args, **kwargs):
return false_func(request, *args, **kwargs)
return view(request, *args, **kwargs)
return wrapper
return decorator(view) if view else decorator
check_decorator — это базовая функция, которая принимает view, функцию условия(condition_func) и функцию, которая используется при отрицательном результате условия(false_func).
Теперь что бы создать функцию, которая авторизованных пользователей выкидывает в личный кабинет(предположим с регистрации) нам следует сделать следующие шаги:
from functools import partial
is_anonymous = lambda request, *args, **kwargs: request.user.is_anonymous()
office_redirect = lambda request, *args, **kwargs: redirect('office') # office - имя view в urls
should_be_anonymous = partial(check_decorator,
condition_func=is_anonymous,
false_func=office_redirect)
Думаю, что написать другую функцию условия или функцию, которая вызывается при не пройденном условии(false_func), у вас не составит труда.
Многие из нас привыкли, что можно указать куда будем пересылать пользователя, указывая redirect_url:
@login_required(redirect_url=reverse_lazy('my_view_name'))
def some_view(request, *args, **kwargs):
pass
В данном случае у нас функция false_func всегда производит redirect, а мы должны указывать куда производить url.
Создадим данную функцию на основе нашей «заготовки»:
def redirect_decorator(view=None, redirect_url=None, **kwargs):
'''
Uses :function:`check_decorator` with false_func that returns
:param:`redirect_url`
'''
assert not redirect_url is None, "Redirect_url should be setted"
if 'false_handle_func' in kwargs:
del kwargs['false_func']
redirect_func = lambda request, *args, **kwargs: redirect(redirect_url)
return check_decorator(view=view, false_func=redirect_func,
**kwargs)
В функции redirect_decorator мы проверяем передан ли нам redirect_url, и если нам передали
false_func — удаляем её. Затем возвращаем значение функции check_decorator.
Функцию should_be_anonymous можем переписать так:
should_be_anonymous = partial(redirect_decorator,
condition_func=is_anonymous)
И использовать в привычной нам форме:
@should_be_anonymouse(redirect_url=reverse_lazy('office'))
def some_view(request, *args, **kwargs):
pass
В django есть замечательный механизм сообщений django.messages [2], при помощи которого мы можем передать сообщения нашему пользователю.
Посмотрим как он работает:
Пишем во view:
from django.contrib import messages
def view(request, *args, **kwargs):
...
messages.info("Hello World!") #Передаем сообщение польpователю
...
Показываем в шаблоне:
{% if messages %}
<ul>
{% for message in messages %}
<li>{{ message }}</li>
{% endfor %}
</ul>
{% endif %}
При помощи данного механизма мы можем уведомить пользователя, почему он не попал на какую-то страницу.
Создадим функцию, которая будет производить редирект и передавать наше сообщение:
def redirect_message_decorator(view=None, message=None, redirect_url=None,
**kwargs):
'''
Uses :function: c`check_decorator` with false_func thar returns
:param:`redirect_url`
'''
assert not redirect_url is None, "Redirect_url should be setted"
assert not message is None, "Message should be setted"
if 'false_func' in kwargs:
del kwargs['false_func']
def redirect_func(request, *args, **kwargs):
messages.info(request, message)
return redirect(redirect_url)
return check_decorator(view=view, false_func=redirect_func,
**kwargs)
Функция should_be_anonymous с сообщением выглядит так:
should_be_anonymouse = partial(redirect_message_decorator,
condition_func=is_anonymous)
И использование данного декоратора:
@should_be_anonymouse(message=u'Вам туда нельзя',
redirect_url=reverse_lazy('office'))
def some_view(request, *args, **kwargs):
pass
Для использование декоратора с CBV [3] можно использовать этот сниппет [4]
Статья не очень сложная, но для новичков, надеюсь, она будет интересна.
Всем приятного изучения/использования/разработки чудесного фреймворка django.
Автор: Zapix
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/django-2/9996
Ссылки в тексте:
[1] functools.partial: http://docs.python.org/library/functools.html#functools.partial
[2] django.messages: https://docs.djangoproject.com/en/1.4/ref/contrib/messages/
[3] CBV: https://docs.djangoproject.com/en/1.4/topics/class-based-views/
[4] сниппет: http://djangosnippets.org/snippets/2505/
Нажмите здесь для печати.