Django中在CBV(基于类的视图)中添加装饰器

Django的视图分为FBV(基于函数的视图)和CBV(基于类的视图)两种实现方法。FBV比较简单,但是缺点在于很难通过继承等方式重复利用已有代码;CBV使用起来略微繁琐一些,但是却很容易通过类继承等方法重复利用已有代码。当然,FBV如果通过一些方法把内部功能抽取出来做成单独的外部函数也是可以实现重复利用的,只不过CBV的继承更加直观。

Python装饰器用于函数的时候是很方便的,类中的方法与独立函数略有不同,所以用于FBV的装饰器不能直接用在CBV上,所以说用于类就不太方便。当Django使用CBV时,装饰器的使用就要比FBV繁琐一些。

大体上分为3种方法:

对CBV类的某一个方法加装饰器

Django中提供了method_decorator装饰器用于将函数装饰器转换为方法装饰器

from django.views import View
from django.utils.decorators import method_decorator
from lib.decorator import my_decorator

class AddClass(View):

    @method_decorator(my_decorator)
    def get(self, request):
        return render(request, "add_class.html")

    def post(self, request):
        class_name = request.POST.get("class_name")
        models.Classes.objects.create(name=class_name)
        return redirect("/class_list/")

比如说开发者在lib.decorator中自己开发了一个装饰器my_decorator,就可以通过

@method_decorator(my_decorator)

把这个my_decorator加到CBV类内特定的函数上。比如说上面的例子就是加载了get函数上,这样当访问者通过GET方法访问到这个AddClass时,就会调用这个装饰器。

在dispatch方法加装饰器

在CBV的各个方法中,有一个比较特殊的方法dispatch,这个方法执行的时间比get、post等函数更早,所以可以添加一些对request.method无关的装饰器

class AddClass(View):

	 def get(self,request, year):
	 	print('this is add method')
	 	return return render(request, "add_class.html")

	 @method_decorator(my_decorator)
	 def dispatch(self, request, *args, **kwargs):
	 	print('this is dispatch method')
	 	return None

要特别说明的是:Django自带的各个_required方法都无法加在get、post等方法上,而是必须要加在dispatch方法上。另外csrf_exempt和csrf_protect这两个装饰器也只能加在dispatch方法上。

给CBV类加装饰器

通过method_decorator可以给类加装饰器,在添加的时候只要增加一个name参数就可以指定该装饰器是对CBV内哪个方法来添加

@method_decorator(my_decorator_post, name='post')
@method_decorator(my_decorator_get, name='get') 
class AddClass(View):

    def get(self, request):
        return render(request, "add_class.html")

    def post(self, request):
        class_name = request.POST.get("class_name")
        models.Classes.objects.create(name=class_name)
        return redirect("/class_list/")

在路由中加装饰器

https://stackoverflow.com/questions/6069070/how-to-use-permission-required-decorators-on-django-class-based-views

对如何在CBV上加装饰器有一些讨论,其中提到,其实可以在路由文件urls.py中加装饰器。

from django.urls import path
from django.contrib.auth.decorators import login_required
from django.views.decorators.csrf import csrf_exempt
from . import views

app_name = 'rbac'  # pylint: disable=invalid-name
urlpatterns = [
    path(r'Login/', csrf_exempt(views.LoginView.as_view()), name='Login'),
    path(r'Logout/', login_required(views.LogoutView.as_view()), name='Logout'),
]

 这种方法的效果和在dispatch方法上加装饰器是一样的,代码可以少很多;不过缺点就是在视图文件views.py中看不出来,有可能会导致误解,如果urls.py和view.py是两个不同的人编写的,可能会冲突。

采用Mixin方式

其实还有一种方法也可以实现类似的功能,不过这种方法已经不能被视为装饰器了。

其实装饰器的功能说到底其实就是在被装饰的函数运行前和运行后进行一些特定的运算罢了。如果把这些运算直接写到类当中,其实也是可以的。Django在CBV的基类View中在__init__构造函数中保留了特定的接口,只不过默认的内容是pass。采用一些特定的Mixin类混入View类中,可以用Mixin类中的特定函数替换掉View默认的pass,这样就可以把相关代码加入到特定的位置来执行。

https://docs.djangoproject.com/zh-hans/4.1/topics/auth/default/#the-loginrequired-mixin

就对login_required装饰器的使用给出了Mixin方法。只要在构造CBV的类时

from django.contrib.auth.mixins import LoginRequiredMixin

class MyView(LoginRequiredMixin, View):
    login_url = '/login/'
    redirect_field_name = 'redirect_to'

在类的基类列表中增加一个LoginRequiredMixin类,就可以实现同样的功能,而且还可以在CBV中直接操作相关变量如login_url、redirect_field_name等。功能更加强大,当然,代码量也要多一些。

还有一个更多内容的例子

https://docs.djangoproject.com/zh-hans/4.1/topics/auth/default/#django.contrib.auth.mixins.UserPassesTestMixin

from django.contrib.auth.mixins import UserPassesTestMixin

class MyView(UserPassesTestMixin, View):

    def test_func(self):
        return self.request.user.email.endswith('@example.com')

采用UserPassesTextMixin基类混入的话,不仅可以定义个别变量,甚至对于请求执行时的特别函数都可以重载,在这里可以根据需要设定特殊的功能。

关于在View中混入类,更多的介绍参见

https://docs.djangoproject.com/zh-hans/4.1/topics/class-based-views/mixins/

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值