真实的国产乱ⅩXXX66竹夫人,五月香六月婷婷激情综合,亚洲日本VA一区二区三区,亚洲精品一区二区三区麻豆

成都創(chuàng)新互聯(lián)網(wǎng)站制作重慶分公司

drf 過(guò)濾、排序、分頁(yè)、異常處理

內(nèi)容概要

  • 過(guò)濾
  • 排序
  • 分頁(yè)
  • 異常處理

內(nèi)容詳細(xì)

過(guò)濾

過(guò)濾是涉及到查詢數(shù)據(jù)的接口才需要過(guò)濾功能

公司主營(yíng)業(yè)務(wù):網(wǎng)站制作、網(wǎng)站建設(shè)、移動(dòng)網(wǎng)站開(kāi)發(fā)等業(yè)務(wù)。幫助企業(yè)客戶真正實(shí)現(xiàn)互聯(lián)網(wǎng)宣傳,提高企業(yè)的競(jìng)爭(zhēng)能力。創(chuàng)新互聯(lián)是一支青春激揚(yáng)、勤奮敬業(yè)、活力青春激揚(yáng)、勤奮敬業(yè)、活力澎湃、和諧高效的團(tuán)隊(duì)。公司秉承以“開(kāi)放、自由、嚴(yán)謹(jǐn)、自律”為核心的企業(yè)文化,感謝他們對(duì)我們的高要求,感謝他們從不同領(lǐng)域給我們帶來(lái)的挑戰(zhàn),讓我們激情的團(tuán)隊(duì)有機(jī)會(huì)用頭腦與智慧不斷的給客戶帶來(lái)驚喜。創(chuàng)新互聯(lián)推出正定免費(fèi)做網(wǎng)站回饋大家。

DRF 中使用的過(guò)濾方式:

  • 1、 內(nèi)置過(guò)濾類(lèi) 在請(qǐng)求數(shù)據(jù)中用“search=字符”條件過(guò)濾(模糊查詢)
  • 2、 第三方過(guò)濾類(lèi) 在請(qǐng)求數(shù)據(jù)中用“字段名=字符”條件過(guò)濾 (嚴(yán)格查詢)
  • 3、 自定義過(guò)濾類(lèi)

內(nèi)置過(guò)濾類(lèi)

使用模塊: from rest_framework.filters import SearchFilter

在視圖層中使用內(nèi)置過(guò)濾類(lèi)

前提:需要使用 GenericAPIView 類(lèi)中的filter_backends屬性,所以視圖類(lèi)得繼承 GenericAPIView

class GenericAPIView(views.APIView):
    queryset = None
    serializer_class = None
    lookup_field = 'pk'
    lookup_url_kwarg = None
    filter_backends = api_settings.DEFAULT_FILTER_BACKENDS
    pagination_class = api_settings.DEFAULT_PAGINATION_CLASS

步驟

  1. 視圖類(lèi)內(nèi)filter_backends中使用SearchFilter
  2. 類(lèi)屬性search_fields指定過(guò)濾的字段
from rest_framework.filters import SearchFilter


class BookViewSet(ViewSetMixin, ListAPIView):
    queryset = models.Book.objects
    serializer_class = BookModelSerializer
    authentication_classes = [LoginAuth, ]
    # throttle_classes = [IPThrottling, ]
    filter_backends = [SearchFilter]
    search_fields = ['name', 'price', ]

如果是過(guò)濾外鍵字段:

使用雙下滑的正向查詢方式

class BookViewSet(ViewSetMixin, ListAPIView):
    queryset = models.Book.objects
    serializer_class = BookModelSerializer
    authentication_classes = [LoginAuth, ]
    # throttle_classes = [IPThrottling, ]
    filter_backends = [SearchFilter, ]
    search_fields = ['publish__name', ]

總結(jié)

  • 內(nèi)置過(guò)濾類(lèi)的使用,模糊查詢會(huì)將包含過(guò)濾字段的數(shù)據(jù)都過(guò)濾出來(lái),前提是在search_fields列表內(nèi)指定的字段;
  • 內(nèi)置過(guò)濾的特點(diǎn)是模糊查詢
  • 過(guò)濾字段參數(shù)為search
  • 過(guò)濾外鍵字段,使用雙下滑的正向查詢方式

第三方過(guò)濾類(lèi)

1、安裝: pip install django-filter

2、使用模塊: from django_filters.rest_framework import DjangoFilterBackend

3、在項(xiàng)目配置文件 settings.py 中注冊(cè)下載的 app

4、第三方過(guò)濾類(lèi)在filter_backends字段中寫(xiě),filter_fields字段指定過(guò)濾的字段

INSTALLED_APPS = [
    ...
    'django_filters',  # 需要注冊(cè)應(yīng)用,
]

4、視圖層中使用

class BookViewSet(ViewSetMixin, ListAPIView):
    queryset = models.Book.objects
    serializer_class = BookModelSerializer
    authentication_classes = [LoginAuth, ]
    filter_backends = [DjangoFilterBackend, ]
    filter_fields = ['name', 'price']

總結(jié)

  • 第三方過(guò)濾類(lèi)在filter_backends字段中寫(xiě),filter_fields字段指定過(guò)濾的字段
  • 第三方過(guò)濾類(lèi)不支持模糊查詢,是精準(zhǔn)匹配
  • 第三方過(guò)濾類(lèi)的使用,視圖類(lèi)也必須繼承GenericAPIView才能使用
  • 在鏈接內(nèi)通過(guò)&來(lái)表示和的關(guān)系

外鍵字段怎么查?

自定義過(guò)濾類(lèi)

1、新建一個(gè)過(guò)濾文件,寫(xiě)一個(gè)類(lèi)繼承BaseFilterBackend,重寫(xiě)filter_queryset(self, request, queryset, view)方法,返回queryset對(duì)象,qs對(duì)象是過(guò)濾后的

2、視圖層使用,只需要指定filter_backend屬性為自定義類(lèi)列表

3、查詢過(guò)濾,支持模糊查詢(自己定制過(guò)濾方式),在filter_queryset方法自定義過(guò)濾規(guī)則

自定義過(guò)濾類(lèi)的書(shū)寫(xiě):

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


class Myfilter(BaseFilterBackend):
    def filter_queryset(self, request, queryset, view):
        # 獲取過(guò)濾參數(shù)
        qs_name = request.query_params.get('name')
        qs_price = request.query_params.get('price')
        # title__contains:精確大小寫(xiě)查詢,SQL中-->like BINARY
        # 利用Q查詢構(gòu)造或關(guān)系
        if qs_name:
            queryset = queryset.filter(name__contains=qs_name)
        elif qs_price:
            queryset = queryset.filter(price__contains=qs_price)
        elif qs_name or qs_price:
            queryset = queryset.filter(Q(name__contains=qs_name) | Q(price__contains=qs_price))
        return queryset

視圖類(lèi):

from app01.filter import Myfilter


class BookViewSet(ViewSetMixin, ListAPIView):
    queryset = models.Book.objects
    serializer_class = BookModelSerializer
    authentication_classes = [LoginAuth, ]
    filter_backends = [Myfilter, ]

源碼分析

我們知道過(guò)濾的前提條件是視圖繼承了GenericAPIView才能使用,那么在GenericAPIView中的執(zhí)行流程是什么?

1、調(diào)用了GenericAPIView中的filter_queryset方法
2、filter_queryset方法源碼:
    def filter_queryset(self, queryset):
        for backend in list(self.filter_backends):
            queryset = backend().filter_queryset(self.request, queryset, self)
        return queryset
'''
1.backend是通過(guò)遍歷該類(lèi)的filter_backends列表的得到的,也就是我們指定的過(guò)濾類(lèi)列表,那么backend就是我們的過(guò)濾類(lèi)
2.通過(guò)實(shí)例化得到對(duì)象來(lái)調(diào)用了類(lèi)內(nèi)的filter_queryset返回了過(guò)濾后的對(duì)象
'''

排序

使用模塊:from rest_framework.filters import OrderingFilter

步驟

  1. 視圖類(lèi)中配置,且視圖類(lèi)必須繼承GenericAPIView
  2. 與過(guò)濾類(lèi)一樣要把排序類(lèi)存入 filter_backends 屬性的列表中
  3. 通過(guò)ordering_fields指定要排序的字段
  4. 排序過(guò)濾,-號(hào)代表倒序,且必須使用ordering指定排序字段

視圖類(lèi)書(shū)寫(xiě):

from app01.filter import Myfilter
from rest_framework.filters import OrderingFilter


class BookViewSet(ViewSetMixin, ListAPIView):
    queryset = models.Book.objects
    serializer_class = BookModelSerializer
    authentication_classes = [LoginAuth, ]
    # throttle_classes = [IPThrottling, ]
    filter_backends = [Myfilter, OrderingFilter, ]  # 先過(guò)濾后排序
    ordering_fields = ['id', 'price']

注意:過(guò)濾可以和排序同時(shí)使用,但是先執(zhí)行過(guò)濾再執(zhí)行排序,提升了代碼的效率(先過(guò)濾后排序),因?yàn)槿绻扰判颍敲磾?shù)據(jù)庫(kù)的數(shù)量龐大的話,直接操作了整個(gè)數(shù)據(jù)庫(kù),消耗資源,過(guò)濾完成后排序只是針對(duì)一小部分?jǐn)?shù)據(jù)

分頁(yè)

分頁(yè)只在查詢所有接口中使用

導(dǎo)入分頁(yè)類(lèi): from rest_framework.pagination import PageNumberPagination,LimitOffsetPagination,CursorPagination

DRF 中分頁(yè)的三種方式:

  • 1、PageNumberPagination,基本分頁(yè)
  • 2、LimitOffsetPagination,偏移分頁(yè)
  • 3、CursorPagination,游標(biāo)分頁(yè)

PageNumberPagination

步驟

自定義類(lèi),繼承PageNumberPagination,重寫(xiě)四個(gè)類(lèi)屬性

  • page_size:設(shè)置每頁(yè)默認(rèn)顯示的條數(shù)
  • page_query_param:url中的查詢條件,books/?page=2表示第二頁(yè)
  • page_size_query_param:每頁(yè)顯示多少條的查詢條件,books/?page=2&size=5,表示查詢第二頁(yè),顯示5條
  • max_page_size:設(shè)置每頁(yè)最多顯示條數(shù),不管查多少條,最大顯示該值限制的條數(shù)

注意: 配置在視圖類(lèi)中,通過(guò)pagination_class指定,必須繼承GenericAPIView才有

分頁(yè)類(lèi)書(shū)寫(xiě):

from rest_framework.pagination import PageNumberPagination


class BookPagination(PageNumberPagination):
    page_size = 3  # 默認(rèn)每頁(yè)顯示2條
    page_query_param = 'page'  # 查詢條件,eg:page=3
    page_size_query_param = 'size'  # 查詢條件參數(shù)size=5顯示五條
    max_page_size = 10  # 每頁(yè)最大顯示條數(shù)

視圖層類(lèi):

pagination_class 屬性賦值分頁(yè)類(lèi)

from app01.page import BookPagination


class BookViewSet(ViewSetMixin, ListAPIView):
    queryset = models.Book.objects.all()
    serializer_class = BookModelSerializer
    authentication_classes = []
    filter_backends = [Myfilter, OrderingFilter, ]  # 先過(guò)濾后排序
    ordering_fields = ['id', 'price']
    pagination_class = BookPagination

LimitOffsetPagination

步驟

  1. 自定義類(lèi),繼承LimitOffsetPagination,重寫(xiě)四個(gè)類(lèi)屬性
    • default_limit:默認(rèn)每頁(yè)獲取的條數(shù)
    • limit_query_param:每頁(yè)顯示多少條的查詢條件,比如?limit=3,表示獲取三條,如果不寫(xiě)默認(rèn)使用default_limit設(shè)置的條數(shù)
    • offset_query_param:表示偏移量參數(shù),比如?offset=3表示從第三條開(kāi)始往后獲取默認(rèn)的條數(shù)
    • max_limit:設(shè)置最大顯示條數(shù)
  2. 視圖類(lèi)內(nèi)配置,pagination_class參數(shù)指定,必須繼承GenericAPIView才有

分頁(yè)類(lèi)書(shū)寫(xiě):

from rest_framework.pagination import PageNumberPagination, LimitOffsetPagination

class MyLimitOffset(LimitOffsetPagination):
    default_limit = 2  # 默認(rèn)每頁(yè)顯示2條
    limit_query_param = 'limit'  # ?limit=3,查詢出3條
    offset_query_param = 'offset'  # 偏移量,?offset=2,從第2條后開(kāi)始
    max_limit = 5  # 最大顯示5條

視圖層類(lèi):

pagination_class 屬性賦值分頁(yè)類(lèi)

from app01.page import BookPagination, MyLimitOffset


class BookViewSet(ViewSetMixin, ListAPIView):
    queryset = models.Book.objects.all()
    serializer_class = BookModelSerializer
    authentication_classes = []
    filter_backends = [Myfilter, OrderingFilter, ]  # 先過(guò)濾后排序
    ordering_fields = ['id', 'price']
    pagination_class = MyLimitOffset

CursorPagination

步驟

  1. 自定義類(lèi),繼承CursorPagination,重寫(xiě)三個(gè)類(lèi)屬性
    • page_size:每頁(yè)顯示的條數(shù)
    • cursor_query_param:查詢條件
    • ordering:排序規(guī)則,指定排序字段
  2. 視圖類(lèi)內(nèi)配置,pagination_class參數(shù)指定,必須繼承GenericAPIView才有

分頁(yè)類(lèi)書(shū)寫(xiě):

from rest_framework.pagination import CursorPagination

class MyCursor(CursorPagination):
    page_size = 3
    cursor_query_param = 'cursor'
    ordering = 'id'

視圖層類(lèi):

pagination_class 屬性賦值分頁(yè)類(lèi)

from app01.page import BookPagination, MyLimitOffset, MyCursor

class BookViewSet(ViewSetMixin, ListAPIView):
    queryset = models.Book.objects.all()
    serializer_class = BookModelSerializer
    authentication_classes = []
    filter_backends = [Myfilter, ]  # 使用了 cursor 游標(biāo)分頁(yè),不要指定排序規(guī)則,會(huì)報(bào)錯(cuò)
    ordering_fields = ['id', 'price']
    pagination_class = MyCursor

查詢方式

http://127.0.0.1:8000/books/?cursor=cD02

注意:分頁(yè)類(lèi)內(nèi)指定了排序,視圖內(nèi)不要寫(xiě)排序規(guī)則,不然報(bào)錯(cuò)

  • 跟上面兩種的區(qū)別:上面兩種,可以從中間位置獲取某一頁(yè),Cursor方式只能上一頁(yè)和下一頁(yè)
  • 下面這種方式,先排序,內(nèi)部維護(hù)了一個(gè)游標(biāo),游標(biāo)只能選擇往前走或往后走,在取某一頁(yè)的時(shí)候,不需要過(guò)濾之前的數(shù)據(jù)
  • 這種分頁(yè)方式特殊,只能選擇上一頁(yè)和下一頁(yè),不能指定某一頁(yè),但是速度快,適合大數(shù)據(jù)量的分頁(yè)
  • 大數(shù)據(jù)量和app分頁(yè)---》下拉加載下一頁(yè),不需要指定跳轉(zhuǎn)到第幾頁(yè)

異常處理

之前讀APIView源碼的時(shí)候,捕獲了全局異常,在執(zhí)行三大認(rèn)證,視圖類(lèi)的方法時(shí)候,如果出了異常,會(huì)被全局異常捕獲

以下是APIView捕獲異常 的流程

1、 APIView源碼
# dispatch方法源碼
    except Exception as exc:
         response = self.handle_exception(exc)
# handle_exception方法源碼
    exception_handler = self.get_exception_handler()
    response = exception_handler(exc, context)

2、 默認(rèn)配置文件
get_exception_handler() 調(diào)用的是 views 中的 exception_handler

'EXCEPTION_HANDLER': 'rest_framework.views.exception_handler',


3、views種的exception_handler方法
def exception_handler(exc, context):
    if isinstance(exc, Http404):
        exc = exceptions.NotFound()
    elif isinstance(exc, PermissionDenied):
        exc = exceptions.PermissionDenied()
    if isinstance(exc, exceptions.APIException):
        headers = {}
        if getattr(exc, 'auth_header', None):
        else:
            data = {'detail': exc.detail}
        return Response(data, status=exc.status_code, headers=headers)

    return None

由上源碼可知,exception_handler(exc, context) 方法,如果報(bào)的是已知的錯(cuò)會(huì)返回 Response 對(duì)象,未知錯(cuò)誤返回 None

自定義異常

可以自定義出現(xiàn)異常之后的處理方法和返回?cái)?shù)據(jù)的格式

  • exc:錯(cuò)誤原因
  • context:字典,包含了當(dāng)前請(qǐng)求對(duì)象和視圖類(lèi)對(duì)象

重寫(xiě)異常處理方法:

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


def myexception_handler(exc, context):
    # 先執(zhí)行原來(lái)的exception_handler幫助我們處理
    res = exception_handler(exc, context)
    if res:
        # res有值代表處理過(guò)了APIException對(duì)象的異常了,返回的數(shù)據(jù)再定制
        res = Response(data={'code': 998, 'msg': res.data.get('detail', '服務(wù)器異常,請(qǐng)聯(lián)系系統(tǒng)管理員')})
        # res = Response(data={'code': 998, 'msg': '服務(wù)器異常,請(qǐng)聯(lián)系系統(tǒng)管理員'})
        # res.data.get從響應(yīng)中獲取原來(lái)的處理詳細(xì)信息
    else:
        res = Response(data={'code': 999, 'msg': str(exc)})
        print(exc)  # list index out of range

    '''模擬日志處理'''
    request = context.get('request')  # 當(dāng)次請(qǐng)求的request對(duì)象
    view = context.get('view')  # 當(dāng)次執(zhí)行的視圖類(lèi)對(duì)象
    print('錯(cuò)誤原因:%s,錯(cuò)誤視圖類(lèi):%s,請(qǐng)求地址:%s,請(qǐng)求方式:%s' % (str(exc), str(view), request.path, request.method))
    '''結(jié)果:
    錯(cuò)誤原因:list index out of range,錯(cuò)誤視圖類(lèi):,請(qǐng)求地址:/test/,請(qǐng)求方式:GET
    '''
    return res

修改異常的配置路徑:

REST_FRAMEWORK = {
    'EXCEPTION_HANDLER': 'app01.myexception.exception_handler' # 再出異常,會(huì)執(zhí)行自己定義的函數(shù)
}

視圖類(lèi)中報(bào)錯(cuò)就會(huì)自動(dòng)觸發(fā)異常處理:

from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.exceptions import APIException
# 測(cè)試異常視圖
class Test(APIView):
    def get(self,request):

        # 1、 其他報(bào)錯(cuò)
        # l = [1,2,3]
        # print(l[100])

        # 2、APIException異常
        # raise APIException('APIException errors!')

        return Response('success!')

REST framework定義的異常

  • APIException 所有異常的父類(lèi)
  • ParseError 解析錯(cuò)誤
  • AuthenticationFailed 認(rèn)證失敗
  • NotAuthenticated 尚未認(rèn)證
  • PermissionDenied 權(quán)限決絕
  • NotFound 未找到
  • MethodNotAllowed 請(qǐng)求方式不支持
  • NotAcceptable 要獲取的數(shù)據(jù)格式不支持
  • Throttled 超過(guò)限流次數(shù)
  • ValidationError 校驗(yàn)失敗

文章標(biāo)題:drf 過(guò)濾、排序、分頁(yè)、異常處理
文章起源:http://weahome.cn/article/dsoghco.html

其他資訊

在線咨詢

微信咨詢

電話咨詢

028-86922220(工作日)

18980820575(7×24)

提交需求

返回頂部