五、课程相关功能开发
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 }} </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 %}
<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
class CourseListView(View):
def get(self, request, *args, **kwargs):
all_courses = Course.objects.order_by("-add_time")
sort = request.GET.get("sort", "")
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(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
class CourseListView(View):
def get(self, request, *args, **kwargs):
all_courses = Course.objects.order_by("-add_time")
hot_courses = Course.objects.order_by("-click_nums")[:3]
sort = request.GET.get("sort", "")
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>
<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>
<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
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:
if UserFavorite.objects.filter(user=request.user, fav_id=course.id, fav_type=1):
has_fav_course = True
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()
将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">时 长:</span><span>{{ course.learn_times }}</span></li>
<li><span class="pram word3">章 节 数:</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>
<span>课 程 数: {{ course.course_org.course_set.all.count }}</span>
</li>
<li>
<span>教 师 数: {{ course.course_org.teacher_set.all.count }}</span>
</li>
<li>所在地区: {{course.course_org.address}}</li>
{% if course.course_org.is_gold %}
<li>认 证 :
<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:
if UserFavorite.objects.filter(user=request.user, fav_id=course.id, fav_type=1):
has_fav_course = True
if UserFavorite.objects.filter(user=request.user, fav_id=course.course_org.id, fav_type=2):
has_fav_org = True
tag = course.tag
related_courses = []
if tag:
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()
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
在后台管理系统中进行配置,在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
class CourseDetailView(View):
def get(self, request, course_id, *args, **kwargs):
if request.user.is_authenticated:
if UserFavorite.objects.filter(user=request.user, fav_id=course.id, fav_type=1):
has_fav_course = True
if UserFavorite.objects.filter(user=request.user, fav_id=course.course_org.id, fav_type=2):
has_fav_org = True
tags = course.coursetag_set.all()
tag_list = [tag.tag for tag in tags]
course_tags = CourseTag.objects.filter(tag__in=tag_list).exclude(course__id=course.id)
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>></li>
<li><a href="{% url 'course:list' %}">公开课</a>></li>
<li><a href="">课程详情</a>></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> {{ 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">
<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
class CourseLessonView(LoginRequiredMixin, View):
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中:
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)
password = generate_random(10, 2)
user.set_password(password)
user.mobile = mobile
user.save()
login(request, user)
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})
class LoginView(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 = LoginForm(request.POST)
if login_form.is_valid():
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:
login(request, user)
next = request.GET.get("next", "")
if next:
return HttpResponseRedirect(next)
return HttpResponseRedirect(reverse("index"))
else:
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中:
class CourseLessonView(LoginRequiredMixin, View):
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)
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)
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">
<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>></li>
<li><a href="{% url 'course:list' %}">公开课</a>></li>
<li><a href="">课程详情</a>></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> {{ 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">
<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
class CourseCommentsView(LoginRequiredMixin, View):
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)
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)
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
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
class UserFavForm(forms.ModelForm):
class Meta:
model = UserFavorite
fields = ["fav_id", "fav_type"]
class CommentsForm(forms.ModelForm):
class Meta:
model = CourseComments
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">
<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
class VideoView(LoginRequiredMixin, View):
login_url = "/login/"
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 = []
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
运行项目,点击章节,便可进行视频的播放。
|