课程模块表结构

课程模块

我们要开始写课程模块了~~课程模块都有哪些功能呢~~

我们的课程模块,包括了免费课程以及专题课程两个方向~~

主要是课程的展示,点击课程进入课程详细页面~~

课程详细页面展示,课程的概述,课程的价格策略,课程章节,评价以及常见问题~~

以及一些周边的字段~~~这是主线路~~

根据功能设计表结构

对照着对标路飞网站,我们可以先讨论下表结构~~

我们初步能够确定下来12张表~~

from django.db import models
from django.contrib.contenttypes.fields import GenericRelation, GenericForeignKey
from django.contrib.contenttypes.models import ContentType# Create your models here.
__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.titleclass Meta:verbose_name = "01-课程分类表"db_table = verbose_name  # 数据库表名verbose_name_plural = verbose_name  # 复数class Course(models.Model):"""课程表"""title = models.CharField(max_length=128, unique=True, verbose_name="课程的名称")course_img = models.ImageField(upload_to="course/%Y-%m", verbose_name='课程的图片')# media/course/2018-11/xxx.pngcategory = models.ForeignKey(to="Category", verbose_name="课程的分类")COURSE_TYPE_CHOICES = ((0, "付费"), (1, "vip专享"), (2, "学位课程"))course_type = models.SmallIntegerField(choices=COURSE_TYPE_CHOICES)degree_course = models.ForeignKey(to="DegreeCourse", blank=True, null=True, help_text="如果是学位课程,必须关联学位表")# course_type    degree_course_id#  0                null#  1                null#  2                2
brief = models.CharField(verbose_name="课程简介", max_length=1024)level_choices = ((0, '初级'), (1, '中级'), (2, '高级'))level = models.SmallIntegerField(choices=level_choices, default=1)status_choices = ((0, '上线'), (1, '下线'), (2, '预上线'))status = models.SmallIntegerField(choices=status_choices, default=0)pub_date = models.DateField(verbose_name="发布日期", blank=True, null=True)order = models.IntegerField(verbose_name="课程顺序", help_text="从上一个课程数字往后排, 建议中间空几个数字")study_num = models.IntegerField(verbose_name="学习人数", help_text="只要有人买课程,订单表加入数据的同时给这个字段+1")is_free = models.BooleanField(default=False)# order_details = GenericRelation("OrderDetail", related_query_name="course")# coupon = GenericRelation("Coupon")# 只用于反向查询不生成字段price_policy = GenericRelation("PricePolicy")often_ask_questions = 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.titleclass Meta:verbose_name = "02-课程表"db_table = verbose_nameverbose_name_plural = verbose_nameclass CourseDetail(models.Model):"""课程详细表"""course = models.OneToOneField(to="Course")hours = models.IntegerField(verbose_name="课时")course_slogan = models.CharField(max_length=125, blank=True, null=True, verbose_name="课程口号")video_brief_link = models.CharField(max_length=255, blank=True, null=True)summary = models.TextField(max_length=2048, verbose_name="课程概述")why_study = models.TextField(verbose_name="为什么学习这门课程")service = models.TextField(verbose_name="你将获得哪些服务")what_to_study_brief = models.TextField(verbose_name="我将学到哪些内容")career_improvement = models.TextField(verbose_name="此项目如何有助于我的职业生涯")prerequisite = models.TextField(verbose_name="课程先修要求", max_length=1024)recommend_courses = models.ManyToManyField("Course", related_name="recommend_by", blank=True)teachers = models.ManyToManyField("Teacher", verbose_name="课程讲师")def __str__(self):return self.course.titleclass Meta:verbose_name = "03-课程详细表"db_table = verbose_nameverbose_name_plural = verbose_nameclass Teacher(models.Model):"""讲师表"""name = models.CharField(max_length=32, verbose_name="讲师名字")brief = models.TextField(max_length=1024, verbose_name="讲师介绍")def __str__(self):return self.nameclass Meta:verbose_name = "04-教师表"db_table = verbose_nameverbose_name_plural = verbose_nameclass DegreeCourse(models.Model):"""字段大体跟课程表相同,哪些不同根据业务逻辑去区分"""title = models.CharField(max_length=32, verbose_name="学位课程名字")def __str__(self):return self.titleclass Meta:verbose_name = "05-学位课程表"db_table = verbose_nameverbose_name_plural = verbose_nameclass CourseChapter(models.Model):"""课程章节表"""course = models.ForeignKey(to="Course", related_name="course_chapters")# 排序用的chapter = models.SmallIntegerField(default=1, verbose_name="第几章")title = models.CharField(max_length=32, verbose_name="课程章节名称")def __str__(self):return self.titleclass Meta:verbose_name = "06-课程章节表"db_table = verbose_nameverbose_name_plural = verbose_nameunique_together = ("course", "chapter")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至2个值,以备后续插入课时")section_type_choices = ((0, '文档'), (1, '练习'), (2, '视频'))free_trail = models.BooleanField("是否可试看", default=False)section_type = models.SmallIntegerField(default=2, choices=section_type_choices)section_link = models.CharField(max_length=255, blank=True, null=True, help_text="若是video,填vid,若是文档,填link")def __str__(self):return "%s-%s" % (self.chapter, self.title)class Meta:verbose_name = "07-课程课时表"db_table = verbose_nameverbose_name_plural = verbose_nameunique_together = ('chapter', 'section_link')class PricePolicy(models.Model):"""价格策略表"""content_type = models.ForeignKey(ContentType)object_id = models.PositiveIntegerField()# 关联course or degree_coursecontent_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个月'))valid_period = models.SmallIntegerField(choices=valid_period_choices)price = models.FloatField()def __str__(self):return "%s(%s)%s" % (self.content_object, self.get_valid_period_display(), self.price)class Meta:verbose_name = "08-价格策略表"db_table = verbose_nameverbose_name_plural = verbose_nameunique_together = ("content_type", 'object_id', "valid_period")class OftenAskedQuestion(models.Model):"""常见问题"""content_type = models.ForeignKey(ContentType)  # 关联course or degree_courseobject_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 "%s-%s" % (self.content_object, self.question)class Meta:verbose_name = "09-常见问题表"db_table = verbose_nameverbose_name_plural = verbose_nameunique_together = ('content_type', 'object_id', 'question')class Comment(models.Model):"""通用的评论表"""# 定位表content_type = models.ForeignKey(ContentType, blank=True, null=True)# 定位对象的idobject_id = models.PositiveIntegerField(blank=True, null=True)# 定位对象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.contentclass Meta:verbose_name = "10-评价表"db_table = verbose_nameverbose_name_plural = verbose_nameclass Account(models.Model):username = models.CharField(max_length=32, verbose_name="用户姓名")def __str__(self):return self.usernameclass Meta:verbose_name = "11-用户表"db_table = verbose_nameverbose_name_plural = verbose_nameclass CourseOutline(models.Model):"""课程大纲"""course_detail = models.ForeignKey(to="CourseDetail", related_name="course_outline")title = models.CharField(max_length=128)order = models.PositiveSmallIntegerField(default=1)# 前端显示顺序
content = models.TextField("内容", max_length=2048)def __str__(self):return "%s" % self.titleclass Meta:verbose_name = "12-课程大纲表"db_table = verbose_nameverbose_name_plural = verbose_nameunique_together = ('course_detail', 'title')
课程模块表结构

media配置

图片位置需要在settings配置下

# media配置
MEDIA_URL = "media/"
MEDIA_ROOT = os.path.join(BASE_DIR, "media")
media 在settings配置下
from django.conf.urls import url, include
from django.contrib import admin
from app import settings
from django.views.static import serveurlpatterns = [url(r'^admin/', admin.site.urls),url(r'^api/course/', include("course.urls")),# media路径配置url(r'media/(?P<path>.*)$', serve, {'document_root': settings.MEDIA_ROOT})
]
url也要加上

接口的编写

图片位置需要在settings配置下

我们表结构定下来以后,可以根据业务场景看需要哪些接口~~~

对于我们课程这个模块,所有的功能都是展示,基于数据展示的,我们通常称为数据接口~~

这种接口对于我们来说是最简单的~~因为我们只是从数据库拿数据~然后进行展示~~

我们来看下都需要哪些接口~~~

  -- 课程页面  有课程所有分类这个接口

  -- 课程页面  有展示课程的接口

  -- 点击课程进入课程详情页面,详情页面的数据接口~~

  -- 详情页面下的子路由对应子组件的数据接口

    -- 课程章节课时

    -- 课程的评论

    -- 课程的常见问题

这些所有的数据接口~~套路都是读取数据库,序列化数据,返回~~~

那主要就是用DRF的序列化组件~~那我们从路由~然后序列化组件~然后看视图~~

from django.conf.urls import url, include
from .views import CourseListView, CourseCategoryView, CourseDetailView, CourseChapterView
from .views import CourseCommentView, OftenAskedQuestionView# 在项目路由下做了一层分发
# url(r'^api/course/', include("course.urls")),
urlpatterns = [url(r"^$", CourseListView.as_view()),url(r"^category$", CourseCategoryView.as_view()),url(r"^detail/(?P<pk>\d+)$", CourseDetailView.as_view()),url(r"^(?P<pk>\d+)/chapters$", CourseChapterView.as_view()),url(r"^(?P<pk>\d+)/comment$", CourseCommentView.as_view()),url(r"^(?P<pk>\d+)/often-asked-question$", OftenAskedQuestionView.as_view()),
url
class CourseCategoryView(APIView):"""课程分类接口"""def get(self, request):queryset = Category.objects.all()ser_obj = CourseCategorySerializer(queryset, many=True)return Response(ser_obj.data)class CourseListView(APIView):"""查看所有免费课程的接口"""def get(self, request):category_id = request.query_params.get("category", 0)if category_id == 0:# 证明没有分类,可以拿所有的课程数据queryset = Course.objects.all().order_by("order")else:queryset = Course.objects.filter(category_id=category_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 = CourseDetail.objects.filter(course__id=pk).first()if course_detail_obj:ser_obj = CourseDetailSerializer(course_detail_obj)return Response(ser_obj.data)else:return Response({"code": "1001", "msg": "查询的课程不存在"})class CourseChapterView(APIView):"""课程章节接口"""def get(self, request, pk):# 首先我们要清楚数据结构# 我们要的是[章节一:{课时,课时2}]queryset = CourseChapter.objects.filter(course_id=pk).order_by("chapter")ser_obj = CourseChapterSerializer(queryset, many=True)return Response(ser_obj.data)class CourseCommentView(APIView):def get(self, request, pk):queryset = Course.objects.filter(pk=pk).first().course_comments.all()ser_obj = CourseCommentSerializer(queryset, many=True)return Response(ser_obj.data)class OftenAskedQuestionView(APIView):def get(self, request, pk):queryset = Course.objects.filter(pk=pk).first().often_ask_questions.all()ser_obj = OftenAskQuestionSerializer(queryset, many=True)return Response(ser_obj.data)
views
from rest_framework import serializers
from . import modelsclass CategorySerializers(serializers.ModelSerializer):class Meta:model = models.Categoryfields = "__all__"class CourseSerializers(serializers.ModelSerializer):# 有些字段自己重写level = serializers.CharField(source="get_level_display")price = serializers.SerializerMethodField()def get_price(self, obj):price_policy_obj = obj.price_policy.all().order_by("price").first()# print(obj)# print(type(price_policy_obj))return price_policy_obj.pricecourse_img = serializers.SerializerMethodField()def get_course_img(self, obj):return "http://127.0.0.1:8000/media/" + str(obj.course_img)class Meta:model = models.Coursefields = ["id", "title", "course_img", "brief", "level", "study_num", "is_free", "price"]class CourseDetailSerializer(serializers.ModelSerializer):# 自己获取字段title = serializers.SerializerMethodField()level = serializers.SerializerMethodField()study_num = serializers.SerializerMethodField()recommend_courses = serializers.SerializerMethodField()teachers = serializers.SerializerMethodField()outline = serializers.SerializerMethodField()  # 大纲price_policy = serializers.SerializerMethodField()def get_title(self, obj):return obj.course.titledef get_level(self, obj):return obj.course.get_level_display()def get_study_num(self, obj):return obj.course.study_numdef 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": teacher.id, "name": teacher.name, "brief": teacher.brief} for teacher in obj.teachers.all()]def get_outline(self, obj):return [{"id": item.id, "title": item.title, "content": item.content} for item inobj.course_outline.all().order_by("order")]def get_price_policy(self, obj):return [{"id": item.id, "valid_period": item.get_valid_period_display(), "price": item.price} for item inobj.course.price_policy.all().order_by("price")]class Meta:model = models.CourseDetail# fields = "__all__"exclude = ["course"]
serializers

我们的课程的视图还可以重写编写一下~~利用我们之前学的视图的封装的那些类~~

class CourseCategoryView(generics.ListAPIView):queryset = Category.objects.all()serializer_class = CourseCategorySerializer"""课程分类接口"""# def get(self, request):#     queryset = Category.objects.all()#     ser_obj = CourseCategorySerializer(queryset, many=True)#     return Response(ser_obj.data)class CourseChapterView(generics.RetrieveAPIView):queryset = CourseChapter.objects.all()serializer_class = CourseChapterSerializer# 指定过滤的类 用排序的过滤类filter_backends = (filters.OrderingFilter,)# 排序的字段ordering = ("chapter",)# def get(self, request, pk):#     # 首先我们要清楚数据结构#     # 我们要的是[章节一:{课时,课时2}]#     queryset = CourseChapter.objects.filter(course_id=pk).order_by("chapter")#     ser_obj = CourseChapterSerializer(queryset, many=True)#     return Response(ser_obj.data)
升级版视图

我们可以根据上面的更改的视图的示例~~来更改我们所有的视图~~小伙伴们~自己动起手来吧~~

我们课程这个模块下的数据接口我们就介绍这些~~

我们这里涉及课程图片~~用我们Django的mediaURL~~

Django的MEDIA配置

STATIC_URL = '/static/'
# Media配置
MEDIA_URL = "media/"
MEDIA_ROOT = os.path.join(BASE_DIR, "media")
settings
from django.conf.urls import url, include
from django.contrib import admin
from django.views.static import serve
from new_luffy import settingsurlpatterns = [url(r'^admin/', admin.site.urls),url(r'^api/course/', include("course.urls")),# media路径配置url(r'media/(?P<path>.*)$', serve, {'document_root': settings.MEDIA_ROOT})
]
urls

这样我们上传的图片~数据库存的是路径地址~~我们前端向后端的media路径发送请求~~

拿到我们想要的图片,视频等资源~~

转载于:https://www.cnblogs.com/clbao/p/9998141.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/250202.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

[tensorflow、神经网络] - 使用tf和mnist训练一个识别手写数字模型,并测试

参考 包含: 1.层级的计算、2.训练的整体流程、3.tensorboard画图、4.保存/使用模型、5.总体代码(含详细注释) 1. 层级的计算 如上图,mnist手写数字识别的训练集提供的图片是 28 * 28 * 1的手写图像,初始识别的时候,并不知道一次要训练多少个数据,因此输入的规模为 [None, 784].…

面向过程、面向函数、面向对象的区别浅谈

Python的面向过程、面向函数、面向对象的区别浅谈 转自--猎奇古今&#xff0c;加上其他 有人之前私信问我&#xff0c;python编程有面向过程、面向函数、面向对象三种&#xff0c;那么他们区别在哪呢&#xff1f; 面向过程就是将编程当成是做一件事&#xff0c;要按步骤完成&am…

[pytorch、学习] - 3.5 图像分类数据集

参考 3.5. 图像分类数据集 在介绍shftmax回归的实现前我们先引入一个多类图像分类数据集 本章开始使用pytorch实现啦~ 本节我们将使用torchvision包,它是服务于PyTorch深度学习框架的,主要用来构建计算机视觉模型。torchvision主要由以下几部分构成: torchvision.datasets: …

[pytorch、学习] - 3.6 softmax回归的从零开始实现

参考 3.6 softmax回归的从零开始实现 import torch import torchvision import numpy as np import sys sys.path.append("..") import d2lzh_pytorch as d2l3.6.1. 获取和读取数据 batch_size 256 train_iter, test_iter d2l.load_data_fashion_mnist(batch_si…

[pytorch、学习] - 3.7 softmax回归的简洁实现

参考 3.7. softmax回归的简洁实现 使用pytorch实现softmax import torch from torch import nn from torch.nn import init import numpy as np import sys sys.path.append("..") import d2lzh_pytorch as d2l3.7.1. 获取和读取数据 batch_size 256 train_iter…

[pytorch、学习] - 3.9 多重感知机的从零开始实现

参考 3.9 多重感知机的从零开始实现 import torch import numpy as np import sys sys.path.append("..") import d2lzh_pytorch as d2l3.9.1. 获取和读取数据 batch_size 256 train_iter, test_iter d2l.load_data_fashion_mnist(batch_size)3.9.2. 定义模型参…

C语言逗号运算符和逗号表达式基础总结

逗号运算符的作用&#xff1a; 1&#xff0c;起分隔符的作用&#xff1a; 定义变量用于分隔变量&#xff1a;int a,b输入或输出时用于分隔输出表列 printf("%d%d",a,b) 2,用于逗号表达式的顺序运算符 语法&#xff1a;表达式1&#xff0c;表达式2&#xff0c;...,表达…

[pytorch、学习] - 3.10 多重感知机的简洁实现

参考 3.10. 多重感知机的简洁实现 import torch from torch import nn from torch.nn import init import numpy as np import sys sys.path.append("..") import d2lzh_pytorch as d2l3.10.1. 定义模型 num_inputs, num_outputs, num_hiddens 784, 10, 256 # 参…

如何从 Android 手机免费恢复已删除的通话记录/历史记录?

有一个有合作意向的人给我打电话&#xff0c;但我没有接听。更糟糕的是&#xff0c;我错误地将其删除&#xff0c;认为这是一个骚扰电话。那么有没有办法从 Android 手机恢复已删除的通话记录呢&#xff1f;” 塞缪尔问道。如何在 Android 上恢复已删除的通话记录&#xff1f;如…

[pytorch、学习] - 3.11 模型选择、欠拟合和过拟合

参考 3.11 模型选择、欠拟合和过拟合 3.11.1 训练误差和泛化误差 在解释上述现象之前&#xff0c;我们需要区分训练误差&#xff08;training error&#xff09;和泛化误差&#xff08;generalization error&#xff09;。通俗来讲&#xff0c;前者指模型在训练数据集上表现…

[pytorch、学习] - 3.12 权重衰减

参考 3.12 权重衰减 本节介绍应对过拟合的常用方法 3.12.1 方法 正则化通过为模型损失函数添加惩罚项使学出的模型参数更小,是应对过拟合的常用手段。 3.12.2 高维线性回归实验 import torch import torch.nn as nn import numpy as np import sys sys.path.append("…

Scapy之ARP询问

引言 校园网中&#xff0c;有同学遭受永恒之蓝攻击&#xff0c;但是被杀毒软件查下&#xff0c;并知道了攻击者的ip也是校园网。所以我想看一下&#xff0c;这个ip是PC&#xff0c;还是路由器。 在ip视角&#xff0c;路由器和pc没什么差别。 实现 首先是构造arp报文&#xff0c…

转:org.apache.maven.archiver.MavenArchiver.getManifest错误

eclipse导入新的maven项目时&#xff0c;pom.xml第一行报错&#xff1a; org.apache.maven.archiver.MavenArchiver.getManifest(org.apache.maven.project.MavenProject, org.apache.maven.archiver.MavenArchiveConfiguration) 解决办法&#xff1a; 1、Help——>Install …

Codeforces Round #524 Div. 2 翻车记

A&#xff1a;签到。room里有一个用for写的&#xff0c;hack了一发1e8 1&#xff0c;结果用了大概600ms跑过去了。惨绝人寰。 #include<iostream> #include<cstdio> #include<cmath> #include<cstdlib> #include<cstring> #include<algorith…

[pytorch、学习] - 3.13 丢弃法

参考 3.13 丢弃法 过拟合问题的另一种解决办法是丢弃法。当对隐藏层使用丢弃法时,隐藏单元有一定概率被丢弃。 3.12.1 方法 3.13.2 从零开始实现 import torch import torch.nn as nn import numpy as np import sys sys.path.append("..") import d2lzh_pytorc…

[pytorch、学习] - 4.1 模型构造

参考 4.1 模型构造 让我们回顾以下多重感知机的简洁实现中包含单隐藏层的多重感知机的实现方法。我们首先构造Sequential实例,然后依次添加两个全连接层。其中第一层的输出大小为256,即隐藏层单元个数是256;第二层的输出大小为10,即输出层单元个数是10. 4.1.1 继承Module类来…

springboot---基本模块详解

概述 1.基于Spring框架的“约定优先于配置&#xff08;COC&#xff09;”理念以及最佳实践之路。 2.针对日常企业应用研发各种场景的Spring-boot-starter自动配置依赖模块&#xff0c;且“开箱即用”&#xff08;约定spring-boot-starter- 作为命名前缀&#xff0c;都位于org.…

[pytorch、学习] - 4.2 模型参数的访问、初始化和共享

参考 4.2 模型参数的访问、初始化和共享 在3.3节(线性回归的简洁实现)中,我们通过init模块来初始化模型的参数。我们也介绍了访问模型参数的简单方法。本节将深入讲解如何访问和初始化模型参数,以及如何在多个层之间共享同一份模型参数。 import torch from torch import nn…

IEnumerableT和IQueryableT区分

哎&#xff0c;看了那么多&#xff0c;这个知识点还是得开一个文章 IQueryable和IEnumerable都是延时执行(Deferred Execution)的&#xff0c;而IList是即时执行(Eager Execution) IQueryable和IEnumerable在每次执行时都必须连接数据库读取&#xff0c;而IList读取一次后&…

表的转置 行转列: DECODE(Oracle) 和 CASE WHEN 的异同点

异同点 都可以对表行转列&#xff1b;DECODE功能上和简单Case函数比较类似&#xff0c;不能像Case搜索函数一样&#xff0c;进行更复杂的判断在Case函数中&#xff0c;可以使用BETWEEN, LIKE, IS NULL, IN, EXISTS等等&#xff08;也可以使用NOT IN和NOT EXISTS&#xff0c;但是…