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条

原文地址:https://www.cnblogs.com/chmily/p/12055011.html