7

drf——权限、认证源码分析、过滤、排序、分页 - 抱紧小洪

 11 months ago
source link: https://www.cnblogs.com/XxMa/p/17433187.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

权限、认证源码(了解)

# 继承了APIView才有的---》执行流程---》dispatch中的三大认证
		self.initial(request, *args, **kwargs)
	# 1. APIView的dispatch中self.initial(request, *args, **kwargs)
    	def initial(self, request, *args, **kwargs):
            self.perform_authentication(request)  # 认证
        	self.check_permissions(request)  # 权限
        	self.check_throttles(request)  # 频率
            
    # 2. 读权限:APIView的方法self.check_permissions(request)
    	def check_permissions(self, request):
            for permission in self.get_permissions():
            # self.get_permissions()是我们配置在视图类中permission_classer列表中的认证类实例化出来的一个一个对象
           """
           permission_classes = [AdminPermission,]
           self.get_permissions()是AdminPermission()实例化出的对象
           """
                if not permission.has_permission(request, self): # 权限没通过会执行
                # 写的权限类需要重写has_permission方法
                # permission是自己写的权限类的对象 
                # 对象点方法时 先从自己类中找has_permission
                # 后面括号中的self参数是视图类的对象
                    self.permission_denied(
                        request,
                        message=getattr(permission, 'message', None),
                        # self.message 错误文字
                        code=getattr(permission, 'code', None)
                    )
    
    # 3. APIView中的self.get_permissions()
    	def get_permissions(self):
        	return [permission() for permission in self.permission_classes]
        """
        permission_classes是我们配置在视图类中的权限类
        self是自己写的视图类的对象
        self.permission_classes获取所有配置的权限类
        列表生成式 也可以写成
        l = []
        for permission in self.permission_classes
        	l.append(permission())
       	return l
        """
        # 返回一个列表 列表中是一个个自己写的权限类的对象
        
# 总结
	写的权限类 一定要写一个方法has_permission,返回True或False 不写则报错
    配置在视图类上
# 继承了APIView才有的---》执行流程---》dispatch中的三大认证
		self.initial(request, *args, **kwargs)
	# 1. APIView的dispatch中self.initial(request, *args, **kwargs)
    	def initial(self, request, *args, **kwargs):
            self.perform_authentication(request)  # 认证
        	self.check_permissions(request)  # 权限
        	self.check_throttles(request)  # 频率
            
    # 2. self.perform_authentication(request)
    	def perform_authentication(self, request):
        	request.user  # user这是个方法 包装成了数据属性
        """
        此时的request是走三大认证之前 dispatch中重新定义了新的request
        	request = self.initialize_request(request, *args, **kwargs)
        """
        
   # 3. Request类中的user
		@property
        def user(self):
            if not hasattr(self, '_user'):
                with wrap_attributeerrors():
                    self._authenticate()
            return self._user
        
   # 4. Request类的self._authenticate()
		def _authenticate(self):
            for authenticator in self.authenticators:
            """
            self.authenticators就是你写的认证类列表
            authenticators是在定义新的request时self.initialize_request调用这个方法的时候 return出的authenticators=self.get_authenticators(),
            get_authenticators是APIView中的方法
            def get_authenticators(self):
        		return [auth() for auth in self.authentication_classes]
        	循环视图类中的类属性authentication_classes获取列表中的每个认证类
        	然后给认证类加括号 实例化得到对象 再返回
        	即 authenticators是认证类实例化得到的对象放在列表中
        	
        	authenticator是一个个认证类实例化的对象
            """
                try:
                    user_auth_tuple = authenticator.authenticate(self)
                # authenticate是在认证类中重写的方法 如果认证成功返回的是元祖(user,token)
                except exceptions.APIException:
                    # 抛了异常被捕获了
                if user_auth_tuple is not None:  # 如果返回有值即认证通过执行
                    # self是Request的对象 
                    self.user, self.auth = user_auth_tuple  # (user,token)
                    return
            self._not_authenticated()
            
  # 总结
	1.认证类 必须写一个方法authenticate
    2.如果认证通过 可以返回None,也可以返回两个值 但是第一个值尽量是当前登录用户 第二个值一般放token
    3.认证失败 抛异常AuthenticationFailed('你没有登录,不能访问'),它继承了APIException,他能捕获

补充 Django中的国际化

# 只要做了国际化 会自动翻译成,当前国家的语言
from django.utils.translation import gettext_lazy as _
_('hello')
# restful规范中
	-请求地址中带过滤条件
# 排序功能的接口:查询所有

from rest_framework.filters import OrderingFilter

class BookView(GenericViewSet,ListModelMixin):
    queryset = Book.objects.all()
    serializer_class = BookSerializer
    filter_backends = [OrderingFilter]  # 排序类
    ordering_fields = ['price','id']  # 指定哪些字段可以排序
    # ordering = ['id']  # 默认排序
    # http://127.0.0.1:8000/api/v1/books/?ordering=-price,-id
    # -是倒序 先按价格倒序排 再按id倒序排
# restful规范中
	-请求地址中带过滤条件
    
# 带过滤的接口只有:查询所有

'''1.内置过滤类'''
from  rest_framework.filters import SearchFilter

class BookView(GenericViewSet,ListModelMixin):
    queryset = Book.objects.all()
    serializer_class = BookSerializer
    filter_backends = [SearchFilter]
    # search_fields = ['name']
    # http://127.0.0.1:8000/api/v1/books/?search=红
    # 只要name中有红的都能搜索出
    search_fields = ['name','price']
    # http://127.0.0.1:8000/api/v1/books/?search=11
    # 只要name或者price中带有11的都能搜出来
    
'''2.第三方过滤类'''
# pip38 install django-filter
# 下载之后如果要使用的话 必须去配置文件INSTALLED_APPS下注册才可
from django_filters.rest_framework import DjangoFilterBackend
class BookView(GenericViewSet,ListModelMixin):
    queryset = Book.objects.all()
    serializer_class = BookSerializer
    filter_backends = [DjangoFilterBackend]
    filterset_fields = ['name','price']
    # http://127.0.0.1:8000/api/v1/books/?name=红楼梦&price=45
    # 按名字和价格精准匹配
    
'''3.自定义过滤类 很复杂的搜索 自己来写'''
'''视图类'''
from .filter import MyFilter
from rest_framework.filters import OrderingFilter

class BookView(GenericViewSet,ListModelMixin):
    queryset = Book.objects.all()
    serializer_class = BookSerializer
    # filter_backends = [MyFilter]
    # http://127.0.0.1:8000/api/v1/books/?name=红楼梦&price=11
    # 过滤出name为红楼梦或者price为11的
    # 过滤类可以配多个 执行顺序是从左往右
    filter_backends = [MyFilter,OrderingFilter]
    ordering_fields = ['price']
    # http://127.0.0.1:8000/api/v1/books/?price=44&name=红楼梦&ordering=-price
    # 过滤出name为红楼梦或者price为44的并且按价格降序排序
    
'''自定义过滤类'''
from rest_framework import filters
from django.db.models import Q

class MyFilter(filters.BaseFilterBackend):
    # 重写父类中的方法 返回的数据就是过滤后的数据
    def filter_queryset(self, request, queryset, view):
        price = request.query_params.get('price')
        name = request.query_params.get('name')
        queryset = queryset.filter(Q(price=price) | Q(name=name))
        return queryset
# 查询所有接口,过滤和排序了,但是实际上,这个接口,都需要有分页功能
	-分页的展现形式
    	web:下一页点击
        app,小程序:下滑下一页
    -接口都一样,要支持分页
    
# 带过滤的接口只有:查询所有

# drf提供给咱们,三种分页方式
# 基本分页
# 偏移分页
# 游标分页
    
'''视图类'''
'''分页 --->>> 必须是获取所有的接口 必须继承GenericAPIView及其子类'''
from .page import MyPageNumberPagination,MyLimitOffsetPagination,MyCursorPagination

class BookView(GenericViewSet,ListModelMixin):
    queryset = Book.objects.all()
    serializer_class = BookSerializer

    # pagination_class = MyPageNumberPagination  # 只能按一种方式分页,不要放到列表中了
    # # http://127.0.0.1:8000/api/v1/books/?page=1&page_size=3
    # # 查询第1页 每页显示3条

    # pagination_class = MyLimitOffsetPagination
    # # http://127.0.0.1:8000/api/v1/books/?limit=4&offset=3
    # # 从第三条数据开始,取4条

    pagination_class = MyCursorPagination
    # 只有上一页和下一页
    
'''分页类 page.py'''
from rest_framework.pagination import PageNumberPagination,LimitOffsetPagination,CursorPagination

# 基本分页
class MyPageNumberPagination(PageNumberPagination):
    # 重写的几个类属性 4个
    page_size = 2  # 每页显示的条数
    page_query_param = 'page'  # page=4 表示第4页
    page_size_query_param = 'page_size'  # page=4&page_size=5 表示查询第4页每页显示5条
    max_page_size = 5  # 每页最大显示多少条

# 偏移分页
class MyLimitOffsetPagination(LimitOffsetPagination):
    # 重写几个类属性 :4个
    default_limit = 2  # 每页显示多少条
    limit_query_param = 'limit'  # limit=3 这一页取3条
    offset_query_param = 'offset'  # 偏移量是多少 offset=3&limit=2 从第三条开始拿两条
    max_limit = 5  # 最多取5条

# 游标分页,只能上一页和下一页,不能直接跳到某一页,但是这个的速度快---》app上用它多
class MyCursorPagination(CursorPagination):
    # 重写几个类属性 :3个
    cursor_query_param = 'cursor'  # 查询参数,其实用不到
    page_size = 2  # 每页显示多少条
    ordering = 'id'  # 必须是要分页的数据表中的字段 一般按id来

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK