0


【Django+Vue3 线上教育平台项目实战】构建课程详情页与集成视频播放功能

在这里插入图片描述


文章目录


前言

    随着数字化教育的兴起,构建一个高效、用户友好的线上教育平台至关重要。本文将探讨如何使用Django与Vue.js 3结合,实现一个包含课程列表和课程详情页(含视频播放功能)的线上教育平台部分。本文主要介绍了如何设计数据库模型、处理数据查询、构建动态前端界面,并集成视频播放功能,为用户带来流畅的学习体验。


一、课程列表页面

获取所有一级分类,获取所有二级分类,获取所有课程(课程分页处理),点击方向和分类时获取此方向或者此分类下的数据信息

页面展示:
在这里插入图片描述

a.后端代码

url配置信息:

    path('nav/cates/', CategoryView.as_view()),#课程列表页面 /project-方向/一级分类 ----- 侧边栏-获取一二级分类 -
    path('nav/category/', CateView.as_view()),#课程列表页面 /project-二级分类#课程列表页面 / project
    path('courseSearch/', CourseSearch.as_view()),# /project页面--搜索课程---

获取方向、分类及课程信息:

# 2.获取一、二级分类classCategoryView(APIView):defget(self, request):# 查询所有一级分类:parent is null# query_set
        categories = CategoryModel.objects.filter(is_delete=0,parent__id__isnull=True)#query_set

        clist =[]#侧边栏 二级分类显示几个for category in categories:# 获取一级下面所有的二级分类,操作显示二级分类数据条数
            sondata = category.son.all()[0:2]#query_set# d对二级数据进行序列化操作
            son = SonCategorySerializer(sondata, many=True)
            clist.append({"id": category.id,"name": category.name,"son": son.data})return Response({"code":"200","data":clist})# 2.2 categoryId指定类别时,展示categoryId的子分类# 获取project页面的二级分类classCateView(APIView):defget(self, request):
        categoryId =int(request.GET.get('categoryId'))print(categoryId)if categoryId:
            category = CategoryModel.objects.filter(is_delete=False, parent_id=categoryId).all()else:
            category = CategoryModel.objects.filter(is_delete=False, parent_id__isnull=False).all()
        cates = SonCategorySerializer(category, many=True)return Response({"cood":200,"cateList": cates.data})# 8.搜索课程classCourseSearch(APIView):defget(self,request):
     topId =int(request.GET.get('topId'))
     cid =int(request.GET.get('cid'))
     page =int(request.GET.get('page'))
     pageSize =int(request.GET.get('pageSize'))print(page,pageSize)if topId:
         course = CourseModel.objects.filter(topid=topId)if cid:
         course = CourseModel.objects.filter(parent_id=cid)ifnot topId andnot cid:
         course = CourseModel.objects.all()

     courseTotal = CourseSerializer(course,many=True)

     coursePage = Paginator(course, pageSize)
     courseList = CourseSerializer(coursePage.get_page(page),many=True)return Response({"code":200,"pagetion":{"page":page,"pageSize":pageSize,"total":len(courseTotal.data)},'cousers': courseList.data})

b.前端代码

主要代码(方向、分类、课程的获取与展示)- src/views/Course.vue:

<divclass="type"><divclass="type-wrap"><!-- 方向: --><divclass="one warp"><spanclass="name">方向:</span><ulclass="items"><li:class="{cur: course.current_direction === 0}"><ahref=""@click.prevent="course.current_direction=0">全部</a></li><li:class="{cur: course.current_direction === direction.id}"v-for="direction in category.data"><ahref=""@click.prevent="course.current_direction=direction.id">{{direction.name}}</a></li></ul></div><!-- 分类 --><divclass="two warp"><spanclass="name">分类:</span><ulclass="items"><li:class="{cur: course.current_category === 0}"><ahref=""@click.prevent="course.current_category=0">不限</a></li><li:class="{cur: course.current_category === category.id}"v-for="category in category.cateList"><ahref=""@click.prevent="course.current_category=category.id">{{category.name}}</a></li></ul></div></div></div>
<!-- Main课程部分 --><divclass="main"><divclass="main-wrap"><divclass="filter clearfix"><divclass="sort l"><ahref="":class="{on:course.ordering==='-id'}"@click.prevent.stop="course.ordering=(course.ordering==='-id'?'':'-id')">最新</a><ahref="":class="{on:course.ordering==='-students'}"@click.prevent.stop="course.ordering=(course.ordering==='-students'?'':'-students')">销量</a><ahref="":class="{on:course.ordering==='-orders'}"@click.prevent.stop="course.ordering=(course.ordering==='-orders'?'':'-orders')">推荐</a></div><divclass="other r clearfix"><aclass="course-line l"href=""target="_blank">学习路线</a></div></div><ulclass="course-list clearfix"><!-- 遍历展示课程信息 --><liclass="course-card"v-for="course_info in category.course_list"><router-link:to="`/project/${course_info.id}`"><divclass="img"><img:src="course_info.picurl"alt=""></div><pclass="title ellipsis2">{{course_info.name}}</p><pclass="one"><span>{{ course_info.level }} · {{ course_info.sales }}人报名</span></p><pclass="two clearfix"><spanclass="price l red bold"v-if="course_info.price !== undefined">¥{{parseFloat(course_info.price).toFixed(2)}}</span><spanclass="price l red bold"v-else>¥{{parseFloat(course_info.price).toFixed(2)}}</span><spanclass="origin-price l delete-line"v-if="course_info.price !== undefined">¥{{parseFloat(course_info.price).toFixed(2)}}</span><el-popconfirmtitle="您确认添加当前课程加入购物车吗?"@confirm.prevent.stop="add_course_to_cart(course_info)"confirmButtonText="买买买!"cancelButtonText="误操作!"><template#reference><spanclass="add-shop-cart r"@click.stop.prevent=""><imgclass="icon imv2-shopping-cart"src="../assets/cart2.svg">加购物车</span></template></el-popconfirm></p></router-link></li></ul><!-- 分页功能 --><divclass="page"><divstyle="position: absolute;left: 50%;transform:translateX(-50%)"><el-paginationstyle="margin: auto"backgroundlayout="prev, pager, next":total='category.pageTion.total':page-size="category.pageTion.pageSize"@current-change="change"/></div></div></div></div>
import category from"../api/cetory.js";//++

category.get_category();
category.search_course(0,0,pageTion);
category.get_cate(0);

src/api/cetory.js:

import{ reactive }from"vue";import http from"../http";const category =reactive({data:[],// 方向 / 一级分类course_list:[],// 课程信息cateList:[],//二级分类pageTion:{},// 分页get_category(id){return http.get("/home/nav/cates/",{params:{cateid: id }}).then(response=>{//课程列表页面-project-获取方向(一级分类)// console.log("response.data.data*************/home/nav/cates/******************");// console.log(response.data.data);this.data = response.data.data;})},get_cate(categoryId){return http.get("/home/nav/category/",{params:{categoryId: categoryId }}).then(response=>{//课程列表页面-project-获取二级分类// console.log("response.data*********************/home/nav/category/***************************");// console.log(response.data);this.cateList = response.data.cateList;})},// 分页、搜索对应方向或分类的课程topid-->方向,cid-->分类search_course(topId, cid, page){const params ={topId: topId,cid: cid,page: page.page,pageSize: page.pageSize
        }return http.get(`/home/courseSearch/`,{ params }).then(response=>{
            console.log("response.data****************/home/courseSearch/*********************");
            console.log(response.data);this.course_list = response.data.cousers;this.pageTion = response.data.pagetion;})},})exportdefault category;

二、课程详情页面

a. 视频播放功能的集成

这里以七牛云服务器 (存储视频)+ vue-alipayer视频播放组件为例实现视频播放功能

1.获取上传视频的链接地址

具体操作步骤如下:

  • 1.七牛云注册登录:https://www.qiniu.com/
  • 2.点击对象存储:在这里插入图片描述
  • 3.创建存储空间:在这里插入图片描述
  • 4.创建成功:在这里插入图片描述
  • 5.上传一段视频用于在课程详情页面展示:在这里插入图片描述
  • 6.视频上传成功:在这里插入图片描述
  • 7.查看文件详情,可获得文件链接:在这里插入图片描述

2.集成在前端页面中

1>使用vue-alipayer视频播放组件
<AliPlayerV3ref="player"class="h-64 md:h-96 w-full rounded-lg"style="height: 100%;width: 100%;":source="course.info.course[0].video_url":cover="course.info.course_cover":options="options"@play="onPlay($event)"@pause="onPause($event)"@playing="onPlaying($event)"/>

source属性绑定的值,存放视频播放地址。(通过向后端发送请求获取数据库中的数据)

页面效果如下图:
在这里插入图片描述

2>使用video标签

可参考菜鸟教程:https://www.runoob.com/html/html-videos.html
示例代码:

<videowidth="320"height="240"controls><sourcesrc="http://sgigui51q.hb-bkt.clouddn.com/scenery.mp4"type="video/mp4"></video>

b. 页面主要内容展示

1.后端代码

1>分析表
  • 1.课程表CourseModel - 新加字段:total_jie(总节数)、hours(总时长)、vide_url(课程总介绍)、question常见问题
  • 2.课程章表 - 字段:id、名称、课程id(外键)、总节数、时间(用于页面展示)、总时长(秒)
  • 3.课程节表 - 字段:id、名称、课程id、章id(外键)、视频id、时间、时长(秒)
  • 4.教师表(课程表+teacher字段关联教师表) - 字段:id、姓名、头像、介绍、教授的课程
  • 5.用户表 - 字段:id、用户名、手机号、密码、积分、头像、个性签名
  • 6.评价表 - 字段:id、userid(外键)、courseid(外键)、评价、评分
  • 7.回复表 - 字段:id、回复人id(用户id)、评价id(外键)、内容
2>核心逻辑
# 0.课程详情classCourseDetailView(APIView):defget(self, request,id):
        r.delete_str("testdata")# 先取一下缓存
        test_data = r.get_str("testdata")if test_data:# 序列化 str-->json
            test_data = json.loads(test_data)return Response({"message":"test111111","data":test_data})

        course_list = CourseModel.objects.filter(id=id)
        ser = CourseSerializer(course_list, many=True)# 放入缓存 json-->str
        r.set_str('testdata',json.dumps(ser.data))return Response({"message":"test22222222222","code":"200","data":ser.data})# 1.获取章节信息classChaptersView(APIView):defget(self, request,id):# 根据课程id查对应章节
        course = CourseModel.objects.filter(id=id).first()# course + chapters
        chapt = course.chapters.all()
        ser = ChaptersSerializer(chapt, many=True)return Response({"code":"200","data": ser.data})#2.评论及其回复classCommentView(APIView):defget(self, request,id):# id---> 课程id ---对应查询课程下面的评论
        comments = CommentModel.objects.filter(course_id=id)
        comments_ser = CommentsSerializer(comments, many=True)return Response({"code":"200","data": comments_ser.data})

2.前端代码

课程详情页面src/views/Info.vue:

<template><divclass="detail"><Header/><!-- 主体内容 --><divclass="main"><!-- 课程详情 -上半部分 --><divclass="course-info"><divclass="wrap-left"><!-- 视频播放器 --><AliPlayerV3ref="player"class="h-64 md:h-96 w-full rounded-lg"style="height: 100%;width: 100%;":source="course.info.course[0].video_url":cover="course.info.course_cover":options="options"@play="onPlay($event)"@pause="onPause($event)"@playing="onPlaying($event)"/></div><divclass="wrap-right"><h3class="course-name">{{course.info.course[0].name}}</h3><pclass="data">
              {{course.info.course[0].sales}}人在A学&nbsp;&nbsp;&nbsp;&nbsp;
              课程总时长:{{course.info.pub_lessons}}课时/{{course.info.lessons}}课时
              &nbsp;&nbsp;&nbsp;&nbsp;
              难度:{{course.info.course[0].level}}
            </p><divclass="sale-time"v-if="!course.info.discount.type"><pclass="sale-type">课程价格 ¥{{parseFloat(course.info.course[0].price).toFixed(2)}}</p></div><pclass="course-price"v-if="course.info.discount.price !== undefined"><span>活动价</span><spanclass="discount">¥{{parseFloat(course.info.discount.price).toFixed(2)}}</span><spanclass="original">¥{{parseFloat(course.info.price).toFixed(2)}}</span></p><pclass="course-price"v-if="course.info.credit>0"><span>抵扣积分</span><spanclass="discount">{{course.info.credit}}</span></p><divclass="buy"><divclass="buy-btn"><buttonclass="buy-now">立即购买</button><buttonclass="free">免费试学</button></div><el-popconfirmtitle="您确认添加当前课程加入购物车吗?"@confirm="add_course_to_cart"confirmButtonText="买买买!"cancelButtonText="误操作!"><template#reference><divclass="add-cart"><imgsrc="../assets/cart-yellow.svg"alt="">加入购物车</div></template></el-popconfirm></div></div></div><!-- 课程标签、课程选项卡 -中间部分 --><divclass="course-tab"><ulclass="tab-list"><li:class="course.tabIndex===1?'active':''"@click="course.tabIndex=1">详情介绍</li><li:class="course.tabIndex===2?'active':''"@click="course.tabIndex=2">课程章节 <span:class="course.tabIndex!==2?'free':''"v-if="course.info.can_free_study">(试学)</span></li><li:class="course.tabIndex===3?'active':''"@click="course.tabIndex=3">用户评论 </li><li:class="course.tabIndex===4?'active':''"@click="course.tabIndex=4">常见问题</li></ul></div><!-- 课程内容 -章节-下半部分 --><!-- 章节:{{course.chapter_list[0].name}} --><divclass="course-content"><!-- 选项卡-内容 --><divclass="course-tab-list"><!-- 选项卡1:详情介绍 --><divclass="tab-item"v-if="course.tabIndex===1"v-html="course.info.course[0].describe"></div><!-- 选项卡2:课程章节 --><divclass="tab-item"v-if="course.tabIndex===2"><divclass="tab-item-title"><pclass="chapter">课程章节</p><pclass="chapter-length">共{{course.chapter_list.length}}章 {{course.info.course[0].hours}}个课时</p></div><divclass="chapter-item"v-for="chapter,index in course.chapter_list":key="index"><pclass="chapter-title"><imgsrc="../assets/1.svg"alt="">第{{chapter.id}}章·{{chapter.name}}</p><divclass="chapter-title"style="padding-left: 2.4rem;"v-if="chapter.summary"v-html="chapter.summary"></div><!-- jie:{{chapter.sections}} --><ulclass="lesson-list"><liclass="lesson-item"v-for="lesson,index in chapter.sections":key="index"><pclass="name"><spanclass="index">{{chapter.orders}}-{{lesson.orders}}</span>
                      {{lesson.name}}
                      <spanclass="free"v-if="lesson.free_trail">免费</span></p><pclass="time">{{lesson.duration}} <imgsrc="../assets/chapter-player.svg"></p><buttonclass="try"v-if="lesson.free_trail">立即试学</button><buttonclass="try"v-else>购买课程</button></li></ul></div></div><!-- 选项卡3:用户评论 --><divclass="tab-item"v-if="course.tabIndex===3"><h2>用户评论</h2><divclass="teacher-content"><divclass="cont1"><imgstyle="border-radius: 50%;":src="course.comments_list[0].user.avatar"><pclass="teacher-name">{{course.comments_list[0].user.username}}</p></div><divclass="narrative"v-html="course.comments_list[0].message"></div></div></div><!-- 选项卡4:常见问题 --><divclass="tab-item"v-if="course.tabIndex===4"><h2>常见问题</h2><divv-html="course.info.course[0].question"></div></div></div><!-- 课程旁边的老师 --><!-- 教师:{{course.info.course[0].teacher}} --><divclass="course-side"><divclass="teacher-info"><h4class="side-title"><span>授课老师</span></h4><divclass="teacher-content"><divclass="cont1"><imgstyle="border-radius: 50%;":src="course.info.course[0].teacher.avatar"><divclass="name"><pclass="teacher-name">{{course.info.course[0].teacher.name}}</p><pclass="teacher-title">{{course.info.course[0].teacher.get_role_display}}角色:教师,教授的课程:{{course.info.course[0].teacher.courses}}</p></div></div><divclass="narrative"v-html="course.info.course[0].teacher.introduce"></div></div></div></div></div></div><Footer/></div></template>

课程详情src/api/course.js:

get_course(){// 获取课程详情return http.get(`/info/courses/${this.course_id}/`).then(response=>{
      console.log("response.data:**************/info/courses/*******************");
      console.log(response.data);this.info.course = response.data.data;returnthis.get_course_chapters();})},get_course_chapters(){// 获取指定课程的章节列表return http.get(`/info/chapters/${this.course_id}/`).then(response=>{// console.log("response.data---*******************/info/chapters********************");// console.log(response.data);this.chapter_list = response.data.data;})},get_comments_list(){// 获取对应课程下面的评论信息return http.get(`/info/comments/${this.course_id}/`).then(response=>{
      console.log("response.data-----------/info/comments/*****************");
      console.log(response.data);
      console.log(response.data.data);this.comments_list = response.data.data;})},

3.效果图

  • 详情介绍在这里插入图片描述
  • 课程章节在这里插入图片描述
  • 用户评论在这里插入图片描述
  • 常见问题在这里插入图片描述

在这里插入图片描述

标签: django 音视频 python

本文转载自: https://blog.csdn.net/m0_48173416/article/details/140386676
版权归原作者 么凹猫' 所有, 如有侵权,请联系我们删除。

“【Django+Vue3 线上教育平台项目实战】构建课程详情页与集成视频播放功能”的评论:

还没有评论