zoukankan      html  css  js  c++  java
  • DRF 认证、权限、限流、分页、过滤、序列 化

    2.1 user/urls.py

      ModelViewSet注册路由三部曲

    from django.urls import include, path
    from user import views
    from rest_framework.routers import SimpleRouter, DefaultRouter
    # 自动生成路由方法, 必须使用视图集
    # router = SimpleRouter() # 没有根路由 /user/ 无法识别
    router = DefaultRouter() # 1.有根路由
    router.register(r'user', views.UserViewSet) # 2.配置路由
    urlpatterns = [
        path('index/', views.index),
        path('api-auth/', include('rest_framework.urls', namespace='rest_framework'))
    # 认证地址
    ]
    urlpatterns += router.urls # 3.模块地址
    [<URLPattern '^user/$' [name='user-list']>,
    <URLPattern '^user.(?P<format>[a-z0-9]+)/?$' [name='user-list']>,
    <URLPattern '^user/actived/$' [name='user-actived']>,
    <URLPattern '^user/actived.(?P<format>[a-z0-9]+)/?$' [name='user-actived']>,
    <URLPattern '^user/unactived/$' [name='user-unactived']>,
    <URLPattern '^user/unactived.(?P<format>[a-z0-9]+)/?$' [name='userunactived']>, <URLPattern '^user/(?P<pk>[^/.]+)/$' [name='user-detail']>,
    <URLPattern '^user/(?P<pk>[^/.]+).(?P<format>[a-z0-9]+)/?$' [name='userdetail']>, <URLPattern '^$' [name='api-root']>, <URLPattern '^.(?P<format>[a-z0-
    9]+)/?$' [name='api-root']>] DRF

    2.2 创建 user/serializers.py 写序列化器

      功能一:数据校验, 创建/修改数据

        在创建数据或者修改数据时校验用户提交的数据是否合法

        用户名必须是8位以上,邮箱、手机号是合法的

      功能二:序列化

        把通过model查询的queryset对象转换成JSON格式

    from rest_framework import serializers
    from user.models import User
    
    
    def address_validate(data):
        print(data)
        # data:是用户提交的地址这个字段的数据(河南省 郑州市)
        # 独立校验器
        # raise serializers.ValidationError('请填写实际地址') # 有错就抛出异常
        # 没错就返回数据
        return data
    
    
    class UserSerializer(serializers.ModelSerializer):
        # 1.独立校验器:重新设定字段, 替换掉模型中的设定, 重新设定地址的长度为5
        # address_validate是自定义的数据校验函数
        address = serializers.CharField(max_length=255, min_length=5, validators=[address_validate])
        
        # 2.单一字段验证(validate_字段名), 验证地址
        def validate_address(self, data):
            if data == '测试':
                raise serializers.ValidationError('请填写实际地址') # 有错就抛出异常
            return data # 没错就返回结果
        
        def validate_phone(self, data):
            # 不符合手机号格式
            # raise serializers.ValidationError('手机号格式不正确')
            model = self.root.Meta.model
            num = model.objects.filter(phone=data).count()
            if num > 0:
                raise serializers.ValidationError('手机号已存在')
            return data
        
            # 3.所有属性验证器
        def validate(self, attrs):
            # attrs:{"username":"zhangsan", "phone":"18538752511", ....}
            # 所有属性验证器
            # self.context 中有request和view上下文
            # self.context['view'].action 可以取到动作
            # attrs 是需要序列化的数据
            # raise serializers.ValidationError('xxx错误') # 有问题报错
            return attrs # 没问题返回数据
    
        class Meta:
            model = User
            # fields = ('id', ) # 临时添加字段也需要写在这里
            fields = '__all__' # 所有字段
            # exclude = ['id'] # 排除 id 字段
            read_only_fields = ('',) # 指定字段为 read_only,
    
            # 扩展address: extra_kwargs = {} # 局部替换某些字段的设定, 或者新增设定
            extra_kwargs = {
                "address": {
                    "min_length": 5, # 给地址增加 最小长度限制
                    "default": '默认测试地址', # 增加默认值
                }
            }
    
    class UserUnActiveSerializer(serializers.ModelSerializer):
        class Meta:
            model = User
            fields = ('id', 'username', 'is_active') # 临时添加字段也需要写在这里
            # fields = '__all__' # 所有字段
    View Code

    2.3 user/views.py

    from django.http import HttpResponse
    from django_filters.rest_framework import DjangoFilterBackend
    from rest_framework import viewsets
    from rest_framework.authentication import BasicAuthentication,
    SessionAuthentication
    from rest_framework.decorators import action
    from rest_framework.filters import OrderingFilter
    from rest_framework.permissions import AllowAny, IsAdminUser, IsAuthenticated,IsAuthenticatedOrReadOnly
    from rest_framework.response import Response
    from rest_framework.throttling import UserRateThrottle
    from rest_framework.pagination import PageNumberPagination
    from rest_framework.views import APIView
    from rest_framework.permissions import BasePermission, SAFE_METHODS
    from user.models import User
    from user.serializers import UserSerializer, UserUnActiveSerializer
    
    
    def index(request):
        # 需要认证才能访问的视图
        return HttpResponse('hello')
    
    
    # 分页(局部):自定义分页器 局部
    class PageNum(PageNumberPagination):
        # 查询字符串中代表每页返回数据数量的参数名, 默认值: None
        page_size_query_param = 'page_size'
        # 查询字符串中代表页码的参数名, 有默认值: page
        # page_query_param = 'page'
        # 一页中最多的结果条数
        max_page_size = 2
    
    
    # 自定义权限(局部)
    class MyPermission(BasePermission):
        # has_permission 是用户对这个视图有没有 GET POST PUT PATCH DELETE 权限的分别判断
        def has_permission(self, request, view):
            print('has_perm')
            # print(view.kwargs.get("pk"), request.user.id)
            """判断用户对模型有没有访问权"""
            # 任何用户对使用此权限类的视图都有访问权限
            if request.user.is_superuser:
                # 管理员对用户模型有访问权
                return True
            elif view.kwargs.get('pk') == str(request.user.id):
                # 携带的id和用户的id相同时有访问权
                return True
            return False
    
            # has_object_permission 是用户过了 has_permission 判断有权限以后,再判断这个用户有没有对一个具体的对象有没有操作权限
            # 这样设置以后,即使是django admin管理员也只能查询自己user标的信息,不能查询其他用户的单条信息
        def has_object_permission(self, request, view, obj):
            print('has_object_perm')
            """获取单个数据时,判断用户对某个数据对象是否有访问权限"""
            if request.user.id == obj.id:
                return True
            return False
    
    
    
    class UserViewSet(viewsets.ModelViewSet):
        """
        完成产品的增删改查
        """
        queryset = User.objects.all()
        serializer_class = UserSerializer # 优先使用 get_serializer_class 返回的序列化器
        # # 1.认证:自定义认证类, 自定义会覆盖全局配置
        # authentication_classes = (BasicAuthentication, SessionAuthentication)
        # # 2.权限:自定义权限类
        # permission_classes = (MyPermission,)
    
        # 3.分页:自定义分页器 覆盖全局配置
        pagination_class = PageNum
    
        # 4.限流:自定义限流类
        throttle_classes = [UserRateThrottle]
    
        # 5.过滤:指定过滤方法类, 排序方法类, 一个或多个
        filter_backends = (DjangoFilterBackend, OrderingFilter) # 同时支持过滤和排序
        # 5.1指定排序字段, 不设置, 排序功能不起效
        ordering_fields = ('date_joined', 'id') # ?ordering=-id
        # 5.2指定过滤字段, 不设置, 过滤功能不起效
        filter_fields = ('username', 'phone', 'is_active') # ?username=tom&phone=&is_active=true
    
        # 根据不同的请求, 获得不同的序列化器
        def get_serializer_class(self):
            if self.action == 'unactived':
                return UserUnActiveSerializer
            else:
                return UserSerializer
        
        @action(methods=['get'], detail=False)
        def unactived(self, request, *args, **kwargs):
            # 获取查询集, 过滤出未激活的用户
            qs = self.queryset.filter(is_active=False)
            # 使用序列化器, 序列化查询集, 并且是
            ser = self.get_serializer(qs, many=True)
            return Response(ser.data)
        
        @action(methods=['get'], detail=False)
        def actived(self, request, *args, **kwargs):
            # 获取查询集, 过滤出未激活的用户
            qs = self.queryset.filter(is_active=True)
            # 使用序列化器, 序列化查询集, 并且是
            ser = self.get_serializer(qs, many=True)
            return Response(ser.data)
    View Code

    3.测试接口

    3.1 查询 接口

    #1.查询所有用户
    http://192.168.56.100:8888/user/user/
    #2.查询id=1的用户
    http://192.168.56.100:8888/user/user/1/
    #3.查询 用户名(tom),激活的用户
    http://192.168.56.100:8888/user/user/?username=tom&phone=&is_active=true
    #4.查询所有用户 用id 反向排序
    http://192.168.56.100:8888/user/user/?ordering=-id
    #5.查询用户表中第一页,每页显示一条数据
    http://192.168.56.100:8888/user/user/?page=1&page_size=1

    3.2 自定义认证权限

    3.2.1 测试 全局权限 功能

    在浏览器中,打开任意接口,未登录用户只能发送get请求,只有登录用户才能发送post等请求

    # http://192.168.56.100:8888/user/user/
    '''syl/settings.py中设置,只有认证用户可以访问, 否则只能读取
    REST_FRAMEWORK = {
        #2.权限配置(全局): 顺序靠上的严格
        'DEFAULT_PERMISSION_CLASSES': [
            'rest_framework.permissions.IsAuthenticatedOrReadOnly', # 认证用户可以访问, 否则只能读取
        ],
    }

    3.2.2 测试 自定义权限 功能

      注:自定义权限会覆盖settings.py中配置的全局权限

    1.自定义权限( 其实应该写到一个单独的文件内进行公用,这里先写到这里进行测试 )

    # 自定义权限(局部)
    class MyPermission(BasePermission):
        # has_permission 是用户对这个视图有没有 GET POST PUT PATCH DELETE 权限的分别判断
        def has_permission(self, request, view):
            print('has_perm')
            # print(view.kwargs.get("pk"), request.user.id)
            """判断用户对模型有没有访问权"""
            # 任何用户对使用此权限类的视图都有访问权限
            if request.user.is_superuser:
                # 管理员对用户模型有访问权
                return True
            elif view.kwargs.get('pk') == str(request.user.id):
            # 携带的id和用户的id相同时有访问权
                return True
            return False
    
            # has_object_permission 是用户过了 has_permission 判断有权限以后,再判断这个用户有没有对一个具体的对象有没有操作权限
        def has_object_permission(self, request, view, obj):
            print('has_object_perm')
            """获取单个数据时,判断用户对某个数据对象是否有访问权限"""
            if request.user.id == obj.id:
                return True
            return False

    2. user/viesws.py视图函数中指定当前视图要用的 权限类

    class UserViewSet(viewsets.ModelViewSet):
        # 2.权限:自定义权限类
        permission_classes = (MyPermission,)

    3.3 限流

    syl/settings.py中配置限流

    http://192.168.56.100:8888/user/apiview/
    '''修改syl/settings.py配置限速设置'''
    REST_FRAMEWORK = {
        #3.1 限流策略
        'DEFAULT_THROTTLE_RATES': {
            'user': '3/hour', # 认证用户每小时10次
            'anon': '3/day', # 未认证用户每天
        },
    }

     3.4 序列化

      user/serialzers.py

     

    from rest_framework import serializers
    from user.models import User
    
    def address_validate(data):
        # 独立校验器
        # raise serializers.ValidationError('请填写实际地址') # 有错就抛出异常
        # 没错就返回数据
        return data
    
    
    class UserSerializer(serializers.ModelSerializer):
    
    
        # 1.独立校验器:重新设定字段, 替换掉模型中的设定, 重新设定地址的长度为5
        address = serializers.CharField(max_length=255, min_length=5, validators=
        [address_validate])
    
    
        # 2.单一字段验证, 验证地址,validate_字段名
        def validate_address(self, data):
            if data == '测试':
                raise serializers.ValidationError('请填写实际地址')  # 有错就抛出异常
    
    
            return data  # 没错就返回结果
    
    
        def validate_phone(self, data):
    
    
            # 不符合手机号格式
            # raise serializers.ValidationError('手机号格式不正确')
            model = self.root.Meta.model
            num = model.objects.filter(phone=data).count()
            if num > 0:
                raise serializers.ValidationError('手机号已存在')
            return data
        
    
        # 3.所有属性验证器
        def validate(self, attrs):
    
        
            # attrs:{"username":"zhangsan", "phone":"18538752511", ....}
            # 所有属性验证器
            # self.context 中有request和view上下文
            # self.context['view'].action 可以取到动作
            # attrs 是需要序列化的数据
            # raise serializers.ValidationError('xxx错误') # 有问题报错
            return attrs  # 没问题返回数据
        
    
        class Meta:
            model = User  # 指定表
    
    
            # fields = ('id', ) # 临时添加字段也需要写在这里
            fields = '__all__'  # 所有字段
            # exclude = ['id'] # 排除 id 字段
            read_only_fields = ('id',)  # 指定字段为 read_only,
            # 扩展address: extra_kwargs = {} # 局部替换某些字段的设定, 或者新增设定
            extra_kwargs = {
                "address": {
                    "min_length": 5,  # 给地址增加 最小长度限制
                    "default": '默认测试地址',  # 增加默认值
                }
            }
    View Code

     3.5 自定义分页

    http://192.168.56.100:8888/user/user/?page=1&page_size=1

    1. user/views.py 中定义自定义分页类

    # 分页(局部):自定义分页器 局部
    class PageNum(PageNumberPagination):
        # 查询字符串中代表每页返回数据数量的参数名, 默认值: None
        page_size_query_param = 'page_size'
        # 查询字符串中代表页码的参数名, 有默认值: page
        # page_query_param = 'page'
        # 一页中最多的结果条数
        max_page_size = 2

    2. user/views.py 视图函数中使用

    class UserViewSet(viewsets.ModelViewSet):
        # 3.分页:自定义分页器 覆盖全局配置
        pagination_class = PageNum

    3.6 过滤和排序

      测试url

    #1.过滤:查询 用户名(tom),激活的用户
    http://192.168.56.100:8888/user/user/?username=tom&phone=&is_active=true
    #2.排序:查询所有用户 用id 反向排序
    http://192.168.56.100:8888/user/user/?ordering=-id

      user/views.py 视图函数中配置过滤和排序字段

    class UserViewSet(viewsets.ModelViewSet):
        # 5.过滤:指定过滤方法类, 排序方法类, 一个或多个
        filter_backends = (DjangoFilterBackend, OrderingFilter) # 同时支持过滤和排序
        # 5.1指定排序字段, 不设置, 排序功能不起效
        ordering_fields = ('date_joined', 'id') # ?ordering=-id
        # 5.2指定过滤字段, 不设置, 过滤功能不起效
        filter_fields = ('username', 'phone', 'is_active') # ?username=tom&phone=&is_active=true
  • 相关阅读:
    LeetCode 81 Search in Rotated Sorted Array II(循环有序数组中的查找问题)
    LeetCode 80 Remove Duplicates from Sorted Array II(移除数组中出现两次以上的元素)
    LeetCode 79 Word Search(单词查找)
    LeetCode 78 Subsets (所有子集)
    LeetCode 77 Combinations(排列组合)
    LeetCode 50 Pow(x, n) (实现幂运算)
    LeetCode 49 Group Anagrams(字符串分组)
    LeetCode 48 Rotate Image(2D图像旋转问题)
    LeetCode 47 Permutations II(全排列)
    LeetCode 46 Permutations(全排列问题)
  • 原文地址:https://www.cnblogs.com/gaodenghan/p/13886031.html
Copyright © 2011-2022 走看看