开发 Django 博客文章阅读量统计功能
文中所涉及的示例代码,已同步更新到 HelloGitHub-Team 仓库
如何精确地记录一篇文章的阅读量是一个比较复杂的问题,不过对于我们的博客来说,没有必要记录的那么精确。因此我们使用一种简单但有效的方式来记录博客文章的阅读量:文章每被浏览一次,则其阅读量 +1,即所谓的文章页面 PV(Page View)数。虽然简单粗暴,但却高效实用。
增加新字段
为了记录文章的浏览量,需要在文章的数据库表中新增一个用于存储阅读量的字段。因此给博客文章的模型新增一个 views
字段:
blog/models.py
class Post(models.Model):
# ... 其它已有字段
# 新增 views 字段记录阅读量
views = models.PositiveIntegerField(default=0, editable=False)
注意 views
字段的类型为 PositiveIntegerField
,该类型的值只允许为正整数或 0,因为阅读量不可能为负值。初始化时 views
的值为 0。将 editable
参数设为 False
将不允许通过 django admin 后台编辑此字段的内容。因为阅读量应该根据被访问次数统计,而不应该人为修改。
增加模型方法
一旦用户访问了某篇文章,这时就应该将 views
的值 +1,这个过程最好由 Post
模型自己来完成,因此再给模型添加一个自定义的方法:
blog/models.py
class Post(models.Model):
# ... 其它已有字段
# 新增 views 字段记录阅读量
views = models.PositiveIntegerField(default=0)
# ... 其它已有的模型方法
def increase_views(self):
self.views += 1
self.save(update_fields=['views'])
increase_views
方法首先将自身对应的 views
字段的值 +1(此时数据库中的值还没变),然后调用 save
方法将更改后的值保存到数据库。注意这里使用了 update_fields
参数来告诉 Django 只更新数据库中 views
字段的值,以提高效率。
你也许担心如果两个人同时访问一篇文章,更改数据库中的阅读量字段的值时会不会冲突?其实不必担心,我们本来就不是精确地统计阅读量,而且个人博客的流量通常也不会很大,所以偶尔的冲突导致的数据误差是可以忽略不计的。
迁移数据库
一旦更改了模型,就需要迁移数据库,以便让 Django 将更改反应到数据库中。在项目根目录运行如下两条命令:
$ pipenv run python manage.py makemigrations
$ pipenv run python manage.py migrate
关于数据库的迁移,具体可以参考 Django 迁移、操作数据库。
修改视图函数
当用户请求访问某篇文章时,处理该请求的视图函数为 detail
。一旦该视图函数被调用,说明文章被访问了一次,因此我们修改 detail
视图函数,让被访问的文章在视图函数被调用时阅读量 +1。
blog/views.py
def detail(request, pk):
post = get_object_or_404(Post, pk=pk)
# 阅读量 +1
post.increase_views()
md = markdown.Markdown(extensions=[
'markdown.extensions.extra',
'markdown.extensions.codehilite',
# 记得在顶部引入 TocExtension 和 slugify
TocExtension(slugify=slugify),
])
post.body = md.convert(post.body)
m = re.search(r'<div class="toc">\s*<ul>(.*)</ul>\s*</div>', md.toc, re.S)
post.toc = m.group(1) if m is not None else ''
return render(request, 'blog/detail.html', context={'post': post})
即只需在视图函数中调用模型的 increase_views
方法即可。
在模板中显示阅读量
在模板中显示阅读量和显示其它字段一样,只需要使用模板变量即可。即模板适当的地方使用 {{ post.views }} 模板变量。这里我们分别修改两个地方,分别是 index.html 和 detail.html。
templates/blog/index.html
<div class="entry-meta">
...
<span class="views-count"><a href="{{ post.get_absolute_url }}">{{ post.views }} 阅读</a></span>
</div>
templates/blog/detail.html
<div class="entry-meta">
...
<span class="views-count"><a href="#">{{ post.views }} 阅读</a></span>
</div>
好了,这样当用户每访问一次文章详情,views
记录的数值就会 +1,从而达到粗略统计阅读量的目的。
『讲解开源项目系列』——让对开源项目感兴趣的人不再畏惧、让开源项目的发起者不再孤单。跟着我们的文章,你会发现编程的乐趣、使用和发现参与开源项目如此简单。欢迎留言联系我们、加入我们,让更多人爱上开源、贡献开源~
开发 Django 博客文章阅读量统计功能的更多相关文章
- 利用Github Pages创建的Jekyll模板个人博客添加阅读量统计功能
目录 前言 准备工作 模板文件修改 写在最后 内容转载自我自己的博客 @(文章目录) 前言 Jekyll 是一个简单的免费的 Blog 生成工具,类似 WordPress .它只是一个生成静态网页的工 ...
- 基于.NetCore开发博客项目 StarBlog - (6) 页面开发之博客文章列表
系列文章 基于.NetCore开发博客项目 StarBlog - (1) 为什么需要自己写一个博客? 基于.NetCore开发博客项目 StarBlog - (2) 环境准备和创建项目 基于.NetC ...
- 为你的CSDN博客添加CNZZ流量统计功能
一.流量统计介绍 流量统计是指通过各种科学的方式,准确的纪录来访某一页面的访问者的流量信息,目前而言,必须具备可以统计. 1.简介 统计独立的访问者数量(独立用户.独立访客): 可以统计独立的IP地址 ...
- web开发-Django博客系统
项目界面图片预览 项目代码github地址 项目完整流程 项目流程: 1 搞清楚需求(产品经理) (1) 基于用户认证组件和Ajax实现登录验证(图片验证码) (2) 基于forms组件和Ajax实现 ...
- 搭建自己的博客(九):使用shell模式批量添加博客文章并增加分页功能
想做个博客分页功能,但是没有太多的文章.所以使用shell命令行创建多篇文章. 1.打开pycharm下的terminal终端 python manage.py shell # 打开python终端 ...
- WordPress文章阅读量统计和显示(非插件, 刷新页面不累加)
本文已同步到专业技术网站 www.sufaith.com, 该网站专注于前后端开发技术与经验分享, 包含Web开发.Nodejs.Python.Linux.IT资讯等板块. WordPress文章阅读 ...
- Django 博客开发教程目录索引
Django 博客开发教程目录索引 本项目适合 0 基础的 Django 开发新人. 项目演示地址:Black & White,代码 GitHub 仓库地址:zmrenwu/django-bl ...
- django博客项目8:文章详情页
首页展示的是所有文章的列表,当用户看到感兴趣的文章时,他点击文章的标题或者继续阅读的按钮,应该跳转到文章的详情页面来阅读文章的详细内容.现在让我们来开发博客的详情页面,有了前面的基础,开发流程都是一样 ...
- 使用IntelliJ IDEA开发SpringMVC网站(五)博客文章管理
原文:使用IntelliJ IDEA开发SpringMVC网站(五)博客文章管理 摘要 通过对博客文章的管理,实现外键操作. 目录[-] 八.博客文章管理 1.查看文章 2.添加博客 3 ...
随机推荐
- 2019最新WEB全栈架构师第八期视频教程
下载链接:https://www.yinxiangit.com/117.html
- kubernetes部署高可用Harbor
前言 本文Harbor高可用依照Harbor官网部署,主要思路如下,大家可以根据具体情况选择搭建. 部署Postgresql高可用集群.(本文选用Stolon进行管理,请查看文章<kuberne ...
- 基于redis(订阅发布)实现python和java进程间通信
主要结构为: python进程发布消息,java进程订阅消息. 依赖环境: python: pip install redis java: jedis 1. python端: PubSub.py ...
- valueForKey与valueForKeyPath 区别
1.删除数组中重复的数据 2.valueForKeyPath:可以深层次取到子属性,不管隐藏的多深 valueForKey:无法取到深层次子属性 但是也有其相似的地方: 比如:快速找到字典数组中ke ...
- 注解@Async解决异步调用问题
序言:Spring中@Async 根据Spring的文档说明,默认采用的是单线程的模式的.所以在Java应用中,绝大多数情况下都是通过同步的方式来实现交互处理的. 那么当多个任务的执行势必会相互影响. ...
- mybatis-geneator
一.简介 在使用mybatis时我们需要重复的去创建pojo类.mapper文件以及dao类并且需要配置它们之间的依赖关系,比较麻烦且做了大量的重复工作,mybatis官方也发现了这个问题, 因此给我 ...
- PHPCon 2019 第七届 PHP 开发者大会总结
往届回顾-2018:PHPCon 2018链接: https://pan.baidu.com/s/17nfrfqk9K4vwKPAsjBVW7A——提取码:rjbr 随着PHP7的诞生,兼顾了高性能和 ...
- 字符串转化成int
将str转化成int #include<stdio.h> #include<string> int err = 0; int str_to_int(char *s) { lon ...
- activity的隐式和显式启动
显式Intent(Explicit intent):通过指定Intent组件名称来实现的,它一般用在知道目标组件名称的前提下,一般是在相同的应用程序内部实现的. 隐式Intent(Implicit i ...
- 素数路径Prime Path POJ-3126 素数,BFS
题目链接:Prime Path 题目大意 从一个四位素数m开始,每次只允许变动一位数字使其变成另一个四位素数.求最终把m变成n所需的最少次数. 思路 BFS.搜索的时候,最低位为0,2,4,6,8可以 ...