专栏首页零基础使用Django2.0.1打造在线教育网站零基础使用Django2.0.1打造在线教育网站(二十):课程相关页面配置
原创

零基础使用Django2.0.1打造在线教育网站(二十):课程相关页面配置

关于博主

努力与运动兼备~~~有任何问题可以加我好友或者关注微信公众号,欢迎交流,我们一起进步!

                 微信公众号:  啃饼思录
                 QQ: 2810706745(啃饼小白)

写在前面

本篇笔记我们将介绍课程相关页面的配置,具体包括课程章节信息,章节视频信息,课程评论页面,相关课程推荐,课程播放页面等功能,下面我们依次介绍一下。

本篇笔记对应于第二十篇代码,对应于github的位置是https://github.com/licheetools/eduline

课程章节信息配置

老规矩,把前端资料里面的course-video.htmlcourse-comment.html页面拷贝到我们的templates文件夹里面,接着修改course-video.html页面,保留部分信息,其余删除,{% block content %} <div id="main">{% endblock %}里面 <div id="main">是原来course-video.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:course_list' %}">公开课程</a>></li>
				<li><a href="{% url 'course:course_detail' course.id %}">课程详情</a>></li>
                <li>章节信息</li>
            </ul>
        </div>
</section>
{% 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 content %} 
  <div id="main">
{% endblock %}

就是这个样子(这里面的静态文件路径和url的跳转我都做好了,你按照图示进行修改即可):

然后打开course/urls.py文件,新增以下信息:

from .views import CourseInfoView

# 课程章节信息页url
    re_path('info/(?P<course_id>.*)/', CourseInfoView.as_view(), name="course_info"),

接着打开course/views.py文件,新增以下信息:

# 课程章节信息
class CourseInfoView(View):
    def get(self, request, course_id):
        course = Course.objects.get(id=int(course_id))
        return render(request, "course-video.html", {
            "course": course,
        })

现在打开course-detail.html页面,ctrl+F搜索“开始学习”,配置跳转路径:

<div class="buy btn"><a style="color: white" href="{% url 'courses:course_info' course.id %}">开始学习</a></div>
就是这个样子:

然后运行项目,点击课程详情页面的开始学习就进入到课程章节信息页面了:

现在在后台为指定某一门课添加课程章节信息,便于我们后面的测试:

章节视频信息配置

接下来获取课程的章节:打开courses/models.py文件,在Course函数里面,新定义函数def get_course_lesson用于获取课程的章节:

    def get_course_lesson(self):
        # 获取课程所有章节
        return self.lesson_set.all()

在lesson函数里面,新定义函数def get_lesson_video用于获取章节的视频信息:

    def get_lesson_video(self):
        # 获取章节视频信息
        return self.video_set.all()

现在打开course-video.html页面,配置数据的动态显示:

{% for lesson in course.get_course_lesson %}
                        <div class="chapter chapter-active" >
                        <h3>
                            <strong><i class="state-expand"></i>{{ lesson.name }}</strong>
                        </h3>
                        <ul class="video">
                           {% for video in lesson.get_lesson_video %}
                               <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 %}
就是这个样子:

前面说过,你可以选择不定义函数,自己调用它的queryset方法,那么只需修改course-video.html页面,修改如下:

{% for lesson in course.lesson_set.get_queryset%}
                        <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.get_queryset %}
                               <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 %}
刷新一下我们的页面:

资源下载功能

第一步,前往xadmin后台为某一门课添加课程资源,第二步打开courses/views.py文件,修改视图函数:

from .models import  CourseResource

all_resources = CourseResource.objects.filter(course=course)
return render(request, "course-video.html", {
            "all_resources": all_resources,
        })
就是这个样子:

现在打开course-video.html页面,配置资源下载的动态显示:

{% for resources in all_resources %}
                               <li>
                                <span ><i class="aui-iconfont aui-icon-file"></i>&nbsp;&nbsp;{{ resources.name }}</span>
                                <a href="{{ MEDIA_URL }}{{ resources.download }}" class="downcode" target="_blank" download="" data-id="274" title="">下载</a>
                            </li>
                           {% endfor %}
就是这个样子:

然后刷新页面,发现显示没有问题。

接下在course-video.html页面完成课程信息的修改:

<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"><strong>{{ course.learn_times }}分钟</strong></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>

在配置讲师提示的时候,发现讲师和课程之间没有建立外键连接,所以在courses/models.py文件的Course函数,新增讲师字段 :

from organization.models import Teacher

teacher = models.ForeignKey(Teacher, on_delete=models.CASCADE, verbose_name="讲师", null=True, blank=True)

记得数据库的变动需要两部曲:makemigrations和migrate

然后前往xadmin后台为这门课添加一个讲师。

然后修改course-video.html页面,修改信息成图示:

然后刷新页面,发现显示没有问题。

课程评论页面配置

打开courses/urls.py文件,配置课程评论页面的url

from .views import CourseCommentView

 # 课程评论页面url
    re_path('comment/(?P<course_id>.*)/', CourseCommentView.as_view(), name="course_comment"),

然后打开courses/views.py文件,新定义课程评论页面函数:

from operation.models import CourseComments

# 课程评论页面
class CourseCommentView(View):
    def get(self, request, course_id):
        course = Course.objects.get(id=int(course_id))
        all_resources = CourseResource.objects.filter(course=course)
        all_comments = CourseComments.objects.all()
        return render(request, "course-comment.html", {
            "course": course,
            "all_resources": all_resources,
            "all_comments": all_comments,
        })

接着打开course-comment.html页面,修改跳转代码:

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

然后打开course-comment.html页面,修改课程信息,资料下载,讲师提示等(和前面在video页面配置的一模一样,这里不再介绍):

接下来打开courses/views.py文件,新定义用于用户增加课程评论的函数:

# 用户增加课程评论
class AddCommentView(View):
    def post(self, request):
        if not request.user.is_authenticated:
            # 未登录时页面提示未登录,并跳转到登录页面
            return HttpResponse('{"status":"fail", "msg":"用户未登录"}', content_type='application/json')
        course_id = request.POST.get("course_id", 0)
        comments = request.POST.get("comments", '')
        if course_id >0 and comments:
            course_comments = CourseComments()
            # get方法只能取出一条数据,如果有多条则抛出异常而且没有数据也抛异常
            # filter方法可以取一个列表出来(可以遍历的queryset),没有数据返回空的queryset,是不会抛异常的
            course = Course.objects.get(id=int(course_id))
            course_comments.course = course
            course_comments.comment = comments   # 前面comment为数据库中定义字段,要保持一致,否则数据存入不数据库
            course_comments.user = request.user
            course_comments.save()
            return HttpResponse('{"status":"success", "msg":"评论成功"}', content_type='application/json')
        else:
            return HttpResponse('{"status":"fail", "msg":"评论失败"}', content_type='application/json')

现在回到courses/urls.py文件,我们来配置访问的url:

from .views import  AddCommentView

    # 用户增加课程评论页面url,注意此处为普通的url因为在post中,我们已经有了参数
    path('add_comment/', AddCommentView.as_view(), name="add_comment"),

然后打开course-comment.html页面,在页面底部增加js代码:

{% block custom_js %}
<script type="text/javascript">
    //添加评论
    $('#js-pl-submit').on('click', function(){
        var comments = $("#js-pl-textarea").val()
        if(comments == ""){
            alert("评论不能为空")
            return
        }
        $.ajax({
            cache: false,
            type: "POST",
            url:"{% url 'course:add_comment' %}",
            data:{'course_id':{{ 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="{% url 'login' %}";
                    }else{
                        alert(data.msg)
                    }

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

</script>
{% endblock %}

继续在该页面修改如下代码,使页面评论可以动态加载出来:

{% for user_comments in all_comments %}
                                  <li class="post-row">
                                <div class="media">
                                    <span target="_blank"><img src='{{ MEDIA_URL }}{{ user_comments.user.image }}' width='40' height='40' /></span>
                                </div>
                                <div class="bd">
                                    <div class="tit">
                                        <span target="_blank">{{ user_comments.user.username }}</span>
                                    </div>
                                    <p class="cnt">{{ user_comments.user.comment }}</p>
                                    <div class="footer clearfix">
                                        <span title="创建时间" class="l timeago">{{ user_comments.add_time }}</span>
                                    </div>
                                </div>
                            </li>
                             {% endfor %}

然后你可以在图示位置打上断点,开启debug模式:

发现没有问题,我们可以去掉断点,自己再增加一条,页面是不是已经自动更新了你的评论内容。

相关课程推荐配置

打开courses/views.py文件,找到CourseInfoView这个函数,修改为如下:

# 课程章节信息
class CourseInfoView(View):
    def get(self, request, course_id):
        course = Course.objects.get(id=int(course_id))
        all_resources = CourseResource.objects.filter(course=course)

        # 取出所有选过这门课的学生
        user_courses = UserCourse.objects.filter(course=course)
        # 取出所有选过这门课的学生的id,采用递归表达式形式
        user_ids = [user_course.user.id for user_course in user_courses]
        # 取出刚才那些学生选过的所有的课程
        all_user_courses = UserCourse.objects.filter(user_id__in=user_ids)
        # 取出刚才那些学生选过的所有的课程的id,同样采用递归表达式形式
        course_ids = [all_user_course.course_id for all_user_course in all_user_courses]
        # 取出学过该课程用户学过的其他课程
        relate_courses = Course.objects.filter(id__in=course_ids).order_by("-click_nums")[:5]
        return render(request, "course-video.html", {
            "course": course,
            "all_resources": all_resources,
            "relate_courses": relate_courses,
        })

注意:双下划线代表代表传进来的是一个可以遍历的list。

接着就是在前端页面配置动态加载信息了(记得course-video.html和course_comment.html这两个页面都需要配置,一模一样):

 <ul class="other-list">
                                    {% for relate_course in relate_courses %}
                                        <li class="curr">
                                            <a href="{% url 'course:course_detail' relate_course.id %}" target="_blank">
                                                <img src="{{ MEDIA_URL }}{{ relate_course.image }}"
                                                     alt="{{ relate_course.name }}">
                                                <span class="name autowrap">{{ relate_course.name }}</span>
                                            </a>
                                        </li>
                                    {% endfor %}

                                </ul>
就是这个样子:

然后刷新一下我们的页面,发现没有问题!

不过还有一个问题,那就是用户如果没有登录,那是不能让他进入课程章节这个页面的,因此需要判断一下。这里因为使用的是方法型编程所以可以使用装饰器loginrequired来进行判断。

在utils文件夹下面,新建一个名为mixin_utils.py文件,在里面添加如下代码:

from django.contrib.auth.decorators import login_required
from django.utils.decorators import method_decorator


class LoginRequiredMixin(object):

    @method_decorator(login_required(login_url='/login/'))
    def dispatch(self, request, *args, **kwargs):
        return super(LoginRequiredMixin, self).dispatch(request, *args, **kwargs)

接着打开courses/views.py文件,在里面修改CourseInfoView和CourseCommentView,修改后如下:

from utils.mixin_utils import LoginRequiredMixin

# 课程章节信息
class CourseInfoView(LoginRequiredMixin, View):
     login_url = '/login/'
    redirect_field_name = 'redirect_to'
    def get(self, request, course_id):
        course = Course.objects.get(id=int(course_id))
        all_resources = CourseResource.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)
            course.students += 1
            course.save()
            user_course.save()

        # 取出所有选过这门课的学生
        user_courses = UserCourse.objects.filter(course=course)
        # 取出所有选过这门课的学生的id,采用递归表达式形式
        user_ids = [user_course.user.id for user_course in user_courses]
        # 取出刚才那些学生选过的所有的课程
        all_user_courses = UserCourse.objects.filter(user_id__in=user_ids)
        # 取出刚才那些学生选过的所有的课程的id,同样采用递归表达式形式
        course_ids = [all_user_course.course_id for all_user_course in all_user_courses]
        # 取出学过该课程用户学过的其他课程
        relate_courses = Course.objects.filter(id__in=course_ids).order_by("-click_nums")[:5]
        return render(request, "course-video.html", {
            "course": course,
            "all_resources": all_resources,
            "relate_courses": relate_courses,
        })


# 课程评论页面
class CourseCommentView(LoginRequiredMixin, View):
    login_url = '/login/'
    redirect_field_name = 'redirect_to' 
    def get(self, request, course_id):
        course = Course.objects.get(id=int(course_id))
        all_resources = CourseResource.objects.filter(course=course)
        all_comments = CourseComments.objects.all()
        return render(request, "course-comment.html", {
            "course": course,
            "all_resources": all_resources,
            "all_comments": all_comments,
        })

刷新一下页面,点几个课程试试看,发现都在该同学还学过哪些课里推荐了。

课程播放页面配置

老规矩,把前端资料里面的course-play.html拷贝到我们的templates文件夹里面,然后替换继承base页面,这里就不细说了,直接贴图:

打开courses/urls.py文件,新增代码:

from .views import  VideoPlayView

# 视频播放页面url
re_path('video/(?P<video_id>.*)/', VideoPlayView.as_view(), name="video_play"),
或者 re_path('video/(?P<video_id>\d+)/', VideoPlayView.as_view(), name="video_play"),都是可以的

接着打开courses/views.py文件,新增代码:

from .models import  Video

# 视频播放页面
class VideoPlayView(LoginRequiredMixin, View):
    login_url = '/login/'
    redirect_field_name = 'redirect_to'
    
    def get(self, request, video_id):
        video = Video.objects.get(id=int(video_id))
        course = video.lesson.course
        all_resources = CourseResource.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)
            course.students += 1
            course.save()
            user_course.save()

        # 取出所有选过这门课的学生
        user_courses = UserCourse.objects.filter(course=course)
        # 取出所有选过这门课的学生的id,采用递归表达式形式
        user_ids = [user_course.user.id for user_course in user_courses]
        # 取出刚才那些学生选过的所有的课程
        all_user_courses = UserCourse.objects.filter(user_id__in=user_ids)
        # 取出刚才那些学生选过的所有的课程的id,同样采用递归表达式形式
        course_ids = [all_user_course.course_id for all_user_course in all_user_courses]
        # 取出学过该课程用户学过的其他课程
        relate_courses = Course.objects.filter(id__in=course_ids).order_by("-click_nums")[:5]

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

上面的代码和之前在课程章节信息里面定义的几乎一模一样,只是course的来源不一样。

接着打开course-video.html文件,配置跳转链接:

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

然后打开course-video.html文件,配置视频链接,记住由于我们这边是type='video/mp4'所以后台所添加的视频必须是.mp4结尾,否则会出错。

刷新一下,发现页面跳转没有问题,显示也没有问题。

大家可以把自己的视频上传到七牛云,然后把生成的外键添加到后台即可,这里不详细介绍,直接开启传送大门:七牛云存储如何上传视频文件

至此,本篇关于课程相关页面的配置介绍就到此结束,感谢你的赏阅。

本篇笔记对应于第二十篇代码,对应于github的位置是https://github.com/licheetools/eduline

原创声明,本文系作者授权云+社区发表,未经许可,不得转载。

如有侵权,请联系 yunjia_community@tencent.com 删除。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 零基础使用Django2.0.1打造在线教育网站(十八):机构详情页配置

    努力与运动兼备~~~有任何问题可以加我好友或者关注微信公众号,欢迎交流,我们一起进步!

    啃饼小白
  • 零基础使用Django2.0.1打造在线教育网站(十二):错误信息提示

    努力与运动兼备~~~有任何问题可以加我好友或者关注微信公众号,欢迎交流,我们一起进步!

    啃饼小白
  • TCP/IP 七层网络模型 三次握手

    TCP/IP(TransmissionControlProtocol/Internet Protocol),中文名为传输控制协议/因特网互联协议,又名网络通讯协...

    啃饼小白
  • 原生JS自己构建一个0-1之间的随机小数

    原生JS自己构建一个0-1之间的随机小数 前言 我们都知道使用Math.random()来得到一个随机数。但是很多人都没有深入的思考过,如何这个随机数是怎么来的...

    FungLeo
  • 罗湖联手腾讯深耕智慧民生服务 打造湾区精品教育

    3月21日,深圳市罗湖区人民政府与腾讯签约,聚焦罗湖区“数字政府”及“智慧城区”建设需求,共同推进罗湖区高质量创新型数字化城区建设。当天,罗湖区教育局、罗湖区智...

    腾讯智慧教育
  • 看我如何利用打印机窃取目标系统哈希值

    背景 这是我今年早些时候接手的一个渗透测试项目,我要做的是获取到目标系统的控制权限。但在后渗透测试阶段,我仅仅只发现了一台与目标内网无任何关联的计算机,这也使我...

    FB客服
  • poj 2886 Who Gets the Most Candies?

    题意:n个人围城一圈,每个人决定下一个出局的人在他的第几个位置,首先出局的人是第k个人 分析:反素数+约瑟夫 这道题最主要需要理解的就是线段树是如何模拟的反素...

    用户1624346
  • 50行代码教你打造一个公众号文章采集器

    Alfred的女票是一枚数据科学领域的新媒体运营官(是的,Alfred是一名程序员,Alfred有女票

    IT派
  • dataguard归档路径的问题(r7笔记第99天)

    最近处理了一起看似比较奇怪的dataguard归档路径问题。 问题的背景是这样的。 有一套一主两备的环境,备库1和主库在同一个机房,可以尝试在failover的...

    jeanron100
  • poj 2886 Who Gets the Most Candies?

    题意:n个人围城一圈,每个人决定下一个出局的人在他的第几个位置,首先出局的人是第k个人 分析:反素数+约瑟夫 这道题最主要需要理解的就是线段树是如何模拟的反素...

    用户1624346

扫码关注云+社区

领取腾讯云代金券