如何在cbv的情况下添加装饰器

前言

首先,什么是装饰器我们都知道,有什么作用,也很清楚,比如说你要在淘宝上查看你购物车的详情,或者已经购买过的历史订单,那就需要你先登录淘宝账户,那这时候为了方便,就需要一个通用的登录的认证装饰器,所以接下来就开始吧!

先用cbv写一个简单的用户登录和查看订单接口

class Login(View):
    # 用户登录
    def get(self, request, *args, **kwargs):
        return render(request, 'login.html')

    def post(self, request, *args, **kwargs):
        name = request.POST.get('name')
        pwd = request.POST.get('pwd')
        ret = models.User.objects.filter(name=name, pwd=pwd).first()
        # 登录成功记录session
        if ret:
            request.session['id'] = ret.pk
            request.session['name'] = ret.name
            return HttpResponse('登录成功')
        else:
            return HttpResponse('用户名或密码错误')



class Order(View):
    # 订单详情
    def get(self, request, *args, **kwargs):
        return HttpResponse('订单详情。。。')
    
    def post(self, request, *args, **kwargs):
        return HttpResponse('ok')

再写一个简单的前端登录界面

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>login</title>
</head>
<body>
<form action="" method="post">
    <p>name:<input type="text" name="name"></p>
    <p>pwd:<input type="password" name="pwd"></p>
    <input type="submit" value="登录">
</form>
</body>
</html>

OK!现在可以编写一个简单的无参装饰器

def login_auth(func):
    # 登录认证装饰器
    def inner(request, *args, **kwargs):
        url = request.get_full_path()
        if request.session.get('id'):
            res = func(request, *args, **kwargs)
        else:
            return redirect('/login/?next={}'.format(url))
        return res

    return inner

给Order类添加装饰器

注意:不能直接将装饰器加在函数上面,不然会报错('Order' object has no attribute 'get_full_path'),此时装饰器inner函数中的request参数是Order实例化后的self,self去调get_full_path()肯定出错,那如果你说我给request加个self不就OK了(self.request),是的,但是这样做你这个装饰器就不能通用了

# 错误的使用方法
class Order(View):
    @login_auth
    def get(self, request, *args, **kwargs):
        return HttpResponse('订单详情。。。')

    def post(self, request, *args, **kwargs):
        return HttpResponse('ok')

加给函数不行,那加给类就更不行了,程序直接就会跑不起来的

那这个时候就需要导入Django的method_decorator方法,此时为了实现登录后跳转的功能,就需要对Login类的post方法做个简单的修改

添加装饰器的第一种方法:

from django.shortcuts import render, redirect, HttpResponse
from django.views import View
from app01 import models
from django.utils.decorators import method_decorator



class Login(View):
    def get(self, request, *args, **kwargs):
        return render(request, 'login.html')

    def post(self, request, *args, **kwargs):
        name = request.POST.get('name')
        pwd = request.POST.get('pwd')
        ret = models.User.objects.filter(name=name, pwd=pwd).first()
        # 登录成功记录session
        if ret:
            url = request.GET.get('next')
            request.session['id'] = ret.pk
            request.session['name'] = ret.name
            # return HttpResponse('登录成功')
            return redirect(url)
        else:
            return HttpResponse('用户名或密码错误')

# 方法一:加在类上面,将装饰器当参数传给method_decorator,然后指定要装饰的方法名
@method_decorator(login_auth, name='get')
@method_decorator(login_auth, name='post')
class Order(View):
    def get(self, request, *args, **kwargs):
        return HttpResponse('订单详情。。。')

    def post(self, request, *args, **kwargs):
        return HttpResponse('ok')

 添加装饰器的第二种方法:

from django.shortcuts import render, redirect, HttpResponse
from django.views import View
from app01 import models
from django.utils.decorators import method_decorator


class Login(View):
    def get(self, request, *args, **kwargs):
        return render(request, 'login.html')

    def post(self, request, *args, **kwargs):
        name = request.POST.get('name')
        pwd = request.POST.get('pwd')
        ret = models.User.objects.filter(name=name, pwd=pwd).first()
        # 登录成功记录session
        if ret:
            url = request.GET.get('next')
            request.session['id'] = ret.pk
            request.session['name'] = ret.name
            # return HttpResponse('登录成功')
            return redirect(url)
        else:
            return HttpResponse('用户名或密码错误')


class Order(View):
    # 方法二,直接在方法上加装饰器,将装饰器当做参数传给method_decorator
    @method_decorator(login_auth)
    def get(self, request, *args, **kwargs):
        return HttpResponse('订单详情。。。')

    @method_decorator(login_auth)
    def post(self, request, *args, **kwargs):
        return HttpResponse('ok') 

最后别忘了配置理由

from django.conf.urls import url
from django.contrib import admin
from app01 import views

urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^login/', views.Login.as_view()),
    url(r'^order/', views.Order.as_view()),
]

OK!这就简单实现了在cbv的情况下,给函数(类)加装饰器

 

posted @ 2019-01-21 09:03  cnblogs用户  阅读(350)  评论(0编辑  收藏  举报