一. 课程分类接口
1. course/views.py
from rest_framework.viewsets import GenericViewSet
from rest_framework.mixins import ListModelMixin
from .models import CourseCategory
from .serializer import CourseModelSerializer
class CourseCategoryView(ListModelMixin, GenericViewSet):
queryset = CourseCategory.objects.filter(is_delete=False, is_show=True).order_by('orders')
serializer_class = CourseModelSerializer
2. course/serializer.py
from rest_framework import serializers
from .models import CourseCategory
class CourseModelSerializer(serializers.ModelSerializer):
class Meta:
model = CourseCategory
fields = ('id', 'name')
3. course/urls.py
router.register('categories', views.CourseCategoryView, 'categories')
4. apps/urs.py
path('course/', include('course.urls')),
5. 流程
1. 视图定义课程分类视图, 继承GenericViewSet, ListModelMixin
2. 对课程分类接口进行is_delete, is_show过滤, 再使用orders进行排序
3. 序列化定义课程分类序列化类. 不过需要给课程分类的id, 在分类的时候, 需要前端传递过来实现分类. 然后只需要给课程分类名即可.
4. 配置course中的路由, 配置总路由
二. 课程接口
1. views.py
from .pagination import PageNumberPagination
from rest_framework.filters import OrderingFilter, SearchFilter
from django_filters.rest_framework import DjangoFilterBackend
class CourseView(ListModelMixin, GenericViewSet):
queryset = Course.objects.filter(is_delete=False, is_show=True).order_by('orders')
serializer_class = CourseModelSerializer
pagination_class = PageNumberPagination
filter_backends = []
# 内置排序
filter_backends.append(OrderingFilter)
ordering_param = 'ordering'
ordering_fields = ('id', 'price', 'students')
# 内置过滤(搜索组件)
"""
filter_backends.append(SearchFilter)
search_param = 'search'
search_fields = ['course_category'] # 外键字段的操作将会抛出异常
"""
# django-filter过滤
filter_backends.append(DjangoFilterBackend)
# 指定过滤字段方式一:
filter_fields = ['course_category', 'students']
2. serialier.py
class TeacherModelSerializer(serializers.ModelSerializer):
class Meta:
model = Teacher
fields = ('name', 'role_name', 'title', 'signature', 'image', 'brief')
class CourseModelSerializer(serializers.ModelSerializer):
# teacher子序列化
teacher = TeacherModelSerializer()
class Meta:
model = Course
fields = (
'id',
'name',
'course_img',
'brief',
'attachment_path',
'pub_sections',
'price',
'students',
'period',
'sections',
'course_type_name',
'level_name',
'status_name',
'teacher',
'section_list',
)
3. models.py
class Course(BaseModel):
...
@property
def level_name(self):
return self.get_level_display()
@property
def course_type_name(self):
return self.get_course_type_display()
@property
def status_name(self):
return self.get_status_display()
@property
def section_list(self):
course_chapter_queryset = self.coursechapters.all()
course_section_list = []
for course_chapter in course_chapter_queryset:
course_section_queryset = course_chapter.coursesections.all()
for course_section in course_section_queryset:
course_section_list.append({
'name': course_section.name,
'section_type': course_section.section_type,
'section_link': course_section.section_link,
'duration': course_section.duration,
})
if len(course_section_list) == 4:
return course_section_list
return course_section_list
class Teacher(BaseModel):
...
@property
def role_name(self):
return self.get_role_display()
from rest_framework.pagination import PageNumberPagination as PNP
class PageNumberPagination(PNP):
page_size = 1
page_query_param = 'page'
page_size_query_param = 'size'
max_page_size = 5
4. filters.py 自定义过滤类
from rest_framework.filters import BaseFilterBackend
class CustomFilter(BaseFilterBackend):
def filter_queryset(self, request, queryset, view):
# 老师的模糊匹配
name = request.GET.get('teacher')
if not name:
return queryset
teacher_queryset = queryset.filter(teacher__name__contains=name)
return teacher_queryset
5. urls.py
router.register('free', views.CourseView, 'free')
6. 流程
1. 视图中定义课程视图类继承GenericViewSet,ListModelMixin
2. 视图中queryset的查询过滤is_delete, is_show, 再使用orders字段进行排序
3. 序列化中定义课程序列化类, 控制序列化的字段, 在序列化类中针对teacher使用子序列化进行控制teacher包含字段对应数值的展示
4. 对应choices字段的展示, 有2种方式进行控制, 在序列化类中重写字段, 使用serializerMethod, 模型类中使用@property装饰返回对应get_字段_display()字段参数对应的值.
5. 配置路由
6. 配置分页器. 自定义分页器, 使用了as的特殊用法
三. 排序和过滤组件
1. 内置排序组件OrderingFilter
# 1)在视图文件views.py中导入drf的搜索组件
from rest_framework.filters import OrderingFilter
# 2)将搜索组件配置给群查接口视图类的filter_backends
filter_backends = [OrderingFilter]
# 3)配置视图类关联的Model表允许排序的字段
ordering_fields = ['id', 'price']
# 4)前台访问该群查接口,采用拼接参数方式用search关键字将搜索目标提供给后台
http://127.0.0.1:8000/course/free/?ordering=price,-id # 按price升序,如果price相同,再按id降序
2. 过滤组件
1) 内置过滤组件SearchFilter
# 缺点: 外键字段的搜索操作将会抛出异常: Related Field got invalid lookup: icontains
# 1)在视图文件views.py中导入drf的搜索组件
from rest_framework.filters import SearchFilter
# 2)将搜索组件配置给群查接口视图类的filter_backends
filter_backends = [SearchFilter]
# 3)配置视图类关联的Model表参与搜索的字段
search_fields = ['name', 'id']
# 4)前台访问该群查接口,采用拼接参数方式用search关键字将搜索目标提供给后台
http://127.0.0.1:8000/course/free/?search=2 # id或name中包含2的所有结果
2) 第三方过滤组件django-filter
# 介绍: 争对django内置搜索组件的拓展, 在django内置的基础之上还拓展了外键字段的过滤功能.
# 前提:安装django-filter插件
pip install django-filter (注意: 不要安装成了django-filters)
"""方式一"""
# 1)在视图文件views.py中导入django-filter的功能组件
from django_filters.rest_framework import DjangoFilterBackend
# 2)将搜索组件配置给群查接口视图类的filter_backends
filter_backends = [DjangoFilterBackend]
# 3)配置视图类关联的Model表可以分类的字段(通常是可以分组的字段)
filter_fields = ['course_category']
# 4)前台访问该群查接口,采用拼接参数方式用分类course_category字段将分类条件提供给后台
http://127.0.0.1:8000/course/free/?course_category=1 # 拿课程分类1下的所有课程
'''方式二'''
# 1)自定义过滤类继承django-filter插件的FilterSet类,绑定Model表,并设置分类字段
from django_filters.filterset import FilterSet
from . import models
class CourseFilterSet(FilterSet):
class Meta:
model = models.Course
fields = ['course_category']
# 2)在视图文件views.py中导入django-filter的功能组件及自定义的过滤类
from django_filters.rest_framework import DjangoFilterBackend
from .filters import CourseFilterSet
# 3)将搜索组件配置给群查接口视图类的filter_backends
filter_backends = [DjangoFilterBackend]
# 4)配置视图类关联的自定义过滤类
filter_class = CourseFilterSet
# 5)前台访问该群查接口,采用拼接参数方式用分类course_category字段将分类条件提供给后台
http://127.0.0.1:8000/course/free/?course_category=1 # 拿课程分类1下的所有课程
3) django-filter实现区间过滤
# 1)自定义过滤类继承django-filter插件的FilterSet类,绑定Model表,并设置自定义区间规则字段
from django_filters.filterset import FilterSet
from . import models
class CourseFilterSet(FilterSet):
# 区间过滤: students学生中总人数要大于等于min_students, 要小于等于max_students. [min_students, max_students]
max_students = filters.NumberFilter(field_name='students', lookup_expr='lte')
min_students = filters.NumberFilter(field_name='students', lookup_expr='gte')
class Meta:
model = Course
fields = ['course_category', 'students', 'min_students', 'max_students']
# 2)在视图文件views.py中导入django-filter的功能组件及自定义的过滤类
from django_filters.rest_framework import DjangoFilterBackend
from .filters import CourseFilterSet
# 3)将搜索组件配置给群查接口视图类的filter_backends
filter_backends = [DjangoFilterBackend]
# 4)配置视图类关联的自定义过滤类
filter_class = CourseFilterSet
# 5)前台访问该群查接口,采用拼接参数方式用自定义区间规则字段将区间条件提供给后台
http://127.0.0.1:8000/course/free/?min_students=230&max_students=250 # 获取学生总人数230~250之间的数据
'''
# django-filter区间过滤源码流程
关键: filter_queryset
get_filterset_class:
反射filter_class
MetaBase
AutoFilterSet
filterset就是我们自定义类实例化出来的对象
有值调用: filterset.is_valid()
reutrn filterset.qs qs在BaseFilterSet中
return self.qs = qs queryset对象
反射filter_fields
'''
4) 自定义过滤
# filters.py
from rest_framework.filters import BaseFilterBackend
class CustomFilter(BaseFilterBackend):
def filter_queryset(self, request, queryset, view):
# 老师的模糊匹配
name = request.GET.get('teacher')
if not name:
return queryset
teacher_queryset = queryset.filter(teacher__name__contains=name)
return teacher_queryset
# views.py
# 自定义过滤: 通过老师名进行模糊匹配
filter_backends = [CustomFilter]
四. 总结
# 过滤, 排序, 分页的使用范围
视图类继承关系中必须含有的视图类: ListModelMixin, GenericAPIView
ListModelMixin中实现的是调用GenericAPIView中对应的过滤,排序(filter_queryset), 分页(paginate_queryset)方法
GenericAPIView中实现的是循环调用视图类中配置的类, 调用视图类中对应的方法
def filter_queryset(self, queryset):
for backend in list(self.filter_backends):
queryset = backend().filter_queryset(self.request, queryset, self)
return queryset