drf過濾器、篩選器、分類器、搜索器、分頁器(各種組件等)


過濾器(組件)使用

群查接口各種篩選、過濾數據准備

models.py

# 數據庫表數據
class Course(BaseModel):
    """課程"""
    course_type = (
        (0, '付費'),
        (1, 'VIP專享'),
        (2, '學位課程')
    )
    level_choices = (
        (0, '初級'),
        (1, '中級'),
        (2, '高級'),
    )
    status_choices = (
        (0, '上線'),
        (1, '下線'),
        (2, '預上線'),
    )
    name = models.CharField(max_length=128, verbose_name="課程名稱")
    course_img = models.ImageField(upload_to="courses", max_length=255, verbose_name="封面圖片", blank=True, null=True)
    course_type = models.SmallIntegerField(choices=course_type, default=0, verbose_name="付費類型")
    # 使用這個字段的原因
    brief = models.TextField(max_length=2048, verbose_name="詳情介紹", null=True, blank=True)
    level = models.SmallIntegerField(choices=level_choices, default=0, verbose_name="難度等級")
    pub_date = models.DateField(verbose_name="發布日期", auto_now_add=True)
    period = models.IntegerField(verbose_name="建議學習周期(day)", default=7)
    attachment_path = models.FileField(upload_to="attachment", max_length=128, verbose_name="課件路徑", blank=True,
                                       null=True)
    status = models.SmallIntegerField(choices=status_choices, default=0, verbose_name="課程狀態")
    course_category = models.ForeignKey("CourseCategory", on_delete=models.SET_NULL, db_constraint=False, null=True, blank=True,
                                        verbose_name="課程分類")
    students = models.IntegerField(verbose_name="學習人數", default=0)
    sections = models.IntegerField(verbose_name="總課時數量", default=0)
    pub_sections = models.IntegerField(verbose_name="課時更新數量", default=0)
    price = models.DecimalField(max_digits=6, decimal_places=2, verbose_name="課程原價", default=0)
    teacher = models.ForeignKey("Teacher", on_delete=models.DO_NOTHING, null=True, blank=True, verbose_name="授課老師")
    orders = models.IntegerField(default=0)
	# 自定義插拔式字段
    @property
    def level_name(self):
        return self.get_level_display()
	# 連表查詢
    @property
    def section_list(self):
        temp_section_list = []
        for chapter in self.coursechapters.all():
            for section in chapter.coursesections.all():
                if len(temp_section_list) >= 4:
                    return temp_section_list
                temp_section_list.append({
                    'chapter': chapter.chapter,
                    'name': section.name,
                    'free_trail': section.free_trail,
                })
        return temp_section_list

    class Meta:
        db_table = "luffy_course"
        verbose_name = "課程"
        verbose_name_plural = "課程"

    def __str__(self):
        return "%s" % self.name
  
class CourseCategory(BaseModel):
    """分類"""
    name = models.CharField(max_length=64, unique=True, verbose_name="分類名稱")
    orders = models.IntegerField(default=0)
    class Meta:
        db_table = "luffy_course_category"
        verbose_name = "分類"
        verbose_name_plural = verbose_name

    def __str__(self):
        return "%s" % self.name
    
  
class CourseChapter(BaseModel):
    """章節"""
    course = models.ForeignKey("Course", related_name='coursechapters', on_delete=models.CASCADE, verbose_name="課程名稱")
    chapter = models.SmallIntegerField(verbose_name="第幾章", default=1)
    name = models.CharField(max_length=128, verbose_name="章節標題")
    summary = models.TextField(verbose_name="章節介紹", blank=True, null=True)
    pub_date = models.DateField(verbose_name="發布日期", auto_now_add=True)
    orders = models.IntegerField(default=0)

    class Meta:
        db_table = "luffy_course_chapter"
        verbose_name = "章節"
        verbose_name_plural = verbose_name

    def __str__(self):
        return "%s:(第%s章)%s" % (self.course, self.chapter, self.name)


class CourseSection(BaseModel):
    """課時"""
    section_type_choices = (
        (0, '文檔'),
        (1, '練習'),
        (2, '視頻')
    )
    chapter = models.ForeignKey("CourseChapter", related_name='coursesections', on_delete=models.CASCADE,
                                verbose_name="課程章節")
    name = models.CharField(max_length=128, verbose_name="課時標題")
    orders = models.PositiveSmallIntegerField(verbose_name="課時排序")
    section_type = models.SmallIntegerField(default=2, choices=section_type_choices, verbose_name="課時種類")
    section_link = models.CharField(max_length=255, blank=True, null=True, verbose_name="課時鏈接",
                                    help_text="若是video,填vid,若是文檔,填link")
    duration = models.CharField(verbose_name="視頻時長", blank=True, null=True, max_length=32)  # 僅在前端展示使用
    pub_date = models.DateTimeField(verbose_name="發布時間", auto_now_add=True)
    free_trail = models.BooleanField(verbose_name="是否可試看", default=False)


    class Meta:
        db_table = "luffy_course_Section"
        verbose_name = "課時"
        verbose_name_plural = verbose_name

    def __str__(self):
        return "%s-%s" % (self.chapter, self.name)

adminx.py

import xadmin
from . import models
# 注冊xadmin后台管理
xadmin.site.register(models.Course)
xadmin.site.register(models.CourseCategory)
xadmin.site.register(models.CourseChapter)
xadmin.site.register(models.CourseSection)

urls.py

from django.urls import path, re_path
from . import views
urlpatterns = [
    path('free', views.FreeCourseListAPIView.as_view()),
    re_path('^free/(?P<pk>\d+)$', views.FreeCourseRetrieveAPIView.as_view()),
    
    path('category', views.CategoryListAPIView.as_view()),
    path('chapters', views.ChapterListAPIView.as_view()),
]

serializers.py

from rest_framework import serializers
from .import models
# 課程序列化
class FreeCourseModelSerializer(serializers.ModelSerializer):
    class Meta:
        model = models.Course
        fields = (
                  'id',
                  'name',
                  'course_img',
                  'brief',
                  'level_name',
                  'period',
                  'students',
                  'price',
                  )
# 分類序列化
class CategoryModelSerializer(serializers.ModelSerializer):
    class Meta:
        model = models.CourseCategory
        fields = ('name', 'id')

class CourseSectionModelSerialize(serializers.ModelSerializer):
    class Meta:
        model = models.CourseSection
        fields = '__all__'  # 所有字段
# 章節
class CourseChapterModelSerializer(serializers.ModelSerializer):
    coursesections = CourseSectionModelSerialize(many=True) # 子序列化
    class Meta:
        model = models.CourseChapter
        fields = (
            'id',
            'name',
            'chapter',
            'summary',
            'coursesections'
        )

views.py

from rest_framework.generics import ListAPIView
from . import models, serializers

# 配置過濾器類,導包, 排序過濾器
from rest_framework.filters import OrderingFilter

# 導包, 搜索過濾器
from rest_framework.filters import SearchFilter

# 自定義過濾器,導入
from .filters import LimitFilter

# 分類過濾器
from django_filters.rest_framework import DjangoFilterBackend

# 導入自定義分頁器
from .paginations import CouerPageNumberPagination

# 自定義分類區間篩選導入
from.filters import CourseFilterSet

# 群查
class FreeCourseListAPIView(ListAPIView):
    queryset = models.Course.objects.filter(is_delete=False, is_show=True).order_by('-orders').all()
    serializer_class = serializers.FreeCourseModelSerializer

# 群查排序過濾器  1、導包
    # 2、配置過濾器類
    # # LimitFilter 自定義過濾器 訪問url格式http://127.0.0.1:8000/course/free?limit=2
    filter_backends = [OrderingFilter, SearchFilter, LimitFilter, DjangoFilterBackend ]
    # 3.添加過濾的字段
    # 訪問接口方式為http://127.0.0.1:8000/course/free?ordering=-id,price
    # ordering = 'price'
    ordering_fields = ['price', 'id']

# 群查搜索過濾器
# 1、 導包
# 2、 配置過濾器類,統一配置在filter_backends中,如上
# 3、 添加搜索字段,訪問鏈接格式 http://127.0.0.1:8000/course/free?search=python
    search_fields = ['name', 'brief']

# 自定義過濾器,新建filters.py文件,完成自定義
# LimitFilter 自定義過濾器 訪問url格式http://127.0.0.1:8000/course/free?limit=2

# 分類過濾器
# 分類篩選過濾器:1、安裝環境-- pip install django-filter
#  2、然后在過濾器庫:filter_backends =[]中配置DjangoFilterBackend
# 3、在filter_fields 中配置分組篩選字段
#  訪問數據格式:http://127.0.0.1:8000/course/free?course_category=2
# 參與分類篩選的字段:所有字段都可以,但是用於分組的字段更有意義
    filter_fields = ['course_category']
    # 自定義區間分組篩選過濾器,從自定義文件導入
    filter_class = CourseFilterSet


# 分頁器
# 新建 paginations.py
# 1、導入自定義分頁器
# 2、選擇分頁器, 訪問格式:http://127.0.0.1:8000/course/free?page=2
    pagination_class = CouerPageNumberPagination

# 單查
from rest_framework.generics import RetrieveAPIView
class FreeCourseRetrieveAPIView(RetrieveAPIView):
    queryset = models.Course.objects.filter(is_delete=False, is_show=True).order_by('-orders')
    serializer_class = serializers.FreeCourseModelSerializer


# 分類查詢 群查
class CategoryListAPIView(ListAPIView):
    queryset = models.CourseCategory.objects.filter(is_delete=False, is_show=True).order_by('-orders').all()
    serializer_class = serializers.CategoryModelSerializer


# 課程章節查詢, 群查
class ChapterListAPIView(ListAPIView):
    queryset = models.CourseChapter.objects.filter(is_delete=False, is_show=True).order_by('-orders').all()
    serializer_class = serializers.CourseChapterModelSerializer

自定義過濾器文件入口

filters.py

# 自定義過濾器
from rest_framework.filters import BaseFilterBackend
# 自定義限制過濾器,限制顯示條數
class LimitFilter(BaseFilterBackend):
    def filter_queryset(self, request, queryset, view):
        # request:從前台請求獲取過濾的條件 query_params
		# queryset:要處理的數據
		# view:從視圖中反射過濾相關的配置
        limit = request.query_params.get('limit')
        try:
            return queryset[:int(limit)]  # queryset數據庫查詢結果
        except:
            return queryset


# 分類篩選,自定義區間篩選        
# 基於django-filter插件,自定義分類篩選器,完成指定區間篩選(一般都是對應數字字段)
from django_filters.rest_framework.filterset import FilterSet
from django_filters import filters
from . import models
class CourseFilterSet(FilterSet):
    # 自定義過濾字段及條件
    max_price = filters.NumberFilter(field_name='price', lookup_expr='lte')
    min_price = filters.NumberFilter(field_name='price', lookup_expr='gte')
    class Meta:
        model = models.Course
        fields = ['course_category', 'max_price', 'min_price']

自定義分頁器導入

paginations.py

# 分頁器
from rest_framework.pagination import PageNumberPagination
from rest_framework.pagination import LimitOffsetPagination
from rest_framework.pagination import CursorPagination

class CouerPageNumberPagination(PageNumberPagination):
    # 默認一頁條數
    page_size = 2
    # 訪問路徑的額外參數(選擇哪一頁的 key)
    page_query_param = 'page'
    # 用戶自定義一頁條數
    page_size_query_param = 'page_size'
    # 用戶自定義一頁最大控制條數
    max_page_size = 10

class CourseLimitOffsetPagination(LimitOffsetPagination):
    # 默認一頁條數
    default_limit = 2

    limit_query_param = 'limit'
    offset_query_param = 'offset'
    max_limit = 2

class CourseCursorPagination(CursorPagination):
    cursor_query_param = 'cursor'
    page_size = 2
    page_size_query_param = 'page_size'
    max_page_size = 2
# ordering = 'id'  # 默認排序規則,不能和排序過濾器OrderingFilter共存

補充

群查接口各種篩選組件數據准備

models.py

class Car(models.Model):
    name = models.CharField(max_length=16, unique=True, verbose_name='車名')
    price = models.DecimalField(max_digits=10, decimal_places=2, verbose_name='價格')
    brand = models.CharField(max_length=16, verbose_name='品牌')

    class Meta:
        db_table = 'api_car'
        verbose_name = '汽車表'
        verbose_name_plural = verbose_name

    def __str__(self):
        return self.name

admin.py

admin.site.register(models.Car)

serializers.py

class CarModelSerializer(serializers.ModelSerializer):
    class Meta:
        model = models.Car
        fields = ['name', 'price', 'brand']

urls.py

url(r'^cars/$', views.CarListAPIView.as_view()),

drf搜索過濾組件

views.py 搜索組件使用方法:路由后綴加 /?search=1 (name和price中包含1的數據都會被查詢出來)

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的數據都會被查詢出

drf排序過濾組件

views.py

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升序


drf基礎分頁組件

paginations.py

from rest_framework.pagination import PageNumberPagination

class MyPageNumberPagination(PageNumberPagination):
    # ?page=頁碼  定義代表頁碼的屬性,如果寫pages,就是?pages=頁碼
    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

  #eg:/cars/  顯示第一頁三條
    /cars/?page=2&page_size=4   每頁顯示4條,顯示第二頁的4條


免責聲明!

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



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