django之drf框架(排序、过滤、分页、异常处理)

发布时间:2023年12月28日

排序

排序的快速使用

1.必须是继承GenericAPIView及其子类才能是用排序

导入OrderingFilter类,from rest_framework.filters import OrderingFilter

2.在类中配置类属性

filter_backends=[OrderingFilter]

3.类中写属性

ordering_fields = ['price','id'] # 必须是表的字段
# 按照按照读书的价格和id排序

4.以后在前端,就可以访问

http://127.0.0.1:8000/api/v1/books/?ordering=price  # 按price升序排
http://127.0.0.1:8000/api/v1/books/?ordering=-price  # 按price降序排
http://127.0.0.1:8000/api/v1/books/?ordering=-price,id  # 先按price降序排,在按id升序排

views.py

class BookListView(ViewSet, ListAPIView):
    queryset = Book.objects.all()
    serializer_class = BookSerializer
    filter_backends = [OrderingFilter]
    ordering_fields = ['price','id']

在这里插入图片描述

继承VPIView写排序

过滤规则自己写

class BookListView(ViewSet, APIView):
    def list(self, request):
        # 从请求地址栏中取出用户过滤条件
        query_params = request.query_params
        # 分组查咨
        obj_list = Book.objects.all().order_by(query_params.get('ordering'))
        # 反序列化
        ser = BookSerializer(instance=obj_list, many=True)
        return Response(ser.data)

但是这个只能支持单个条件查询,如果要做多个的话需要一下步骤

class BookListView(ViewSet, APIView):
    def list(self, request):
        # 从请求地址栏中取出用户过滤条件
        query_params = request.query_params
        # 支持多个条件排序,判断如果','在ordering中就切分
        if ',' in query_params.get('ordering'):
            query = query_params.get('ordering').split(',')
        # 分组查咨
        obj_list = Book.objects.all().order_by(*query)
        # 反序列化
        ser = BookSerializer(instance=obj_list, many=True)
        return Response(ser.data)

过滤

restful规范中,要求请求地址中带过滤条件,五个接口中,只有查询所有接口需要过滤和排序。

 # 过滤,必须继承GenericAPIView及其子类,才能使用这种方法---》配置过滤类的方式
from rest_framework.filters import SearchFilter
class BookView(ViewSetMixin,ListAPIView):
	queryset = Book.objects.all()
	serializer_class = BookSerializer
    """ 前面配置了权限,认证,频率,这里需要取消掉"""
    permission_classes = []
    authentication_classes = []
    throttle_classes = []
	# SerchFilter内置的,固定用法,模糊匹配
	# 就有了过滤功能了,指定哪个字段过滤
    # search_fields = ['name']  # 可以按名字模糊匹配
	filter_fields =['name','price']  # 可以按名字模糊匹配或价格模糊匹配
	
    
    # 可以使用的搜索方法
    1.http://127.0.0.1:8000/api/v1/books/?name=# name只要有红就会搜出来
	2.http://127.0.0.1:8000/api/v1/books/?search=# name或price中只要有红就会搜出来

使用第三方django-filter实现过滤

安装django-filter

pip install django-filter

# 使用第三方djagno_filter过滤器
from django_filters.rest_framework import DjangoFilterBackend
class BookView(ViewSetMixin, ListAPIView):
    queryset = Book.objects.all()
    serializer_class = BookSerializer
    # 第三方过滤器
    filter_backends = [DjangoFilterBackend]
    # 就有了过滤功能了,指定哪个字段过滤
    # filterset_fields = ['price']
    filterset_fields =['name','price']  # 支持完整匹配 name=红楼梦$price=345
    
    # 支持的查询方式
http://127.0.0.1:8000/api/v1/books/?price=33
http://127.0.0.1:8000/api/v1/books/?price=33&name=西游记

自定义过滤类

实现名字模糊匹配,价格精准匹配,价格大于50

定义一个过滤器,继承BaseFileterBackend,重写filter_queryset方法

from rest_framework.filters import BaseFilterBackend
class CommonFilter(BaseFilterBackend):
    def filter_queryset(self, request, queryset, view):
        # 在里面实现过滤,返回qs对象,就是过滤后的数据
        name = request.query_params.get('name')
        price = request.query_params.get('price')
        price__gt = request.query_params.get('price__gt')
        if name:
            queryset = queryset.filter(name__contains=name)
        if price:
            queryset = queryset.filter(price=price)
        if price__gt:
            queryset = queryset.filter(price__gt=price__gt)
        return queryset

views.py

class BookListView(ViewSet, ListAPIView):
    queryset = Book.objects.all()
    serializer_class = BookSerializer
    filter_backends = [CommonFilter]
	
	# 不需要写字段,在CommonFilter类中已经写死了

继承APIView的写法

class BookListView(ViewSet, APIView):
    def list(self, request):
        name = request.query_params.get('name')
        price = request.query_params.get('price')
        price__gt = request.query_params.get('price__gt')
        queryset = Book.objects.all()
        if name:
            queryset = queryset.filter(name__contains=name)
        if price:
            queryset = queryset.filter(price=price)
        if price__gt:
            queryset = queryset.filter(price__gt=price__gt)
        ser = BookSerializer(instance=queryset,many=True)
        return Response(ser.data)

分页

分页只针对查询所有的接口,其他四个接口不需要分页。drf内置了三个分页器,对应三种分页方式,内置的分页类不能直接使用,需要继承,定制一些参数后才能使用。一个接口只能有一种分页方式,不能混合分页方式

基本分页

分页类

from rest_framework.pagination import PageNumberPagination
class CommonPageNumberPagination(PageNumberPagination):
    # page_size = api_settings.PAGE_SIZE  # 每页大小,一页显示多少条
    page_size = 2
    page_query_param = 'page'  # 分页查询,?page=1   ?page=2
    page_size_query_param = 'size'  # 每页最多显示多少条的查询条件
    max_page_size = 5  # 每页最多显示多少条
    # http://127.0.0.1:8888/api/v1/books/?page=2  # 查询第二页,显示2条
    # http://127.0.0.1:8888/api/v1/books/?page=2&size=99  # 查询第二页,显示99条,但是最多显示只有5条

views.py

from .pagination import CommonPageNumberPagination
class BookListView(ViewSet, ListAPIView):
    queryset = Book.objects.all()
    serializer_class = BookSerializer
    filter_backends = [CommonFilter]
    pagination_class = CommonPageNumberPagination  # 分页方式只能选一种,不要放在列表里

偏移分页

分页类

from rest_framework.pagination import LimitOffsetPagination
class CommonLimitOffsetPagination(LimitOffsetPagination):
    default_limit = 2  # 每页大小,一页显示多少条
    limit_query_param = 'limit'  # 每页显示的条数,查询条数,?limit=100,每页显示100条,如果不传,显示2条
    offset_query_param = 'offset'  # 偏移量 从第6条开始,拿30条 offset=6&limit=30
    max_limit = 5  # 每页最多显示多少条

views.py

from .pagination import CommonLimitOffsetPagination
class BookListView(ViewSet, ListAPIView):
    queryset = Book.objects.all()
    serializer_class = BookSerializer
    filter_backends = [CommonFilter]
    pagination_class = CommonLimitOffsetPagination  # 分页方式只能选一种,不要放在列表里
# http://127.0.0.1:8888/api/v1/books/?limit=4&offset=1 #从第一条开始拿4条数据

游标分页

分页类

from rest_framework.pagination import CursorPagination
class CommonCursorPagination(CursorPagination):
    cursor_query_param = 'cursor'  # 按游标查询的查询条件
    page_size = 2  # 每页大概显示多少条
    ordering = 'id'  # 排序规则,必须是表中字段

views.py

class BookListView(ViewSet, ListAPIView):
    queryset = Book.objects.all()
    serializer_class = BookSerializer
    authentication_classes = []
    # filter_backends = [CommonFilter]
    pagination_class = CommonCursorPagination  # 分页方式只能选一种,不要放在列表里
# 游标分页不能再和排序一起使用了,但是web用的不多,app会用到
# 只能选择上一页,下一页,不能指定跳到某一页,但是速度块,针对量特别大的分页,优势大

异常处理

使用步骤

from rest_framework.response import Response
from rest_framework.views import exception_handler


# 自己写个函数,处理drf的异常和自己的异常,以后只要出现异常,都会走到它
def common_exception_handler(exc, context):
    res = exception_handler(exc, context)
    if res:
        # 有就是drf的一场,没有就是自己的异常
        # data = {'detail': exc.detail}
        # return Response(data)
        detail = res.data.get('detail') or 'drf异常,请联系管理员'
        return Response({'code': 999, 'msg': detail})
    else:
        return Response({'code': 888, 'msg': '系统异常,请联系系统管理员:%s' % str(exc)})

views.py

class BookView(ViewSetMixin,APIView):
        def list(self,request):
        # 主动抛drf的异常
        # raise APIException('我是drf异常')

        
        # 主动抛非drf异常
        raise Exception('我是非DRF异常')

        books = Book.objects.all()
文章来源:https://blog.csdn.net/shiyaopeng11/article/details/135271116
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。