课程表模型
from django.db import models
# Create your models here.
from utils.models import BaseModel
# 课程分类,课程,老师,章节,课时
class CourseCategory(BaseModel):
"""分类"""
name = models.CharField(max_length=64, unique=True, verbose_name="分类名称") # 字段
class Meta:
db_table = "luffy_course_category"
verbose_name = "分类" # 表名
verbose_name_plural = verbose_name
def __str__(self):
return "%s" % self.name
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="课程名称")
# blank 后台管理录入可以为空,null存到数据库字段可以为空
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="付费类型")
# TextField 大文本, 存html
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="课程状态")
# 优化字段
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)
# 关联字段
# ForeignKey的on_delete的选择:
# models.CASCADE 级联删除,用的少,除非真的要删除
# models.SET_NULL 关联字段设为空 null=True
# models.SET_DEFAULT 关联字段设为默认值 defalut='asfasd'
# models.DO_NOTHING 什么都不做, 不用强外键关联
# models.SET() 放一个函数内存地址,关联字段删除时,执行这个函数
# 外键关联的好处和坏处
# -好处在于 插入修改数据,有校验,能够保证数据不会错乱,不会出现脏数据
# -坏处在于 有校验,速度慢,数量越大,越慢,咱们可以通过程序控制不加入脏数据
# 公司内部为了效率,一般不建立外键关联,关系在 ,只是没有那条线了
# 在django中不建立外键关联,只是不创建外键,关联关系还在【关联查询】,也是使用ForeignKey,只是加一个参数,加了之后,没有约束,但你们关系还在
teacher = models.ForeignKey("Teacher", on_delete=models.DO_NOTHING, null=True, blank=True, verbose_name="授课老师",
db_constraint=False)
course_category = models.ForeignKey("CourseCategory", on_delete=models.SET_NULL, db_constraint=False, null=True,
blank=True, verbose_name="课程分类")
class Meta:
db_table = "luffy_course"
verbose_name = "课程"
verbose_name_plural = "课程"
def __str__(self):
return "%s" % self.name
# 序列化的字段
def course_type_name(self):
# 选择字段需要显示中文
return self.get_course_type_display()
def level_name(self):
return self.get_level_display()
def status_name(self):
return self.get_status_display()
# 重写序列化显示字段,在序列化类中展示
def teacher_detail(self):
return {'name': self.teacher.name, 'title': self.teacher.title, 'image': str(self.teacher.image)}
def section_list(self):
section_list = []
# 课程取出所有章节,循环每个章节,取出所有课时,拼接列表,当列表长度等于四就结束
coursechapter_list = self.coursechapters.all() # 所有章节
for coursechapter in coursechapter_list:
# 获取当前章节下所有的课时
coursesections_list = coursechapter.coursesections.all()
for section in coursesections_list:
section_list.append({'id': section.id,
'name': section.name,
'duration': section.duration,
'section_link': section.section_link,
'free_trail': section.free_trail
})
if len(section_list) > 3: # 在结束之前已经追加了一个值了所以需要加一就是显示的数量
return section_list
return section_list
class Teacher(BaseModel):
"""导师"""
role_choices = (
(0, '讲师'),
(1, '导师'),
(2, '班主任'),
)
name = models.CharField(max_length=32, verbose_name="导师名")
role = models.SmallIntegerField(choices=role_choices, default=0, verbose_name="导师身份")
title = models.CharField(max_length=64, verbose_name="职位、职称")
signature = models.CharField(max_length=255, verbose_name="导师签名", help_text="导师签名", blank=True, null=True)
image = models.ImageField(upload_to="teacher", null=True, verbose_name="导师封面")
brief = models.TextField(max_length=1024, verbose_name="导师描述")
class Meta:
db_table = "luffy_teacher"
verbose_name = "导师"
verbose_name_plural = verbose_name
def __str__(self):
return "%s" % self.name
def role_name(self):
return self.get_role_display()
class CourseChapter(BaseModel):
"""章节"""
# 跟课程一对多,一个课程多个章节,关联字段写在多的一方
# related_name='coursechapters' 反向操作时,使用的字段名,用于代替原反向查询时的’表名_set’
# 拿课程下所有章节 course.coursechapter_set.all() course.coursechapters.all()
# related_query_name='字符串' 反向查询操作时,使用的连接前缀,用于替换表名
# __ 连表查询 __表名小写__ __字符串__
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)
def section_detail(self):
section_list = []
coursesections_list = self.coursesections.all()
for section in coursesections_list:
section_list.append({'id': section.id,
'name': section.name,
'duration': section.duration,
'section_link': section.section_link,
'free_trail': section.free_trail})
return section_list
class Meta:
db_table = "luffy_course_chapter"
verbose_name = "章节"
verbose_name_plural = verbose_name
def __str__(self):
# 可能会出异常
try:
return "%s:(第%s章)%s" % (self.course, self.chapter, self.name)
except Exception as e:
return "未知课程:(第%s章)%s" % (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)
课程视图view.py
from utils.common_mixin import CommonListModelMixin
from rest_framework.viewsets import GenericViewSet
from .serializer import CourseCategorySerializer, CourseSerializer, CourseChapterSerializer
from .models import CourseCategory, Course, CourseChapter
from .page import CoursePageNumberPagination
from rest_framework.filters import OrderingFilter,SearchFilter
from django_filters.rest_framework import DjangoFilterBackend
from rest_framework.mixins import RetrieveModelMixin
"""课程分类视图"""
class CourseCategoryView(GenericViewSet, CommonListModelMixin):
queryset = CourseCategory.objects.all().filter(is_delete=False, is_show=True).order_by('orders')
serializer_class = CourseCategorySerializer
"""课程列表接口"""
# 带分页过滤排序
# 加上RetrieveModelMixin详情接口
class CourseView(GenericViewSet, CommonListModelMixin, RetrieveModelMixin):
queryset = Course.objects.all().filter(is_delete=False, is_show=True).order_by('orders')
serializer_class = CourseSerializer # 序列化
pagination_class = CoursePageNumberPagination # 分页类
filter_backends = [OrderingFilter, DjangoFilterBackend] # 排序和过滤类
filterset_fields = ['course_category'] # 按分类字段过滤
ordering_fields = ('orders', 'price', 'students') # 排序按价格,学生人数,优先级别
序列化
- 注:----->章节表可以直接点章节课时coursechapter_list = 章节.coursechapters.all()coursechapters是章节表隐藏字段可以通过该字段点到课时表,是个对象,子序列化使用
from rest_framework import serializers
from .models import CourseCategory, Course, Teacher,CourseChapter
"""分类序列化"""
class CourseCategorySerializer(serializers.ModelSerializer):
class Meta:
model = CourseCategory
fields = ['id', 'name']
"""讲师序列化"""
class TeacherSerializer(serializers.ModelSerializer):
class Meta:
model = Teacher
fields = ('id', 'name', 'image', 'role_name', 'signature', 'brief')
"""课程序列化讲师字段使用了子序列化有其他两种方法可以写"""
class CourseSerializer(serializers.ModelSerializer):
teacher = TeacherSerializer()
class Meta:
model = Course
# fields = ['id', 'name'] # 添加序列化更多字段
fields = [
'id',
'name',
'course_img',
'brief', # 课程简介
'attachment_path', # 课件地址
'pub_sections', # 发布时间
'price', # 价格
'students', # 学生数量
'period', # 建议学习周期
'sections', # 总课时数量
'course_type_name', # 课程类型名字表中没有该字段,在表模型中重写方法
'level_name',
'status_name',
'teacher', # 老师{name:xxx,title:xxx}
# 'teacher_detail',
'section_list', # 课时最多四个课时[{},{},{}]
]
# 方法一:序列化中写写在外层 obj是课程对象需要跨表到讲师
# 方法二:中表模型中写方法返回,显示的时候写表模型的方法名
# 方法三:子序列化写好序列化类讲师对象通过序列化类序列化之后在显示配置成当前序列化类的属性即可 注--->需要表模型中有字段才可以子序列化
# teacher = serializers.SerializerMethodField()
#
# def get_teacher(self, obj):
# return {'name': obj.teacher.name, 'title': obj.teacher.title,'image':str(self.teacher.image)}
class CourseChapterSerializer(serializers.ModelSerializer):
class Meta:
model = CourseChapter
fields = ['id', 'name','summary','pub_date','section_detail']
视图中使用的分页
from rest_framework.pagination import PageNumberPagination
class CoursePageNumberPagination(PageNumberPagination):
page_size = 5 # 每页五条
page_query_param = 'page'
page_size_query_param = 'size'
max_page_size = 5
课程模块路由
from rest_framework.routers import SimpleRouter
from .views import CourseCategoryView,CourseView,CourseChapterView,SearchCourseView
router = SimpleRouter()
router.register('category', CourseCategoryView, 'category') # 分类 第一个是路径,视图函数,反向解析用的别名
router.register('list', CourseView, 'list') # 课程
router.register('chapter', CourseChapterView, 'chapter') # 章节
router.register('search', SearchCourseView, 'search') # 章节
urlpatterns = [
]
urlpatterns += router.urls