美文网首页
django项目--在线播放

django项目--在线播放

作者: 昆仑草莽 | 来源:发表于2019-08-27 15:28 被阅读0次

    在线课堂

    一、功能需求分析

    1. 分析

    在线直播,或点播设计到视频的存储,转码,加密,播放很多细节,个人单独开发不现实。本项目的在线课堂选择在线播放视频的形式。实际项目中一般选择云点播或者内嵌视频网站的方式进行。本项目选择是用百度云VOD点播来实现。

    2. 功能

    • 视频展示页面

    • 视频播放详情

    二、模型设计

    1. 表字段分析

    • 老师表

      • 姓名

      • 职称

      • 简介

      • 头像

    • 课程分类表

      • 名称
    • 课程表

      • 课程名称

      • 封面

      • 视频地址

      • 时长

      • 简介

      • 大纲

      • 老师

      • 分类

    2.模型定义

    在course/models.py中定义如下模型

    from django.db import models
    ​
    from utils.models import BaseModel
    ​
    ​
    class Teacher(BaseModel):
     name = models.CharField('讲师姓名', max_length=150, help_text='讲师姓名')
     title = models.CharField('职称', max_length=150, help_text='职称')
     profile = models.TextField('简介', help_text='简介')
     photo = models.URLField('头像url', default='', help_text='头像url')
    ​
     class Meta:
     db_table = 'tb_teachers'
     verbose_name = '讲师'
     verbose_name_plural = verbose_name
    ​
     def __str__(self):
     return self.name
    ​
    ​
    class CourseCategory(BaseModel):
     name = models.CharField('课程分类名', max_length=100, help_text='课程分类名')
    ​
     class Meta:
     db_table = 'tb_course_category'
     verbose_name = '课程分类'
     verbose_name_plural = verbose_name
    ​
     def __str__(self):
     return self.name
    ​
    ​
    class Course(BaseModel):
     title = models.CharField('课程名', max_length=150, help_text='课程名')
     cover_url = models.URLField('封面url', help_text='封面url')
     video_url = models.URLField('课程视频url', help_text='课程视频url')
     duration = models.DurationField('课程时长', help_text='课程时长')
     profile = models.TextField('课程简介', null=True, blank=True, help_text='课程简介')
     outline = models.TextField('课程大纲', null=True, blank=True, help_text='课程大纲')
     teacher = models.ForeignKey('Teacher', on_delete=models.SET_NULL, null=True, blank=True)
     category = models.ForeignKey('CourseCategory', on_delete=models.SET_NULL, null=True, blank=True)
    ​
     class Meta:
     db_table = 'tb_course'
     verbose_name = '课程'
     verbose_name_plural = verbose_name
    ​
     def __str__(self):
     return self.title
    

    三、百度云VOD音视频点播

    1. 开通百度VOD音频点播功能

    1. 注册后登陆首页,找到vod服务


    开通即送55元包


    2.添加媒资

    官方使用说明

    1563342650830.png 1563343001477.png 1563343108603.png

    3.导入测试数据

    # 在mysql数据库中添加自己的测试数据
    INSERT INTO `tb_teachers`
    (create_time, update_time, is_delete, name, title,`profile`,photo)
     VALUES
     ( '2019-07-17 14:26:05.000000', '2019-07-17 14:26:09.000000', '0', '心蓝', 'python高级讲师', 'python学院最帅的老师', '/media/xinlan.jpg');
    ​
    # 导入课程分类数据
    INSERT INTO `tb_course_category` VALUES ('1', '2019-07-17 14:34:33.000000', '2019-07-17 14:34:36.000000', '0', 'python基础');
    INSERT INTO `tb_course_category` VALUES ('2', '2019-07-17 14:34:52.000000', '2019-07-17 14:34:55.000000', '0', 'python高级');
    INSERT INTO `tb_course_category` VALUES ('3', '2019-07-17 14:35:20.000000', '2019-07-17 14:35:16.000000', '0', 'python框架');
    ​
    # 导入课程数据
    insert into tb_course (title, cover_url, video_url, duration, `profile`, outline, teacher_id, category_id, create_time, update_time, is_delete) values
    ('你的测试视频1名称', '你的测试视频缩略图URL', '你的测试视频URL', 212000000, '你的测试视频简介', '你的视频大纲', 1, 2, now(), now(), 0),
    ​
    ('你的测试视频2名称', '你的测试视频缩略图URL', '你的测试视频URL', '你的测试视频时长整数表示微秒', '你的测试视频简介', '你的视频大纲', 1, 2, now(), now(), 0);
    

    四、视频展示列表

    1.接口设计

    1. 接口说明:
    类目 说明
    请求方法 GET
    url定义 /course/
    参数格式 无参数
    1. 返回结果:

      文档下载页面

    2.后端代码

    1. 视图
    # 在course/views.py文件下创建如下视图
        from django.shortcuts import render, Http404
        from django.views import View
        ​
        from . import models
        ​
        ​
        def course_list(request):
         """
         在线课程列表
         url:/course/
         :param request:
         :return:
         """
         courses = models.Course.objects.only('title', 'cover_url', 'teacher__title', 'teacher__name').filter(
         is_delete=False).select_related(
         'teacher')
         return render(request, 'course/course.html', context={'courses': courses})
    
    1. 路由
    # 在course/urs.py中定义如下路由
        from django.urls import path
        ​
        from . import views
        ​
        app_name = 'course'
        ​
        urlpatterns = [
         path('', views.course_list, name='index'),
        ]
    

    3.前端代码

    1. html
    <!-- 创建模板templates/course/course.html -->
        {% extends 'base/base.html' %}
        {% load static %}
        {% block title %}在线课堂{% endblock %}
        {% block link %}
         <link rel="stylesheet" href="{% static 'css/course/course.css' %}">
        {% endblock %}
        {% block main_start %}
         <main id="course-container">
         <div class="w1200">
         <ul class="course-list">
         {% for course in courses %}
         <li class="course-item">
         <a href="{% url 'course:course_detail' course.id %}">
         <img class="course-img" src="{{ course.cover_url }}"
         alt="{{ course.title }}">
         <div class="course-content">
         <p class="course-info">{{ course.title }}</p>
         <p class="course-author">{{ course.teacher.name}}({{ course.teacher.title }})</p>
         <p class="course-price free">免费</p>
         </div>
         </a>
         </li>
         {% endfor %}
         </ul>
         </div>
         </main>
        {% endblock %}
    
    2.  css
    
            /* ==== 修改course.css如下 ====*/
            /* ========== top-wrap start =========  */
            #top-wrap {
             background: #fff;
             line-height: 60px;
             box-shadow: 0 4px 4px rgba(0,0,0,.1);
            }
            #top-wrap .top-title {
             float: left;
             font-size: 22px;
             margin-right: 140px;
            ​
            }
            #top-wrap .top-nav {
             display: flex;
             justify-content: space-between;
             width: 400px;
             color: #878787;
             font-size: 18px;
            }
            #top-wrap .top-nav li.active {
             color: #212121;
            }
            #top-wrap .top-nav  li:hover {
             text-shadow: 1px 1px 2px #212121;
            }
            /* ========== top-wrap end =========  */
            /* ========== course-container  start =========  */
            #course-container {
             flex: 1;
            }
            #course-container .course-list {
             display: flex;
             flex-flow: row wrap;
             margin-bottom: 20px;
            }
            #course-container .course-list .course-item {
             margin: 20px;
             width: 260px;
             height: 260px;
             background: #fff;
             position: relative;
             /* float: left; */
            }
            .course-list .course-item .course-img {
             width: 100%;
             height: 61.8%;
            }
            .course-list .course-item .course-content {
             padding: 0 20px;
             height: 150px;
             box-sizing: border-box;
            }
            .course-list .course-item:hover {
             box-shadow: 0 4px 8px rgba(0,0,0,.1);
            }
            .course-item .course-content .course-info {
             font-size: 16px;
             line-height: 1.5;
             max-height: 50px;
             overflow: hidden;
            }
            .course-item .course-content .course-author{
             color: #848383;
             font-size: 14px;
             line-height: 36px;
             overflow: hidden;
             text-overflow: ellipsis;
             white-space: nowrap;
            }
            .course-item .course-content .course-price {
             position: absolute;
             bottom: 10px;
             right: 21px;
             font-size: 16px;
             line-height: 30px;
             color: #6fa026;
            ​
            }
            .course-item .course-content .course-price span{
             font-size: 14px;
            }
            .course-item .course-content .course-price.free {
             color: green;
             float: right;
            }
            /* ========== course-container  end =========  */
            ​
    

    五、视频播放详情页面

    1.接口设计

    1. 接口说明:
    类目 说明
    请求方法 GET
    url定义 /course/<int:course_id>/
    参数格式 路径参数
    1. 参数说明:
    参数名 类型 是否必须 描述
    course_id 整数 视频id
    1. 返回结果:

      视频播放详情页面

    2. 后端代码

    1. 视图
        # 在course/views.py文件下创建如下视图
        class CourseDetailView(View):
         """
         课程详情视图
         url:/course/<int:course_id>/
         """
        ​
         def get(self, request, course_id):
         course = models.Course.objects.only('title', 'cover_url', 'video_url', 'profile', 'outline', 'teacher__name',
         'teacher__photo', 'teacher__title', 'teacher__profile').select_related(
         'teacher').filter(is_delete=False, id=course_id).first()
        ​
         if course:
        ​
         return render(request, 'course/course_detail.html', context={'course': course})
         else:
         return Http404('此课程不存在')
        
    
    1. 路由
        # 在course/urs.py中添加如下路由
        path('<int:course_id>/', views.CourseDetailView.as_view(), name='course_detail')
    

    3.前端代码

    1. html
        <!-- 创建模板templates/course/course_detail.html -->
    {% extends 'base/base.html' %}
    {% load static %}
    {% block title %}视频详情-{{ course.title }}{% endblock %}
    {% block link %}
        <link rel="stylesheet" href="{% static 'css/course/course-detail.css' %}">
    {% endblock %}
    {% block main_start %}
        <main id="main">
            <div class="w1200">
                <div class="course-contain">
                    <div class="course-top-contain">
                        <h4 class="course-title">{{ course.title }}</h4>
                        <div class="course-other clearfix">
                            <div class="share">
                                 <i></i>
                                <span>分享</span>
                                <div class="share-list">
                                        <div class="bshare-custom icon-medium"><div class="bsPromo bsPromo2"></div><a title="分享到QQ空间" class="bshare-qzone"></a><a title="分享到新浪微博" class="bshare-sinaminiblog"></a><a title="分享到QQ好友" class="bshare-qqim" href="javascript:void(0);"></a><a title="分享到微信" class="bshare-weixin" href="javascript:void(0);"></a><a title="更多平台" class="bshare-more bshare-more-icon more-style-addthis"></a><span class="BSHARE_COUNT bshare-share-count" style="float: none;">62.9K</span></div><script type="text/javascript" charset="utf-8" src="http://static.bshare.cn/b/buttonLite.js#style=-1&amp;uuid=&amp;pophcol=2&amp;lang=zh"></script><script type="text/javascript" charset="utf-8" src="http://static.bshare.cn/b/bshareC0.js"></script>
                                </div>
                            </div>
                            <div class="buy-list">
                                <span class="price">免费</span>
                            </div>
                        </div>
                    </div>
    
                    <div class="course-video" id="course-video">
                        <span class="course-data" style="display: none" data-video-url="{{ course.video_url }}"
                              data-cover-url="{{ course.cover_url }}"></span>
                    </div>
    
                    <div class="course-bottom-contain">
                        <div class="course-detail-list">
                            <div class="course-item clearfix">
                                <h5 class="course-title">{{ course.teacher.name }}</h5>
                                <div class="teacher-box clearfix">
                                    <img src="{{ course.teacher.photo }}" alt="{{ course.teacher.name }}"
                                         title="{{ course.teacher.name }}" class="teacher-avatar">
                                    <div class="teacher-info">
                                        <p class="teacher-name">{{ course.teacher.name }}</p>
                                        <p class="teacher-identify"> {{ course.teacher.title }}</p>
                                    </div>
                                </div>
                                <div class="item-content">
                                    {{ course.teacher.profile }}
                                </div>
                            </div>
                            <div class="course-item clearfix">
                                <h5 class="course-title">课程简介</h5>
                                <div class="item-content">
                                    {{ course.profile }}
                                </div>
                            </div>
                            <div class="course-item clearfix">
                                <h5 class="course-title">课程大纲</h5>
                                <div class="item-content">
                                    <p>{{ course.outline }}</p>
                                </div>
                            </div>
                            <div class="course-item clearfix">
                                <h5 class="course-title">帮助中心</h5>
                                <div class="item-content">
                                    <p>1. 购买后的课程在线可反复观看学习,视频有效期以具体课程信息为准。 </p>
                                    <p>2. 课程暂不支持下载观看,均为在线观看视频。 </p>
                                    <p>3. 课程一经购买,不可转让、不可退款;仅限购买账号观看。</p>
                                    <p>4. 如有问题请咨询客服: 400-1567-315 </p>
                                </div>
                            </div>
                            <div class="course-item clearfix">
                                <h5 class="course-title">关于潭州课堂</h5>
                                <div class="item-content">
                                    湖南潭州教育网络科技有限公司拥有千余人的优秀师资团队,是一家师资丰富、教育产品类别众多的在线培训公司。公司总部座落于美丽的星城长沙,2015年9月正式入驻芯城科技园目前拥有近两万平米办公面积。
                                    在潭州学习的学员已突破1000万人次在线学员覆盖全球,包括中国、加拿大、日本、美国、韩国等诸多国家。
                                </div>
                            </div>
    
                        </div>
                        <div class="course-side">
                            <h4 class="side-title">推荐课程</h4>
                        </div>
                    </div>
                </div>
            </div>
        </main>
    
    {% endblock %}
    {% block script %}
        <script src="https://cdn.bdstatic.com/jwplayer/latest/cyberplayer.js"></script>
        <script src="{% static 'js/course/course_detail.js' %}"></script>
    {% endblock %}
    
    
        ​
    
    1. js
        // 创建js文件 static/js/course/course.js
        $(function () {
          let $course_data = $(".course-data");
          let sVideoUrl = $course_data.data('video-url');
          let sCoverUrl = $course_data.data('cover-url');
    
          let player = cyberplayer("course-video").setup({
            width: '100%',
            height: 650,
            file: sVideoUrl,
            image: sCoverUrl,
            autostart: false,
            stretching: "uniform",
            repeat: false,
            volume: 100,
            controls: true,
            ak: '你自己的ak'
          });
    
        });
        
    
    3.  css
    
            /*== 修改course_detail.css 代码如下===*/
            #main {
                flex: 1;
            }
    
            .course-contain {
                width: 100%;
            }
    
            .course-contain .course-top-contain, #course-video{
                width: 100%;
                background: #fff;
                /*padding:0 20px;*/
            }
            .course-top-contain .course-title {
                font-size: 30px;
                line-height: 2.5;
                margin: 0 20px;
            }
    
            .course-top-contain .course-other {
                line-height: 3.5;
                margin: 0 20px;
            }
            .course-other  .share {
                float: left;
            }
            .share span {
                 margin-right: 8px;
            }
            .share i {
                    display: inline-block;
                vertical-align: middle;
                width: 14px;
                height: 14px;
                margin-right: 5px;
                background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA4AAAAOCAYAAAAfSC3RAAABM0lEQVQokY2Sr0tEQRSFv/dYsIiwYVFkg/deERZBbEaDiJpEBP8Ck6jYxCBuMlgNikGTIIjBIIhbBDGISUSwzIwW4wbtrmHnwWNxf5w099z7MXeYk1SrVbpJ1IrANjAKnAXvbgpdqaYegPF4Xha1hbSH2yQHZVrpCIpaCdj9p/WVxoFhUdsQtcVY94vaHhCAErAD/EboGTgoiNpYLAYiVAMmgU9gLnj3GP0ToAy8Bu8aBWArg6JmgbXg3VF+t+BdHahndQo0WvZvAFed3p6Bh8B3zvsB7kRtKj8oamOiNiFqCUAavHsHKsAmMAMMAtfAvahdiFpZ1NaBN+AFeBK1YtIuOaI2AhwD00AC9OXa+23/MXj3EbybB1ZbIIChrskJ3p0DtRb7stesLtEMQQU4Dd7d/gHKLE8gSrHhJgAAAABJRU5ErkJggg==);
            }
            .share .share-list{
                display: none;
                /*width: 130px;*/
                position: relative;
                background: #fff;
                text-align: center;
                line-height: 45px;
                left: 8px;
                /*box-shadow: 0 1px 2px #ccc;*/
                /*border: 1px solid #ddd;*/
                border-radius: 5px;
                z-index: 1;
            }
            .share:hover .share-list{
                display: inline-block;
            }
            .share-list:after{
                content: "";
                border: 12px solid transparent;
                border-right-color: #eee;
                position: absolute;
                top: 0px;
                left: -25px;
            }
            .share-list a{
                cursor: pointer;
            }
            .share-list a img{
                vertical-align: middle;
            }
            .course-other .buy-list {
                float: right;
            }
    
            .price {
                color: #f76363;
                float: right;
                margin-right: 20px;
                line-height: 40px;
                font-size: 20px;
            }
    
            .buy-btn {
                background-color: #ff8d3f;
                border: none;
                width: 120px;
                text-align: center;
                line-height: 40px;
                color: #fff;
                border-radius: 5px;
                font-size: 16px;
                float: right;
            }
    
            .course-video {
                border-top: 1px solid #ddd;
                height: 400px;
            }
    
            .course-bottom-contain {
                width: 100%;
                margin-top: 30px;
            }
    
            .curse-bottom-contain {
                margin-top: 30px;
                width: 100%;
            }
    
            .course-detail-list {
                width: 800px;
                float: left;
            }
    
            .course-detail-list .course-item {
                margin-bottom: 20px;
                background-color: #fff;
                padding: 20px;
            }
    
            .course-item .course-title{
                border-left: 6px solid #5b86db;
                padding: 0 10px;
                color: #202020;
                font-size: 18px;
            }
    
            .course-item .teacher-box {
                margin-top: 20px;
            }
    
            .teacher-box  .teacher-avatar {
                width: 62px;
                height: 62px;
                border-radius: 50%;
                float: left;
            }
    
            .teacher-box .teacher-info {
                float: left;
                margin-left: 10px;
                position: relative;
                font-size: 16px;
                color: #696969;
                height: 62px;
                width: 90%;
            }
    
            .teacher-name {
                position: absolute;
                left: 0;
                top: 8px;
            }
            .teacher-identify {
                position: absolute;
                bottom: 8px;
                left: 0;
            }
    
            .item-content {
                font-size: 14px;
                color: #888;
                line-height: 2em;
                margin-top: 20px;
            }
    
            .item-course-title {
                font-size: 18px;
                color: #202020;
                float: left;
                line-height: 40px;
            }
    
            .item-buy-list {
                float: right;
                margin-top: 0;
            }
    
            .course-side {
                float: right;
                width: 360px;
                background-color: #fff;
                padding: 20px;
                padding-bottom: 0;
                box-sizing: border-box;
            }
            .course-side  .side-title {
                font-size: 18px;
                line-height: 2.4;
            }
    
           
    

    相关文章

      网友评论

          本文标题:django项目--在线播放

          本文链接:https://www.haomeiwen.com/subject/heyeectx.html