• drf之--认证组件、权限组件(django项目国际化)、频率组件、排序


    视图集回顾
    1 认证组件
    1.1 登录功能
    1.2 认证组件
    2 权限组件
    2.1 django项目国际化
    3 频率组件
    4 排序

    视图集回顾

    # 1 9 个视图子类
    	-GenericAPIView+5个视图扩展类的组合
        -ListAPIView,CreateAPIView,DestroyAPIView,RetrieveAPIView,UpdateAPIView
        -ListCreateAPIView
        -RetrieveDestroyAPIView,RetrieveUpdateAPIView,RetrieveUpdateDestroyAPIView
    	-class TestView(ListAPIView):
            queryset
            serializer_calss
            
    # 2 视图集
    	-ModelViewSet:GenericViewSet+5个视图扩展类
        	-路由写法变了的5个接口
            -PublishView.as_view({'get':'list','post':'create'})
            -自动生成路由:本质:把get和list对应,把post和create对应
            -可以重写父类方法,完成自己的定制
        -ReadOnlyModelViewSet:2个接口,只读的
        -ViewSet:ViewSetMixin+APIView
        -GenericViewSet:ViewSetMixin+GenericAPIView
        -ViewSetMixin:重写了as_view 路由写法变了
    #  3 drf路由,继承ViewSetMixin+APIView
    	ViewSetMixin+ListAPIView---》自动生成路由
        
        -自动生成路由步骤
        -action装饰器---/publish/被装饰函数名字/    post请求就会执行
        	- @action(methods=['POST'], detail=False)
    # 4 视图类对象中:self.action  路由匹配成功,执行视图类中方法的名字的字符串
    
    
    
    # 补充:
    # 如果自动生成路由,哪个请求能执行这个list?路由匹配成功后的get请求,就会执行这个list,自动生成的
    class TestView(GenericViewSet):
        def list(self, request):
            return Response('sdafs')
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34

    1 认证组件

    1.1 登录功能

    # 写登录的时候,可以使用auth提供的user表,也可以自定义---》自定义
    
    # 写登录接口,登录成功,要有标志,生成一个随机字符串,放到表中,以后它只要带着这个随机字符串过来,我们就认为是这个人登录的
    
    • 1
    • 2
    • 3
    ### ### ### ### ### ### ### 视图类### ### ### ### ### ### ### ### ### ### ### ### ###
    
    from rest_framework.views import APIView
    from rest_framework.generics import GenericAPIView
    from rest_framework.viewsets import ViewSetMixin, ViewSet
    from rest_framework.response import Response
    from rest_framework.decorators import action
    from .models import User, UserToken
    import uuid
    
    
    # class UserView(ViewSetMixin,APIView):
    class UserView(ViewSet):
        @action(methods=['POST'], detail=False) # /user/login/    post 请求就会执行
        def login(self, request, *args, **kwargs):
            # 前端传入用户名密码
            username = request.data.get('username')
            password = request.data.get('password')
            user = User.objects.filter(username=username, password=password).first()
    
            if user:
                # 生成一个随机字符串,返回给前端,并且要把随机字符串存到token表中
                # 随机字符串使用uuid生成
                token = str(uuid.uuid4())
                # 把随机字符串存到token表中会有两种情况(如果之前没有登录过就是新增,如果之前登录过修改)
                # 先去UserToken表中,根据user查,如果能查到,就修改,查不到就新增一条记录
                ##### 方式一:麻烦方式
                # user_token=UserToken.objects.filter(user=user).first()
                # if user_token:
                #     user_token.token=token
                #     user_token.save()
                # else:
                #     UserToken.objects.create(user=user,token=token)
    
                ## 方式二:通过user去UserToken表中查,如果能查到用defaults的更新,如果查不到,就用user和defaults新增一条记录
                UserToken.objects.update_or_create(defaults={'token': token}, user=user)
                return Response({'code': 100, 'msg': '登录成功', 'token': token, 'username': user.username})
    
            else:
                return Response({'code': 101, 'msg': '用户名或密码错误'})
    
    ### ### ### ### ### ### ### 路由### ### ### ### 
    from rest_framework.routers import SimpleRouter
    
    router = SimpleRouter()
    router.register('user', UserView, 'user')
    
    urlpatterns = [
        path('admin/', admin.site.urls),
        path('', include(router.urls)),
    ]
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52

    1.2 认证组件

    # 认证有什么作用?
    	-一些接口,想限制登录后才能访问,没登录不能访问
        -做登录认证,限制如果没登录,不允许访问该接口
        
        
    # drf中,认证类如何使用
    	 # 1 写一个类,继承BaseAuthentication
         #  2 类中重写 :authenticate方法
         # 3 在authenticate完成登录认证,如果登录了,返回两个值,如果没登录抛异常
         # 4 在视图类中配置使用
            class BookView(ViewSet):
        		authentication_classes = [LoginAuth]
                
    # 如果登录了,在视图类的方法中,能拿出当前登录用户
    	request.user
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    1.2.1 auth.py

    from .models import UserToken
    
    # 按照如下步骤写
    # 1 写一个类,继承BaseAuthentication
    # 2 类中重写 :authenticate方法
    # 3 在authenticate完成登录认证,如果登录了,返回两个值,如果没登录抛异常
    # 4 在视图类中配置使用
    
    from rest_framework.authentication import BaseAuthentication
    from rest_framework.exceptions import AuthenticationFailed
    
    
    class LoginAuth(BaseAuthentication):
        def authenticate(self, request):
            # 如何知道当前请求这个人是登录了?
            # 拿到前端传入的token:当时给的随机字符串---》去UserToken表中查,如果能查到,说明就是这个人在访问,如果查不到,说明这个人没有登录过
            # 前端传入的token,从哪拿?如何拿?---》后端定的:1 请求地址中  2 请求体中  3 请求头中
            token = request.query_params.get('token')
            user_token = UserToken.objects.filter(token=token).first()
            if user_token:  # 是登录状态
                return user_token.user, token  # 返回两个值,第一个是当前登录用户,第二个是前端token
            else:
                raise AuthenticationFailed('您没有登录')
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    1.2.2 视图类

    from django.shortcuts import render
    
    # Create your views here.
    
    # 路由自动生成吗?    自动生成继承:ViewSetMixin   我想
    # 要不要序列化,要不要跟数据库打交道,继承GenericAPIView:查出所有数据(只要一条),还要写个序列化类()
    from rest_framework.views import APIView
    from rest_framework.generics import GenericAPIView
    from rest_framework.viewsets import ViewSetMixin, ViewSet
    from rest_framework.response import Response
    from rest_framework.decorators import action
    from .models import User, UserToken
    import uuid
    
    from .auth import LoginAuth
    
    
    # class UserView(ViewSetMixin,APIView):
    class UserView(ViewSet):
        @action(methods=['POST'], detail=False)  # /user/login/    post 请求就会执行
        def login(self, request, *args, **kwargs):
            # 前端传入用户名密码
            username = request.data.get('username')
            password = request.data.get('password')
            user = User.objects.filter(username=username, password=password).first()
    
            if user:
                # 生成一个随机字符串,返回给前端,并且要把随机字符串存到token表中
                # 随机字符串使用uuid生成
                token = str(uuid.uuid4())
                # 把随机字符串存到token表中会有两种情况(如果之前没有登录过就是新增,如果之前登录过修改)
                # 先去UserToken表中,根据user查,如果能查到,就修改,查不到就新增一条记录
                ##### 方式一:麻烦方式
                # user_token=UserToken.objects.filter(user=user).first()
                # if user_token:
                #     user_token.token=token
                #     user_token.save()
                # else:
                #     UserToken.objects.create(user=user,token=token)
    
                ## 方式二:通过user去UserToken表中查,如果能查到用defaults的更新,如果查不到,就用user和defaults新增一条记录
                UserToken.objects.update_or_create(defaults={'token': token}, user=user)
                return Response({'code': 100, 'msg': '登录成功', 'token': token, 'username': user.username})
    
            else:
                return Response({'code': 101, 'msg': '用户名或密码错误'})
    
    
    class BookView(ViewSet):
        authentication_classes = [LoginAuth]  # 这个认证类,管理了当前类下所有的方法
    
        def list(self, request):
            print(request.user.username)  # 当前登录用户
            return Response("你好:%s,你看到了好多书啊"%request.user.username)
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55

    1.2.3 路由

    from rest_framework.routers import SimpleRouter
    
    router = SimpleRouter()
    router.register('user', UserView, 'user')
    router.register('books', BookView, 'books')
    urlpatterns = [
        path('', include(router.urls)),
    ]
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    1.3 小结

    # 1 认证类写好,使用
    	-配置在视图类上---》局部使用
        -配置文件中配置--》全局使用---》所有接口都必须登录后才能用
            REST_FRAMEWORK = {
            'DEFAULT_AUTHENTICATION_CLASSES': [
                'app01.auth.LoginAuth'
            	],
        	}
        -局部禁用:
        class UserView(ViewSet):
        	authentication_classes = []
    # 2 写的认证类:要重写authenticate方法,必须返回两个参数:当前登录用户:user_token.user,用户的 token----》后续再视图类中:request.user  就是认证类返回的第一个参数,request.auth 就是认证类返回的第二个参数
    
    # 3 如果认证失败,抛异常AuthenticationFailed,会被drf捕获,处理,不会报错到前端
    
    # 4 前端传入的token,从哪取?
    	-后端定的,我们这个项目是从请求地址中取
        -还可以从请求头或请求体中取
    # 5 UserToken.objects.update_or_create
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    2 权限组件

    # 系统中:有普通用户,超级用户,超级管理员,他们都登录了,又分权限,有的人有权限,就能访问这个接口,没权限,就不能访问
    
    
    # 使用步骤:
    # 1 写一个类,继承 BasePermission
    # 2 重写 has_permission
    # 3 在方法中校验用户是否有权限,如果有,就返回True,如果没有,就返回False
    	-由于它的执行是在认证之后,所有从request.user中取出当前等用户,判断权限
    # 4 在视图类中局部使用,在settings中全局使用,局部可以禁用
    	class PublishView(ViewSet):
        	permission_classes = [UserPermission] 
           
        REST_FRAMEWORK = {
        'DEFAULT_AUTHENTICATION_CLASSES': [
            'app01.auth.LoginAuth'
        ],
        'DEFAULT_PERMISSION_CLASSES': [
            'app01.permissions.UserPermission',
        ],
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    from rest_framework.permissions import BasePermission
    
    
    # 1 写一个类,继承 BasePermission
    # 2 重写 has_permission
    # 3 在方法中校验用户是否有权限,如果有,就返回True,如果没有,就返回False
    # 4
    
    class UserPermission(BasePermission):
    
        def has_permission(self, request, view):
            # request 当次请求的request,  新的,它是在认证类之后执行的,如果认证通过了request.user 就是当前登录用户
            # 拿到当前登录用户,查看它的类型,确定有没有权限
            if request.user.user_type == 3:
    
                return True
            else:
                self.message = '您的用户类型是:%s,您没有权限操作' % (request.user.get_user_type_display())
                return False
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    2.1 django项目国际化

    # 配置文件中--->以后所有英文都会转成中文
    INSTALLED_APPS = [
        'rest_framework'
    ]
    
    LANGUAGE_CODE = 'zh-hans'
    TIME_ZONE = 'Asia/Shanghai'
    USE_I18N = True
    USE_L10N = True
    USE_TZ = False
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    3 频率组件

    # 控制一个接口,访问频次,比如一分钟只能访问1次
    # 对接口进行访问次数限制
    
    
    # 使用步骤:
    	# 1 写一个类,继承SimpleRateThrottle
        # 2 重写get_cache_key,返回什么,就以什么做限制: IP地址,用户id限制
        # 3 写一个类属性   scope = 'drf_day08'
        # 4 配置文件中配置
        '''
            'DEFAULT_THROTTLE_RATES': {
                'drf_day08': '3/m',  # 一分钟访问三次   5/s,m,h,d
            },
        '''
    
        # 5 局部使用,全局使用,局部禁用
        class PublishView(ViewSet):
        	throttle_classes = [IPRateThrottle]
        #6 全局使用
        	 'DEFAULT_THROTTLE_CLASSES': ['app01.throttling.IPRateThrottle'],
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    from rest_framework.throttling import SimpleRateThrottle
    
    
    # 1 写一个类,继承SimpleRateThrottle
    # 2 重写get_cache_key,返回什么,就以什么做限制: IP地址,用户id限制
    # 3 写一个类属性   scope = 'drf_day08'
    # 4 配置文件中配置
    '''
        'DEFAULT_THROTTLE_RATES': {
            'drf_day08': '3/m',  # 一分钟访问三次
        },
    '''
    
    # 5 局部使用,全局使用,局部禁用
    
    
    class IPRateThrottle(SimpleRateThrottle):
        scope = 'drf_day08'  # 写一个类属性
        def get_cache_key(self, request, view):
            # 返回ip,以ip地址限制
            print(request.META)
            return request.META.get('REMOTE_ADDR')
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    4 排序

    # 只有5个接口中的查询所有,才涉及到排序
    
    # 查询所有用户---》接口
    
    
    # 使用步骤
    	- 1 必须写在继承:GenericAPIView 类的视图类中才行
        -2 配置类属性:
            filter_backends = [OrderingFilter]
        	ordering_fields=['id','user_type'] #可以排序的字段
            
        -3 使用:规定必须使用ordering 降序带负号
        	http://127.0.0.1:8000/user/?ordering=user_type #用户类型升序排
            http://127.0.0.1:8000/user/?ordering=-user_type #用户类型降序排
        	http://127.0.0.1:8000/user/?ordering=user_type,-id#先按用户类型升序排,如果用户类型一样,再按id降序排
        	
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    代码展示

    # 由于要和数据库打交道,这里不适合用ViewSet, 而要用GenericViewSet
    # 但是多了两个功能 queryset 和 serializer_class,但不影响我们的使用
    from rest_framework.viewsets import GenericViewSet
    from rest_framework.generics import ListAPIView  # 继承ListAPIView可以
    from rest_framework.mixins import ListModelMixin  # 继承ListModelMixin也可以
    # 排序
    from rest_framework.filters import OrderingFilter
    
    from .models import User
    from .serializer import UserSerializer
    
    
    # 演示排序,写查询所有用户,视图类必须继承GenericAPIView
    # 视图类 + 扩展类,要和数据库打交道
    class UserView(GenericViewSet, ListModelMixin):
        # 配置了全局是,局部禁用认证
        authentication_classes = []
        # 局部禁用权限
        permission_classes = []
        # 局部禁用频率
        throttle_classes = []
    
        queryset = User.objects.all()
        serializer_class = UserSerializer
    
        # 排序
        filter_backends = [OrderingFilter]
        # 指定按照什么排序
        ordering_fields = ['id', 'user_type']
    
        @action(methods=['POST'], detail=False)  # 访问 /user/login/    post请求就会执行
        def login(self, request, *args, **kwargs):
            # 前端传入用户名密码
            username = request.data.get('username')
            password = request.data.get('password')
    
            user = User.objects.filter(username=username, password=password).first()
            if user:
                token = str(uuid.uuid4())
                UserToken.objects.update_or_create(defaults={'token': token, 'user': user})
    
                return Response({'code': 100, 'msg': '登录成功', 'token': token})
    
            return Response({'code': 101, 'msg': '用户名或密码错误'})
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
  • 相关阅读:
    Nginx 配置错误导致漏洞
    Linux | gdb的基本使用
    eNSP新手学习:01-软件安装
    IB和A-Level哪个的含金量高?
    学过的汇编指令整合
    JavaScript-es6-新版语法-export-import
    一、k8s的安装部署
    计算机视觉基础入门指南
    Java智慧工地SaaS管理平台源码:AI/云计算/物联网
    scipy连续小波变换
  • 原文地址:https://blog.csdn.net/weixin_44145338/article/details/132722151