路飞项目实践
01-重要的表结构
课程的表结构(12张)

from django.db import models from django.contrib.contenttypes.models import ContentType from django.contrib.contenttypes.fields import GenericRelation from django.contrib.contenttypes.fields import GenericForeignKey __all__ = ["Category", "Course", "CourseDetail", "Teacher", "DegreeCourse", "CourseChapter", "CourseSection", "PricePolicy", "OftenAskedQuestion", "Comment", "Account", "CourseOutline"] class Category(models.Model): """课程分类""" title = models.CharField(max_length=32, unique=True, verbose_name="课程分类") def __str__(self): return self.title class Meta: db_table = "01-课程分类" # 上线删除 verbose_name_plural = verbose_name = "01-课程分类" class Course(models.Model): """课程表""" COURSE_TYPE_CHOICES = ((0, "付费"), (1, "vip专享"), (2, "学位课程")) course_type = models.SmallIntegerField(choices=COURSE_TYPE_CHOICES) course_img = models.ImageField(upload_to="", verbose_name="课程图片", blank=True, null=True) title = models.CharField(max_length=128, unique=128, verbose_name="课程名称") category = models.ForeignKey(to="Category", verbose_name="课程的分类") degree_course = models.ForeignKey(to="DegreeCourse", null=True, blank=True, help_text="如果是学位课程, 必须关联学位表") LEVEL_CHOICES = ((0, "初级"), (1, "中级"), (3, "高级")) STATUS_CHOICES = ((0, "上线"), (1, "下线"), (2, "预上线")) brief = models.CharField(verbose_name="课程简介", max_length=1024) level = models.SmallIntegerField(choices=LEVEL_CHOICES, default=1) status = models.SmallIntegerField(choices=STATUS_CHOICES, default=0) pub_date = models.DateField(verbose_name="发布日期", blank=True, null=True) order = models.IntegerField("课程顺序", help_text="从上一个数据往后排") study_num = models.IntegerField(verbose_name="学习人数", help_text="只要有人购买, 订单表加入数据的同时给这个字段+1") # 用户反向查找查询, 不生成字段 price_policy = GenericRelation("PricePolicy") often_ask_qeestions = GenericRelation("OftenAskedQuestion") course_comments = GenericRelation("Comment") def save(self, *args, **kwargs): if self.course_type == 2: if not self.degree_course: raise ValueError("学位课程必须关联学位课程表") super(Course, self).save(*args, **kwargs) def __str__(self): return self.title class Meta: verbose_name_plural = verbose_name = "02-课程表" db_table = "02-课程表" class CourseDetail(models.Model): """课程详细表""" hourse = models.IntegerField(verbose_name="课时", default=7) why_study = models.TextField(verbose_name="为什么学习这门课程") summary = models.TextField(max_length=2048, verbose_name="课程概述") what_to_study_brief = models.TextField(verbose_name="我将学到什么内容") vido_brief_link = models.CharField(max_length=255, blank=True, null=True) prerequisite = models.TextField(verbose_name="课程先修要求", max_length=1204) career_improvement = models.TextField(verbose_name="此项目如何有助于我的职业生涯") course = models.OneToOneField(to="Course") recommend_courses = models.ManyToManyField("Course", related_name="recommend_by", blank=True) teachers = models.ManyToManyField("Teacher", verbose_name="课程讲师") def __str__(self): return self.course.title class Meta: verbose_name_plural = verbose_name = "03-课程详细表" db_table = "03-课程详细表" class Teacher(models.Model): """讲师表""" name = models.CharField(max_length=32, verbose_name="讲师名字") brief = models.TextField(max_length=1024, verbose_name="讲师介绍") def __str__(self): return self.name class Meta: verbose_name_plural = verbose_name = "04-讲师表" db_table = "04-讲师表" class DegreeCourse(models.Model): """ 字段大体跟课程表相同, 哪些不同根据业务逻辑去区分 """ title = models.CharField(verbose_name="学位课程", max_length=32) def __str__(self): return self.title class Meta: verbose_name_plural = verbose_name = "05-学位课程" db_table = "05-学位课程" class CourseChapter(models.Model): """课程章节表""" title = models.CharField(max_length=32, verbose_name="课程章节名称") course = models.ForeignKey(to="Course", related_name="course_chapters") chapter = models.SmallIntegerField(default=1, verbose_name="第几章") def __str__(self): return self.title class Meta: verbose_name_plural = verbose_name = "06-课程章节表" db_table = "06-课程章节表" class CourseSection(models.Model): """课时表""" chapter = models.ForeignKey(to="CourseChapter", related_name="course_sections") title = models.CharField(max_length=32, verbose_name="课时") section_order = models.SmallIntegerField(verbose_name="课时安排", help_text="建议每个课时之间空1至两个值, 以备后续插入课时") section_type_choices = ((0, "文档"), (1, "练习"), (2, "视频")) section_link = models.CharField(max_length=255, blank=True, null=True, help_text="若是video, 填vid, 若是文档, 填link") def course_chapter(self): return self.chapter.chapter def course_name(self): return self.chapter.course.title class Meta: verbose_name_plural = verbose_name = "07-课程课时表" db_table = "07-课程课时表" unique_together = ("chapter", "section_link") class PricePolicy(models.Model): """价格策略表""" content_type = models.ForeignKey(ContentType) # 关联course or degree_course object_id = models.PositiveIntegerField() content_object = GenericForeignKey("content_type", "object_id") valid_period_choices = ( (1, "1天"), (3, "3天"), (7, "1周"), (14, "2周"), (30, "1个月"), (60, "2个月"), (90, "3个月"), (120, "4个月"), (180, "6个月"), (210, "12个月"), (540, "18个月"), (720, "24个月"), (722, "24个月"), (723, "24个月"), ) valid_period = models.SmallIntegerField(choices=valid_period_choices) price = models.FloatField() def __str__(self): return "{}({}){}".format(self.content_object, self.get_valid_period_display(), self.price) class Meta: verbose_name_plural = verbose_name = "08-价格策略表" db_table = "08-价格策略表" unique_together = ("content_type", "object_id", "valid_period") class OftenAskedQuestion(models.Model): """常见问题""" content_type = models.ForeignKey(ContentType) # 关联course or degree_course object_id = models.PositiveIntegerField() content_object = GenericForeignKey("content_type", "object_id") question = models.CharField(max_length=255) answer = models.TextField(max_length=1024) def __str__(self): return "{}-{}".format(self.content_object, self.question) class Meta: verbose_name_plural = verbose_name = "09-常见问题" db_table = "09-常见问题" unique_together = ("content_type", "object_id", "question") class Comment(models.Model): """通用评论表""" content_type = models.ForeignKey(ContentType, blank=True, null=True) object_id = models.PositiveIntegerField() content_object = GenericForeignKey("content_type", "object_id") content = models.TextField(max_length=1024, verbose_name="评论内容") account = models.ForeignKey("Account", verbose_name="会员名") date = models.DateTimeField(auto_now_add=True) def __str__(self): return self.content class Meta: verbose_name_plural = verbose_name = "10-评论表" db_table = "10-通用评论表" class Account(models.Model): """账号信息""" username = models.CharField(max_length=32, verbose_name="用户姓名") def __str__(self): return self.username class Meta: verbose_name_plural = verbose_name = "11-用户表" db_table = "11-用户表" class CourseOutline(models.Model): """课程大纲""" course_detail = models.ForeignKey(to="CourseDetail", verbose_name="课程详细", related_name="course_outline") title = models.CharField(max_length=128) order = models.PositiveIntegerField(default=1) # 前端显示顺序 content = models.TextField("内容", max_length=2048) def __str__(self): return "{}".format(self.title) class Meta: verbose_name_plural = verbose_name = "12-课程大纲" db_table = "12-课程大纲" unique_together = ("course_detail", "title")
接口的编写

import uuid from rest_framework.views import APIView from rest_framework.response import Response from . import models from .serializers import CourseCategorySerializer from .serializers import CourseSerializer from .serializers import CourseDetailSerializer from .serializers import CourseChapterSerializer from .serializers import CourseCommentSerializer from .serializers import UserSerializer from course.models import Account # 导入BaseResponse from utils.base_response import BaseResponse # 认证 from utils.authentications import UserAuthentication class CourseCategory(APIView): """课程分类""" def get(self, request): queryset = models.Category.objects.all() ser_obj = CourseCategorySerializer(queryset, many=True) return Response(ser_obj.data) class Course(APIView): """课程""" def get(self, request): cartegory_id = request.query_params.get("category", "0") if cartegory_id == "0": queryset = models.Course.objects.all().order_by("-order") else: queryset = models.Course.objects.filter(category_id=cartegory_id).order_by("-order") ser_obj = CourseSerializer(queryset, many=True) return Response(ser_obj.data) class CourseDetailView(APIView): """课程详细页面""" def get(self, request, pk): course_detail_obj = models.CourseDetail.objects.filter(course_id=pk).first() if not course_detail_obj: return Response({"code": 1001, "errors": "不存在这门课程"}) ser_obj = CourseDetailSerializer(course_detail_obj) return Response(ser_obj.data) class CourseChapter(APIView): """课程章节""" def get(self, request, pk): queryset = models.CourseChapter.objects.filter(course_id=pk) ser_obj = CourseChapterSerializer(queryset, many=True) return Response(ser_obj.data) class CourseContentView(APIView): """课程评论""" def get(self, request): queryset = models.Comment.objects.all() ser_obj = CourseCommentSerializer(queryset, many=True) return Response(ser_obj.data)
序列化器

import hashlib from rest_framework import serializers from . import models class CourseCategorySerializer(serializers.ModelSerializer): class Meta: model = models.Category fields = ["id", "title"] class CourseSerializer(serializers.ModelSerializer): level = serializers.CharField(source="get_level_display") price_policy = serializers.SerializerMethodField() def get_price_policy(self, obj): print(obj.price_policy) for price in obj.price_policy.all(): return price.price class Meta: model = models.Course fields = ["id", "title", "course_img", "category", "level", "study_num", "price_policy", "brief"] class CourseDetailSerializer(serializers.ModelSerializer): level = serializers.CharField(source="course.get_level_display") study_num = serializers.IntegerField(source="course.study_num") price_policy = serializers.SerializerMethodField() course_outline = serializers.SerializerMethodField() recommend_courses = serializers.SerializerMethodField() teachers = serializers.SerializerMethodField() def get_price_policy(self, obj): return [{"id": price_obj.id, "valid_price_display": price_obj.get_valid_period_display(), "price": price_obj.price} for price_obj in obj.course.price_policy.all()] def get_course_outline(self, obj): outlines = obj.course_outline.all().order_by("order") return [{"title": outline.title, "content": outline.content} for outline in outlines] def get_recommend_courses(self, obj): return [{"id": item.id, "title": item.title} for item in obj.recommend_courses.all()] def get_teachers(self, obj): return [{"id": item.id, "name": item.name} for item in obj.teachers.all()] class Meta: model = models.CourseDetail fields = ["id", "summary", "hourse", "level", "study_num", "price_policy", "why_study", "what_to_study_brief", "course_outline", "career_improvement", "prerequisite", "recommend_courses", "teachers"] class CourseChapterSerializer(serializers.ModelSerializer): sections = serializers.SerializerMethodField() def get_sections(self, obj): sections = obj.course_sections.all().order_by("section_order") print(sections) return [{"id": item.id, "title": item.title} for item in sections] class Meta: model = models.CourseChapter fields = ["id", "title", "chapter", "course", "sections"] class CourseCommentSerializer(serializers.ModelSerializer): account = serializers.CharField(source="account.username") class Meta: model = models.Comment fields = ["id", "account", "content", "date"]