当前位置:网站首页>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](06)ROS通信 —— 话题(Topic)通信
- 8576 Basic operations of sequential linear tables
- Steps to connect the virtual machine with xshell_establish a network connection between the host and the vm virtual machine
- 第十二单元 关联序列化处理
- [ROS] The difference between roscd and cd
- 一维卷积神经网络_卷积神经网络的基础知识「建议收藏」
- deal!It's July 30th!
- How to solve mysql service cannot start 1069
- Verilog学习 系列
- [ROS]ROS常用工具介绍(待续)
猜你喜欢
Flask项目的完整创建 七牛云与容联云
如何选择正规的期货交易平台开户?
How does Apache, the world's largest open source foundation, work?
The most complete ever!A collection of 47 common terms of "digital transformation", read it in seconds~
云GPU(恒源云)训练的具体操作流程
yolov5改进(一) 添加注意力集中机制
Linux:CentOS 7 安装MySQL5.7
Chapter6 visualization (don't want to see the version)
深度学习框架pytorch快速开发与实战chapter4
The IDEA of packaged jar package
随机推荐
Flask framework
【Tensorflow】AttributeError: '_TfDeviceCaptureOp' object has no attribute '_set_device_from_string'
网络剪枝(1)
STM32(F407)—— 堆栈
VMM是什么?_兮是什么意思
[ROS] The difference between roscd and cd
Basic operations of 8583 sequential stack
云GPU(恒源云)训练的具体操作流程
replay视频播放器_怎么让手机音乐跟视频一起放
一维卷积神经网络_卷积神经网络的基础知识「建议收藏」
Unit 14 Viewsets and Routing
What's wrong with running yolov5 (1) p, r, map are all 0
Briefly write about the use and experience of PPOCRLabel
Some impressions of the 519 plummet 2021-05-21
The world's largest Apache open source foundation is how it works?
第四单元 路由层
Data Organization---Chapter 6 Diagram---Graph Traversal---Multiple Choice Questions
rpm包的卸载与安装[通俗易懂]
Flask-RESTful请求响应与SQLAlchemy基础
MySQL数据库语法格式