第六篇: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'
]
}