IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> JavaScript知识库 -> Django在线教育平台项目完整实现(二) -> 正文阅读

[JavaScript知识库]Django在线教育平台项目完整实现(二)

五、课程相关功能开发

1.课程列表页面的显示与排序

修改一下的之前页面的url跳转:
在templates/org-list.html中:

{% extends 'base.html' %}
{% load staticfiles %}
{% block title %}机构列表页-慕学在线网{% endblock %}
{% block custom_bread %}
<section>
    <div class="wp">
        <ul  class="crumbs">
            <li><a href="{% url 'index' %}">首页</a>></li>
            <li>课程机构</li>
        </ul>
    </div>
</section>

在templates/base.html中:

<ul>
    <li ><a href="{% url 'index' %}">首页</a></li>
    <li >
        <a href="{% url 'course:list' %}">
            公开课<img class="hot" src="{% static 'images/nav_hot.png' %}">
        </a>
    </li>
    <li >
        <a href="teachers-list.html">授课教师</a>
    </li>
    <li class="active" ><a href="{% url 'org:list' %}">授课机构</a></li>
</ul>

在templates/index.html中:(85行左右)

<a href="{% url 'course:list' %}">
    公开课<img class="hot" src="{% static 'images/nav_hot.png' %}">

将course相关的html页面拷贝到templates目录下,包括course-comment.html和course-detail.html和course-list.html和course-play.html和course-video.html

将templates/course-list.html修改为:

{% extends 'base.html' %}
{% load staticfiles %}
{% block title %}课程列表页-慕学在线网{% endblock %}
{% block custom_bread %}
<section>
    <div class="wp">
        <ul  class="crumbs">
            <li><a href="{% url 'index' %}">首页</a>></li>
            <li>公开课</li>
        </ul>
    </div>
</section>
{% endblock %}
{% block content%}
<section>
<div class="wp">
    <div class="list" style="margin-top:0;">
        <div class="left layout">
            <div class="head">
                <ul class="tab_header">
                    <li class="active"><a href="?sort=">最新 </a></li>
                    <li ><a href="?sort=hot">最热门</a></li>
                    <li ><a href="?sort=students">参与人数</a></li>
                </ul>
            </div>
            <div id="inWindow">
                <div class="tab_cont " id="content">
                <div class="group_list">
                    {% for course in all_courses.object_list %}
                        <div class="box">
                            <a href="course-detail.html">
                                <img width="280" height="350" class="scrollLoading" src="{{ MEDIA_URL }}{{ course.image }}"/>
                            </a>
                            <div class="des">
                                <a href="course-detail.html">
                                    <h2>{{ course.name }}</h2>
                                </a>
                                <span class="fl">时长:<i class="key">{{ course.learn_times }}</i></span>
                                <span class="fr">学习人数:{{ course.students }}&nbsp;&nbsp;</span>
                            </div>
                            <div class="bottom">
                                <a href="course-detail.html"><span class="fl">来自{{ course.course_org.name }}</span></a>
                                <span class="star fr  notlogin
                                    " data-favid="15">
                                    {{ course.fav_nums }}
                                </span>
                            </div>
                        </div>
                    {% endfor %}




                </div>
                <div class="pageturn">
            <ul class="pagelist">
                <!-- 如果有上一页 -->
                {% if all_courses.has_previous %}
                    <!-- querystring方法自动生成上一页的链接 -->
                    <li class="long"><a href="?{{ all_courses.previous_page_number.querystring }}">上一页</a></li>
                {% endif %}

                {% for page in all_courses.pages %}
                    {% if page %}
                        <!-- 如果为当前页 -->
                        {% ifequal page all_courses.number %}
                            <li class="active"><a href="?{{ page.querystring }}">{{ page }}</a></li>
                        <!-- 如果不为当前页 -->
                        {% else %}
                            <li><a href="?{{ page.querystring }}" class="page">{{ page }}</a></li>
                        {% endifequal %}
                    {% else %}
                        <li class="none">...</li>
                    {% endif %}
                {% endfor %}
                <!-- 如果还有下一页 -->
                {% if all_courses.has_next %}
                    <li class="long"><a href="?{{ all_courses.next_page_number.querystring }}">下一页</a></li>
                {% endif %}
            </ul>
        </div>
            </div>
            </div>
        </div>
        <div class="right layout">
            <div class="head">热门课程推荐</div>
            <div class="group_recommend">

                <dl>
                    <dt>
                        <a target="_blank" href="">
                            <img width="240" height="220" class="scrollLoading" src="../media/courses/2016/11/540e57300001d6d906000338-240-135_n0L8vbw.jpg"/>
                        </a>
                    </dt>
                    <dd>
                        <a target="_blank" href=""><h2> django与vuejs实战项目2</h2></a>
                        <span class="fl">难度:<i class="key">高级</i></span>
                    </dd>
                </dl>

                <dl>
                    <dt>
                        <a target="_blank" href="">
                            <img width="240" height="220" class="scrollLoading" src="../media/courses/2016/12/python面向对象.jpg"/>
                        </a>
                    </dt>
                    <dd>
                        <a target="_blank" href=""><h2> python面向对象</h2></a>
                        <span class="fl">难度:<i class="key">中级</i></span>
                    </dd>
                </dl>

                <dl>
                    <dt>
                        <a target="_blank" href="">
                            <img width="240" height="220" class="scrollLoading" src="../media/courses/2016/12/python文件处理.jpg"/>
                        </a>
                    </dt>
                    <dd>
                        <a target="_blank" href=""><h2> python文件处理</h2></a>
                        <span class="fl">难度:<i class="key">中级</i></span>
                    </dd>
                </dl>



            </div>
        </div>
    </div>
</div>
</section>
{% endblock %}

在apps/courses/views.py中:

from django.shortcuts import render
from django.views.generic.base import View
from pure_pagination import Paginator, PageNotAnInteger

from apps.courses.models import Course

# Create your views here.
# 获取课程列表信息
class CourseListView(View):
    def get(self, request, *args, **kwargs):
        # 根据添加时间进行倒序排列,最新的放在最前面
        all_courses = Course.objects.order_by("-add_time")

        # 课程排序
        # 如果未找到取空值
        sort = request.GET.get("sort", "")
        # 对应apps/courses/views.py中<<li class="{% if sort == 'students' %}active{% endif %}"><a href="?sort=students">参与人数</a></li>的参数
        if sort == "students":
            all_courses = all_courses.order_by("-students")
        elif sort == "hot":
            all_courses = all_courses.order_by("-click_nums")

        # 对课程机构数据进行分页
        try:
            page = request.GET.get('page', 1)
        except PageNotAnInteger:
            page = 1

        p = Paginator(all_courses, per_page=1, request=request)
        courses = p.page(page)

        return render(request, "course-list.html", {
            "all_courses": courses,
            "sort": sort
        })


配置到url中:
在apps/courses/文件夹下新建一个Python File命名为urls.py:

from django.conf.urls import url
from django.urls import path

from apps.courses.views import CourseListView

urlpatterns = [
    url(r'^list/$', CourseListView.as_view(), name="list"),
]

在MxOnline/urls.py中:

urlpatterns = [
    # 省略
    # 机构相关页面
    # 进行子url的管理
    url(r'^org/', include(('apps.organizations.urls', "organizations"), namespace="org")),

    # 课程相关页面
    url(r'^course/', include(('apps.courses.urls', "courses"), namespace="course")),

    # 用户相关操作
    # 省略

]

运行项目,在首页点击公开课便可进行跳转。

在后台管理系统中http://127.0.0.1:8000/xadmin/courses/course/添加一些课程信息,便可在页面上显示。

设置课程排序选项的选中状态:
在templates/course-list.html中:(21行左右)

<li class="{% if sort == '' %}active{% endif %}"><a href="?sort=">最新 </a></li>
<li class="{% if sort == 'hot' %}active{% endif %}"><a href="?sort=hot">最热门</a></li>
<li class="{% if sort == 'students' %}active{% endif %}"><a href="?sort=students">参与人数</a></li>

访问:http://127.0.0.1:8000/course/list/
点击最热门和参与人数可看到已完成排序,可在数据库中的courses_course表进行数据的比对。

2.右侧热门课程推荐

与最热门栏目排序保持一致
在apps/courses/views.py中:

from django.shortcuts import render
from django.views.generic.base import View
from pure_pagination import Paginator, PageNotAnInteger

from apps.courses.models import Course

# Create your views here.
# 获取课程列表信息
class CourseListView(View):
    def get(self, request, *args, **kwargs):
        # 根据添加时间进行倒序排列,最新的放在最前面
        all_courses = Course.objects.order_by("-add_time")
        # 右边栏,热门课程的展示,进行切片只展示前3个
        hot_courses = Course.objects.order_by("-click_nums")[:3]

        # 课程排序
        # 如果未找到取空值
        sort = request.GET.get("sort", "")
        # 对应apps/courses/views.py中<<li class="{% if sort == 'students' %}active{% endif %}"><a href="?sort=students">参与人数</a></li>的参数
        if sort == "students":
            all_courses = all_courses.order_by("-students")
        elif sort == "hot":
            all_courses = all_courses.order_by("-click_nums")

        # 对课程机构数据进行分页
        try:
            page = request.GET.get('page', 1)
        except PageNotAnInteger:
            page = 1

        p = Paginator(all_courses, per_page=1, request=request)
        courses = p.page(page)

        return render(request, "course-list.html", {
            "all_courses": courses,
            "sort": sort,
            "hot_courses": hot_courses
        })

在templates/course-list.html中:

<div class="right layout">
    <div class="head">热门课程推荐</div>
    <div class="group_recommend">
        {% for course in hot_courses %}
            <dl>
            <dt>
                <a target="_blank" href="">
                    <img width="240" height="220" class="scrollLoading" src="{{ course.image.url }}"/>
                </a>
            </dt>
            <dd>
                <a target="_blank" href=""><h2> {{ course.name }}</h2></a>
                <!-- 使用get_degree_display来显示degree字段对应的中文,而不是存储在数据库中的英文缩写 -->
                <span class="fl">难度:<i class="key">{{ course.get_degree_display }}</i></span>
            </dd>
        </dl>
        {% endfor %}
    </div>
</div>

设置上边栏目的选中状态:
在templates/base.html中:

<div class="wp">
    <ul>
        <li class="{% if request.path == '/' %}active{% endif %}"><a href="{% url 'index' %}">首页</a></li>
        <!-- 切片取前7个,以course开头 -->
        <li class="{% if request.path|slice:'7' == '/course' %}active{% endif %}">
            <a href="{% url 'course:list' %}">
                公开课<img class="hot" src="{% static 'images/nav_hot.png' %}">
            </a>
        </li>
        <li >
            <a href="teachers-list.html">授课教师</a>
        </li>
        <li class="{% if request.path|slice:'4' == '/org' %}active{% endif %}" ><a href="{% url 'org:list' %}">授课机构</a></li>
    </ul>
</div>

3.课程详情页面

在apps/courses/views.py中:

from django.shortcuts import render
from django.views.generic.base import View
from pure_pagination import Paginator, PageNotAnInteger

from apps.courses.models import Course
from apps.operations.models import UserFavorite

# Create your views here.

# 课程详情页面,获取课程详情
class CourseDetailView(View):
    def get(self, request, course_id, *args, **kwargs):
        course = Course.objects.get(id=int(course_id))
        # 点击课程时,为课程增加点击数
        course.click_nums += 1
        course.save()
        #获取收藏状态
        # 是否收藏课程
        has_fav_course = False
        # 是否收藏课程机构
        has_fav_org = False
        # 判断用户是否登录
        if request.user.is_authenticated:
            # fav_type=1代表收藏的为课程
            if UserFavorite.objects.filter(user=request.user, fav_id=course.id, fav_type=1):
                has_fav_course = True
            # fav_type=2代表收藏的为课程课程机构
            if UserFavorite.objects.filter(user=request.user, fav_id=course.course_org.id, fav_type=2):
                has_fav_org = True

        return render(request, "course-detail.html", {
            "course": course,
            "has_fav_course": has_fav_course,
            "has_fav_org": has_fav_org
        })
# 获取课程列表信息
# 省略

统计章节数:
在apps/courses/models.py中:

# 省略
    class Meta:
        verbose_name = "课程信息"
        verbose_name_plural = verbose_name

    def __str__(self):
        return self.name

    # 动态统计章节数
    def lesson_nums(self):
        return self.lesson_set.all().count()
    
# 设计第二个实体,继承BaseModel
# 省略

将templates/course-detail.html进行修改:

{% extends 'base.html' %}
{% load staticfiles %}
{% block title %}课程详情页-慕学在线网{% endblock %}
{% block custom_bread %}
<section>
    <div class="wp">
        <ul  class="crumbs">
            <!-- 可点击的面包器 -->
            <li><a href="{% url 'index' %}">首页</a>></li>
            <li><a href="{% url 'course:list' %}">公开课</a>></li>
            <li>课程详情</li>
        </ul>
    </div>
</section>
{% endblock %}
{% block content %}
    <section>
	<div class="wp">
		<div class="groupPurchase_detail detail">
			<div class="toppro">
				<div class="left">
					<div class="picbox">
						<div class="tb-booth tb-pic">
							<img width="440" height="445" src="{{ course.image.url }}" class="jqzoom" />
						</div>

					</div>
					<div class="des">
						<h1 title="django 从入门到精通体验开始了">{{ course.name }}</h1>
						<span class="key">{{ course.desc }}</span>
						<div class="prize">
							<span class="fl">难度:<i class="key">{{ course.get_degree_display }}</i></span>
							<span class="fr">学习人数:12</span>
						</div>
						<ul class="parameter">
							<li><span class="pram word3">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;长:</span><span>{{ course.learn_times }}</span></li>
                            <li><span class="pram word3">&nbsp;&nbsp;数:</span><span>{{ course.lesson_nums }}</span></li>
                            <li><span class="pram word3">课程类别:</span><span title="">{{ course.category }}</span></li>
							<li class="piclist"><span class="pram word4">学习用户:</span>

                                    <span class="pic"><img width="40" height="40" src="../media/image/2016/12/default_big_14.png"/></span>

							</li>
						</ul>
						<div class="btns">
							<div class="btn colectgroupbtn"  id="jsLeftBtn">
                                  {% if has_fav_course %}已收藏{% else %}收藏{% endif %}
                            </div>
                                <div class="buy btn" onClick="window.location.href='{% url 'course:lesson' course.id %}'"><a style="color: white">开始学习</a></div>
						</div>
					</div>
                    <div class="group-share-box">
                        <div class="bdsharebuttonbox"
                             data-text="django开始了"
                             data-desc="我在#慕课网#发现了"
                             data-comment=""
                             data-url="/group/groupdetail/15/">
                            <span class="fl">分享到:</span>
                            <a href="#" class="bds_more" data-cmd="more"></a>
                            <a title="分享到QQ空间" href="#" class="bds_qzone" data-cmd="qzone"></a>
                            <a title="分享到新浪微博" href="#" class="bds_tsina" data-cmd="tsina"></a>
                            <a title="分享到腾讯微博" href="#" class="bds_tqq" data-cmd="tqq"></a>
                            <a title="分享到人人网" href="#" class="bds_renren" data-cmd="renren"></a>
                            <a title="分享到微信" href="#" class="bds_weixin" data-cmd="weixin"></a>
                        </div>
                    </div>
				</div>
				<div class="right">
					<div class="head">
						<h1>授课机构</h1>
						<p>世界名校,课程权威</p>
					</div>
					<div class="pic">
                        <a href="{% url 'org:home' course.course_org.id %}">
                            <img width="150" height="80" src="{{ course.course_org.image.url }}"/>
                        </a>
                    </div>
					<a href="{% url 'org:home' course.course_org.id %}">
                        <h2 class="center" title="{{ course.course_org.name }}">{{ course.course_org.name }}</h2>
                    </a>
					<div class="btn  notlogin
					     "data-favid="14" id="jsRightBtn">
                         {% if has_fav_org %}已收藏{% else %}收藏{% endif %}
                    </div>
					<div class="clear">
						<ul>
                            <li>
                                <!-- 调用count方法来统计 -->
                                <span>&nbsp;&nbsp; 数:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;   {{ course.course_org.course_set.all.count }}</span>
                            </li>
                            <li>
                                <span>&nbsp;&nbsp; 数:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  {{ course.course_org.teacher_set.all.count }}</span>
                            </li>
							<li>所在地区:&nbsp;&nbsp;{{course.course_org.address}}</li>
                            {% if course.course_org.is_gold %}
							<li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;:
                                &nbsp;&nbsp;
								    <img title="金牌机构", src="{% static 'images/gold.pn' %}"/>
							</li>
                            {% endif %}
						</ul>
					</div>
				</div>
			</div>
		</div>
	</div>
</section>
    <section>
	<div class="wp">
		<div class="list groupPurchase_detail_pro">
			<div class="left layout">
				<div class="head">
					<ul class="tab_header">
						<li class="active">课程详情</li>
					</ul>
				</div>
				<div class="tab_cont tab_cont1">
                    {{ course.detail }}
				</div>
				<div class="tab_cont tab_cont2" >
					<div class="comment">
						<div class="comenlist">

	                    </div>
					</div>
				</div>
			</div>
			<div class="right layout">
				<div class="head">相关课程推荐</div>
                <div class="group_recommend">

                        <dl>
                            <dt>
                                <a target="_blank" href="">
                                    <img width="240" height="220" class="scrollLoading" src="../media/courses/2016/11/540e57300001d6d906000338-240-135_mvvGYHL.jpg"/>
                                </a>
                            </dt>
                            <dd>
                                <a target="_blank" href=""><h2> django实战项目</h2></a>
                                <span class="fl">学习时长:<i class="key">0</i></span>
                            </dd>
                        </dl>



                </div>
			</div>
		</div>
	</div>
</section>
{% endblock %}

在apps/courses/urls.py中:

from django.conf.urls import url
from django.urls import path

from apps.courses.views import CourseListView,CourseDetailView

urlpatterns = [
    # 课程列表页
    url(r'^list/$', CourseListView.as_view(), name="list"),
    # 课程详情页
    url(r'^(?P<course_id>\d+)/$', CourseDetailView.as_view(), name="detail"),
]

设置之前页面的跳转:
在templates/course-list.html中:
CTRL+R全局将
course-detail.html替换为{% url 'course:detail' course.id %}

运行项目。访问:http://127.0.0.1:8000/course/4/
即可看到课程详情页面已显示。

4.课程详情页面的收藏

在templates/course-detail.html中(末尾加):
此为Ajax请求

<script type="text/javascript">
//收藏分享
function add_fav(current_elem, fav_id, fav_type){
    $.ajax({
        cache: false,
        type: "POST",
        url:"{% url 'op:fav' %}",
        data:{'fav_id':fav_id, 'fav_type':fav_type},
        async: true,
        beforeSend:function(xhr, settings){
            xhr.setRequestHeader("X-CSRFToken", "{{ csrf_token }}");
        },
        success: function(data) {
            if(data.status == 'fail'){
                if(data.msg == '用户未登录'){
                    {# 若未登录,跳转到登录页面 #}
                    window.location.href="{% url 'login' %}";
                }else{
                    alert(data.msg)
                }
            }else if(data.status == 'success'){
                current_elem.text(data.msg)
            }
        },
    });
}
$(document).ready(function() {
    {# 对应左侧收藏按钮 #}
    $('#jsLeftBtn').on('click', function () {
        {# 调用add_fav方法,对后端接口发出数据请求#}
        add_fav($(this), {{ course.id }}, 1);
    });
});

$(document).ready(function() {
    {# 对应右侧收藏按钮 #}
	$('#jsRightBtn').on('click', function(){
		add_fav($(this), {{ course.course_org.id }}, 2);
	});
});

</script>

{% endblock %}

在课程详情页面点击左侧和右侧的收藏按钮便可以完成收藏。http://127.0.0.1:8000/course/4/

5.课程详情页面的相关课程推荐

根据model中的tag字段相同的来做推荐。
在apps/courses/views.py中:

# 课程详情页面,获取课程详情
# 省略
        # 判断用户是否登录
        if request.user.is_authenticated:
            # fav_type=1代表收藏的为课程
            if UserFavorite.objects.filter(user=request.user, fav_id=course.id, fav_type=1):
                has_fav_course = True
            # fav_type=2代表收藏的为课程课程机构
            if UserFavorite.objects.filter(user=request.user, fav_id=course.course_org.id, fav_type=2):
                has_fav_org = True
                
 # 通过课程的tag做课程的推荐
        tag = course.tag
        related_courses = []
        if tag:
            # 找标签相同的课程,取前3个。使用exclude方法排除当前课程,要去掉一批数据则使用__in,将列表中的数据全部去除
            related_courses = Course.objects.filter(tag=tag).exclude(id__in=[course.id])[:3]
            
        return render(request, "course-detail.html", {
            "course": course,
            "has_fav_course": has_fav_course,
            "has_fav_org": has_fav_org,
            "related_courses": related_courses
        })

在templates/course-detail.html中:

<div class="right layout">
    <div class="head">相关课程推荐</div>
    <div class="group_recommend">
        {% for course in related_courses %}
            <dl>
                <dt>
                    <a target="_blank" href="{% url 'course:detail' course.id %}">
                        <img width="240" height="220" class="scrollLoading" src="{{ course.image.url }}"/>
                    </a>
                </dt>
                <dd>
                    <a target="_blank" href="{% url 'course:detail' course.id %}"><h2> {{ course.name }}</h2></a>
                    <span class="fl">学习时长:<i class="key">{{ course.learn_times }}</i></span>
                </dd>
            </dl>
        {% endfor %}
    </div>
</div>

访问课程详情页面:http://127.0.0.1:8000/course/4/
便可看到相关课程推荐,若无显示可添加相同标签的课程。

一个课程可能对应多个tag,需要重新设计表。
在apps/courses/models.py中:

# 省略
    # 动态统计章节数
    def lesson_nums(self):
        return self.lesson_set.all().count()


# 针对一个课程可能对应多个tag情况重新设计一张tag表
class CourseTag(BaseModel):
    course = models.ForeignKey(Course, on_delete=models.CASCADE, verbose_name="课程")
    tag = models.CharField(max_length=100, verbose_name="标签")

    class Meta:
        verbose_name = "课程标签"
        verbose_name_plural = verbose_name

    def __str__(self):
        return self.tag


# 设计第二个实体,继承BaseModel
# 省略

在后台管理系统中进行配置,在apps/courses/adminx.py中:

import xadmin

from apps.courses.models import Course, Lesson, Video, CourseResource, CourseTag


# 省略

class CourseResourceAdmin(object):
    list_display = ['course', 'name', 'file', 'add_time']
    search_fields = ['course', 'name', 'file']
    list_filter = ['course', 'name', 'file', 'add_time']

class CourseTagAdmin(object):
    list_display = ['course', 'tag', 'add_time']
    search_fields = ['course', 'tag']
    list_filter = ['course', 'tag', 'add_time']


# 省略
xadmin.site.register(CourseResource, CourseResourceAdmin)
xadmin.site.register(CourseTag, CourseTagAdmin)

菜单栏-Tools-Run manage.py Task
makemigrations
migrate

访问后台管理系统:http://127.0.0.1:8000/xadmin/courses/coursetag/
进行课程标签的添加,可在课程信息中后面的外键关联中进行添加。

通过外键的方式将数据进行关联
在apps/courses/views.py中:

# 省略
from pure_pagination import Paginator, PageNotAnInteger

from apps.courses.models import Course, CourseTag
from apps.operations.models import UserFavorite

# Create your views here.

# 课程详情页面,获取课程详情
class CourseDetailView(View):
    def get(self, request, course_id, *args, **kwargs):
        # 省略
        # 判断用户是否登录
        if request.user.is_authenticated:
            # fav_type=1代表收藏的为课程
            if UserFavorite.objects.filter(user=request.user, fav_id=course.id, fav_type=1):
                has_fav_course = True
            # fav_type=2代表收藏的为课程课程机构
            if UserFavorite.objects.filter(user=request.user, fav_id=course.course_org.id, fav_type=2):
                has_fav_org = True

        # # 通过课程的tag做课程的推荐
        # tag = course.tag
        # related_courses = []
        # if tag:
        #     # 找标签相同的课程,取前3个。使用exclude方法排除当前课程,要去掉一批数据则使用__in,将列表中的数据全部去除
        #     related_courses = Course.objects.filter(tag=tag).exclude(id__in=[course.id])[:3]
        # 取到所有的tag
        tags = course.coursetag_set.all()
        # tag_list = []
        # for tag in tags:
        #     tag_list.append(tag.tag)
        tag_list = [tag.tag for tag in tags]
        course_tags = CourseTag.objects.filter(tag__in=tag_list).exclude(course__id=course.id)
        # 使用set,避免出现有多个tag的同一个课程重复显示
        related_courses = set()
        for course_tag in course_tags:
            related_courses.add(course_tag.course)
            
        return render(request, "course-detail.html", {
            "course": course,
            "has_fav_course": has_fav_course,
            "has_fav_org": has_fav_org,
            "related_courses": related_courses
        })
# 获取课程列表信息

再进行课程详情页的访问:http://127.0.0.1:8000/course/2/
便显示相关课程的推荐。

6.课程的章节信息

在课程的详情页面点击开始学习后,课程的章节信息。
将templates/course-video.html改为:

{% extends 'base.html' %}
{% load staticfiles %}
{% block title %}课程章节信息-慕学在线网{% endblock %}
{% block custom_css%}
    <link rel="stylesheet" type="text/css" href="{% static 'css/muke/base.css' %}" />
    <link rel="stylesheet" type="text/css" href="{% static 'css/muke/common-less.css' %}" />
    <link rel="stylesheet" type="text/css" href="{% static 'css/muke/course/learn-less.css' %}" />
    <link rel="stylesheet" type="text/css" href="{% static 'css/aui.css' %}" />
    <link rel="stylesheet" type="text/css" href="{% static 'css/mooc.css' %}" />
    <link rel="stylesheet" type="text/css" href="{% static 'css/muke/course/common-less.css' %}" />
{% endblock %}
{% block custom_bread %}
<section>
    <div class="wp">
        <ul  class="crumbs">
            <!-- 可点击的面包器 -->
            <li><a href="{% url 'index' %}">首页</a>&gt;</li>
            <li><a href="{% url 'course:list' %}">公开课</a>&gt;</li>
            <li><a href="">课程详情</a>&gt;</li>
            <li>章节信息</li>
        </ul>
    </div>
</section>
{% endblock %}
{% block content %}
        <div id="main">
    <div class="course-infos">
        <div class="w pr">
            <div style="height: 15px" class="path">
            </div>
            <div class="hd">
                <h2 class="l">{{ course.name }}</h2>
            </div>
            <div class="statics clearfix">
                <div class="static-item ">
                    <span class="meta-value"><strong>{{ course.get_degree_display }}</strong></span>
                    <span class="meta">难度</span>
                    <em></em>
                </div>
                <div class="static-item static-time">
                    <span class="meta-value">{{ course.learn_times }}分钟</span>
                    <span class="meta">时长</span>
                    <em></em>
                </div>
                <div class="static-item">
                    <span class="meta-value"><strong>{{ course.students }}</strong></span>
                    <span class="meta">学习人数</span>
                    <em></em>
                </div>
            </div>
        </div>
    </div>
    <div class="course-info-main clearfix w has-progress">

        <div class="info-bar clearfix">
        <div class="content-wrap clearfix">
            <div class="content">
                <div class="mod-tab-menu">
                    <ul class="course-menu clearfix">
                        <li><a class="ui-tabs-active active" id="learnOn"  href="course-video.html"><span>章节</span></a></li>
                        <li><a id="commentOn" class="" href="course-comment.html"><span>评论</span></a></li>
                    </ul>
                </div>
            {% if course.notice %}
                <div id="notice" class="clearfix">
                    <div class="l"> <strong>课程公告:</strong> <a  href="javascript:void(0)">{{ course.notice }}</a> </div>
                </div>
            {% endif %}
                <div class="mod-chapters">
                    {% for lesson in course.lesson_set.all %}
                    <div class="chapter chapter-active" >
                        <h3>
                            <strong><i class="state-expand"></i>{{ lesson.name }}</strong>
                        </h3>
                        <ul class="video">
                            {% for video in lesson.video_set.all %}
                            <li>
                                <a target="_blank" href='/video/3662' class="J-media-item studyvideo">{{ video.name }} ({{ video.learn_times }})
                                    <i class="study-state"></i>
                                </a>
                            </li>
                            {% endfor %}

                        </ul>
                    </div>
                    {% endfor %}


                </div>

            </div>
            <div class="aside r">
                <div class="bd">

                    <div class="box mb40">
                        <h4>资料下载</h4>
                        <ul class="downlist">
                            {% for resource in course_resources %}
                            <li>
                                <span ><i class="aui-iconfont aui-icon-file"></i>&nbsp;&nbsp;{{ resource.name }}</span>
                                <a href="{{ resource.file.url }}" class="downcode" target="_blank" download="" data-id="274" title="">下载</a>
                            </li>
                            {% endfor %}
                        </ul>
                    </div>
                    <div class="box mb40">
                        <h4>讲师提示</h4>
                        <div class="teacher-info">
                            <a href="/u/315464/courses?sort=publish" target="_blank">
                                <img src='{{ course.teacher.image.url }}' width='80' height='80' />
                            </a>
        <span class="tit">
          <a href="/u/315464/courses?sort=publish" target="_blank">{{ course.teacher.name }}</a>
        </span>
                            <span class="job">{{ course.teacher.work_position }}</span>
                        </div>
                        <div class="course-info-tip">
                            <dl class="first">
                                <dt>课程须知</dt>
                                <dd class="autowrap">{{ course.youneed_know }}</dd>
                            </dl>
                            <dl>
                                <dt>老师告诉你能学到什么?</dt>
                                <dd class="autowrap">{{ course.teacher_tell }}</dd>
                            </dl>
                        </div>
                    </div>


                    <div class="cp-other-learned  js-comp-tabs">
                        <div class="cp-header clearfix">
                            <h2 class="cp-tit l">该课的同学还学过</h2>
                        </div>
                        <div class="cp-body">
                            <div class="cp-tab-pannel js-comp-tab-pannel" data-pannel="course" style="display: block">
                                <!-- img 200 x 112 -->
                                <ul class="other-list">

                                    <li class="curr">
                                        <a href="course-detail.html" target="_blank">
                                            <img src="../media/courses/2016/11/540e57300001d6d906000338-240-135_n0L8vbw.jpg" alt="django与vuejs实战项目2">
                                            <span class="name autowrap">django与vuejs实战项目2</span>
                                        </a>
                                    </li>

                                    <li class="curr">
                                        <a href="course-detail.html" target="_blank">
                                            <img src="../media/courses/2016/12/python面向对象.jpg" alt="python面向对象">
                                            <span class="name autowrap">python面向对象</span>
                                        </a>
                                    </li>

                                    <li class="curr">
                                        <a href="course-detail.html" target="_blank">
                                            <img src="../media/courses/2016/12/python文件处理.jpg" alt="python文件处理">
                                            <span class="name autowrap">python文件处理</span>
                                        </a>
                                    </li>

                                    <li class="curr">
                                        <a href="course-detail.html" target="_blank">
                                            <img src="../media/courses/2016/11/mysql.jpg" alt="django入门">
                                            <span class="name autowrap">django入门</span>
                                        </a>
                                    </li>

                                    <li class="curr">
                                        <a href="course-detail.html" target="_blank">
                                            <img src="../media/courses/2016/12/mysql.jpg" alt="xadmin进阶开发">
                                            <span class="name autowrap">xadmin进阶开发</span>
                                        </a>
                                    </li>

                                </ul>
                            </div>
                            <div class="cp-tab-pannel js-comp-tab-pannel" data-pannel="plan">
                                <ul class="other-list">
                                    <li class="curr">
                                        <a href="/course/programdetail/pid/31?src=sug" target="_blank">
                                            <img src="http://img.mukewang.com/56551e6700018b0c09600720-240-135.jpg" alt="Java工程师">
                                            <span class="name autowrap">Java工程师</span>
                                        </a>
                                    </li>
                                </ul>
                            </div>
                        </div>
                    </div>

                </div>    </div>
        </div>
        <div class="clear"></div>

    </div>

</div>
</div>
{% endblock %}


在apps/courses/views.py中:

from django.shortcuts import render
from django.views.generic.base import View
from pure_pagination import Paginator, PageNotAnInteger
from django.contrib.auth.mixins import LoginRequiredMixin

from apps.courses.models import Course, CourseTag, CourseResource
from apps.operations.models import UserFavorite, UserCourse

# Create your views here.

# 课程章节信息
# LoginRequiredMixin对view进行login登录的验证,可参考文档:https://docs.djangoproject.com/en/2.2/topics/auth/default/
class CourseLessonView(LoginRequiredMixin, View):
    # 若未登录,指向的url
    login_url = "/login/"
    def get(self, request, course_id, *args, **kwargs):
        """
        获取课程章节信息
        """
        course = Course.objects.get(id=int(course_id))
        # 点击课程时,为课程增加点击数
        course.click_nums += 1
        course.save()

        # 查询用户是否已经关联了课程
        user_courses = UserCourse.objects.filter(user=request.user, course=course)
        # 若没有查询到记录,则生成一条记录
        if not user_courses:
            user_course = UserCourse(user=request.user, course=course)
            user_course.save()

            course.students += 1
            course.save()

        # 课程资料的下载
        course_resources = CourseResource.objects.filter(course=course)
        return render(request, "course-video.html", {
            "course": course,
            "course_resources": course_resources
        })


# 课程详情页面,获取课程详情
# 省略

配置url:
在apps/courses/urls.py中:

from django.conf.urls import url
from django.urls import path

from apps.courses.views import CourseListView, CourseDetailView, CourseLessonView

urlpatterns = [
    # 课程列表页
    url(r'^list/$', CourseListView.as_view(), name="list"),
    # 课程详情页
    url(r'^(?P<course_id>\d+)/$', CourseDetailView.as_view(), name="detail"),
    # 课程章节信息
    url(r'^(?P<course_id>\d+)/lesson/$', CourseLessonView.as_view(), name="lesson"),
]

在templates/course-detail.html中(49行左右):

<div class="buy btn"><a style="color: white" href="{% url 'course:lesson' course.id %}">开始学习</a></div>

在:http://127.0.0.1:8000/xadmin/courses/course/
进行章节和章节视频信息的添加。

添加课程公告字段:
在apps/courses/models.py中:

# 省略
# 继承BaseModel
# 课程
class Course(BaseModel):
    # 省略
    click_nums = models.IntegerField(default=0, verbose_name="点击数")
    notice = models.CharField(verbose_name="课程公告", max_length=300, default="")
    category = models.CharField(default=u"后端开发", max_length=20, verbose_name="课程类别")

菜单栏-Tools-Run manage.py Task
makemigrations
migrate

进行右上角登录状态栏的修改:
在templates/base.html中:(29行左右)

<section class="headerwrap ">
    <header>
		<div  class=" header">
            <div class="top">
				<div class="wp">
					<div class="fl"><p>服务电话:<b>33333333</b></p></div>
					<!--登录后跳转-->

                        <!--如果用户已经登录-->
                        {% if request.user.is_authenticated %}

                            <div class="personal">
                                <dl class="user fr">
                                    <dd>bobby<img class="down fr" src="{% static 'images/top_down.png' %}"/></dd>
                                    <dt><img width="20" height="20" src="{% static 'media/image/2016/12/default_big_14.png' %}"/></dt>
                                </dl>
                                <div class="userdetail">
                                    <dl>
                                        <dt><img width="80" height="80" src="{% static 'media/image/2016/12/default_big_14.png' %}"/></dt>
                                        <dd>
                                            <h2>django</h2>
                                            <p>bobby</p>
                                        </dd>
                                    </dl>
                                    <div class="btn">
                                        <a class="personcenter fl" href="usercenter-info.html">进入个人中心</a>
                                        <a class="fr" href="{% url 'logout' %}">退出</a>
                                    </div>
                                </div>
                            </div>
                            {% else %}
                            <!--如果用户未登录-->
                            <a style="color:white" class="fr registerbtn" href="{% url 'register' %}">注册</a>
                            <a style="color:white" class="fr loginbtn" href="{% url 'login' %}">登录</a>
                        {% endif %}


				</div>
			</div>

若用户未登录,点击开始学习,转跳到登录页面,在登录之后跳转到当前页面:
在apps/users/views.py中:

# 省略
# 动态验证码的登录
class DynamicLoginView(View):
    def get(self, request, *args, **kwargs):
        if request.user.is_authenticated:
            return HttpResponseRedirect(reverse("index"))
        next = request.GET.get("next", "")
        login_form = DynamicLoginForm()
        return render(request, "login.html", {
            "login_form": login_form,
            "next": next
        })

    def post(self, request, *args, **kwargs):
        login_form = RegisterPostForm(request.POST)
        dynamic_login = True
        if login_form.is_valid():
            # 设置没有注册账号仍然可以登录
            # 先查询用户是否存在
            mobile = login_form.cleaned_data["mobile"]
            existed_users = UserProfile.objects.filter(mobile=mobile)
            if existed_users:
                user = existed_users[0]
            else:
                # 用户不存在,新建用户
                # 用户名为必填字段,用手机号填充
                user = UserProfile(username=mobile)
                # 此时用户未输入密码,可以进行密码的生成,生成10位
                password = generate_random(10, 2)
                # 密码为加密的,不能直接赋值明文,使用set_password方法进行密码的加密
                user.set_password(password)
                # 填入必填字段手机号
                user.mobile = mobile
                user.save()
            # 进行登录
            login(request, user)
            # 如果有next跳转到next,若没有则跳转到首页
            next = request.GET.get("next", "")
            if next:
                return HttpResponseRedirect(next)
            # 跳转到首页
            return HttpResponseRedirect(reverse("index"))
        else:
            d_form = DynamicLoginForm()
            return render(request, "login.html", {"login_form": login_form,
                                                  "d_form": d_form,
                                                  "dynamic_login": dynamic_login})
# 省略


# 用户登录
# 继承Django内部的View
class LoginView(View):
    # 重载get方法,request为django自动注入的参数
    # 有可能传递多个参数,设置接受多变量的方式,可以点入View中从def dispatch中的return中查看源码
    def get(self, request, *args, **kwargs):
        # 在index.html已经判断了用户是否登录,获取此属性is_authenticated
        if request.user.is_authenticated:
            # 如果已经是登录状态,重定向到首页
            return HttpResponseRedirect(reverse("index"))
        next = request.GET.get("next", "")
        # 进行实例化
        login_form = DynamicLoginForm()
        return render(request, "login.html", {
            # 将变量传递进html中
            "login_form": login_form,
            "next": next
        })
    # 用户数据的获取
    def post(self, request, *args, **kwargs):
        # 表单验证
        login_form = LoginForm(request.POST)
        if login_form.is_valid():

        # # 在页面上点击F12选中login.html中手机号/邮箱输入栏,可看到input name="username",据此来进行获取
        # # 获取username,默认值为空
        # user_name = request.POST.get("username","")
        # password = request.POST.get("password","")

        # # 若用户名为空,没有必要执行之后的逻辑
        # if not user_name:
        #     return render(request, "login.html", {"msg": "请输入用户名"})
        # # 密码为空
        # if not password:
        #     return render(request, "login.html", {"msg": "请输入密码"})
        # if len(password) < 3:
        #     return render(request, "login.html", {"msg": "密码格式不正确"})
        # 用于通过用户名和密码查询用户是否存在,使用django内置的方法,因为数据库中存储的密码为密文,所以不能直接使用UserProfile来验证

            # 取出表单中的数据
            user_name = login_form.cleaned_data["username"]
            password = login_form.cleaned_data["password"]
            user = authenticate(username=user_name, password=password)
            if user is not None:
                # 若查询到用户,则进行登录
                # Django内部的login方法会自动完成cookie的设置
                login(request, user)
                # 如果有next跳转到next,若没有则跳转到首页
                next = request.GET.get("next", "")
                if next:
                    return HttpResponseRedirect(next)
                # 登录成功之后返回页面
                # reverse方法通过url的名称来定位url
                return HttpResponseRedirect(reverse("index"))
            else:
                # 未查询到用户,要将login_form传递回去,保留用户输入的错误的用户名和密码在页面上
                return render(request, "login.html", {"msg":"用户名或密码错误", "login_form": login_form})
        else:
            return render(request, "login.html", {"login_form": login_form})

再将next传递到login.html页面中:
在templates/login.html中:(约73行)

<form class="tab-form {% if dynamic_login %}hide{% else %}{% endif %}" action="{% url 'login' %}?next={{ next }}" method="post" autocomplete="off" id="form1">

通过后台管理系统中的课程信息页面进行相应课程资源的添加,
再访问章节信息页面就完成的了章节的显示,以及右侧的资料下载。

章节信息右下角,该课的同学还学过:
在apps/courses/views.py中:

# 省略

# 课程章节信息
# LoginRequiredMixin对view进行login登录的验证,可参考文档:https://docs.djangoproject.com/en/2.2/topics/auth/default/
class CourseLessonView(LoginRequiredMixin, View):
    # 若未登录,指向的url
    login_url = "/login/"

    def get(self, request, course_id, *args, **kwargs):
        """
        获取课程章节信息
        """
        course = Course.objects.get(id=int(course_id))
        # 点击课程时,为课程增加点击数
        course.click_nums += 1
        course.save()

        # 查询用户是否已经关联了课程
        user_courses = UserCourse.objects.filter(user=request.user, course=course)
        # 若没有查询到记录,则生成一条记录
        if not user_courses:
            user_course = UserCourse(user=request.user, course=course)
            user_course.save()

            course.students += 1
            course.save()

        # 该课的同学还学过
        # 学习过该课程的所有同学
        user_courses = UserCourse.objects.filter(course=course)
        # 学过该课程的所有同学的id
        user_ids = [user_course.user.id for user_course in user_courses]
        all_courses = UserCourse.objects.filter(user_id__in=user_ids).order_by("-course__click_nums")[:5]
        related_courses = []
        for item in all_courses:
            # 去掉当前的课程
            if item.course.id != course.id:
                related_courses.append(item.course)
        # # 也可使用列表生成式
        # related_courses = [user_course.course for user_course in all_courses if user_course.course.id != course.id]

        # 课程资料的下载
        course_resources = CourseResource.objects.filter(course=course)
        return render(request, "course-video.html", {
            "course": course,
            "course_resources": course_resources,
            "related_courses": related_courses
        })


# 课程详情页面,获取课程详情
# 省略

在templates/course-video.html中:(130行左右)

<div class="cp-other-learned  js-comp-tabs">
    <div class="cp-header clearfix">
        <h2 class="cp-tit l">该课的同学还学过</h2>
    </div>
    <div class="cp-body">
        <div class="cp-tab-pannel js-comp-tab-pannel" data-pannel="course" style="display: block">
            <!-- img 200 x 112 -->
            <ul class="other-list">
                {% for course in related_courses %}
                <li class="curr">
                    <a href="course-detail.html" target="_blank">
                        <img src="{{ course.image.url }}" alt="{{ course.name }}">
                        <span class="name autowrap">{{ course.name }}</span>
                    </a>
                </li>
                {% endfor %}


            </ul>
        </div>

7.课程评论

将templates/course-comment.html改为:

{% extends 'base.html' %}
{% load staticfiles %}
{% block title %}课程章节信息-慕学在线网{% endblock %}
{% block custom_css%}
    <link rel="stylesheet" type="text/css" href="{% static 'css/muke/course/learn-less.css' %}" />
	<link rel="stylesheet" type="text/css" href="{% static 'css/muke/course/course-comment.css' %}" />
    <link rel="stylesheet" type="text/css" href="{% static 'css/muke/base.css' %}">
    <link rel="stylesheet" type="text/css" href="{% static 'css/muke/common-less.css' %}">
    <link rel="stylesheet" type="text/css" href="{% static 'css/muke/course/common-less.css' %}">
    <link rel="stylesheet" type="text/css" href="{% static 'css/mooc.css' %}" />
{% endblock %}
{% block custom_bread %}
<section>
    <div class="wp">
        <ul  class="crumbs">
            <!-- 可点击的面包器 -->
            <li><a href="{% url 'index' %}">首页</a>&gt;</li>
            <li><a href="{% url 'course:list' %}">公开课</a>&gt;</li>
            <li><a href="">课程详情</a>&gt;</li>
            <li>课程评论</li>
        </ul>
    </div>
</section>
{% endblock %}

{% block content %}
    <div id="main">
    <div class="course-infos">
        <div class="w pr">
            <div style="height: 15px" class="path">
            </div>
            <div class="hd">
                <h2 class="l">{{ course.name }}</h2>
            </div>
            <div class="statics clearfix">
                <div class="static-item ">
                    <span class="meta-value"><strong>{{ course.get_degree_display }}</strong></span>
                    <span class="meta">难度</span>
                    <em></em>
                </div>
                <div class="static-item static-time">
                    <span class="meta-value">{{ course.learn_times }}分钟</span>
                    <span class="meta">时长</span>
                    <em></em>
                </div>
                <div class="static-item">
                    <span class="meta-value"><strong>{{ course.students }}</strong></span>
                    <span class="meta">学习人数</span>
                    <em></em>
                </div>
            </div>
        </div>
    </div>
    <div class="course-info-main clearfix w has-progress">

        <div class="info-bar clearfix">
            <div class="content-wrap clearfix">
                <div class="content">
                    <div class="mod-tab-menu">
                        <ul class="course-menu clearfix">
                            <li><a class="ui-tabs-active " id="learnOn"  href="{% url 'course:lesson' course.id %}"><span>章节</span></a></li>
                                <li><a id="commentOn" class="active" href="{% url 'course:comments' course.id %}"><span>评论</span></a></li>
                        </ul>
                    </div>

                    <!--发布评论-->
                    <div id="js-pub-container" class="issques clearfix js-form">
                        <div class="wgt-ipt-wrap pub-editor-wrap " id="js-pl-input-fake">
                            <textarea id="js-pl-textarea" class="" placeholder="扯淡、吐槽、表扬、鼓励……想说啥就说啥!" ></textarea>
                        </div>
                        <input type="button" id="js-pl-submit" class="pub-btn" data-cid="452" value="发表评论">
                        <p class="global-errortip js-global-error"></p>
                    </div>
                    <div id="course_note">
                        <ul class="mod-post" id="comment-list">
                            {% for comment in comments %}
                            <li class="post-row">
                                <div class="media">
                                    <span target="_blank"><img src='{{ comment.user.image.url }}' width='40' height='40' /></span>
                                </div>
                                <div class="bd">
                                    <div class="tit">
                                            <span target="_blank">{% if comment.user.nick_name %}{{ comment.user.nick_name }}{% else %}{{ comment.user.username }}{% endif %}</span>
                                    </div>
                                    <p class="cnt">{{ comment.comments }}</p>
                                    <div class="footer clearfix">
                                        <span title="创建时间" class="l timeago">时间:{{ comment.add_time }}</span>
                                    </div>
                                </div>
                            </li>
                            {% endfor %}




                        </ul>
                    </div>

                </div>
                            <div class="aside r">
                <div class="bd">

                    <div class="box mb40">
                        <h4>资料下载</h4>
                        <ul class="downlist">
                            {% for resource in course_resources %}
                            <li>
                                <span ><i class="aui-iconfont aui-icon-file"></i>&nbsp;&nbsp;{{ resource.name }}</span>
                                <a href="{{ resource.file.url }}" class="downcode" target="_blank" download="" data-id="274" title="">下载</a>
                            </li>
                            {% endfor %}
                        </ul>
                    </div>
                    <div class="box mb40">
                        <h4>讲师提示</h4>
                        <div class="teacher-info">
                            <a href="/u/315464/courses?sort=publish" target="_blank">
                                <img src='{{ course.teacher.image.url }}' width='80' height='80' />
                            </a>
        <span class="tit">
          <a href="/u/315464/courses?sort=publish" target="_blank">{{ course.teacher.name }}</a>
        </span>
                            <span class="job">{{ course.teacher.work_position }}</span>
                        </div>
                        <div class="course-info-tip">
                            <dl class="first">
                                <dt>课程须知</dt>
                                <dd class="autowrap">{{ course.youneed_know }}</dd>
                            </dl>
                            <dl>
                                <dt>老师告诉你能学到什么?</dt>
                                <dd class="autowrap">{{ course.teacher_tell }}</dd>
                            </dl>
                        </div>
                    </div>


                    <div class="cp-other-learned  js-comp-tabs">
                        <div class="cp-header clearfix">
                            <h2 class="cp-tit l">该课的同学还学过</h2>
                        </div>
                        <div class="cp-body">
                            <div class="cp-tab-pannel js-comp-tab-pannel" data-pannel="course" style="display: block">
                                <!-- img 200 x 112 -->
                                <ul class="other-list">
                                    {% for course in related_courses %}
                                    <li class="curr">
                                        <a href="{% url 'course:detail' course.id %}" target="_blank">
                                            <img src="{{ course.image.url }}" alt="{{ course.name }}">
                                            <span class="name autowrap">{{ course.name }}</span>
                                        </a>
                                    </li>
                                    {% endfor %}


                                </ul>
                            </div>
                            <div class="cp-tab-pannel js-comp-tab-pannel" data-pannel="plan">
                                <ul class="other-list">
                                    <li class="curr">
                                        <a href="/course/programdetail/pid/31?src=sug" target="_blank">
                                            <img src="http://img.mukewang.com/56551e6700018b0c09600720-240-135.jpg" alt="Java工程师">
                                            <span class="name autowrap">Java工程师</span>
                                        </a>
                                    </li>
                                </ul>
                            </div>
                        </div>
                    </div>

                </div>    </div>

            </div>
            <div class="clear"></div>

        </div>

    </div>
</div>

{% endblock %}

{% block custom_js %}
<script type="text/javascript">
    //添加评论
    $(document).ready(function() {
        $('#js-pl-submit').on('click', function () {
            var comments = $("#js-pl-textarea").val()
            if (comments == "") {
                alert("评论不能为空")
                return
            }
            $.ajax({
                cache: false,
                type: "POST",
                url: "/course/add_comment/",
                data: {'course_id': 10, 'comments': comments},
                async: true,
                beforeSend: function (xhr, settings) {
                    xhr.setRequestHeader("X-CSRFToken", "5I2SlleZJOMUX9QbwYLUIAOshdrdpRcy");
                },
                success: function (data) {
                    if (data.status == 'fail') {
                        if (data.msg == '用户未登录') {
                            window.location.href = "login.html";
                        } else {
                            alert(data.msg)
                        }

                    } else if (data.status == 'success') {
                        window.location.reload();//刷新当前页面.
                    }
                },
            });
        });
    });

</script>

{% endblock %}


在apps/courses/views.py中:

# 省略
from apps.courses.models import Course, CourseTag, CourseResource
from apps.operations.models import UserFavorite, UserCourse, CourseComments


# Create your views here.

# 课程评论信息
# LoginRequiredMixin对view进行login登录的验证,可参考文档:https://docs.djangoproject.com/en/2.2/topics/auth/default/
class CourseCommentsView(LoginRequiredMixin, View):
    # 若未登录,指向的url
    login_url = "/login/"

    def get(self, request, course_id, *args, **kwargs):
        """
        获取课程章节信息
        """
        course = Course.objects.get(id=int(course_id))
        # 点击课程时,为课程增加点击数
        course.click_nums += 1
        course.save()

        # 课程评论
        comments = CourseComments.objects.filter(course=course)

        # 查询用户是否已经关联了课程
        user_courses = UserCourse.objects.filter(user=request.user, course=course)
        # 若没有查询到记录,则生成一条记录
        if not user_courses:
            user_course = UserCourse(user=request.user, course=course)
            user_course.save()

            course.students += 1
            course.save()


        # 该课的同学还学过
        # 学习过该课程的所有同学
        user_courses = UserCourse.objects.filter(course=course)
        # 学过该课程的所有同学的id
        user_ids = [user_course.user.id for user_course in user_courses]
        all_courses = UserCourse.objects.filter(user_id__in=user_ids).order_by("-course__click_nums")[:5]
        related_courses = []
        for item in all_courses:
            # 去掉当前的课程
            if item.course.id != course.id:
                related_courses.append(item.course)
        # # 也可使用列表生成式
        # related_courses = [user_course.course for user_course in all_courses if user_course.course.id != course.id]

        # 课程资料的下载
        course_resources = CourseResource.objects.filter(course=course)

        return render(request, "course-comment.html", {
            "course": course,
            "course_resources": course_resources,
            "related_courses": related_courses,
            "comments": comments
        })


# 课程章节信息
# 省略

在templates/course-video.html中:(60行左右)

<li><a class="ui-tabs-active active" id="learnOn"  href="{% url 'course:lesson' course.id %}"><span>章节</span></a></li>
<li><a id="commentOn" class="" href="{% url 'course:comments' course.id %}"><span>评论</span></a></li>

在apps/courses/urls.py中:

from django.conf.urls import url
from django.urls import path

from apps.courses.views import CourseListView, CourseDetailView, CourseLessonView, CourseCommentsView

urlpatterns = [
    # 课程列表页
    url(r'^list/$', CourseListView.as_view(), name="list"),
    # 课程详情页
    url(r'^(?P<course_id>\d+)/$', CourseDetailView.as_view(), name="detail"),
    # 课程章节信息
    url(r'^(?P<course_id>\d+)/lesson/$', CourseLessonView.as_view(), name="lesson"),
    # 课程评论
    url(r'^(?P<course_id>\d+)/comments/$', CourseCommentsView.as_view(), name="comments"),
]

开发Ajax接口完成评论的发表:
在apps/operations/views.py中:

from django.views.generic import View
from django.http import JsonResponse

from apps.operations.forms import UserFavForm, CommentsForm
from apps.operations.models import UserFavorite, CourseComments
from apps.courses.models import Course
from apps.organizations.models import CourseOrg, Teacher


# Create your views here.

# 课程评论
class CommentView(View):
    def post(self, request, *args, **kwargs):
        if not request.user.is_authenticated:
            return JsonResponse({
                "status": "fail",
                "msg": "用户未登录"
            })

        comment_form = CommentsForm(request.POST)
        if comment_form.is_valid():
            course = comment_form.cleaned_data["course"]
            comments = comment_form.cleaned_data["comments"]

            comment = CourseComments()
            comment.user = request.user
            comment.comments = comments
            comment.course = course
            comment.save()

            return JsonResponse({
                "status": "success",
            })
        # 若表单验证失败
        else:
            return JsonResponse({
                "status": "fail",
                "msg": "参数错误"
            })


# 用户收藏,取消收藏
# 省略

在apps/operations/urls.py中:

from django.conf.urls import url

from apps.operations.views import AddFavView, CommentView
urlpatterns = [
    url(r'^fav/$', AddFavView.as_view(), name="fav"),
    url(r'^comment/$', CommentView.as_view(), name="comment"),

]

在apps/operations/forms.py中:

import re

from django import forms
from apps.operations.models import UserFavorite, CourseComments

# 使用modelform
class UserFavForm(forms.ModelForm):
    # 指明继承哪个model
    class Meta:
        model = UserFavorite
        # 指明将哪些字段生成form
        fields = ["fav_id", "fav_type"]


class CommentsForm(forms.ModelForm):
    # 指明继承哪个model
    class Meta:
        model = CourseComments
        # 指明将哪些字段生成form
        fields = ["course", "comments"]

在templates/course-comment.html末尾:

{% block custom_js %}
<script type="text/javascript">
    //添加评论
    $(document).ready(function() {
        $('#js-pl-submit').on('click', function () {
            var comments = $("#js-pl-textarea").val()
            if (comments == "") {
                alert("评论不能为空")
                return
            }
            $.ajax({
                cache: false,
                type: "POST",
                url: "{% url 'op:comment' %}",
                data: {'course': {{ course.id }}, 'comments': comments},
                async: true,
                beforeSend: function (xhr, settings) {
                    xhr.setRequestHeader("X-CSRFToken", "{{ csrf_token }}");
                },
                success: function (data) {
                    if (data.status == 'fail') {
                        if (data.msg == '用户未登录') {
                            window.location.href = "login.html";
                        } else {
                            alert(data.msg)
                        }

                    } else if (data.status == 'success') {
                        window.location.reload();//刷新当前页面.
                    }
                },
            });
        });
    });

</script>

{% endblock %}

启动项目并访问:http://127.0.0.1:8000/course/5/comments/

输入评论并发表便在下面显示,但用户的头像还未显示。

可在后台管理系统的用户信息中:http://127.0.0.1:8000/xadmin/users/userprofile/

上传头像,再刷新页面,便可看到评论头像的显示。

8.课程的视频播放

其中使用了video.js组件以及阿里云OSS进行视频的播放,可查看文档:https://docs.videojs.com/

在templates/course-play.html中:

{% extends 'base.html' %}
{% load staticfiles %}
{% block title %}课程章节信息-慕学在线网{% endblock %}
{% block custom_css%}
    <link rel="stylesheet" type="text/css" href="{% static 'css/muke/base.css' %}" />
    <link rel="stylesheet" type="text/css" href="{% static 'css/muke/common-less.css' %}" />
    <link rel="stylesheet" type="text/css" href="{% static 'css/muke/course/learn-less.css' %}" />
    <link rel="stylesheet" type="text/css" href="{% static 'css/aui.css' %}" />
    <link rel="stylesheet" type="text/css" href="{% static 'css/mooc.css' %}" />
    <link rel="stylesheet" type="text/css" href="{% static 'css/muke/course/common-less.css' %}" />
    <link rel="stylesheet" type="text/css" href="{% static 'css/video-js.min.css' %}" />
    <style>
        .video-js .vjs-big-play-button{
            top: 50%;
            left: 50%;
        }
    </style>
{% endblock %}
{% block custom_js %}
        <script src="{% static 'js/video.min.js' %}" type="text/javascript"></script>
{% endblock %}
{% block custom_bread %}
<section>
    <div class="wp">
        <ul  class="crumbs">
            <!-- 可点击的面包器 -->
            <li><a href="{% url 'index' %}">首页</a>></li>
            <li><a href="{% url 'course:list' %}">公开课</a>></li>
            <li><a href="{% url 'course:detail' course.id %}">{{ course.name }}</a>></li>
            <li><a href="">课程详情</a>></li>
            <li>章节信息</li>
        </ul>
    </div>
</section>
{% endblock %}
{% block content %}
    <div id="main">
    <div style="width:1200px;height:675px; margin-left: 340px">
        <video id="example_video_1" class="video-js vjs-default-skin" controls preload="none" width="1200"
              poster="http://video-js.zencoder.com/oceans-clip.png"
              data-setup="{}">
            <source src="http://gmooc-videos.oss-cn-beijing.aliyuncs.com/videos/8-1%20%E5%B9%B6%E5%8F%91%E5%92%8C%E5%B9%B6%E8%A1%8C.mp4?Expires=1557753059&OSSAccessKeyId=TMP.AgFuSH5m2_4qigPY7fHoBeQEguBvf5K8jN8PMdlY8iGFGd_qP6XhHIWi0pmCAAAwLAIUSySwJw2Ci3ol4RNfYmmK1jwTkowCFD5B3gFeMphhCJPWAf3i6-z6PTzg&Signature=KCIhh4afFhi1mgpTYBnvfg4S%2FqE%3D" type='video/mp4'>
        </video>
    </div>
    <div class="course-info-main clearfix w has-progress">

        <div class="info-bar clearfix">
        <div class="content-wrap clearfix">
            <div class="content">
                <div class="mod-tab-menu">
                    <ul class="course-menu clearfix">
                        <li><a class="ui-tabs-active active" id="learnOn"  href="{% url 'course:lesson' course.id %}"><span>章节</span></a></li>
                        <li><a id="commentOn" class="" href="{% url 'course:comments' course.id %}"><span>评论</span></a></li>
                    </ul>
                </div>
            {% if course.notice %}
                <div id="notice" class="clearfix">
                    <div class="l"> <strong>课程公告:</strong> <a  href="javascript:void(0)">{{ course.notice }}</a> </div>
                </div>
            {% endif %}
                <div class="mod-chapters">
                    {% for lesson in course.lesson_set.all %}
                    <div class="chapter chapter-active" >
                        <h3>
                            <strong><i class="state-expand"></i>{{ lesson.name }}</strong>
                        </h3>
                        <ul class="video">
                            {% for video in lesson.video_set.all %}
                            <li>
                                <a target="_blank" href='/video/3662' class="J-media-item studyvideo">{{ video.name }} ({{ video.learn_times }})
                                    <i class="study-state"></i>
                                </a>
                            </li>
                            {% endfor %}

                        </ul>
                    </div>
                    {% endfor %}


                </div>

            </div>
            <div class="aside r">
                <div class="bd">

                    <div class="box mb40">
                        <h4>资料下载</h4>
                        <ul class="downlist">
                            {% for resource in course_resources %}
                            <li>
                                <span ><i class="aui-iconfont aui-icon-file"></i>  {{ resource.name }}</span>
                                <a href="{{ resource.file.url }}" class="downcode" target="_blank" download="" data-id="274" title="">下载</a>
                            </li>
                            {% endfor %}
                        </ul>
                    </div>
                    <div class="box mb40">
                        <h4>讲师提示</h4>
                        <div class="teacher-info">
                            <a href="/u/315464/courses?sort=publish" target="_blank">
                                <img src='{{ course.teacher.image.url }}' width='80' height='80' />
                            </a>
        <span class="tit">
          <a href="/u/315464/courses?sort=publish" target="_blank">{{ course.teacher.name }}</a>
        </span>
                            <span class="job">{{ course.teacher.work_position }}</span>
                        </div>
                        <div class="course-info-tip">
                            <dl class="first">
                                <dt>课程须知</dt>
                                <dd class="autowrap">{{ course.youneed_know }}</dd>
                            </dl>
                            <dl>
                                <dt>老师告诉你能学到什么?</dt>
                                <dd class="autowrap">{{ course.teacher_tell }}</dd>
                            </dl>
                        </div>
                    </div>


                    <div class="cp-other-learned  js-comp-tabs">
                        <div class="cp-header clearfix">
                            <h2 class="cp-tit l">该课的同学还学过</h2>
                        </div>
                        <div class="cp-body">
                            <div class="cp-tab-pannel js-comp-tab-pannel" data-pannel="course" style="display: block">
                                <!-- img 200 x 112 -->
                                <ul class="other-list">
                                    {% for course in related_courses %}
                                    <li class="curr">
                                        <a href="{% url 'course:detail' course.id %}" target="_blank">
                                            <img src="{{ course.image.url }}" alt="{{ course.name }}">
                                            <span class="name autowrap">{{ course.name }}</span>
                                        </a>
                                    </li>
                                    {% endfor %}


                                </ul>
                            </div>
                            <div class="cp-tab-pannel js-comp-tab-pannel" data-pannel="plan">
                                <ul class="other-list">
                                    <li class="curr">
                                        <a href="/course/programdetail/pid/31?src=sug" target="_blank">
                                            <img src="http://img.mukewang.com/56551e6700018b0c09600720-240-135.jpg" alt="Java工程师">
                                            <span class="name autowrap">Java工程师</span>
                                        </a>
                                    </li>
                                </ul>
                            </div>
                        </div>
                    </div>

                </div>    </div>
        </div>
        <div class="clear"></div>

    </div>

</div>
</div>
{% endblock %}


在apps/courses/views.py中:

# 省略
from django.contrib.auth.mixins import LoginRequiredMixin

from apps.courses.models import Course, CourseTag, CourseResource, Video
from apps.operations.models import UserFavorite, UserCourse, CourseComments


# Create your views here.

# 视频播放
class VideoView(LoginRequiredMixin, View):
    login_url = "/login/"
    # url中配置了两个id,此处要接收两个参数
    def get(self, request, course_id, video_id, *args, **kwargs):
        """
        获取课程章节信息
        """
        course = Course.objects.get(id=int(course_id))
        course.click_nums += 1
        course.save()

        video = Video.objects.get(id=int(video_id))

        #查询用户是否已经关联了该课程
        user_courses = UserCourse.objects.filter(user=request.user, course=course)
        if not user_courses:
            user_course = UserCourse(user=request.user, course=course)
            user_course.save()

            course.students += 1
            course.save()

        #学习过该课程的所有同学
        user_courses = UserCourse.objects.filter(course=course)
        user_ids = [user_course.user.id for user_course in user_courses]
        all_courses = UserCourse.objects.filter(user_id__in=user_ids).order_by("-course__click_nums")[:5]
        # related_courses = [user_course.course for user_course in all_courses if user_course.course.id != course.id]
        related_courses = []
        for item in all_courses:
            if item.course.id != course.id:
                related_courses.append(item.course)

        course_resources = CourseResource.objects.filter(course=course)

        return render(request, "course-play.html", {
            "course": course,
            "course_resources": course_resources,
            "related_courses": related_courses,
            "video": video,
        })

# 课程评论信息
# 省略

在apps/courses/urls.py中:

from django.conf.urls import url
from django.urls import path

from apps.courses.views import CourseListView, CourseDetailView, CourseLessonView, CourseCommentsView
from apps.courses.views import VideoView

urlpatterns = [
    # 课程列表页
    url(r'^list/$', CourseListView.as_view(), name="list"),
    # 课程详情页
    url(r'^(?P<course_id>\d+)/$', CourseDetailView.as_view(), name="detail"),
    # 课程章节信息
    url(r'^(?P<course_id>\d+)/lesson/$', CourseLessonView.as_view(), name="lesson"),
    # 课程评论
    url(r'^(?P<course_id>\d+)/comments/$', CourseCommentsView.as_view(), name="comments"),
    # 视频播放
    url(r'^(?P<course_id>\d+)/video/(?P<video_id>\d+)$', VideoView.as_view(), name="video"),
]

在templates/course-video.html中(约78行):

<a target="_blank" href='{% url "course:video" course.id video.id %}' class="J-media-item studyvideo">{{ video.name }} ({{ video.learn_times }})

在templates/course-play.html中(约70行):

<a target="_blank" href='{% url "course:video" course.id video.id %}' class="J-media-item studyvideo">{{ video.name }} ({{ video.learn_times }})
    <i class="study-state"></i>
</a>

购买阿里云OSS对象存储服务,只需将视频传到阿里云上,便会得到一个url,便可以放到video组件中来进行播放。

在OSS控制台中的存储空间中新建一个Bucket,点入文件管理中新建目录,然后进行视频的上传,尽量上传MP4格式。

可复制该上传视频的URL,可在浏览器中访问URL直接进行播放。

在后台管理系统中:http://127.0.0.1:8000/xadmin/courses/video/

可进行视频URL的配置。

在templates/course-play.html中:(42行左右)

<source src="{{ video.url }}" type='video/mp4'>

因为OSS复制下来的视频URL长度很长,所以需要修改字段长度。
在apps/courses/models.py中:

url = models.CharField(max_length=1000, verbose_name=u"访问地址")

菜单栏-Tools-Run manage.py Task
makemigrations
migrate

运行项目,点击章节,便可进行视频的播放。

  JavaScript知识库 最新文章
ES6的相关知识点
react 函数式组件 & react其他一些总结
Vue基础超详细
前端JS也可以连点成线(Vue中运用 AntVG6)
Vue事件处理的基本使用
Vue后台项目的记录 (一)
前后端分离vue跨域,devServer配置proxy代理
TypeScript
初识vuex
vue项目安装包指令收集
上一篇文章      下一篇文章      查看所有文章
加:2022-03-06 12:53:25  更:2022-03-06 12:57:24 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 8:28:28-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码