28-课程主页之课程接口

课程主页之课程接口

一、课程分类接口

1. course/views.py

from rest_framework.viewsets import GenericViewSet
from rest_framework.mixins import ListModelMixin

from . import serializer
from . import models


# 查询所有课程分类接口
class CourseCategoryView(GenericViewSet, ListModelMixin):
	queryset = models.CourseCategory.objects.filter(is_delete=False, is_show=True).order_by('orders').all()
	serializer_class = serializer.CourseCategorySerializer

2. course/serializer.py

from rest_framework import serializers
from . import models


# 课程分类序列化器
class CourseCategorySerializer(serializers.ModelSerializer):
	class Meta:
		model = models.CourseCategory
		fields = ['id', 'name', ]

3. course/urls.py

from django.urls import path, include
from . import views

from rest_framework.routers import SimpleRouter

router = SimpleRouter()

router.register('categories', views.CourseCategoryView, 'categories')

urlpatterns = [
	path('', include(router.urls)),
]

4. apps/urls.py

path('course/', include('course.urls')),

5. 流程

1. 视图定义课程分类视图, 继承GenericViewSet, ListModelMixin
2. 对课程分类接口进行is_delete, is_show过滤, 再使用orders进行排序
3. 序列化定义课程分类序列化类. 不过需要给课程分类的id, 在分类的时候, 需要前端传递过来实现分类. 然后只需要给课程分类名即可.
4. 配置course中的路由, 配置总路由

二、课程接口

1. views.py

# 查询所有课程详情接口
from .paginations import PageNumberPagination
from rest_framework.filters import OrderingFilter, SearchFilter

from django_filters.rest_framework import DjangoFilterBackend
# 自定义的过滤规则
from .filters import Myfilter
# 区间过滤
from .filters import CourseFilterSet


# 单查、群查课程接口
class CourseView(GenericViewSet, ListModelMixin, RetrieveModelMixin):
	queryset = models.Course.objects.filter(is_delete=False, is_show=True).order_by('orders').all()
	serializer_class = serializer.CourseSerializer
	# 分页
	pagination_class = PageNumberPagination
	''' 原始版本的过滤+排序 '''
	# 排序
	# filter_backends = (OrderingFilter, DjangoFilterBackend, SearchFilter)
	filter_backends = (OrderingFilter, DjangoFilterBackend)
	ordering_fields = ['id', 'price', 'students']
	'''
	过滤+排序分析:
		1.先走执行ListModelMixin中的List方法
		2.List方法中回执行self.filter_queryset方法,但是ListModelMixin中没有filter_queryset方法
		3.从GenericViewSet类中找filter_queryset方法,也没有
		4.GenericViewSet类继承了ViewSetMixin, generics.GenericAPIView,ViewSetMixin中也没有,在generics.GenericAPIView类中找到了filter_queryset方法
		5.generics.GenericAPIView中的filter_queryset代码如下
			        for backend in list(self.filter_backends): 遍历CourseView中的filter_backends
			            queryset = backend().filter_queryset(self.request, queryset, self) :实例化filter_backends列表中的类的,并执行filter_queryset方法
				        return queryset:返回queryset对象
	'''
	# 过滤(django内置的过滤)
	# search_field = ['id']

	# 过滤(django-filter提供的过滤,比内置的更加强大,可以过滤外键字段)
	filter_fields = ['course_category', ]
	'''
	排序:
		使用:http://www127.0.0.1:8000/course/free/?ordering=-id
		按照id正序倒序排序
		配置类:
			filter_backends = (OrderingFilter,)
		配置字段:
			ordering_fields = ['id',]
	内置过滤:
		使用:http://www127.0.0.1:8000/course/free/?search=39.00
		按照price过滤(过滤表中自有的字段直接过滤)
		配置类:
			filter_backends = (SearchFilter,)
		配置字段:
			search_field = ['price']
	扩展过滤(django-filter)
		使用:http://www127.0.0.1:8000/course/free/?course_category=1
		按照course_category过滤(无论是过滤表中自有的字段还是外键字段)
		配置类:
			filter_backends = (DjangoFilterBackend)
		配置字段:
			filter_fields = ['course_category', ]
	'''
	''' django-filter版本的过滤 '''
	# filter_backends = (DjangoFilterBackend,)
	# filter_class = CourseFilterSet

2. serializer.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 DRFPageNumberPagination


class PageNumberPagination(DRFPageNumberPagination):
	page_size = 1
	page_query_param = 'page'
	page_size_query_param = 'page_size'
	max_page_size = 10

5. 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

6. urls.py

router.register('free', views.CourseView, 'free')

7. 流程

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
    	# 此时返回的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
原文地址:https://www.cnblogs.com/borntodie/p/14431284.html