drf-异常处理、接口文档
目录
一 异常处理 Exceptions
REST framework提供了异常处理,我们可以自定义异常处理函数。
对于前端来讲,后端即便报错,也要返回统一的格式,前端便于处理
{code:999,msg:'系统异常,请联系系统管理员'}
1.1 异常源码
-1 settings中的
# Exception handling
'EXCEPTION_HANDLER': 'rest_framework.views.exception_handler',
# drf只要出了异常,就会执行上面的
-2 查看异常的源码,入口,APIView的dispatch方法中
def dispatch(self, request, *args, **kwargs):
try:
self.initial(request, *args, **kwargs)
if request.method.lower() in self.http_method_names:
handler = getattr(self, request.method.lower(),
self.http_method_not_allowed)
except Exception as exc:
response = self.handle_exception(exc) # 异常处理***
return self.response
-3 APIView的handle_exception方法
def handle_exception(self, exc):
if isinstance(exc, (exceptions.NotAuthenticated,
exceptions.AuthenticationFailed)):
auth_header = self.get_authenticate_header(self.request)
if auth_header:
exc.auth_header = auth_header
else:
exc.status_code = status.HTTP_403_FORBIDDEN
exception_handler = self.get_exception_handler()
context = self.get_exception_handler_context()
response = exception_handler(exc, context) # ***
response.exception = True
return response
-4 异常函数:exception_handler(位置:rest_framework.views.exception_handler)
def exception_handler(exc, context):
if isinstance(exc, exceptions.APIException):
# 判断这个错误对象exc是否是APIException的对象
if getattr(exc, 'auth_header', None):
headers['WWW-Authenticate'] = exc.auth_header
if getattr(exc, 'wait', None):
headers['Retry-After'] = '%d' % exc.wait
if isinstance(exc.detail, (list, dict)):
# 如果exc.detail是列表或者字典,直接返回这个数据
data = exc.detail
else: # 如果是其他格式,组装成字典形式返回
data = {'detail': exc.detail}
set_rollback()
return Response(data, status=exc.status_code, headers=headers)
return None
总结
# 只要三大认证,视图类的方法出了异常,都会执行一个函数:rest_framework.views import exception_handler
### 注意:exception_handler
# 如果异常对象是drf的APIException对象,就会返回Response
# exception_handler只处理了drf的异常,其它的异常需要我们自己处理
# 如果异常对象不是drf的APIException对象,就会返回None
1.2 自定义异常
exceptions.py
# 只要三大认证,视图类的方法出了异常,都会执行一个函数:rest_framework.views import exception_handler,这个函数是写死的,固定的。所以我们要重写这个函数
# 处理全局异常,返回统一格式
步骤:
-1 重写common_exception_handler()函数
-2 返回自己定义的格式。统一返回格式
-2 在配置文件中设置
from rest_framework.response import Response
from rest_framework.views import exception_handler
# 如果异常对象是drf的APIException对象,就会返回Response
# exception_handler只处理了drf的异常,其它的异常(返回None,页面会直接报错)需要我们自己处理
# 如果异常对象不是drf的APIException对象,就会返回None
# isinstance() 判断一个对象是不是某个类的对象 isinstance(对象,类)
# issubclass() 判断一个类,是不是另一个类的子类
def common_exception_handler(exc, context):
# 只要走到这里,一定出异常了,我们正常的项目要记录日志(后面讲)
# 两种可能:一个是Response对象,一个是None
res = exception_handler(exc, context)
if res:
# 说明有值是drf的异常,它处理了
if isinstance(res.data, dict):
# 显示drf异常的详细信息
detail = res.data.get('detail')
else:
detail = res.data
return Response({'code': 998, 'msg': detail})
else:
# 说明是其它异常None,它没有处理
# return Response({'code': 999, 'msg': '系统异常,请联系系统管理员'})
# 显示错误具体信息
return Response({'code': 999, 'msg': str(exc)})
视图类
########### 1 全局异常处理
# drf只要出了异常,就会执行:'EXCEPTION_HANDLER': 'rest_framework.views.exception_handler'
# 但是源码是不能改的,我们可以自定义一个函数,配置一下,以后出了异常,执行我们自己的函数
from rest_framework.views import exception_handler
from rest_framework.exceptions import APIException
from rest_framework.views import APIView
class BookView(APIView):
# /books/?ordering=-price&name=红楼梦
def get(self, request):
ordering = request.query_params.get('ordering')
name = request.query_params.get('name')
# 异常测试
# 1.drf异常
# raise APIException('我爱你') # 前端能看到这个中文
# 2.其他异常
# raise Exception('我爱你')
# 3.
# l = [1, 2, 3]
# print(l[9])
book_list = Book.objects.all()
if ordering:
book_list = book_list.order_by(ordering)
if name:
book_list = book_list.filter(name__contains=name)
ser = BookSerialzier(instance=book_list, many=True)
return Response(ser.data)
设置配置文件
### 配置文件
REST_FRAMEWORK = {
'EXCEPTION_HANDLER': 'app01.excepitons.common_exception_handler',
}
1.3 REST framework定义的异常
- APIException 所有异常的父类
- ParseError 解析错误
- AuthenticationFailed 认证失败
- NotAuthenticated 尚未认证
- PermissionDenied 权限决绝
- NotFound 未找到
- MethodNotAllowed 请求方式不支持
- NotAcceptable 要获取的数据格式不支持
- Throttled 超过限流次数
- ValidationError 校验失败
也就是说,很多的没有在上面列出来的异常,就需要我们在自定义异常中自己处理了。
二 接口文档
2.1 介绍
# 后端把接口写好后,再写一个接口文档
-登录接口
-注册接口
-查询所有图书带过滤接口
# 前端人员需要根据接口文档,进行前端开发
# 前后端需要做对接----> 对接第一个东西就是这个接口文档---> 前端照着接口文档开发
# 公司3个人,每个人开发了10个接口,3个人都要同时写接口文档
# 接口文档的编写形式
-1 world,md,编写,大家都可以操作,写完放在git,公司的文档管理平台上
-2 第三方的接口文档平台(收费)
https://www.showdoc.com.cn/
-3 公司自己开发接口文档平台
-4 公司使用开源的接口文档平台,搭建
-YAPI:百度开源的
-https://zhuanlan.zhihu.com/p/366025001
-5 项目自动生成接口文档
-coreapi
-swagger
# swaggerAPI文档生成器: https://blog.csdn.net/qq_44614026/article/details/128710326
2.2 使用coreapi自动生成接口文档
-使用步骤:
-1 安装:pip3 install coreapi
-2 加一个路由
from rest_framework.documentation import include_docs_urls
urlpatterns = [
path('docs/', include_docs_urls(title='站点页面标题'))
]
-3 在视图类上加注释(描述信息)
-4 配置文件中配置:
'DEFAULT_SCHEMA_CLASS': 'rest_framework.schemas.coreapi.AutoSchema',
-5 表模型或序列化类的字段上写 help_text--->会显示在接口文档的字段介绍上
-6 访问地址:
http://127.0.0.1:8000/docs/

视图类
在视图类中添加注释
- 单一方法的视图,可直接使用类视图的文档字符串,如
class BookListView(generics.ListAPIView):
"""
返回所有图书信息.
"""
queryset = Book.objects.all()
serializer_class = BookSerializer
2)包含多个方法的视图,在类视图的文档字符串中,分开方法定义,如
class BookListCreateView(generics.ListCreateAPIView):
"""
get:
返回所有图书信息.
post:
新建图书.
"""
queryset = Book.objects.all()
serializer_class = BookSerializer
3)对于视图集ViewSet,仍在类视图的文档字符串中封开定义,但是应使用action名称区分,如
class BookInfoViewSet(mixins.ListModelMixin, mixins.RetrieveModelMixin, GenericViewSet):
"""
list:
返回图书列表数据
retrieve:
返回图书详情数据
latest:
返回最新的图书数据
read:
修改图书的阅读量
"""
queryset = Book.objects.all()
serializer_class = BookSerializer

路由
from django.contrib import admin
from django.urls import path, include
from app01 import views
from rest_framework.routers import SimpleRouter
from rest_framework.documentation import include_docs_urls
router = SimpleRouter()
router.register('books', views.BookInfoViewSet, 'books')
urlpatterns = [
# 接口文档的路由
path('docs/', include_docs_urls(title='电商项目接口文档')),
# 两个视图函数的路由
path('lqz/', views.BookListCreateView.as_view()),
path('zzz/', views.BookListView.as_view()),
]
urlpatterns += router.urls
两点说明
1) 视图集ViewSet中的retrieve名称,在接口文档网站中叫做read
2)参数的Description需要在模型类或序列化器类的字段中以help_text选项定义,如:
class Student(models.Model):
...
age = models.IntegerField(default=0, verbose_name='年龄', help_text='年龄')
...
或
class StudentSerializer(serializers.ModelSerializer):
class Meta:
model = Student
fields = "__all__"
extra_kwargs = {
'age': {
'required': True,
'help_text': '年龄'
}
}


浙公网安备 33010602011771号