DRF整合了非常多的开发常用组件,认证,授权、限流等等,简单配置即可使用
认证和授权
全局配置
开启全局配置,只要请求后端接口,都需要进行认证才可以请求成功
settings.py
1 2 3 4 5 6 7 8 9 10 11 12 13
| REST_FRAMEWORK = { 'DEFAULT_AUTHENTICATION_CLASSES': ( 'rest_framework.authentication.SessionAuthentication', 'rest_framework.authentication.BasicAuthentication', ), 'DEFAULT_PERMISSION_CLASSES': ( 'rest_framework.permissions.IsAuthenticated', ),
|
我们再去请求后端接口,在没有登录的情况下是无法请求成功的
登录管理员后,再去请求就成功了,获得了登录信息
但是,我们并不是后端所有接口都需要认证,比如在登录中的登录接口和验证码接口就不能要求认证,不然就是先有鸡先有蛋的问题出现了,这时候我们可以进行局部认证,让这两个接口不需要进行认证
局部配置
1 2 3 4
|
authentication_classes = [] permission_classes = []
|
此时我们再去请求不需要做认证的接口
发现,没有进行登录也可以访问,访问没有做局部配置的接口,依旧需要认证
除了需要登录这个认证,部分接口是只有管理员才能访问的,所以我们对管理员接口进行局部配置,即使登陆了,不是管理员也不能访问
1 2 3
| authentication_classes = [SessionAuthentication] permission_classes = [IsAdminUser]
|
创建的csq账号,是没有管理员权限的,所以即使是登录也不能请求成功这个接口
换做luffy就可以了
还可以自定义一个认证类,实现一个接口的自定义认证,如下
authentication.py
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| class CustomAuthentication(BaseAuthentication): ''' 自定义认证 ''' def authenticate(self, request): ''' 认证方法 :param request: 客户端发来的http对象 :return: ''' user = request.query_params.get('user') pwd = request.query_params.get('pwd') if user != 'root' or pwd != '123456': return None print('调用用户自定义权限类') user = get_user_model().objects.first() return (user,None)
|
写的很简单,就是要再地址栏拼接上用户名和密码
目前做了全局认证和权限配置,必须登录能访问接口,现在我们把自定义的配置传到接口中测试,测试在未登录的情况下拼接地址能不能请求成功。
发现请求成功,我们不这样拼接,直接登录超级管理员登录后,去请求该接口
发现请求失败,我们在PyCharm中也发现打印信息:
在全局配置中,配置的授权信息是认证就可以访问,现在我们可以自定义权限配置
permission.py
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| class IsXiaoMingPermissions(BasePermission): ''' 自定义权限,可全局,也可局部 ''' def has_permission(self, request, view): ''' 试图权限 True 可以访问 :param request: :param view: :return: ''' role = request.query_params.get('role') return role == 'xiaoming'
def has_object_permission(self, request, view, obj): ''' 模型权限 :param request: :param view: :param obj: :return: ''' return True
|
view.py
1
| permission_classes = [IsXiaoMingPermissions]
|
这样的局部配置完成后,要求请求这个类的接口都要符合 IsXiaoMingPermissions.py
,否则即使是超级管理员也无法请求,测试如下:
用luffy这个超级管理员账户测试
即使登录的是超级管理员,也无法请求成功!必须是通过自定义的授权程序才能请求成功。
总结
- 全局配置决定了程序所有接口的认证和授权信息,但可以通过局部配置进行覆盖,生效的就是局部配置了
- 认证和授权联系紧密,在配置的时候要考虑两者之间的关系
限流
全局配置
settings.py
1 2 3 4 5 6 7 8 9 10 11
| 'DEFAULT_THROTTLE_CLASSES': ( 'rest_framework.throttling.AnonRateThrottle', 'rest_framework.throttling.UserRateThrottle' ),
'DEFAULT_THROTTLE_RATES': { 'anon': '3/day', 'user': '5/day', },
|
未认证用户使用IP区分,已认证用户使用ID用于生成唯一的密钥以进行限制 。
节流率的时间可以用天,小时,分,秒等来进行限定
分别测试未登录和登录用户去请求
达到请求上限,得到预期效果
局部配置
假设全局并没有做限流操作,只是在某个接口中需要做限流,可以采用局部限流的方法,做法有两种
取消全局限流,保留限流率,对需要做限流的操作进行局部限流处理
1 2 3 4 5
| class StudentReadOnlyModelViewSet(ReadOnlyModelViewSet): queryset = Student.objects.all() serializer_class = StudentModelSerializer throttle_classes = [AnonRateThrottle,UserRateThrottle]
|
发现配置了局部限流的接口会受限流率的操作,没有配置的接口则不受限制
第二种方法是,在全局仍需限流操作的情况下,部分接口与全局限流率不一致,这是需要配置局部限流率了
1 2 3 4 5 6 7 8 9 10 11 12
| 'DEFAULT_THROTTLE_CLASSES': ( 'rest_framework.throttling.AnonRateThrottle', 'rest_framework.throttling.UserRateThrottle' ),
'DEFAULT_THROTTLE_RATES': { 'anon': '3/day', 'user': '5/day', 'Hom': '10/day', },
|
局部限流配置10次/day,全局限流配置登录用户3次/day
view.py
1 2 3 4 5 6 7 8
| from rest_framework.throttling import ScopedRateThrottle class StudentReadOnlyModelViewSet(ReadOnlyModelViewSet): queryset = Student.objects.all() serializer_class = StudentModelSerializer
throttle_classes = [ScopedRateThrottle] throttle_scope = 'Hom'
|
过滤
settings.py
1 2 3 4 5 6 7 8 9
| INSTALLED_APPS = [ .... 'django_filters', ... ]
'DEFAULT_FILTER_BACKENDS': ['django_filters.rest_framework.DjangoFilterBackend'],
|
view.py
1
| filter_fields = ['sex','classmate']
|
简单的配置就是这样,全局开启过滤配置,具备设置过滤字段,就可以发送带参过滤Get请求了
还有很多强大的配置,等到时候工作用到了再去文档里看
排序
setting.py
1 2 3 4 5
| 'DEFAULT_FILTER_BACKENDS':[ 'django_filters.rest_framework.DjangoFilterBackend', 'rest_framework.filters.OrderingFilter', ],
|
view.py
1 2 3 4
|
ordering_fields = ['id','age']
|
分页
全局配置
settings.py
1 2 3 4 5 6
|
'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination',
'PAGE_SIZE': 3,
|
这样配置,视图层只要是返回list就会分页
但是通常不会设置全局分页,因为有很多业务是不需要分页的,我们需要配置局部分页
局部配置
局部配置就是自己写个自己的分页器,然后在需要进行分页的时候引入即可
pagiation.py
1 2 3 4 5
| class StudentPageNumberPagination(PageNumberPagination): page_size = 10 max_page_size = 20 page_query_param = 'page' page_size_query_param = 'page_size'
|
在 view.py
中引入自定义分页器
1 2 3
|
pagination_class = StudentPageNumberPagination
|
注意:如果在视图内关闭分页功能,只需在视图内设置
异常处理
DRF的 Respone
已经给我们封装了很多错误信息,比如下面限流的
[
但是还是会有很多异常不能处理返回,一旦没有处理就之间返回错误页面,对前端是很不友好的,比如我们做一个除0操作
我们要对异常进行处理,就要自己去写个类,去处理 Response
无法处理的异常
execeptions.py
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
| from rest_framework.views import exception_handler from rest_framework import status from rest_framework.response import Response from django.db import DatabaseError def custom_exception_handle(exc,context): ''' 自定义异常函数 要注册到setting中
:param exc: 异常对象 :param context: 上下文,字典 :return: ''' response = exception_handler(exc,context) if response is None: view = context['view'] request = context['request'] if isinstance(exc,DatabaseError): print('[%s]:%s'%(view,exc)) response = Response({'detail':'服务器内部错误'},status=status.HTTP_507_INSUFFICIENT_STORAGE) elif isinstance(exc,ZeroDivisionError): response = Response({'detail': '算术异常'}, status=status.HTTP_500_INTERNAL_SERVER_ERROR) else: response = Response({'detail': '未捕获异常'}, status=status.HTTP_500_INTERNAL_SERVER_ERROR) return response
|
这个异常处理类最好写在父组件下,因为所有组件都需要这个全局异常处理
配置自定义异常处理 setting.py
1 2
| 'EXCEPTION_HANDLER': 'drfdemo.exceptions.custom_exception_handle',
|
测试效果
自动生成接口文档
coreapi
需要先下载库
settings.py
1 2
| 'DEFAULT_SCHEMA_CLASS':'rest_framework.schemas.AutoSchema',
|
urls.py
1
| path('docs/',include_docs_urls(title='API文档')),
|
浏览器访问http://127.0.0.1:8000/docs/,即可看到接口文档了,还可以进行测试
swagger
SpringBoot常用的API接口文档就是Swagger,DRF也可以整合Swagger
下载库
添加组件
1 2 3 4 5 6
| INSTALLED_APPS = [ ... 'drf_yasg', ... ]
|
swagger_setting.py
1 2 3 4 5 6 7 8 9 10 11 12
| schema_view = get_schema_view( openapi.Info( title="接口文档平台", default_version='v1', description="文档描述", terms_of_service='', contact=openapi.Contact(email="389783961@qq.com"), license=openapi.License(name="BSD LICENSE") ), public=True, )
|
urls.py
1 2 3 4 5 6 7 8 9
| urlpatterns = [ path('admin/', admin.site.urls), path('stu/', include('students.urls')), path('req/', include('req.urls')), path('swagger/', schema_view.with_ui('swagger', cache_timeout=0), name='schema-swagger'), path('redoc/', schema_view.with_ui('redoc', cache_timeout=0), name='schema-redoc'), ]
|
浏览器访问http://127.0.0.1:8000/swagger/
DRF系列总结
作为Django的插件,DRF对API的封装非常完美,但是有时候又显得很鸡肋,不够相比它带给我们的便利,就不值一提了。
drfdemo源码
DRF中文官方文档
2022年3月27日10点06分完结!