rest framework十大组件

认证:

首先

导入rest_framework.views中的 APIView方法
from rest_framework.views import APIView  

我们来看一段伪代码,MyClassView继承了APIView就有了APIView的功能

class APIView(View):
    pass

class MyClassView(APIView):
    pass
在class类里面的(APIView)在pycharm按住ctrl点击APIView,就会跳到这个方法里面 "例如最后面的大写字母,“DEFAULT_AUTHENTICATION_CLASSES"就是各个组件的配置名”

我们开始进入认证的操作流程:

首先在model中创建两个模型
from django.db import models


# Create your models here.
class UserInfo(models.Model):
    """用户表"""
    user_type_choices = (
        (1, "普通用户"),
        (2, "VIP"),
        (3, "SVIP")
    )
    user_type = models.IntegerField(choices=user_type_choices)
    username = models.CharField(max_length=32, unique=True)
    password = models.CharField(max_length=64)


class UserToken(models.Model):
    """token表"""
    user = models.OneToOneField(to="UserInfo")
    token = models.CharField(max_length=64)

一个是用户表 一个是token表 用户表中加入了用户类型 token表关联用户表 成一对一的类型 所以一个用户只能有一个token

然后我们开始写view视图 首先我们要创建token生成加密字符

#创建md5函数 继承token模型的user对象
def md5(user):
    #导入哈希加密
    import hashlib
    #导入时间
    import time
    #变量名ctime 接收现在的时间转为字符str类型
    ctime = str(time.time())
    #将user对象转为字节并用哈希md5加密 变为16进制字符
    m = hashlib.md5(bytes(user, encoding="utf-8"))
    #修改并加入时间戳
    m.update(bytes(ctime, encoding="utf-8"))
    #并返回
    return m.hexdigest()
    

另一种写法

import hashlib
import time
#创建token
def createToken(user):

    md5 = hashlib.md5()
    #修改账户名字节并加入时间戳 和utf-8(时间戳)
    md5.update(bytes(user + str(time.time()), encoding='utf-8'))
    #返回摘要,作为十六进制数据字符串值
    token = md5.hexdigest()
    #返回给token
    return token

然后设置登录功能:

#设置登录类
class AuthView(APIView):
    # 提交我们用 内置源码的post请求
    def post(self,request,*args,**kwargs):
        # 设置状态码
        ret = {"state_code": 1000, "msg": None}
        #判断异常
        try:
            #原生_request改写request方法 获取前端表单里面的用户名
            username = request._request.POST.get("username")
            #获取前端表单里面的密码
            password = request._request.POST.get("password")
            # 用变量名obj 接收数据库里的信息并进行 前端表单与数据库的匹配
            obj = models.UserInfo.object.filter(username=username,password=password).first()
            #然后进行判断 如果匹配的内容不对 
            if not obj:
                # 就发送状态码 1001
               ret["state_code"] = 1001
               # 用户名或者 密码错误
               ret["msg"] = "用户名或者密码错误"
            # 否则为登陆用户创建一个token
            token = md5(username)
            # 存到数据库 存在就更新,不存在就创建
            models.UserToken.objects.update_or_create(user=obj, defaults={"token": token})
            # 发送状态码 
            ret["token"] = token
            #告知请求成功
            ret["msg"] = "请求成功"
        #判断异常
        except Exception as e:
            # 发送状态码
            ret["state_code"] = 1002
            # 请求异常
            ret["msg"] = "请求异常"
        #返回JsonResponse
        return JsonResponse(ret)
            

这时我们在 Django项目 我的应用中myapp就是我的应用里面创建 我的工具包 myutils 里面去创建各种组件的方法 这样看着明显而且 省地方! 随后我们创建auth.py来写我们的 认证组件方法:

然后进入 auth.py 导入rest_framework.authentication里面的BaseAuthentication方法,导入应用中的模型类,导入判断不包括在内的方法

from rest_framework.authentication import BaseAuthentication

from myapp import models

from rest_framework import exceptions
#创建一个我的认证类 继承BaseAuthentication方法
class MyAuthtication(BaseAuthentication):
    # 设置内置authenticate重写authenticate这个方法
    def authenticate(self, request):
        # 将用户输入的token用变量接收
        token = request._request.GET.get("token")
        # 然后在数据库进行匹配
        token_obj = models.UserToken.objects.filter(token=token).first()
        # 如果认证失败
        if not token_obj:
            #就返回失败
            raise exceptions.AuthenticationFailed("用户认证失败")
        # 在 rest framework内部 会将这两个字段赋值给request,以供后续操作使用
        #正确就返回用户和token
        return (token_obj.user, token)
        



# 如果pass 就调用原有的方法
class MyAuthtication_None(BaseAuthentication):
    def authenticate(self, request):
        pass

另一种方法

#创建 我的Authtication
class MyAuthtication(BaseAuthentication):
    #使用authenticate方法
    def authenticate(self, request):
        #获取token
        token = request._request.GET.get('token')
        #进行判断 如果不是token
        if not token:
            #返回元组验证失败
            raise AuthenticationFailed('未登录')
        #否则
        else:
            #在数据库UserToken表中进行比对 从第一个开始
            usertoken = UserToken.objects.filter(token=token).first()
            #如果是usertoken
            if usertoken:
                #就返回用户的token
                return (usertoken.user, token)
            #否则验证失败
            else:
                raise AuthenticationFailed('验证失败')

然后我们在settings设置全局配置

在class类里面的(APIView)在pycharm按住ctrl点击APIView,就会跳到这个方法里面 "例如最后面的大写字母,“DEFAULT_AUTHENTICATION_CLASSES"就是各个组件的配置名”

然后我们在settings设置全局配置

在class类里面的(APIView)在pycharm按住ctrl点击APIView,就会跳到这个方法里面 "例如最后面的大写字母,“DEFAULT_AUTHENTICATION_CLASSES"就是各个组件的配置名”

将"DEFAULT_AUTHENTICATION_CLASSES":[设置类的路径]

然后就可以在view视图中加入

    authentication_classes = []

如果不在settings配置全局设置 就要单独写这个进行验证 所以 我们要先在view中导入

from myapp.myutils.throttle import MyAuthtication

#将登录类里写入 进行认证
authentication_classes = [MyAuthtication]

就像这样

然后我们试着 在postman 软件中 输入用户名及密码 申请登录尝试我们的代码使用是否正确

输入我们在urls.py中设置的接口 也就是路由

from django.contrib import admin
from myapp import views

urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^api/v1/auth/$', views.AuthView.as_view()),
    ]

然后输入到postman 中 点击body 中的 X-www-form-urlencoded 输入 用户名 密码进行 登录匹配

登录成功

登录失败

然后我们去看authenticate这个的源码

    def authenticate(self, request):
        token = request._request.GET.get("token")

首先点击

在class类里面的(APIView)在pycharm按住ctrl点击APIView,然后向下翻找到
     def dispatch(self, request, *args, **kwargs):
        """
        `.dispatch()` is pretty much the same as Django's regular dispatch,
        but with extra hooks for startup, finalize, and exception handling.
        """
        self.args = args
        self.kwargs = kwargs
        request = self.initialize_request(request, *args, **kwargs)
        self.request = request
        self.headers = self.default_response_headers  # deprecate?


        try:
            #进这里 #点击这个
            self.initial(request, *args, **kwargs)

            # Get the appropriate handler method
            if request.method.lower() in self.http_method_names:
                handler = getattr(self, request.method.lower(),
                                  self.http_method_not_allowed)
            else:
                handler = self.http_method_not_allowed

            response = handler(request, *args, **kwargs)

        except Exception as exc:
            response = self.handle_exception(exc)

        self.response = self.finalize_response(request, response, *args, **kwargs)
        return self.response

找到def dispatch(self, request, *args, **kwargs):中的 self.initial并点击

        try:
           #进这里 #点击这个
           self.initial(request, *args, **kwargs)

然后将会看到:

        # 代表 认证组件
        self.perform_authentication(request)
        # 代表 权限组件
        self.check_permissions(request)
        # 代表 限流组件
        self.check_throttles(request)

然后 点击self.perform_authentication(request)这个方法


在这里它封装了 request.user方法 点击request.user然后选择第三个

在这里封装了self._authenticate() 点击self._authenticate()



rest framework的第二组件

权限:

首先 观察我们之前创建的 用户表 用户分为三种类型 三种类型 就代表在登录 验证 或者订单中来实现 这三种权限显示的内容

我们先在view.py视图中 写好一个订单表 方便在写权限代码时 用权限功能 来使用 订单表 如何用权限显示订单内容

# 创建一个ORDER_DICT字典 输入一些信息
ORDER_DICT = {
    1: {
        "name": "张三",
        "age": 18,
        "gender": "男",
        "orders": [{
            "name": "娃娃",
            "price": 1000
        }]
    },
    2: {
        "name": "李四",
        "age": 20,
        "gender": "女",
        "orders": [{
            "name": "你猜",
            "price": 1200
        }]
    },

}

# 创建OrderView类 继承APIView
class OrderView(APIView):
    """
    订单相关业务
    """
    # 设置get请求
    def get(self, request, *args, **kwargs):
        # 状态码
        ret = {"state_code": 1000, "msg": None, "data": None}
        # 判断异常
        try:
            # 如果正确 就返回字典的数据
            ret['data'] = ORDER_DICT
        # 错误就返回状态码
        except Exception as e:
            pass
        return JsonResponse(ret)

然后配置路由urls.py进行配置

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

urlpatterns = [
    url(r'^admin/', admin.site.urls),
    # 认证接口
    url(r'^api/v1/auth/$', views.AuthView.as_view()),
    # 订单接口
    url(r'^api/v1/order/$', views.OrderView.as_view()),
    ]

在myapp应用中的工具包myutlis中创建permission.py代表权限组件的配置

# 在rest_framework.permissions 导入BasePermission方法
from rest_framework.permissions import BasePermission

# 创建SVIPPermission类 继承BasePermission方法
class SVIPPermission(BasePermission):
    # 状态码
    message = "无权访问"
    # 重写 has_permission方法
    def has_permission(self, request, view):
        # 如果 用户 user_type 类型 不等于3
        if request.user.user_type != 3:
            # 就无法访问
            return False
         # 否则可以访问
        return True

这个 def has_permission(self, request, view):方法从哪来? 我们要看里面的源码:

首先点击 self.dispatch() 找到 self.initial(request,args,*kwargs)点击 进入

然后点击 代表权限的组件方法

这里会出现 点击这个选择第三个 会出现我们冲的的方法

随后滚动鼠标 会出现这个方法

百度翻译一下

“”"
Allows access only to admin users.
“”"

意思是 仅允许管理员用户访问 所以改写这个方法

随后在views.py里面去配置 订单的权限及认证的组件配置

# 导入的这个负责 认证
# 在 我的应用中从 我的组件包中的 auth 导入MyAuthtication类
from myapp.myutils.auth import MyAuthtication

# 导入的这个负责 权限
# 在 我的应用中从 我的组件包中的 permission 导入SVIPPermission类
from myapp.myutils.permission import SVIPPermission

然后 加入这个 就会加入组件包 来实现 认证 权限两个功能

或者我们在settings.py设置全局组件配置 权限 首先我们要找到源码来写入 这个配置的功能

在class类里面的(APIView)在pycharm按住ctrl点击APIView,然后向下翻找到

DEFAULT_PERMISSION_CLASSES 这个就代表配置 settings.py需要设置的方法 [这里写的是方法类的路径]


然后在view.py订单视图中 写入

class OrderView(APIView):
    """
    订单相关业务
    """
    authentication_classes = []
    permission_classes = []

然后我们用postman进行 实际测试验证

先找到数据库表中 user_type类型为svip的 因为如果是1或者2类型就无法访问

然后进行登录获取token

将获取到的token放在一个文本里 然后在重新打开一个postman的页面 打开配置的路由找到路径 复制这个路径

将这个链接 粘贴到postman 新页面?token=你的文本里面的token

http://127.0.0.1:8000/api/v1/order/?token= 后面放你从文本复制的token

在postman进行验证 输入对的token 就可以获取到表单

输入错误token再次尝试 用户认证失败

在数据库找一个 user_type类型为2 的进行登录 获取token 进行获取订单看看是什么结果

将token输入告诉 无权限访问 那么功能都可以实现


################################################################

rest framework的第三组件

限流:

限流就是限制访问频率或者次数

首先 在我的应用组件包创建限流 throttle.py文件 在里面设置我们的限流方法

# 从rest_framework.throttling 导入BaseThrottle方法
from rest_framework.throttling import BaseThrottle
# 导入时间
import time
# 设置一个空字典
HISTORY_DICT = {}
# 写MyThrottle类继承 BaseThrottle方法
class MyThrottle(BaseThrottle):
    # 初始化self.history
    def __init__(self):
        self.history = None
    # 重写allow_request方法
    def allow_request(self, request, view):
        # 获取 (META["REMOTE_ADDR"])当前用户的ip
        ip_addr = request._request.META["REMOTE_ADDR"]
        # 获取当前时间
        ctime = time.time()
        # 如果 用户当前的ip 不在空字典中
        if ip_addr not in HISTORY_DICT:
            # 那么就把当前ip赋予一个 现在的时间
            HISTORY_DICT[ip_addr] = [ctime, ]
            return True
        # 如果这条ip在空字典中
        history = HISTORY_DICT[ip_addr]
        # 初始化的self.history
        self.history = history
        # 在空字典的ip 找到最后一个ip 是最早的时间那个 小于现在时间的60秒
        while history and history[-1] < ctime - 60:
            # 就删除最后一个
            history.pop()

        # 如果ip记录 小于3次
        if len(history) < 3:
            # 就添加ip 并赋予现在的时间
            history.insert(0, ctime)
            return True

        # 如果访问返回True表示可以继续往下走,False被限制访问
        return False

    def wait(self):
        # 这里是应该返回 剩余的 等待时间
        # 要先拿到历史记录
        # 当前时间
        ctime = time.time()
        return 60 - (ctime - self.history[-1])

我们重写了def allow_request(self, request, view):方法 我们可以看看源码是怎样写的

首先点击 self.dispatch() 找到 self.initial(request,args,*kwargs)点击 进入

然后点击 代表限流的组件方法

在这里会找到封装的allow_request 点击它 选择第三个

这里就会出现allow_request源码的方法 和 wait源码的方法


我们开始在views.py设置 一个类来测试我们书写的代码逻辑是否正确

# 在我的组件包导入 MyThrottle方法
from myapp.myutils.throttle import MyThrottle


class StudentView(APIView):
    authentication_classes = [MyAuthtication]
    permission_classes = [SVIPPermission]

    # 开启这个代表自己设置的限流
    throttle_classes = [MyThrottle]

    
    def get(self, request, *args, **kwargs):
        # 获取当前的ip
        ip = request.META.get('REMOTE_ADDR')
        # 并返回当前的ip
        return JsonResponse({'ip': ip})

也可以在settings.py全局设置组件

怎么找到它呢 ?

在class类里面的(APIView)在pycharm按住ctrl点击APIView,然后向下翻找到
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,378评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,356评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,702评论 0 342
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,259评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,263评论 5 371
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,036评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,349评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,979评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,469评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,938评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,059评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,703评论 4 323
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,257评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,262评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,485评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,501评论 2 354
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,792评论 2 345

推荐阅读更多精彩内容