详解Django中六个常用的自定义装饰器


Posted in Python onJuly 04, 2018

装饰器作用

decorator是当今最流行的设计模式之一,很多使用它的人并不知道它是一种设计模式。这种模式有什么特别之处? 有兴趣可以看看Python Wiki上例子,使用它可以很方便地修改对象行为,通过使用类似例中的接口将修改动作封装在装饰对象中。

decorator 可以动态地修改函数、方法或类的功能,而无需创建子类或修改类的源代码。正因为如此,装饰器可以让代码将变得更干净、更可读、更可维护(这很重要!),并且减少了许多冗余但又不得不写的代码,使我们可以使用单个方法向多个类添加功能。

对于装饰器的重用性和易用性,Django里面的@login_required就是一个很好的例子。使用它只用一句代码就可以检查用户是否通过身份验证,并将未登录用户重定向到登录url。

该装饰器的使用方法如下:

from django.contrib.auth.decorators import login_required

@login_required(login_url='/accounts/login/')
def my_view(request):
  ...

每次用户试图访问 my_view 时,都会进入 login_required 中的代码。

Django装饰器

下面介绍一些个人认为比较有用的,或者是之前使用过的具有积极效果的装饰器。事先声明,如要实现同样的业务场景,并不是只有本文中的方法。Django可以实现各种各样的装饰器,这完全根据您的需要进行定制。

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

这个装饰器是参考Django自带的 login_required 装饰器,但是功能是相反的情况,即用户必须是未登录的,否则用户将被重定向到 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

这个装饰器和上面的 group_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请求,在使用jQuery等Javascript框架时,这是一个非常有用的装饰器,也是一种保护应用程序的好方法。

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个积分,这样才可以发表评论,否则将抛出一个Forbidden。

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

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Python 相关文章推荐
python远程登录代码
Apr 29 Python
python 图片验证码代码
Dec 07 Python
python 自动提交和抓取网页
Jul 13 Python
Python自动化测试工具Splinter简介和使用实例
May 13 Python
Python多进程同步Lock、Semaphore、Event实例
Nov 21 Python
Python3实现从指定路径查找文件的方法
May 22 Python
【Python】Python的urllib模块、urllib2模块批量进行网页下载文件
Nov 19 Python
Python实现自定义函数的5种常见形式分析
Jun 16 Python
PyCharm汉化安装及永久激活详细教程(靠谱)
Jan 16 Python
Django全局启用登陆验证login_required的方法
Jun 02 Python
Python常用模块函数代码汇总解析
Aug 31 Python
Python pickle模块常用方法代码实例
Oct 10 Python
浅析Python pandas模块输出每行中间省略号问题
Jul 03 #Python
python中datetime模块中strftime/strptime函数的使用
Jul 03 #Python
pandas.DataFrame选取/排除特定行的方法
Jul 03 #Python
python 中字典嵌套列表的方法
Jul 03 #Python
Django项目开发中cookies和session的常用操作分析
Jul 03 #Python
Python嵌套列表转一维的方法(压平嵌套列表)
Jul 03 #Python
Python使用matplotlib实现基础绘图功能示例
Jul 03 #Python
You might like
《星际争霸》各版本雷兽特点图文解析 雷兽不同形态一览
2020/03/02 星际争霸
php数组函数序列之krsort()- 对数组的元素键名进行降序排序,保持索引关系
2011/11/02 PHP
php使用PDO操作MySQL数据库实例
2014/12/30 PHP
PHP实现根据图片色界在不同位置加水印的方法
2015/08/08 PHP
PHP CURL采集百度搜寻结果图片不显示问题的解决方法
2017/02/03 PHP
PHP面向对象程序设计重载(overloading)操作详解
2019/06/13 PHP
详解使用php-cs-fixer格式化代码
2020/09/16 PHP
取得父标签
2006/11/14 Javascript
关于javascript中this关键字(翻译+自我理解)
2010/10/20 Javascript
一个简单的实现下拉框多选的插件可移植性比较好
2014/05/05 Javascript
使用GruntJS构建Web程序之合并压缩篇
2014/06/06 Javascript
Javascript中使用parseInt函数需要注意的问题
2015/04/02 Javascript
有关easyui-layout中的收缩层无法显示标题的解决办法
2016/05/10 Javascript
ES6记录异步函数的执行时间详解
2016/08/31 Javascript
Node.js Mongodb 密码特殊字符 @的解决方法
2017/04/11 Javascript
js-FCC算法-No repeats please字符串的全排列(详解)
2017/05/02 Javascript
最通俗易懂的javascript变量提升详解
2017/08/05 Javascript
Vue2 模板template的四种写法总结
2018/02/23 Javascript
仿vue-cli搭建属于自己的脚手架的方法步骤
2019/04/17 Javascript
绘制微信小程序验证码功能的实例代码
2021/01/05 Javascript
[04:03]2014DOTA2西雅图国际邀请赛 LGD战队巡礼
2014/07/07 DOTA
Python中使用PyQt把网页转换成PDF操作代码实例
2015/04/23 Python
Python实现螺旋矩阵的填充算法示例
2017/12/28 Python
10招!看骨灰级Pythoner玩转Python的方法
2019/04/15 Python
python实现堆排序的实例讲解
2020/02/21 Python
使用Python获取当前工作目录和执行命令的位置
2020/03/09 Python
python适合做数据挖掘吗
2020/06/16 Python
html5的input的required使用中遇到的问题及解决方法
2018/04/24 HTML / CSS
PatPat阿根廷:妈妈们的购物平台
2019/05/30 全球购物
新加坡一家在线男士皮具品牌:Faire Leather Co.
2019/12/01 全球购物
请介绍一下Ant
2016/07/22 面试题
大学生职业生涯规划方案
2014/01/03 职场文书
精神文明建设汇报材料
2014/12/24 职场文书
幼儿园五一劳动节活动总结
2015/02/09 职场文书
详解Vue中$props、$attrs和$listeners的使用方法
2022/02/18 Vue.js
Python实现为PDF去除水印的示例代码
2022/04/03 Python