过滤器(组件)使用
群查接口各种筛选、过滤数据准备
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条