基于django的视频点播网站开发-step5-详情页功能

news/2024/5/11 3:58:21/文章来源:https://blog.csdn.net/weixin_34226706/article/details/89545458

在本讲中,我们开始详情页功能的开发,详情页就是对单个视频进行播放并展示视频的相关信息,比如视频标题、描述、评论信息、相关推荐等。我们将会学习到通用视图类DetailView的使用、评论动态加载、以及如何通过ajax实现喜欢和收藏功能,并通过一段段很酷的代码来说明这些功能。

效果展示

整体功能

大家可先通过 网站演示地址 浏览一下网站效果。点击某个视频即可浏览详情页。详情页实现了是对单个视频进行展示,用户可看到视频的一些元信息,包括标题、描述、观看次数、喜欢数、收藏数等等。另外,网站还实现了评论功能,通过上拉网页即可分页加载评论列表,用户还能添加评论。网页侧栏是推荐视频列表,这里使用的推荐逻辑比较简单,就是推荐观看次数最多的视频。

我们把详情页分为4个小的业务模块来开发,分别是:视频详情显示、喜欢和收藏功能、评论功能、推荐功能。下面我们分别对这四个功能模块进行开发讲解。

视频详情显示

因为在上一讲中,我们已经建立了video模型,所以不必再新建模型,我们就在video模型的基础上进行扩展。上一讲,我们创建的字段有title、desc、classification、file、cover、status、create_time。这些字段目前是不够用的,我们再加几个字段,需要加观察次数喜欢的用户收藏的用户。video模型扩展后如下

class Video(models.Model):STATUS_CHOICES = (('0', '发布中'),('1', '未发布'),)title = models.CharField(max_length=100,blank=True, null=True)desc = models.CharField(max_length=255,blank=True, null=True)classification = models.ForeignKey(Classification, on_delete=models.CASCADE, null=True)file = models.FileField(max_length=255)cover = models.ImageField(upload_to='cover/',blank=True, null=True)status = models.CharField(max_length=1 ,choices=STATUS_CHOICES, blank=True, null=True)view_count = models.IntegerField(default=0, blank=True)liked = models.ManyToManyField(settings.AUTH_USER_MODEL,blank=True, related_name="liked_videos")collected = models.ManyToManyField(settings.AUTH_USER_MODEL,blank=True, related_name="collected_videos")create_time = models.DateTimeField(auto_now_add=True, blank=True, max_length=20)

新增了3个字段

  • view_count 观看次数。数据类型是IntegerField,默认是0
  • liked 喜欢的用户。数据类型是ManyToManyField,这是一种多对多的关系,表示一个视频可以被多个用户喜欢,一个用户也可以喜欢多个视频。记得设置用户表为settings.AUTH_USER_MODEL
  • collected 收藏的用户。数据类型是ManyToManyField,这是一种多对多的关系,表示一个视频可以被多个用户收藏,一个用户也可以收藏多个视频。设置用户表为settings.AUTH_USER_MODEL

更多关于ManyToManyField的使用介绍,可以查询django官网的介绍。

下面就是详情展示阶段,我们先配置好详情页的路由信息,在video/urls.py中追加detail的路由信息。


app_name = 'video'
urlpatterns = [path('index', views.IndexView.as_view(), name='index'),path('search/', views.SearchListView.as_view(), name='search'),path('detail/<int:pk>/', views.VideoDetailView.as_view(), name='detail'),
]

path('detail/<int:pk>/', views.VideoDetailView.as_view(), name='detail')即表示详情信息,注意每条视频都是有自己的主键的,所以设置路径匹配为detail/<int:pk>/,其中<int:pk>表示主键,这是django中表示主键的一种方法。这样我们就可以在浏览器输入127.0.0.1:8000/video/detail/xxx来访问详情了。

怎么显示详情呢,聪明的django为我们提供了DetailView。urls.py中设置的视图类是VideoDetailView,我们让VideoDetailView继承DetailView即可。

class VideoDetailView(generic.DetailView):model = Videotemplate_name = 'video/detail.html' 

看起来超级简单,django就是如此的酷,只需要我们配置几行代码,就能实现很强大的功能。这里我们配置model为Video模型,模板为video/detail.html,其它的工作都不用管,全都交给django去干,oh,这棒极了。

模板文件位于templates/video/detail.html,它的代码比较简单,这里就不贴了。

从效果图上我们看到还有个观看次数的展示,这里的观看次数本质上就是数据库里的一个自增字段,每次观看的时候,view_count自动加1。对于这个小需求,我们需要做两件事情,首先这video模型里面,添加一个次数自增函数,命名为increase_view_count,这很简单,如下所示:

    def increase_view_count(self):self.view_count += 1self.save(update_fields=['view_count'])

然后,还需要我们在VideoDetailView视图类里面调用到这个函数。这个时候get_object()派上用场了。因为每次调用DetailView的时候,django都会回调get_object()这个函数。因此我们可以把increase_view_count()放到get_object()里面执行。完美的代码如下

class VideoDetailView(generic.DetailView):model = Videotemplate_name = 'video/detail.html'def get_object(self, queryset=None):obj = super().get_object()obj.increase_view_count()  # 调用自增函数return obj

目前为止,我们就能在详情页看到标题、描述、观看次数、收藏次数、喜欢次数。预览如下

虽然可以显示收藏人数、喜欢人数。但是目前还没实现点击喜欢/收藏的功能。下面我们来实现。

收藏和喜欢功能

收藏和喜欢是一组动作,因此可以用ajax来实现:用户点击后调用后端接口,接口返回json数据,前端显示结果。

既然需要接口,那我们先添加喜欢/收藏接口的路由,在video/urls.py追加代码如下

path('like/', views.like, name='like'),
path('collect/', views.collect, name='collect'),

由于喜欢和收藏的功能实现非常类似,限于篇幅,我们只实现喜欢功能。

我们先写like函数:

@ajax_required
@require_http_methods(["POST"])
def like(request):if not request.user.is_authenticated:return JsonResponse({"code": 1, "msg": "请先登录"})video_id = request.POST['video_id']video = Video.objects.get(pk=video_id)user = request.uservideo.switch_like(user)return JsonResponse({"code": 0, "likes": video.count_likers(), "user_liked": video.user_liked(user)})

首先判断用户是否登录,如果登录了则调用switch_like(user)来实现喜欢或不喜欢功能,最后返回json。注意这里添加了两个注解@ajax_required@require_http_methods(["POST"]),分别验证request必须是ajax和post请求。

switch_like()函数则写在了video/model.py里面

    def switch_like(self, user):if user in self.liked.all():self.liked.remove(user)else:self.liked.add(user)

所有的后端工作都准备好了,我们再把视线转向前端。前端主要是写ajax代码。

由于ajax代码量较大,我们封装到一个单独的js文件中 ==> static/js/detail.js

在detail.js中,我们先实现喜欢的ajax调用:

$(function () {// 写入csrf$.getScript("/static/js/csrftoken.js");// 喜欢$("#like").click(function(){var video_id = $("#like").attr("video-id");$.ajax({url: '/video/like/',data: {video_id: video_id,'csrf_token': csrftoken},type: 'POST',dataType: 'json',success: function (data) {var code = data.codeif(code == 0){var likes = data.likesvar user_liked = data.user_liked$('#like-count').text(likes)if(user_liked == 0){$('#like').removeClass("grey").addClass("red")}else{$('#like').removeClass("red").addClass("grey")}}else{var msg = data.msgalert(msg)}},error: function(data){alert("点赞失败")}});});

上述代码中,关键代码是$.ajax()函数,我们传入了参数:video_idcsrftoken。其中csrftoken可通过/static/js/csrftoken.js生成。在success回调中,通过判断user_liked的值来确定自己是否喜欢过,然后改变模板中相应的css。

推荐功能

每个网站都有自己的推荐功能,且都有自己的推荐逻辑。我们视点的推荐逻辑是根据访问次数最高的n个视频来降序排序,然后推荐给用户的。

实现起来非常容易,我们知道详情页实现用的是VideoDetailView,我们可以在get_context_data()中把推荐内容传递给前端模板。只需要我们改写VideoDetailView的get_context_date()函数。

    def get_context_data(self, **kwargs):context = super(VideoDetailView, self).get_context_data(**kwargs)form = CommentForm()recommend_list = Video.objects.get_recommend_list()context['form'] = formcontext['recommend_list'] = recommend_listreturn context

改写后,我们添加了一行

recommend_list = Video.objects.get_recommend_list()

我们把获取推荐列表的函数get_recommend_list()封装到了Video模型里面。在Video/models.py里面
我们追加代码:

class VideoQuerySet(models.query.QuerySet):def get_recommend_list(self):return self.filter(status=0).order_by('-view_count')[:4]

关键是self.filter(status=0).order_by('-view_count')[:4],通过order_by把view_count降序排序,并选取前4条数据。

注意此处我们用了VideoQuerySet查询器,需要我们在Video下面添加一行依赖。表示用VideoQuerySet作为Video的查询管理器。

objects = VideoQuerySet.as_manager()

当模板拿到数据后,即可渲染显示。这里我们将推荐侧栏的代码封装到templates/video/recommend.html里面。

# templates/video/recommend.html
{% load thumbnail %}
<span class="video-side-title">推荐列表</span>
<div class="ui unstackable divided items">{% for item in recommend_list %}<div class="item"><div class="ui tiny image">{% thumbnail item.cover "300x200" crop="center" as im %}<img class="ui image" src="{{ im.url }}">{% empty %}{% endthumbnail %}</div><div class="middle aligned content"><a class=" header-title" href="{% url 'video:detail' item.pk %}">{{ item.title }}</a><div class="meta"><span class="description">{{ item.view_count }}次观看</span></div></div></div>{% empty %}<h3>暂无推荐</h3>{% endfor %}</div>

并在detail.html中将它包含进来

{% include "video/recommend.html" %}

评论功能

评论区位于详情页下侧,显示效果如下。共分为两个部分:评论form和评论列表。

评论功能是一个独立的模块,该功能通用性较高,在其他很多网站中都有评论功能,为了避免以后开发其他网站时重复造轮子,我们建立一个新的应用,命名为comment

python3 manage.py startapp comment

接下来,我们创建comment模型

# 位于comment/models.pyclass Comment(models.Model):user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)nickname = models.CharField(max_length=30,blank=True, null=True)avatar = models.CharField(max_length=100,blank=True, null=True)video = models.ForeignKey(Video, on_delete=models.CASCADE)content = models.CharField(max_length=100)timestamp = models.DateTimeField(auto_now_add=True) class Meta:db_table = "v_comment"
  • user 用户。数据类型是ForeignKey,外键是settings.AUTH_USER_MODEL,并设置为级联删除on_delete=models.CASCADE
  • nickname 用户昵称。数据类型是CharField。
  • avatar 头像。数据类型是CharField。
  • video 对应的视频。数据类型是ForeignKey,对应Video模型,级联删除 on_delete=models.CASCADE
  • content 评论内容。 数据类型是CharField。
  • timestamp 评论时间。 数据类型是DateTimeField。

有了模型之后,我们就可以专心写业务代码了,首先在comment下建立路由文件urls.py。并写入代码:

from django.urls import path
from . import viewsapp_name = 'comment'
urlpatterns = [path('submit_comment/<int:pk>',views.submit_comment, name='submit_comment'),path('get_comments/', views.get_comments, name='get_comments'),
]

我们配置了两条路由信息:评论提交 和 获取评论。

提交评论,需要一个form,我们把form放到video/forms.py

from django import forms
from comment.models import Commentclass CommentForm(forms.ModelForm):content = forms.CharField(error_messages={'required': '不能为空',},widget=forms.Textarea(attrs = {'placeholder': '请输入评论内容' }))class Meta:model = Commentfields = ['content']

然后在video/views.py的VideoDetailView下添加form的相关代码。

class VideoDetailView(generic.DetailView):model = Videotemplate_name = 'video/detail.html'def get_object(self, queryset=None):obj = super().get_object()obj.increase_view_count()return objdef get_context_data(self, **kwargs):context = super(VideoDetailView, self).get_context_data(**kwargs)form = CommentForm() context['form'] = form return context

在get_context_data()函数里面,我们把form传递给模板。

同样的,提交评论也是异步的,我们用ajax实现,我们打开static/js/detail.js,写入

    // 提交评论var frm = $('#comment_form')frm.submit(function () {$.ajax({type: frm.attr('method'),url: frm.attr('action'),dataType:'json',data: frm.serialize(),success: function (data) {var code = data.codevar msg = data.msgif(code == 0){$('#id_content').val("")$('.comment-list').prepend(data.html);$('#comment-result').text("评论成功")$('.info').show().delay(2000).fadeOut(800)}else{$('#comment-result').text(msg)$('.info').show().delay(2000).fadeOut(800);}},error: function(data) {}});return false;});

评论通过ajax提交后,我们在submit_comment()中就能接收到这个请求。处理如下

def submit_comment(request,pk):video = get_object_or_404(Video, pk = pk)form = CommentForm(data=request.POST)if form.is_valid():new_comment = form.save(commit=False)new_comment.user = request.usernew_comment.nickname = request.user.nicknamenew_comment.avatar = request.user.avatarnew_comment.video = videonew_comment.save()data = dict()data['nickname'] = request.user.nicknamedata['avatar'] = request.user.avatardata['timestamp'] = datetime.fromtimestamp(datetime.now().timestamp())data['content'] = new_comment.contentcomments = list()comments.append(data)html = render_to_string("comment/comment_single.html", {"comments": comments})return JsonResponse({"code":0,"html": html})return JsonResponse({"code":1,'msg':'评论失败!'})

在接收函数中,通过form自带的验证函数来保存记录,然后将这条记录返回到前端模板。

下面我们开始评论列表的开发。

评论列表部分,我们使用了的是上拉动态加载的方案,即当页面拉到最下侧时,js加载代码会自动的获取下一页的数据并显示出来。前端部分,我们使用了一种基于js的开源加载插件。基于这个插件,可以很容易实现网页的上拉动态加载效果。它使用超级简单,仅需要调用$('.comments').dropload({})即可。我们把调用的代码封装在static/js/load_comments.js里面。

完整的调用代码如下:

$(function(){// 页数var page = 0;// 每页展示15个var page_size = 15;// dropload$('.comments').dropload({scrollArea : window,loadDownFn : function(me){page++;$.ajax({type: 'GET',url: comments_url,data:{video_id: video_id,page: page,page_size: page_size},dataType: 'json',success: function(data){var code = data.codevar count = data.comment_countif(code == 0){$('#id_comment_label').text(count + "条评论");$('.comment-list').append(data.html);me.resetload();}else{me.lock();me.noData();me.resetload();}},error: function(xhr, type){me.resetload();}});}});
});

不用过多的解释,这段代码已经非常非常清晰了,本质还是ajax的接口请求调用,调用后返回结果更新前端网页内容。

我们看到ajax调用的接口是get_comments,我们继续来实现它,它位于comment/views.py中。代码如下所示,这段代码也很简单,没有什么复杂的技术。当获取到page和page_size后,使用paginator对象来实现分页。最后通过render_to_string将html传递给模板。

def get_comments(request):if not request.is_ajax():return HttpResponseBadRequest()page = request.GET.get('page')page_size = request.GET.get('page_size')video_id = request.GET.get('video_id')video = get_object_or_404(Video, pk=video_id)comments = video.comment_set.order_by('-timestamp').all()comment_count = len(comments)paginator = Paginator(comments, page_size)try:rows = paginator.page(page)except PageNotAnInteger:rows = paginator.page(1)except EmptyPage:rows = []if len(rows) > 0:code = 0html = render_to_string("comment/comment_single.html", {"comments": rows})else:code = 1html = ""return JsonResponse({"code":code,"html": html,"comment_count": comment_count})

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.luyixian.cn/news_show_748354.aspx

如若内容造成侵权/违法违规/事实不符,请联系dt猫网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

网站ICP备案快速通过,需要做好以下准备工作

网站备案过程中&#xff0c;由于前期准备工作不足&#xff0c;就会遇到各种不通过情况&#xff0c;今天审核说你域名不合格&#xff0c;明天说你网站信息不合格&#xff0c;其实都是前期的准备工作没有做好&#xff0c;网站涉及的资料和步骤多而且繁琐&#xff0c;我们总结了以…

Linux云计算—Apache 服务器概述-安装-搭建 Web 网站服务器之前的环境搭建

Apache 服务器概述-安装 Apache 服务器概述-安装 WEB 服务器也称为 WWW(WORLD WIDE WEB&#xff0c;万维网)服务器&#xff0c;主要功能是提供网上信息浏览 服务。 常见 web 服务器&#xff1a; httpd&#xff08;Apache&#xff09;、nginxPHP Tomcat&#xff1a; jsp htm…

转:构建无坚不摧的网站环境——NLB+Cluster(二)

来自&#xff1a;http://technet.microsoft.com/zh-cn/ff806315.aspx上次咱们已经构建起了基于windows服务器群集&#xff08;Cluster&#xff09;的SQL数据库系统&#xff0c;解决了后台的问题&#xff0c;本次将会借助于windows网络负载平衡群集&#xff08;NLB&#xff09;解…

大型网站架构之应用服务器集群化

随着网站的发展&#xff0c;一台应用服务器无法处理太多用户请求&#xff0c;考虑部署多台应用服务器组成集群来提供服务。此时问题来了&#xff1f; 问题1&#xff1a;扩展到多台应用服务器时&#xff0c;可能同一个用户的先后两次请求由不同的应用服务器处理&#xff0c;这个…

介绍两个测试网页打开速度的网站

第一个是Pingdom Tools - Full page test 这个能详细测试网页各部分打开的时间官方介绍:The Full Page Test loads a complete HTML page including all objects (images, CSS, .s, RSS, Flash and frames/iframes). It mimics the way a page is loaded in a web browser.The …

【SEO优化,网络营销】刘克亚《利润腾挪》,一分钟销售51000元的书

刘克亚新作《利润腾挪》书和视频正式发售的第一分钟&#xff0c;就成交了17个订单&#xff0c;每单3000元&#xff0c;产生了51000元的销售业绩.这本书和视频是2010年9月初问世的&#xff0c;这两年内有超过5万人以上秘密的看过这本书和视频。你已经错过了克亚老师的面授和提前…

Win2003下实现Web虚拟网站

一、IP地址法一般情况下&#xff0c;一块网卡只设置了一个IP地址。如果我们为这块网卡绑定多个IP地址&#xff0c;每个IP地址对应一个Web站点&#xff0c;那么同样可以实现“一机多站”的目的。假定[url]www.ghq.com[/url]、study.ghq.com 和 test.ghq.com 三个网站的IP地址绑定…

.net 开发怎么实现前后端分离_React+Egg前后端分离实现个人网站

利用闲暇时光&#xff0c;对自己的个人网站进行了改版。虽然自己博客没写几篇&#xff0c;但对博客网站却进行了多次改版。转念又想。独乐乐不如众乐乐&#xff0c;于是又开源了出来&#xff0c;供大家学习和交流。这次和上次不同的是&#xff0c;这次使用了Node全栈开发。并且…

让用户关上门说话:覆盖全美6000个社区的邻居私密社交网站Nextdoor是如何壮大的?...

中国人常讲“远亲不如近邻”&#xff0c;老一辈的可能做得不错&#xff0c;可越往信息时代走&#xff0c;邻里之间似乎淡漠得越多。现在有多少人不是一回家就紧闭房门两耳不闻窗外事的&#xff1f;技术方便了我们生活的同时&#xff0c;也一定程度淡化了某些温暖的东西。据美国…

云服务器搭网站需要买域名吗,买了云服务器还要买域名吗

买了云服务器还要买域名吗 内容精选换一换当创建文件系统后&#xff0c;您需要使用云服务器来挂载该文件系统&#xff0c;以实现多个云服务器共享使用文件系统的目的。本章节以Windows 2012版本操作系统为例进行CIFS类型的文件系统的挂载。同一SFS容量型文件系统不能同时支持NF…

MSDTC服务无法启动,导致网站打不开

1. 如果只是提示需要MSDTC 那么点开始→运行→输入命令"net start msdtc",运行该命令即可. 2. 如果启动不了&#xff0c;请查看事件查看器 在系统事件中有错误:Distributed Transaction Coordinator 服务因 3221229584 (0xC0001010) 服务性错误而停止。 经多次试验,发…

网站运维异地备份方案及故障应急备用镜像站

网站运维异地备份方案及故障应急备用镜像站 定期检查异地备份故障应急时,启用应急Web服务 欢迎朋友一起交流&#xff0c;讨论。扣扣&#xff1a;柒⑥柒陆叁⑤叁伍转载于:https://blog.51cto.com/jimmyli/584992

web服务器的教学网站,04-WEB服务器

服务器----电脑WEB服务器-是一个程序---软件。在第二节课&#xff0c;我们购买了一台服务器后。接下来我们就可以通过远程连接IP 和电脑的账号密码 远程登录到这台服务器上面。有一些虚拟主机。就不能远程。只能通过FTP工具 登录上去后 进行文件的上传和下载。web服务器。额前面…

高处不胜寒网站排名理想后更需努力

2019独角兽企业重金招聘Python工程师标准>>> “无限风光虽在险峰&#xff0c;但玉树临风&#xff0c;高处不胜寒冷”&#xff0c;网站制作与网站优化就是这样一个过程&#xff0c;每个人都在追逐数目极其有限的几个位置&#xff0c;都在围着梦想不断冲刺努力。每天不…

优化网站设计(十):最小化JAVASCRIPT和CSS

前言 网站设计的优化是一个很大的话题,有一些通用的原则,也有针对不同开发平台的一些建议。这方面的研究一直没有停止过&#xff0c;我在不同的场合也分享过这样的话题。 作为通用的原则&#xff0c;雅虎的工程师团队曾经给出过35个最佳实践。这个列表请参考 Best Practices f…

易班站内应用、轻应用、网站接入、移动应用的区别

一、站内应用 地址如下&#xff1a; index.jsp对应如下页面 启动tomcat服务器&#xff0c;此时访问站内地址&#xff08; http://f.yiban.cn/wangyang&#xff09;。即可得到如下界面&#xff1a; 可以看到我们的应用是嵌套在易班的一个iframe中 二、轻应用 index.jsp对应如下…

ASP.NET MVC实现网站验证码功能

网站添加验证码&#xff0c;主要为防止机器人程序批量注册&#xff0c;或对特定的注册用户用特定程序暴力破解方式&#xff0c;以进行不断的登录、灌水等危害网站的操作。验证码被广泛应用在注册、登录、留言等提交信息到服务器端处理的页面中。 在ASP.NET网站中应用验证码…

BlueDream.js(蓝梦)——jQuery网站使用引导插件

小菜在前端世界游荡有些时间了&#xff0c;常见的插件多少有些了解&#xff0c;但却很少看到用户引导插件。 所谓用户引导插件&#xff0c;就是在第一次使用某个网站时&#xff0c;会弹出一些小动画&#xff0c;告诉你网站的基本使用方法&#xff0c;帮你快速入门。 这应该是个…

Nginx做为web服务器的网站

2019独角兽企业重金招聘Python工程师标准>>> Nginx 超越Apache的高性能和稳定性,使得国内使用 Nginx 作为 Web 服务器的网站也越来越多,其中有新浪、网易、腾讯等门户网站,六间房、酷6等视频分享网站,Discuz!、水木社区等知名论坛,豆瓣、YUPOO等新兴Web 2.0网站。 N…

ASP.NET vNext MVC 6 电商网站开发实战

国内第一个《微软下一代网站开发框架&#xff1a;ASP.NET MVC 6 新特性揭秘 》课程 微软特邀讲师 徐雷&#xff01;周六晚8点YY预定&#xff1a;http://t.cn/RPKMLGF 微软Visual Studio 2014 即将发布&#xff01;ASP.NET MVC 6有什么新特性&#xff1f; Web API 3.0有什么新变…