06-05 课程主页之课程接口

一. 课程分类接口

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()    

4. pagination.py

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
posted @ 2020-08-01 21:08  给你加马桶唱疏通  阅读(165)  评论(0编辑  收藏  举报