DRF ---- 過濾組件 分頁組件 過濾組件插件使用


DRF過濾組件

1 源碼分析:

入口: 群查 ListModelMixin 內的 list 但是方法都由 GenericAPIView 提供

    def list(self, request, *args, **kwargs):
        
        # 過濾queryset 對象 得到 queryset 對象 方法都在 GenericApiView 里面
        queryset = self.filter_queryset(self.get_queryset())
        # 分頁組件
        page = self.paginate_queryset(queryset)
        
        if page is not None:
            serializer = self.get_serializer(page, many=True)
            return self.get_paginated_response(serializer.data)

        serializer = self.get_serializer(queryset, many=True)
        return Response(serializer.data)

GenericAPIView 找到 filter_queryset

def filter_queryset(self, queryset):
	# 從配置文件中拿到 filter_backends 循環 然后調用 犯法 filter_queryset
	for backend in list(self.filter_backends):
        # filter_backends 就是過濾類們 且 產生的對象 都有 filter_queryset 方法
		queryset = backend().filter_queryset(self.request, queryset, self)
	return queryset

2 全局配置 過濾 類們

filter_backends = api_settings.DEFAULT_FILTER_BACKENDS
'DEFAULT_FILTER_BACKENDS': [], # 全局配置默認為 [] 

3 局部配置 過濾 類們

class Test(generics.GenericAPIView, mixins.ListModelMixin):
    ....
    filter_backends = []
    
    def get(self, request, *args, **kwargs):
        self.list(request,args, **kwargs)

4 系統提供 過濾 類們

restframework 中 找到 filter.py 里面 默認提供了 兩個 過濾類 都是繼承的BaseFilterBackend且 都有 filter_queryset 方法 他啥都不用繼承

class BaseFilterBackend:
    def filter_queryset(self, request, queryset, view):
        # 直接拋異常
        raise NotImplementedError(".filter_queryset() must be overridden.")

OrderingFilter(排序過濾)

view視圖

from rest_framework.generics import ListAPIView

# 第一步:drf的OrderingFilter - 排序過濾
from rest_framework.filters import OrderingFilter

class CarListAPIView(ListAPIView):
    queryset = models.Car.objects.all()
    serializer_class = serializers.CarModelSerializer

    # 第二步:局部配置 過濾類 們(全局配置用DEFAULT_FILTER_BACKENDS)
    filter_backends = [OrderingFilter]

    # 第三步:OrderingFilter過濾類依賴的過濾條件 => 接口:/cars/?ordering=...
    ordering_fields = ['pk', 'price']
    # eg:/cars/?ordering=-price,pk,先按price降序,如果出現price相同,再按pk升序
    
    # 規則:
    #?ordering=price 按價格升序
    #?ordering=-price 按價格降序
    #?ordering=id 按主鍵升序
    #?ordering=-price,id 按價格降序,價格相同時按主鍵升序

**ordering_fields **里面填寫字段 (真實存在的)

接口: 127.0.0.1:8000?ordering=price,name
查詢 按照 price 排序后 在按 name 排序的結果
支持升序和降序 加-號即可

SearchFilter(查詢過濾)

view視圖

from rest_framework.generics import ListAPIView

# 第一步:drf的SearchFilter - 搜索過濾
from rest_framework.filters import SearchFilter

class CarListAPIView(ListAPIView):
    queryset = models.Car.objects.all()
    serializer_class = serializers.CarModelSerializer

    # 第二步:局部配置 過濾類 們(全局配置用 DEFAULT_FILTER_BACKENDS )
    filter_backends = [SearchFilter]

    # 第三步:SearchFilter 過濾類依賴的過濾條件 重點!
    # 接口:/cars/?search=...
    search_fields = ['name', 'price']
    # eg:/cars/?search=1,name和price中包含1的數據都會被查詢出

search_fields 里面填寫字段 (真實存在的)

接口: 127.0.0.1:8000?search=1 
查詢 name 和 price 帶有 1 的數據

聯合使用

127.0.0.1:8000?search=1$ordering=price,name

DRF分頁組件

入口: restfarmework 中的 pagination.py 提供了 3 個 分頁 類 **CursorPagination(游標分頁 加密分頁) LimitOffsetPagination(偏移分頁) PageNumberPagination(基礎分頁) **

且 每一個類都有 方法 paginate_queryset 方法

ef list(self, request, *args, **kwargs):
        
        # 過濾queryset 對象 得到 queryset 對象 方法都在 GenericApiView 里面
        queryset = self.filter_queryset(self.get_queryset())
        # 分頁組件
        page = self.paginate_queryset(queryset)
        # 判斷是否有 分頁 沒有就正常執行 有的話就 執行 get_paginated_response
        if page is not None:
            serializer = self.get_serializer(page, many=True)
            return self.get_paginated_response(serializer.data)

        serializer = self.get_serializer(queryset, many=True)
        return Response(serializer.data)

方法也是有 GenericApiView 提供

pagination_class = api_settings.DEFAULT_PAGINATION_CLASS
 def paginate_queryset(self, queryset):
        if self.paginator is None:
            return None
        # 調用配置的
        return self.paginator.paginate_queryset(queryset, self.request, view=self)

1 全局配置

'DEFAULT_PAGINATION_CLASS': None, 默認為None

2 局部配置

from rest_framework.pagination import PageNumberPagination
class Test(generics.GenericAPIView, mixins.ListModelMixin):
    queryset = models.Banner.objects.all()
    serializer_class = serializers.BannerModelSerializer
    pagination_class = [PageNumberPagination]

3 PageNumberPagination基礎分頁

直接給視圖類配置即可 自定義pahenations 修改 參數值 或者直接使用點修改

pahenations.py

from rest_framework.pagination import PageNumberPagination

class MyPageNumberPagination(PageNumberPagination):
    # ?page=頁碼
    page_query_param = 'page'
    # ?page=頁面 下默認一頁顯示的條數
    page_size = 3
    # ?page=頁面&page_size=條數 用戶自定義一頁顯示的條數
    page_size_query_param = 'page_size'
    # 用戶自定義一頁顯示的條數最大限制:數值超過5也只顯示5條
    max_page_size = 5

views.py

from rest_framework.generics import ListAPIView

class CarListAPIView(ListAPIView):
    # 如果queryset沒有過濾條件,就必須 .all(),不然分頁會出問題
    queryset = models.Car.objects.all()
    serializer_class = serializers.CarModelSerializer
    
    # 分頁組件 - 給視圖類配置分頁類即可 - 分頁類需要自定義,繼承drf提供的分頁類即可
    pagination_class = pagenations.MyPageNumberPagination

4 LimitOffsetPagination偏移分頁

使用方式和基本分頁器一模一樣!

from rest_framework.pagination import LimitOffsetPagination

class MyPageNumberPagination(LimitOffsetPagination):
    # 不設置offset 和 limit 默認顯示3條 只設置offset 默認顯示后3條
    default_limit = 3
    # ?offset=從頭偏移的條數&limit=要顯示的條數
	limit_query_param = 'limit'
	offset_query_param = 'offset'
    # 用戶自定義一頁顯示的條數最大限制:數值超過5也只顯示5條
	max_limit = None
127.0.0.1:8000?offset=2&limit=3 # 偏移2條 取3條

5 CursorPagination游標分頁 加密分頁(了解)

from rest_framework.pagination import CursorPagination

class MyPageNumberPagination(CursorPagination):
    cursor_query_param = 'cursor'
    # 顯示條數
    page_size = 3 
    # 排序
    ordering = '-pk'
    # 用戶自定義
    page_size_query_param = None
    # 最大條數
    max_page_size = None

6.自定義過濾器

filters.py

# 自定義過濾器,接口:?limit=顯示的條數
class LimitFilter:
    def filter_queryset(self, request, queryset, view):
        # 前台固定用 ?limit=... 傳遞過濾參數
        limit = request.query_params.get('limit')
        if limit:
            limit = int(limit)
            return queryset[:limit]
        return queryset

views.py

from rest_framework.generics import ListAPIView

class CarListAPIView(ListAPIView):
    # 如果queryset沒有過濾條件,就必須 .all(),不然分頁會出問題
    queryset = models.Car.objects.all()
    serializer_class = serializers.CarModelSerializer
    
    # 局部配置 過濾類 們(全局配置用DEFAULT_FILTER_BACKENDS)
    filter_backends = [LimitFilter]

7 django-filter 過濾插件(重點)

分類查詢 大白話來講就是 蘇州地區的酒店 可以叫 上海酒店 也可以叫北京大飯店 如果使用 search查詢 上海 關於 起名有上海字的酒店的話 蘇州的也會被查出來

所以我們需要分類查詢 將上海地區分類 然后 在查

安裝

>: pip3 install django-filter

自定義過濾規則類:filters.py

# django-filter插件過濾器類
from django_filters.rest_framework.filterset import FilterSet
from . import models

# 自定義過濾字段
from django_filters import filters
class CarFilterSet(FilterSet):
    # 實現區間:field_name關聯model表屬性,lookup_expr設置過濾規則
    min_price = filters.NumberFilter(field_name='price', lookup_expr='gte')
    max_price = filters.NumberFilter(field_name='price', lookup_expr='lte')
    class Meta:
        model = models.Car
        fields = ['brand', 'min_price', 'max_price']
        # min_price、max_price是自定義字段,需要自己自定義過濾條件
		# 這樣就可以使用?brand=xxx來查詢了&min_pirce=12

的視圖類:views.py

from django_filters.rest_framework import DjangoFilterBackend
from .filters import CourseFilterSet
class FreeCourseListViewSet(ListModelMixin, GenericViewSet):
    queryset = models.Course.objects.filter(is_delete=False, is_show=True).all()
    serializer_class = serializers.CourseModelSerializer
    
    # 配置過濾組件
    filter_backends = [DjangoFilterBackend]
    # 配置過濾規則的類
    filter_class = CarFilterSet
    # 規則:
    # ?course_category=1 課程分組1所有的課程
    # ?min_price=10 課程價格大於等於10的所有課程
    # ?min_price=10&max_price=100 課程價格大於等於10小於等於100的所有課程


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM