过滤排序分页

过滤排序分页

权限,认证(了解)

权限源码

# 继承了APIView,才有的---》执行流程---》dispatch中----》三大认证
	#1  APIView的dispatch的大约497行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):
            # permission_classes = [AdminPermission]
            # self.get_permissions()我们配置再视图类上permission_classes列表中的认证类,一个个的对象
            # self.get_permissions()  是  [AdminPermission(),]
            for permission in self.get_permissions():
                # 写的权限类,要重写has_permission方法
                # 猜permission是我们写的权限类的对象
                # self 是视图类的对象(BookView,PublisViwe)
                if not permission.has_permission(request, self): # 权限没通过。调用的是我们自己重写的这个方法
                    self.permission_denied(
                        request,
                        # self.message 错误文字
                        message=getattr(permission, 'message', None),
                        code=getattr(permission, 'code', None)
                    )
                    
     # 3 读 APIView--->self.get_permissions
        def get_permissions(self):
        	return [permission() for permission in self.permission_classes]
        
        	# 翻译:
        	l=[]
        	for permission in self.permission_classes:
                l.append(permission())
            return l
        
        
# 记住:
	- 写的权限类,一定要写一个方法has_permission,返回True或False
    - 配置再视图类上

补充

# 1 视图类的方法,必须返回 4件套或drf的Response
# 2 return和raise完全不一样
# 3 视图类继承了
	视图类:ViewSetMixin,ListModelMixin----》查询所有好多代码不用写----》可以自动生成路由
    router.register('book',BookView,'book')
    /book/--->get请求过来被映射了 list---》执行视图类中的list----》
    BookView中写了get方法,根本不会执行
    自动生成路由
    
    
# 4 作业
0 认证类的token从请求头中取
1 登录接口,编写图书的5个接口
	-不登录就能查询所有图书
	-查询单条,新增,修改,删除,都需要登录后才访问
	-删除和修改要超级管理员才能操作
	-所有接口,一秒钟只能访问2次

认证源码

# 继承了APIView,才有的---》执行流程---》dispatch中----》三大认证
	#1  APIView的dispatch的大约497行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  # 这是个方法,包装成了数据属性
            
    # 3 Request类的user   219 行
        @property
        def user(self):
            if not hasattr(self, '_user'):
                with wrap_attributeerrors():
                    self._authenticate()
            return self._user
        
   # 4 Request类的self._authenticate()   373 行
    def _authenticate(self):
        # self.authenticators 就是你写的认证类列表---》列表推导式---》[LoginAuth(),]
        for authenticator in self.authenticators:
            try:
                user_auth_tuple = authenticator.authenticate(self)
            except exceptions.APIException:
                # 抛了异常被捕获了

            if user_auth_tuple is not None:
                # 如果返回了两个值,就会执行这句话
                # self是Request的对象
                self.user, self.auth = user_auth_tuple
                return
        self._not_authenticated()
	
    
  # 5 Request类初始化
	APIView---》dispathc的前面
 # 总结:
	1 认证类,必须写一个方法authenticate
    2 如果认证通过,可以返回None,也可也返回两个值,但是第一个值,尽量是当前登录用户,第二个值一般放token
    3 认证失败,抛异常AuthenticationFailed,继承了APIException,他能捕获

django中的翻译函数

# 只要做了国际化,会自动翻译成,当前国家的语言
from django.utils.translation import gettext_lazy as _

_('hello')

过滤

# restful规范中
	-请求地址中带过滤条件
    
# 带过滤的接口只有:查询所有

# 内置过滤类
from rest_framework.filters import SearchFilter
class PublishView(GenericViewSet, ListModelMixin):
    queryset = publish.objects.all()
    serializer_class = PublishSerialzier
    filter_backends = [SearchFilter]
    search_fields = ['name','addr']  # 只要列表中的字段包含你搜索的字就可以匹配出来
# 如http://127.0.0.1:8000/api/ip/publish/?search=11

# 第三方过滤类
### 2.1 第三方过滤类
# pip3 install django-filter
from django_filters.rest_framework import DjangoFilterBackend

class PublishView(GenericViewSet, ListModelMixin):
    queryset = publish.objects.all()
    serializer_class = PublishSerialzier
    filter_backends = [DjangoFilterBackend]
    filterset_fields = ['name', 'addr']
# 注意:第三方的要在配置文件注册,这个是精准匹配
# 如:http://127.0.0.1:8000/api/ip/publish/?name=111出版社&addr=北京(匹配名字是111出版社地址在北京的出版社)

# 自定义过滤类   价格再100----200之间的图书
from .filter import *

class BookView(GenericViewSet, ListModelMixin):
    queryset = book.objects.all()
    serializer_class = BookSerialzier
    filter_backends = [bookfilter]  # 必须配合一个过滤类

   
from django.db.models import Q
from rest_framework.filters import BaseFilterBackend  
    
class bookfilter(BaseFilterBackend):
    def filter_queryset(self, request, queryset, view):
        pricemin = request.query_params.get('pricemin')  # 获取价格下限
        pricemax = request.query_params.get('pricemax')  # 获取价格下限
        # book.objects.filter(price__lt=100)
        queryset = queryset.filter(Q(price__lt=pricemax) & Q(price__gt=pricemin))
        return queryset

# 如:http://127.0.0.1:8000/api/ip/book/?pricemin=100&pricemax=200
    
# 过滤和排序可以一起使用

排序

# restful规范中
	-请求地址中带过滤条件
# 带排序功能的接口:查询所有

from rest_framework.filters import OrderingFilter

class PublishView(GenericViewSet, ListModelMixin):
    queryset = publish.objects.all()
    serializer_class = PublishSerialzier
    filter_backends = [OrderingFilter  # 排序类
    ordering_fields = ['name', 'id']  # 可以根据列表的字段进行排序,先后顺序无所谓字段前加-是倒序
# 具体使用如下:                       
# http://127.0.0.1:8000/api/ip/publish/?ordering=name,-id

分页

# 查询所有接口,过滤和排序了,但是实际上,这个接口,都需要有分页功能
	-分页的展现形式
    	web:下一页点解
        app,小程序:下滑下一页
    -接口都一样,要支持分页

# drf提供给咱们,三种分页方式
# 基本分页
# 偏移分页
# 游标分页

from .page import MyPageNumberPagination,  # 基本分页
MyLimitOffsetPagination,  # 偏移分页
MyCursorPagination  #游标分页

class BookView(GenericViewSet, ListModelMixin):
    queryset = Book.objects.all()
    serializer_class = BookSerialzier
    # pagination_class = MyPageNumberPagination  # 只能按一种方式分页,不要放到列表中了
    # pagination_class = MyLimitOffsetPagination  # 只能按一种方式分页,不要放到列表中了
    pagination_class = MyCursorPagination  # 只能按一种方式分页,不要放到列表中了

    
    
# page.py
from rest_framework.pagination import PageNumberPagination, LimitOffsetPagination, CursorPagination

# 基本分页
class MyPageNumberPagination(PageNumberPagination):
    page_size = 2  # 每页多少条
    page_query_param = 'page'  # 在地址中page=第几页
    page_size_query_param = 'page_size'  # 在地址中page_size是每页显示多少条
    max_page_size = 5  # 每页最大多少条

# 偏移分页
class MyLimitOffsetPagination(LimitOffsetPagination):
    default_limit = 2  # 每页多少条
    limit_query_param = 'limit'  # limit=3  这一页取3条
    offset_query_param = 'offset'  # 偏移量是多少  offset=3&limit=2  从第3条开始,拿2条
    max_limit = 5  # 最多取5条

# 游标分页  速度快,但是不可以跳转
class MyCursorPagination(CursorPagination):
    cursor_query_param = 'cursor'  # 查询参数,其实用不到
    page_size = 2  # 每页显示多少条
    ordering = 'id'  # 必须是要分页的数据表中的字段,一般按id来

实例

视图

from rest_framework.filters import OrderingFilter
from rest_framework.mixins import ListModelMixin
from rest_framework.viewsets import GenericViewSet

from .filter import *
# Create your views here.
from .serializer import *


class PublishView(GenericViewSet, ListModelMixin):
    queryset = publish.objects.all()
    serializer_class = PublishSerialzier
    filter_backends = [publishfilter, OrderingFilter]
    filterset_fields = ['name', 'addr']
    ordering_fields = ['addr','id']

filter

from django.db.models import Q
from rest_framework.filters import BaseFilterBackend


class publishfilter(BaseFilterBackend):
    def filter_queryset(self, request, queryset, view):
        name = request.query_params.get('name')
        addr = request.query_params.get('addr')
        if name and addr:
            queryset = queryset.filter(Q(name__contains=name) | Q(addr__contains=addr))
            return queryset
        elif name and (not addr):
            queryset = queryset.filter(name__contains=name)
            return queryset
        elif addr and (not name):
            queryset = queryset.filter(addr__contains=addr)
            return queryset
        else:
            return queryset

test

http://127.0.0.1:8000/api/ip/publish/?name=4&addr=%南&ordering=addr,-id

继承APIView完成以上操作

视图

class PublishView(APIView):
    ordering_fields = ['addr', 'id']

    def get(self, request):
        queryset = publish.objects.all()
        filtration = publishfilter()  # 实例化过滤类
        queryset = filtration.filter_queryset(request, queryset, self)  # 调用内部的过滤方法
        ordering = OrderingFilter()  # 实例化排序类,注意要给一个列表
        queryset = ordering.filter_queryset(request, queryset, self)  # 调用排序类里的排序方法
        paginator = MyPageNumberPagination()  # 实例化分页类
        qs = paginator.paginate_queryset(queryset, request, self)  # 调用分页方法
        ser = PublishSerialzier(instance=qs, many=True)
        return Response(ser.data)

作业

# 1 写查询所有出版社接口
	-可以按名字或城市  模糊 匹配
    -如果城市一样,可以按id倒序排列
# 2 上述接口,带分页功能

# 3 研究权限和认证源码


#### 高级### 
继承APIView,实现上面1,2


posted @ 2023-05-25 20:30  橘子熊何妨  阅读(23)  评论(0)    收藏  举报