第六篇:DRF之权限、频率、过滤、排序

第六篇:DRF之权限、频率、过滤、排序

一、权限

1、权限的源码分析

有时,我们需要对用户设置一定的访问权限,比如管理员用户、会员用户和普通用户等,不同的用户有不同的访问权限。

我们可以从源码中得到解决方案。首先,从APIView ---> dispatch方法 ---> self.initial(request, *args, **kwargs) ---> self.check_permissions(request) ,我们仔细研究check_permissions的源码。

代码如下。

def check_permissions(self, request):
    # 遍历权限对象列表得到一个个权限对象(权限器),进行权限认证
    for permission in self.get_permissions():
        # 权限类一定有一个has_permission权限方法,用来做权限认证的
        # 参数:权限对象self、请求对象request、视图类对象
        # 返回值:有权限返回True,无权限返回False
        if not permission.has_permission(request, self):
            self.permission_denied(
                request, message=getattr(permission, 'message', None)
            )

2、自定义权限的使用

使用步骤:书写一个权限类,然后类继承BasePermission,重写其中的has_permission方法,如果权限通过,则返回True,权限不通过,就返回False

注:权限是在认证之后,所以在权限类中可以使用request.user来获取当前用户。

为了理清思路,我们重新进行配置。

我们现在models.py中建立数据表

from django.db import models

# 定义一个用户表
class User(models.Model):
    username = models.CharField(max_length=32)
    password = models.CharField(max_length=32)
    user_type = models.IntegerField(
        choices=(
            (1, '超级用户'),
            (2, '普通用户'),
            (3, '游客')
        )
    )

# 定义一个用户token表
class UserToken(models.Model):
    token = models.CharField(max_length=64)
    user = models.OneToOneField(to='User')

接下来,我们新建一个app_permission.py文件,在其中书写认证类和权限类。

from rest_framework.permissions import BasePermission
from rest_framework.authentication import BaseAuthentication
from rest_framework.exceptions import AuthenticationFailed
from app01 import models

# 书写认证类
class MyAuthentication(BaseAuthentication):
    # 必须重写这个方法,因为源码规定
    def authenticate(self, request):
        # 拿到token数据
        token = request.query_params.get('token')
        """
        如果认证通过,返回两个值 request.user和request.auth;
        如果认证失败,抛出AuthenticationFailed异常
        """
        # 判断token是否存在
        if token:
            # 根据token去表中查找
            user_token = models.UserToken.objects.filter(token=token).first()
            # 如果token检测到数据对象
            if user_token:
                return user_token.user, token
            else:
                raise AuthenticationFailed('认证失败')
        else:
            raise AuthenticationFailed('请求地址中需要携带token')

# 书写权限类
class UserPermission(BasePermission):
    """第一个参数为权限类对象,第二个参数为request,第三个参数为视图类对象"""
    def has_permission(self, request, view):
        # 拿到当前登录用户【由于认证通过,request内就有user对象】
        user = request.user
        """ 如果该字段用了choice,通过get_字段名_display()就能取出choice后面的中文"""
        print(user.get_user_type_display())
        """判断用户类型"""
        # 如果是超级用户
        if user.user_type == 1:
            return True
        else:  # 如果是普通用户和游客
            return False

我们在views.py中进行如下进行局部认证和局部权限配置。

from rest_framework.views import APIView
from rest_framework.response import Response
from app01 import models
from app01.app_permission import MyAuthentication, UserPermission
import uuid

# 用户登录,不需要认证和权限
class Login(APIView):
    def post(self, request):
        # 根据请求拿到相关的数据
        username = request.data.get('username')
        password = request.data.get('password')
        # 根据用户名和密码得到用户对象
        user_obj = models.User.objects.filter(username=username, password=password).first()
        # 判断用户对象是否存在
        if user_obj:
            # 生成随机字符串代表token
            token_num = str(uuid.uuid4())
            print(token_num)  # 22e08528-b7d7-4798-b392-5824cd5931fc
            # 将token写入到数据库中
            """使用 models.UserToken.objects.create(token=token,user=user) 不好,用它每次登陆都会记录一条,不好,如有有记录"""
            # 默认修改的defaults={token: 'token'}, 其余字段也需传入
            models.UserToken.objects.update_or_create(defaults={'token': token_num}, user=user_obj)
            # 返回json格式数据
            return Response({'status': 100, 'msg': '登陆成功', 'token': token_num})
        else:
            return Response({'status': 101, 'msg': '用户名或密码错误'})


# 测试视图类【需要认证和权限】
class TestView(APIView):
    # 局部配置认证
    authentication_classes = [MyAuthentication]
    # 局部权限配置【认证和局部必须联合使用】
    permission_classes = [UserPermission]

    def get(self, request):
        # 显示该用户的类型
        print(request.user.get_user_type_display())
        # Response中的data=可以将数据转化成json,然后再返回
        return Response('我是只有超级用户才能看到的数据。')

全局配置如下所示。

我们在settings.py中,进行全局配置的书写。【注意循环导入循环导入问题,找bug太难找了,不用的就不导】

# 配置REST_FRAMEWORK参数
REST_FRAMEWORK = {
    # 认证类配置
    "DEFAULT_AUTHENTICATION_CLASSES": ["app01.app_permission.MyAuthentication"],
    # 权限类配置
    "DEFAULT_PERMISSION_CLASSES": ["app01.app_permission.UserPermission"]
}

局部禁用方式如下。

"""局部禁用"""  # 我们在登录视图中禁用认证和登录
authentication_classes = []  # 局部禁用认证
permission_classes = []  # 局部禁用权限

最终,效果演示如下。

如果是超级用户,显示如下效果。

如果是普通用户,显示如下效果。

3、内置权限使用【了解】

内置权限必须配合内部提供的认证方式,才能实行。

"""步骤"""
1、创建一个超级用户
2、写一个测试视图类
3、超级用户登录到admin,再访问视图路由就有权限
4、正常的话,普通用户,没有权限访问。(判断的是is_staff字段)

我们设置这样的视图类。

from rest_framework.authentication import SessionAuthentication
from rest_framework.permissions import IsAdminUser
# 内置权限的视图类测试
class TestView1(APIView):
    # 内置的认证类
    authentication_classes = [SessionAuthentication]
    # 内置的权限类
    permission_classes = [IsAdminUser]
    
    def get(self, request):
        return Response('这是测试内置认证和内置权限的视图,只有超级管理员才能看。')

效果如下。

二、频率

1、内置的限制未登录用户的访问频率

1.1 局部配置

实例:限制未登录用户1分钟只能访问5次。

  • settings.py
# 配置REST_FRAMEWORK参数
REST_FRAMEWORK = {
    # 给谁限制
    "DEFAULT_THROTTLE_CLASSES": [
        # "rest_framework.throttling.AnonRateThrottle"
    ],
    # 限制要求
    "DEFAULT_THROTTLE_RATES": {
        'anon': '3/m'
    }
}
  • views.py
from rest_framework.throttling import AnonRateThrottle
# 频率限制视图测试
class TestView2(APIView):
    authentication_classes = []
    permission_classes = []
    # 局部频率配置
    throttle_classes = [AnonRateThrottle]

    def get(self, request):
        return Response('这是局部测试频率限制的视图')

测试效果如下所示。

1.2 全局配置

settings.py中,进行配置即可。

# 配置REST_FRAMEWORK参数
REST_FRAMEWORK = {
    # 给谁限制
    "DEFAULT_THROTTLE_CLASSES": [
        "rest_framework.throttling.AnonRateThrottle"

    ],
    # 限制要求
    "DEFAULT_THROTTLE_RATES": {
        'anon': '3/m'
    }
}

2、内置的限制登录用户的访问频率

案例:限制登录用户1分钟只能访问10次。

  • 全局配置
"""settings.py"""
# 配置REST_FRAMEWORK参数
REST_FRAMEWORK = {
    # 给谁限制
    "DEFAULT_THROTTLE_CLASSES": [
        # 限制登录用户
        "rest_framework.throttling.UserRateThrottle",
        # 限制未登录用户
        "rest_framework.throttling.AnonRateThrottle"
        
    ],
    # 限制要求
    "DEFAULT_THROTTLE_RATES": {
        # 登录用户
        'user': '10/m',
        # 未登录用户
        'anon': '3/m'
    }
}
  • 局部配置

    在视图类中配置如下参数即可。

# 局部频率配置
throttle_classes = [UserRateThrottle]

三、过滤

要想实现过滤数据,我们必须安装一个模块。

# 千万不要这种方式,务必在pycharm解释器中安装,它会把django给你卸载
pip3 install django-filter 

使用步骤如下所示。

1、全局配置

"""步骤"""
1 在app中进行注册,'django_filters'
2 在全局进行配置
REST_FRAMEWORK = {
    # 过滤组件的配置
    "DEFAULT_FILTER_BACKENDS": ['django_filters.rest_framework.DjangoFilterBackend']
}

视图类中使用方式如下。

from rest_framework.generics import ListAPIView
# 过滤视图类
class TestView3(ListAPIView):
    queryset = models.Book.objects.all()
    serializer_class = BookModelSerializer
    # 配置可以用来过滤的字段
    filter_fields = ('title', 'price')

2、局部配置

from rest_framework.generics import ListAPIView
# 导入过滤类
from django_filters.rest_framework import DjangoFilterBackend
# 过滤视图类
class TestView3(ListAPIView):
    queryset = models.Book.objects.all()
    serializer_class = BookModelSerializer
    # 局部配置过滤方式
    filter_backends = [DjangoFilterBackend]
    # 定义可以过滤的字段
    filter_fields = ('title', 'price')

现在数据库中数据为。

我们可以找出过滤出所有price=12.50的书。

四、排序

1 、局部配置

"""views.py"""
from rest_framework.generics import ListAPIView
from rest_framework.filters import OrderingFilter
# 排序视图类
class TestView4(ListAPIView):
    queryset = models.Book.objects.all()
    serializer_class = BookModelSerializer
    # 以这种方式配置过滤方式【局部配置】
    filter_backends = [OrderingFilter]
    # 配置可以用哪些字段进行排序
    ordering_fields = ['id', 'price']
    
    
"""排序方式"""
http://127.0.0.1:8000/testview4/?ordering=-id
http://127.0.0.1:8000/testview4/?ordering=-price
http://127.0.0.1:8000/testview4/?ordering=price

效果如下所示。按照价格逆向排序。

2、全局配置

全局配置好排序组件之后,在视图类中只要指定排序字段即可。

# 配置REST_FRAMEWORK参数
REST_FRAMEWORK = {
    # 过滤组件的配置
    "DEFAULT_FILTER_BACKENDS": [
        # 配置过滤
        'django_filters.rest_framework.DjangoFilterBackend',
        # 配置排序
        'rest_framework.filters.OrderingFilter'
    ]
}

posted @ 2021-07-22 22:58  YangYi215  阅读(163)  评论(0编辑  收藏  举报