当前位置:网站首页>drf source code analysis and global catch exception
drf source code analysis and global catch exception
2022-08-02 14:21:00 【Spaghetti Mixed with No. 42 Concrete】
Python之drfSource code analysis and global catch exceptions
一、认证源码分析
views.pyUsed within the authentication class,Custom authentication class with file
# authentication.py
from rest_framework.authentication import BaseAuthentication
# Inherit the authentication base classBaseAuthentication
class bookAuthentication(BaseAuthentication):
# 重写authenticate方法
def authenticate(self,request):
token = request.GET.get('token')
user_token = UserToken.objects.filter(token=token).first()
if user_token:
# 带的token是有效的
# user_token.user当前登录用户
return user_token.user, token
else:
raise AuthenticationFailed('token不合法或没有迭代token')
# views.py
from .serializers import Bookserializers
from .models import Book
from rest_framework.generics import ListCreateAPIView
from .authentication import bookAuthentication
class BookListCreateAPIView(ListCreateAPIView):
queryset = Book.objects.all()
serializer_class = Bookserializers
authentication_classes = [bookAuthentication,]
源码分析
#1 入口---》APIView的dispatch---》self.initial(request, *args, **kwargs)————》The code for the authentication classself.perform_authentication(request)
# 2 self.perform_authentication(request)
def perform_authentication(self, request):
request.user # 新的request对象的user方法
# 2 Request类的user方法
@property
def user(self):
if not hasattr(self, '_user'):
with wrap_attributeerrors():
self._authenticate() # 核心就是这句话,是Request的
return self._user
# 3 Request类的_authenticate(self)方法
def _authenticate(self):
for authenticator in self.authenticators: #self.authenticators是个列表,An object of the authentication class is placed in the list
try:
# self是request,So our authentication classauthenticate,有两个参数,selfThe second parameter is given
user_auth_tuple = authenticator.authenticate(self) # 执行认证类的authenticate方法
except exceptions.APIException:
self._not_authenticated()
raise
if user_auth_tuple is not None:
self._authenticator = authenticator
self.user, self.auth = user_auth_tuple #解压赋值,后续的requtst对象就有user属性了
return
self._not_authenticated()
# 4 Request类的self.authenticators属性
-是在Request初始化的时候,传入的
-RequestWhen is the class initialized---》APIView的dispatchstarting position in
-APIView的dispatch---》request = self.initialize_request(request, *args, **kwargs)
# 5 APIView的self.initialize_request方法
def initialize_request(self, request, *args, **kwargs):
return Request(
request,
parsers=self.get_parsers(),
authenticators=self.get_authenticators(),# APIView
negotiator=self.get_content_negotiator(),
parser_context=parser_context
)
# 6 APIView的get_authenticators
def get_authenticators(self):
# An object of the authentication class is placed in the list
return [auth() for auth in self.authentication_classes]
二、权限源码分析
#1 入口---》APIView的dispatch---》Permission class codeself.check_permissions(request)
#2 APIView的check_permissions(request)方法
def check_permissions(self, request):
for permission in self.get_permissions():
if not permission.has_permission(request, self):
self.permission_denied(
request,
message=getattr(permission, 'message', None),
code=getattr(permission, 'code', None)
)
#3 APIView的self.get_permissions():
def get_permissions(self):
# There are objects of the permission class in the list
return [permission() for permission in self.permission_classes]
# 4 权限认证失败,返回中文
-Configured in the permission classmessage即可(给对象,类都可以)
三、频率源码分析
#1 入口---》APIView的dispatch---》The code for the frequency classself.check_throttles(request)
# 2 APIView的self.check_throttles(request)
def check_throttles(self, request):
throttle_durations = []
for throttle in self.get_throttles():# #列表,It is an object of the frequency class configured in each view class
if not throttle.allow_request(request, self):
throttle_durations.append(throttle.wait())
# 3 APIView的self.get_throttles()
def get_throttles(self):
return [throttle() for throttle in self.throttle_classes]
四、Filter source code analysis
from rest_framework.generics import GenericAPIView,ListAPIView
from rest_framework.mixins import ListModelMixin
class Book(ListAPIView):
filter_backends = ['过滤类']
首先要明确一点,The filter query is to query all the data that meet the conditions
So the view layer must inheritGenericAPIView和ListModelmixin.也就是ListAPIView
ListModelmixin里有list方法————>方法里有queryset = self.filter_queryset(self.get_queryset())This is where the query bar is filtered.self.get_queryset()取出所有数据,然后调用filter_queryset方法进行过滤
在视图类GenericAPIView中有filter_queryset:
def filter_queryset(self, queryset):
for backend in list(self.filter_backends): # Go to the view layer to find itfilter_backends
Find its filter class and add parentheses to call the overridden under itfilter_queryset方法
queryset = backend().filter_queryset(self.request, queryset, self)
return queryset
个人理解:
如果你使用rest_framework.filter中的SearchFilterFor filtering then your code in the view layer will be like this:
from rest_framework.filters import SearchFilter
from rest_framework.generics import GenericAPIView,ListAPIView
from rest_framework.mixins import ListModelMixin
class Book(ListAPIView):
filter_backends = [SearchFilter,]
在其GenericAPIView源码中:视图类GenericAPIView中的filter_queryset方法下的backend().filter_queryset(self.request, queryset, self)就变成了SearchFilter().filter_queryset(self.request, queryset, self)
而SearchFilter().filter_queryset(self.request, queryset, self),Internal filtering is performedSearchFilter()类的filter_queryset()方法.
If you need to customize the filter class, you need to inherit the filter base classBaseFilterBackend,重写BaseFilterBackend类下的filter_queryset()方法
The execution flow of internal source code is the same
五、Paging source code analysis
Pagination is to page through all the data,So the view layer must inheritGenericAPIView和ListModelmixin.也就是ListAPIView
from rest_framework.generics import GenericAPIView,ListAPIView
from rest_framework.mixins import ListModelMixin
class Book(ListAPIView):
pagination_class =['分页类']
ListModelmixin里有list方法————>方法里有:
page = self.paginate_queryset(queryset) # 执行分页
if page is not None:
serializer = self.get_serializer(page, many=True) # Serialize the current paginated data
return self.get_paginated_response(serializer.data) # Returns the previous and next pages and the total number of entries
在视图类GenericAPIView中有paginate_queryset:
if self.paginator is None: # self.paginatorIt is an object of the paging class
return None
# 实现了分页功能,取出从前端地址中传入的,第几页,取多少条
# 在该方法中自动实现分页,返回当前页码的数据
return self.paginator.paginate_queryset(queryset, self.request, view=self)
在视图类GenericAPIView中有get_paginated_response:
# self.paginatorIt is an object of the paging class
return self.paginator.get_paginated_response(data)
Combining personal understandingPageNumberPagination:
如果你使用rest_framework.pagination中PageNumberPagination来进行分页,Your code in the view layer will look like this:
from rest_framework.pagination import PageNumberPagination,LimitOffsetPagination,CursorPagination
from rest_framework.generics import GenericAPIView,ListAPIView
from rest_framework.mixins import ListModelMixin
class Book(ListAPIView):
pagination_class =[PageNumberPagination,]
在其GenericAPIView源码中self.paginate_queryset(queryset)就会变成paginate_queryset(self, queryset)下的
return PageNumberPagination.paginate_queryset(queryset, self.request, view=self)
而get_paginated_response下的self.paginator.get_paginated_response(data)会变成PageNumberPagination.paginate_queryset(queryset, self.request, view=self)
继承APIView实现分页
# 首先需要新建一个pyThe file is written on an inheritancePageNumberPagination的类,And modify the class properties inside as follows:
papg.py
from rest_framework.pagination import PageNumberPagination
class bookPageNumberPagination(PageNumberPagination):
page_size = 5
page_query_param = 'page'
page_size_query_param = 'size'
max_page_size = 10
# 在viewsWrite code in the view class:
from rest_framework.virews import APIView
from .papg import bookPageNumberPagination
from .models import Book
from .serializers import BookserializersModelserializer
from rest_framework.response import Response
class book(APIView):
def get(self,request):
# Get all the data
all_book_queryset = Book.objcets.all()
# Instantiate an object of the paging class
page = bookPageNumberPagination()
# Calls the class inherited from its paging classPageNumberPagination中的paginate_queryset方法,And pass all the data into the method
res= page.paginate_queryset(all_book_queryset,request,self)
# Serialize the data in the pagination class
serializer = BookserializersModelserializer(res, many=True)
# 将data返回出去
return Response(serializer.data)/page.get_paginated_response(serializer.data)
六、Custom global catch exception
from rest_framework.views import exception_handler
from rest_framework.response import Response
# 自定义异常处理
def common_exceptions_handler(exc, context):
response_exceptions = exception_handler(exc,context)
user_id = context.get('request').user.id
if not user_id:
user_id = '用户未登录'
# Precise positioning is abnormal,It is convenient to write to the log later
errors_detail = '视图类:%s出错了,访问者的ip为:%s,访问者的id为:%s,错误原因为:%s'%(
str(context.get('view')),
context.get('request').META.get('REMOTE_ADDR'),
user_id,
str(exc)
)
print(errors_detail)
dic = {
'code':999,'msg':''}
# 如果response_exceptionsA value indicates that the exception is presentexceptions_handler中的Http404、PermissionDenied、exceptions.APIException,异常中
if response_exceptions:
dic['msg'] = response_exceptions.data
return Response(dic)
# No value description is other exception
dic['msg'] = '服务器异常'
return Response(dic)
""" 注意: 自定义异常必须继承APIView及其子类,因为exception_handler()方法就是APIView下的 """
全局配置
REST_FRAMEWORK = {
# Path to custom exception
'EXCEPTION_HANDLER':'appo1.lib.execption.common_exceptions_handler',
}
七、coreapi自动生成接口文档
# front and rear separation
-A group of people at the front
-No idea what interface you wrote,What are the request parameters,What is the response data like
-I don't know what encoding to use
-A group of people at the back end
-We wrote a lot of interfaces
# 需要写接口文档(Different companies have specifications)
-1 The company has an interface documentation platform,The backend enters the interface on the platform
-2 Use a third-party interface documentation platform,The back-end is written in the platform entry
-Yapi:开源
-3 使用md,word文档写,write togit上
-4 自动生成接口文档(swagger,coreapi)
-swagger自动导入,导入到Yapi中
# coreapi
-pip3 install coreapi
-在路由中配置
from rest_framework.documentation import include_docs_urls
path('docs/', include_docs_urls(title='Luffy project interface documentation platform'))
-在配置文件中配置
REST_FRAMEWORK = {
'DEFAULT_SCHEMA_CLASS': 'rest_framework.schemas.coreapi.AutoSchema',
}
-访问地址http://127.0.0.1:8000/docs(As long as there are routes,都能看到)
边栏推荐
- [ROS]ROS常用工具介绍(待续)
- 【ROS】编译软件包packages遇到进度缓慢或卡死,使用swap
- Unit 6 meet ORM
- [ROS](05)ROS通信 —— 节点,Nodes & Master
- IDEA打包jar包
- Building and getting started with the Flask framework
- [ROS] The software package of the industrial computer does not compile
- 第十五单元 分页、过滤
- [ROS](04)package.xml详解
- What is the difference between web testing and app testing?
猜你喜欢
网络剪枝(1)
logback源码阅读(二)日志打印,自定义appender,encoder,pattern,converter
yolov5改进(一) 添加注意力集中机制
The IDEA of packaged jar package
[ROS] Introduction to common tools in ROS (to be continued)
第十五单元 分页、过滤
[ROS] The software package of the industrial computer does not compile
如何选择正规的期货交易平台开户?
STM32(F407)—— 堆栈
What are the file encryption software?Keep your files safe
随机推荐
[ROS] (05) ROS Communication - Node, Nodes & Master
How does Apache, the world's largest open source foundation, work?
rpm包的卸载与安装[通俗易懂]
Unit 11 Serializers
(ROS) (03) CMakeLists. TXT, rounding
第六单元 初识ORM
How to solve 1045 cannot log in to mysql server
第十四单元 视图集及路由
Sentinel源码(三)slot解析
yolov5 improvement (1) Add attention focus mechanism
第十三单元 混入视图基类
Paddle window10 environment using conda installation
[ROS](02)创建&编译ROS软件包Package
第十五单元 分页、过滤
redis延时队列
Unit 8 Middleware
Data Organization---Chapter 6 Diagram---Graph Traversal---Multiple Choice Questions
关于密码加密的一点思路
Raft对比ZAB协议
Haystack的介绍和使用