Что такое декоратор?
Декоратор — это название одного из самых популярных шаблонов проектирования, используемых в наше время, и мы часто пользуемся им, не зная, что мы используем шаблон проектирования. И что же такого особенного в этом шаблоне? Как мы можем прочитать на Python Wiki, используя этот шаблон, мы получаем способ явно изменить поведение объекта, заключив его в украшающий объект с похожим интерфейсом.
Почему стоит использовать декораторы в своем веб-приложении?
Декораторы динамически изменяют поведение функции, метода или класса без необходимости создавать подклассы или изменять исходный код декорированного класса. Благодаря этому наш код станет более чистым, более читаемым, поддерживаемым (что немаловажно) и сократит стандартный код, позволив нам добавлять функциональность к нескольким классам, используя один метод.
Хороший пример важности и простоты использования этих декораторов можно увидеть в декораторе @login_required, который предоставляет django, и который вы, вероятно, использовали, если у вас есть некоторый опыт работы с нашим любимым фреймворком. Это просто кусок кода, где мы проверяем, не прошла ли аутентификация пользователя, и тогда он перенаправляется на URL-адрес входа.
Способ использования декораторов следующий:
from django.contrib.auth.decorators import login_required @login_required def my_view(request) …
Каждый раз, когда пользователь пытается получить доступ к my_view, код внутри login_required будет использоваться.
Несколько наших любимых декораторов
В этом разделе мы покажем вам некоторые из декораторов, которые мы считаем наиболее полезными или которые мы когда-либо использовали с успехом. Помните, что многие из них можно настроить в соответствии с вашими потребностями.
Group Required
Иногда нам нужно защитить некоторые вьюшки, чтобы позволить определенной группе пользователей получить к ней доступ. Вместо того, чтобы проверять в этой вьюшке, принадлежит ли пользователь к этой группе/группам, мы можем использовать следующий декоратор.
from django.contrib.auth.decorators import user_passes_test def group_required(*group_names): """Requires user membership in at least one of the groups passed in.""" def in_groups(u): if u.is_authenticated(): if bool(u.groups.filter(name__in=group_names)) | u.is_superuser: return True return False return user_passes_test(in_groups) # The way to use this decorator is: @group_required(‘admins’, ‘seller’) def my_view(request, pk) ...
Больше информации можно найти тут.
Anonymous required
Этот декоратор основан на декораторе login_required Django, но работает противоположно, и проверяет, является ли пользователь анонимным, в противном случае пользователь перенаправляется на веб-сайт, определенный в нашем файле settings.py, и может быть полезен, когда мы хотим защитить пользовательские вьюшки, такие как вход в систему или регистрация.
def anonymous_required(function=None, redirect_url=None): if not redirect_url: redirect_url = settings.LOGIN_REDIRECT_URL actual_decorator = user_passes_test( lambda u: u.is_anonymous(), login_url=redirect_url ) if function: return actual_decorator(function) return actual_decorator # The way to use this decorator is: @anonymous_required def my_view(request, pk) ...
Дополнительная информация по ссылке.
Superuser required
Это тот же случай, когда мы хотим разрешить определенным группам доступ к вьюхе, но в этом случае только суперпользователи могут посетить её.
from django.core.exceptions import PermissionDenied def superuser_only(function): """Limit view to superusers only.""" def _inner(request, *args, **kwargs): if not request.user.is_superuser: raise PermissionDenied return function(request, *args, **kwargs) return _inner # The way to use this decorator is: @superuser_only def my_view(request): ...
Информация лежит тут.
Ajax required
Этот декоратор проверяет, является ли запрос AJAX-запросом, этот декоратор полезен, когда мы работаем с Javascript-фреймворками такими как jQuery, и является хорошим способом защиты нашего приложения.
from django.http import HttpResponseBadRequest def ajax_required(f): """ AJAX request required decorator use it in your views: @ajax_required def my_view(request): .... """ def wrap(request, *args, **kwargs): if not request.is_ajax(): return HttpResponseBadRequest() return f(request, *args, **kwargs) wrap.__doc__=f.__doc__ wrap.__name__=f.__name__ return wrap # The way to use this decorator is: @ajax_required def my_view(request): ...
Немного больше информации как всегда по ссылке.
Time it
Этот декоратор очень полезен, если вам нужно улучшить время отклика одного из ваших представлений или если вы просто хотите узнать, сколько времени потребуется для запуска.
def timeit(method): def timed(*args, **kw): ts = time.time() result = method(*args, **kw) te = time.time() print('%r (%r, %r) %2.2f sec' % (method.__name__, args, kw, te - ts)) return result return timed # The way to use this decorator is: @timeit def my_view(request): ...
Получить дополнительные знания по этому поводу можно здесь.
Кастомная функциональность
Следующий декоратор — это всего лишь пример того, как вы можете проверить некоторые разрешения совсем просто и на 100% настроить это так, как вам необходимо.
Представьте, что у вас есть блог, магазин, форум… Если у пользователей должно быть несколько очков активности, чтобы написать отзыв, это стало бы хорошим способом избежать спама. Мы создадим декоратор, чтобы проверить, что пользователь вошел в систему и имеет более 10 баллов, поэтому может написать отзыв, в противном случае мы не дадим ему сделать этого.
from django.http import HttpResponseForbidden logger = logging.getLogger(__name__) def user_can_write_a_review(func): """View decorator that checks a user is allowed to write a review, in negative case the decorator return Forbidden""" @functools.wraps(func) def wrapper(request, *args, **kwargs): if request.user.is_authenticated() and request.user.points < 10: logger.warning('The {} user has tried to write a review, but does not have enough points to do so'.format( request.user.pk)) return HttpResponseForbidden() return func(request, *args, **kwargs) return wrapper
Итак, мы рассмотрели несколько интересных декораторов для Django и даже написали свой собственный. От себя лишь можем добавить, что знание декораторов поможет вам писать код во много раз эффективнее.