DRF之过滤,排序,分页

一、权限组件源码解读

1.继承了APIView

才有的---》执行流程---》dispatch中----》三大认证

APIView的dispatch  

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
    - 配置再视图类上

4.补充

视图类的方法,必须返回 4件套或drf的Response

return和raise完全不一样

视图类继承了

视图类:ViewSetMixin,ListModelMixin----》查询所有好多代码不用写----》可以自动生成路由
    router.register('book',BookView,'book')
    /book/--->get请求过来被映射了 list---》执行视图类中的list----》
    BookView中写了get方法,根本不会执行
    自动生成路由

二、认证源码分析

继承了APIView,才有的---》执行流程---》dispatch中----》三大认证

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  # 这是个方法,包装成了数据属性

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):
        # 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规范中
    -请求地址中带过滤条件

带过滤的接口只有:查询所有

1.内置过滤类

from rest_framework.viewsets import GenericViewSet
from rest_framework.mixins import ListModelMixin
from .models import Book
from rest_framework.filters import SearchFilter

# 内置过滤类
class BookView(GenericViewSet, ListModelMixin):
    queryset = Book.objects.all()
    serializer_class = BookSerializer
# 支持这种搜索
# http://127.0.0.1:8000/api/v1/books/?search=红
#     search_fields = ['name']
# http://127.0.0.1:8000/api/v1/books/?search=11  只要name或price中带11都能搜出来
    filter_backends = [SearchFilter]
    search_fields = ['name']

2.第三方过滤类

from django_filters.rest_framework import DjangoFilterBackend


第三方过滤类
class BookView(GenericViewSet, ListModelMixin):
    queryset = Book.objects.all()
    serializer_class = BookSerializer
    # 按名字和价格精准匹配
    # http://127.0.0.1:8000/api/v1/books/?name=红楼梦&price=45
    filter_backends = [DjangoFilterBackend]
    filterset_fields = ['name', 'price']

3.自定义过滤类

views:

from .filter import MyFilter


自定义过滤类
class BookView(GenericViewSet, ListModelMixin):
    queryset = Book.objects.all()
    serializer_class = BookSerializer
    # 返回的数据,就是过滤后的数据
    # http://127.0.0.1:8000/api/v1/books/?name=三国演义&price=25   按名字或价格
    filter_backends = [MyFilter]
    filterset_fields = ['name', 'price']

 filter:

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')

        # 返回的数据,就是过滤后的数据
        # http://127.0.0.1:8000/api/v1/books/?price=44&name=红楼梦
        # 按名字或价格

        queryset = queryset.filter(Q(name=name) | Q(price=price))
        return queryset

小练习:区间过滤

取出价格在100-200元之间的书

views:

# 自定义过滤价格在一百到两百之间的图书
from .filter import BookFilterSet
from rest_framework.filters import SearchFilter


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

    filter_backends = [BookFilterSet]
    search_fields = ['price']

filter:

# 自定义过滤价格在一百到两百之间的图书

from rest_framework import filters
from .models import Book


class BookFilterSet(filters.BaseFilterBackend):
    def filter_queryset(self, request, queryset, view):
        price = request.query_params.get('price')

        min_price = request.query_params.get('min_price')
        max_price = request.query_params.get('max_price')

        queryset = queryset.filter(price__gt=min_price, price__lt=max_price)
        return queryset

过滤和排序可以一起使用:

例:

url:

from django.contrib import admin
from django.urls import path, include
from rest_framework.routers import SimpleRouter
from app01 import views

router = SimpleRouter()
# 图书路由
# router.register('books', views.BookView, 'book')
# 出版社路由
# router.register('publishes', views.PublishView, 'publish')

urlpatterns = [

    path('admin/', admin.site.urls),
    path('api/v1/', include(router.urls)),
]

views:

from .models import Publish
from .serializer import PublishSerializer
from rest_framework.filters import OrderingFilter
from .page import PublishPageNumberPagination


class PublishView(GenericViewSet, ListModelMixin):
    queryset = Publish.objects.all()
    serializer_class = PublishSerializer

    filter_backends = [SearchFilter, OrderingFilter]
    search_fields = ['title', 'addr']
    ordering_fields = ['id']

    pagination_class = PublishPageNumberPagination

page:

class PublishPageNumberPagination(PageNumberPagination):
    page_size = 1
    page_size_query_param = 'page_size'
    page_query_param = 'page'
    max_page_size = 5

五排序

restful规范中
    -请求地址中带过滤条件

排序功能的接口:查询所有

排序
from rest_framework.filters import OrderingFilter


class BookView(GenericViewSet, ListModelMixin):
    queryset = Book.objects.all()
    serializer_class = BookSerializer
    # 排序类
    # http://127.0.0.1:8000/api/v1/books/?ordering=price
    filter_backends = [OrderingFilter]
    ordering_fields = ['price']

六 分页

查询所有接口,过滤和排序了,但是实际上,这个接口,都需要有分页功能

-分页的展现形式
        web:下一页点解
        app,小程序:下滑下一页
    -接口都一样,要支持分页

drf提供给咱们,三种分页方式:


1.基本分页(用的较多)

views:

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

    # 基本分页
    # http://127.0.0.1:8000/api/v1/books/?page=2&page_size=3
    pagination_class = MyPageNumberPagination  # 基本分页

 page:

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  # 每页最大显示多少条


2.偏移分页

view:

 # 偏移分页
    # http://127.0.0.1:8000/api/v1/books/?limit=2&offset=5
    pagination_class = MYLimitOffsetPagination

page:

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


3.游标分页

views:

    # 游标分页
    # http://127.0.0.1:8000/api/v1/books/?ordering=id
    pagination_class = MyCursorPagination


page:

# 游标分页
class MyCursorPagination(CursorPagination):
    # 重写三个类属性
    cursor_query_param = 'cursor'  # 查询参数其实用不到
    page_size = 2  # 每页显示多少条
    ordering = 'id'  # 必须是要分页的数据表中的字段,一般按id来分

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值