4.4 文章的阅读次数
在诸多文章中,哪篇文章最受读者关注?要解决这个问题,就需要记录文章被阅读的次数,本节就学习此功能。下面首先了解一个此前没有接触过的数据库----Redis,维基百科中对此数据库做了如下描述。

本节不对此数据库做详细阐述。下面要探讨的是在Django中使用Redis数据库,实现记录文章阅读次数的功能,如下图所示。

4.4.1 安装Redis
安装包下载地址:https://github.com/MSOpenTech/redis/releases
Redis 支持 32 位和 64 位。这个需要根据你系统平台的实际情况选择,这里我们下载 Redis-x64-xxx.zip压缩包到 D:\azb\Redis。


安装完成后,安装目录下大概会有以下几个文件:
redis-server.exe:服务端程序,提供redis服务
redis-cli.exe: 客户端程序,通过它连接redis服务并进行操作
redis-check-dump.exe:本地数据库检查
redis-check-aof.exe:更新日志检查
redis-benchmark.exe:性能测试,用以模拟同时由N个客户端发送M个 SETs/GETs 查询 (类似于 Apache 的ab 工具).
redis.windows.conf: 配置文件,将redis作为普通软件使用的配置,命令行关闭则redis关闭
redis.windows-service.conf:配置文件,将redis作为系统服务的配置,用以区别开两种不同的使用方式
===============================================================
redis配置文件含义
#是否作为守护进程运行
daemonize no
#Redis 默认监听端口
port 6379
#客户端闲置多少秒后,断开连接
timeout 300
#日志显示级别
loglevel verbose
#指定日志输出的文件名,也可指定到标准输出端口
logfile redis.log
#设置数据库的数量,默认最大是16,默认连接的数据库是0,可以通过select N 来连接不同的数据库
databases 32
#Dump持久化策略
#当有一条Keys 数据被改变是,900 秒刷新到disk 一次
#save 900 1
#当有10 条Keys 数据被改变时,300 秒刷新到disk 一次
save 300 100
#当有1w 条keys 数据被改变时,60 秒刷新到disk 一次
save 6000 10000
#当dump .rdb 数据库的时候是否压缩数据对象
rdbcompression yes
#dump 持久化数据保存的文件名
dbfilename dump.rdb
########### Replication #####################
#Redis的主从配置,配置slaveof则实例作为从服务器
#slaveof 192.168.0.105 6379
#主服务器连接密码
# masterauth <master-password>
############## 安全性 ###########
#设置连接密码
#requirepass <password>
############### LIMITS ##############
#最大客户端连接数
# maxclients 128
#最大内存使用率
# maxmemory <bytes>
########## APPEND ONLY MODE #########
#是否开启日志功能
appendonly no
# AOF持久化策略
#appendfsync always
#appendfsync everysec
#appendfsync no
################ VIRTUAL MEMORY ###########
#是否开启VM 功能
#vm-enabled no
# vm-enabled yes
#vm-swap-file logs/redis.swap
#vm-max-memory 0
#vm-page-size 32
#vm-pages 134217728
#vm-max-threads 4
使用默认配置文件启动redis会报错的,需要修改maxmemory这一项,注意单位时字节(209715200是200MB)
maxmemory 209715200
如果需要设置连接密码,就修改requirepass,设为自己的密码。
requirepass mypassword
===========================================================
用记事本或者Notepad++打开redis.windows.conf并找到“# requirepass foobared”这一行,在这一行下面增加一行“requirepass 你的密码 rms123”,暂不加密码
打开cmd 窗口 使用cd命令切换目录到 D:\Redis 运行
redis-server.exe redis.windows.conf
*注:可以把 redis 的路径加到系统的环境变量里,这样就省得再输路径了,后面的那个 redis.windows.conf 可以省略,如果省略,会启用默认的。

出现以上界面,表示你已经启动redis的服务端,如果想退出就按ctrl+C
这时候另启一个cmd窗口,原来的不要关闭,不然就无法访问服务端了。
安装服务:cmd进去redis目录,执行如下命令。
redis-server --service-install redis.windows.conf

不要关闭该cmd控制台 , 双击打开 redis-cli.exe , 如果不报错,则连接上了本地服务器,然后测试,比如 set命令,get命令,首次输入set命令你会发现出来(error) NOAUTH Authentication required.这是因为你已经更改redis.windows.conf的配置密码,然后键入“auth 你的密码”如果出现OK则说明你已经可以使用Redis的客户端了。就可以在控制台随意插入删除数据了,详情如图
查看redis版本: E:\Redis>redis-server –-version

redis的安装源链接:https://blog.csdn.net/java_peak_zlf/article/details/84062584
4.4.2 在Python中使用Redis
为了能够在Python中使用Redis,还需要安装Redis库,安装方法就是使用我们熟悉的pip3,代码如下。

安装完之后,保持Redis服务在启动状态下,在新的终端进入到Python交互模式中,完成如下操作,进行初步体验。
4.4.3 记录阅读次数
首先在./testsite/settings.py文件中做好数据库的配置,即在文件中增加如下变量。
REDIS_HOST = 'localhost' REDIS_PORT = 6379 REDIS_DB = 0
然后编辑./article/list_views.py文件,建立与Redis数据库的连接,即在文件中的视图函数代码之前增加如下代码。
1 import redis 2 from django.conf import settings #① 3 4 r = redis.StrictRedis(host=settings.REDIS_HOST,port=settings.REDIS_PORT,db=settings.REDIS_DB)
语句①用于引入本项目setting.py中的变量,从而能够在下一句的数据库连接中使用。请读者注意这种方式,如果在别的应用中,如有必要,可以使用这种方式在setting.py中做好变量配置,其配置参数可以在各处使用,如settings.REDIS_PORT就是调用了setting.py文件中的REDIS_PORT的值6379。这种使用方法的本质就是在Python中将.py文件视为模块(语句①的效果),不论文件是变量、函数还是类,都可以通过该模块调用。
编辑本文件中的article_detail()视图函数,其修改之后的全部代码如下。
1 def article_detail(request,id,slug): 2 article = get_object_or_404(ArticlePost,id=id,slug=slug) 3 total_views = r.incr("article:{}:views".format(article.id)) #② 4 return render(request, "article/column/article_detail.html", {"article": article,"total_views":total_views}) #③
语句②是新增加的,其功能就是对访问文章的次数进行记录。这里用到了incr函数,为了理解这个函数的使用方法,可以在Redis的客户端进行一番操作,代码如下。

显然,incr函数的作用就是让当前的键值递增,并返回递增后的值。在语句set foo 0中首先设置键foo的值为零,然后进行递增。
Redis对于键的命名并没有强制的要求,比较好的做法是用“对象类型:对象ID:对象属性”来命名一个键,比如语句②中使用键article:15:views来存储ID为15的文章的浏览次数。
在语句③中将文章访问次数传给模板文件,接下来就要在模板文件中展示计数结果。
编辑./templates/article/list/article_detail.html文件,找到原来显示点赞数量的代码,在那里增加访问次数的代码(下述代码中的语句⑤是针对访问次数新增的部分)。
1 <p> 2 <a href="{% url 'article:author_articles' article.author.username %}"> 3 {{ article.author.username }} 4 </a> 5 <span style="margin-left:20px" class="glyghicon glyphicon-thumbs-up">{{ total_likes }}like{{ total_likes|pluralize }}</span> 6 <span style="margin-left:20px">{{ total_views }}view{{ total_likes|pluralize }}</span> #⑤ 7 </p>
启动Django服务,访问任何一篇文章并查看访问次数,然后刷新该文章,再次观察访问次数,如下图所示。

已经实现了文章访问次数记录的功能。那么,能不能将访问次数最多的文章排列到一个“最热文章”的栏目里面呢?需求层出不穷,只有这样才能提高自己的技能。
4.4.4 显示最“热”文章
在刚刚实现的文章访问计数的基础上,实现显示“最热文章”的功能。继续编辑./article/list_view.py文件中的视图函数article_detail(),增加一些代码。为了能够让读者清晰阅读,下面吧此函数的全部代码列出来。
1 def article_detail(request,id,slug): 2 article = get_object_or_404(ArticlePost,id=id,slug=slug) 3 total_views = r.incr("article:{}:views".format(article.id)) 4 r.zincrby('article_ranking',article.id,1) #① 5 6 article_ranking = r.zrange('article_ranking',0,-1,desc=True)[:10] #② 7 article_ranking_ids = [int(id) for id in article_ranking] 8 most_viewed = list(ArticlePost.objects.filter(id__in=article_ranking_ids)) #③ 9 most_viewed.sort(key=lambda x:article_ranking_ids.index(x.id)) #④ 10 return render(request, "article/list/article_detail.html", {"article": article,"total_views":total_views, 11 "most_viewed":most_viewed}) #⑤
语句①中使用了Redis连接对象的一个方法zincrby(要了解这个方法的具体含义,可以在Python的交互模式中使用help()命令),这个方法的完成形式是zincrby(name,value,amount),其作用是根据amount所设定的步长值增加有序集合(name)中的value的数值。在语句①中实现了article_ranking中的article.id以步长1自增,即文章被访问一次,article_ranking就将该文章id的值增加1.
语句②承接语句①的结果,得到article_ranking中排序前10名的对象。zrange(name,start,end,desc=False,withscores=False,score_cast_func=float)也是数据库连接对象的一个方法,读者从参数的名称中也能理解该方法的基本调用形式。
在上述操作的基础上,语句③得到最“热”文章对象组成的列表。注意“id_in”中间是双下划綫,这是Django里面的一种相当于条件查询的语句,其功能是查询出id在article_ranking_ids中所有的文章对象,并以文章对象为元素生成列表。
语句④是对得到的列表进行排序。请读者注意排序关键词条件,使用了lambda函数。
语句⑤中的“most_viewed”:most_viewed相对未修改之前是新增的,请注意不要丢掉。
完成视图函数代码的修改后,在修改模板文件./templates/article/list/article_detail.html,这是文章详细内容页面,我们要实现的功能是将页面分为左右两部分,左边依然显示文章的完整内容,右边则用于显示刚才所设定的“最热文章”栏目。
先将原有的文章内容HTML代码<div class="col-md-9"></div>包裹起来,然后创建展现“最热文章”栏目的代码块<div class="col-md-3"></div>,详细代码如下。
1 <div class="container"> 2 <div class="col-md-9"> 3 <header> 4 <h1>{{ article.title }}</h1> 5 <p> 6 <a href="{% url 'article:author_articles' article.author.username %}"> 7 {{ article.author.username }} 8 </a> 9 <span style="margin-left:20px" class="glyghicon glyphicon-thumbs-up">{{ total_likes }}like{{ total_likes|pluralize }}</span> 10 <span style="margin-left:20px">{{ total_views }}view{{ total_likes|pluralize }}</span> 11 </p> 12 <p><span style="margin-right:10px"><strong>Tags:</strong></span> {{ article.article_tag.all | join:","}} </p> 13 </header> 14 15 <link rel="stylesheet" href="{% static 'editor/css/editormd.preview.css' %}" /> 16 <div id="editormd-view"> 17 <textarea id="append-test" style="display:none;"> 18 {{ article.body }} 19 </textarea> 20 </div> 21 <div> 22 <p class="text-center"> 23 <a onclick="like_article({{article.id}}, 'like')" href="#"><span class="glyghicon glyphicon-thumbs-up">like</span></a> 24 <a onclick="like_article({{article.id}}, 'unlike')" href="#"><span style="margin_left:15px;" class="glyghicon glyphicon-thumbs-down">unlike</span></a> 25 </p> 26 </div> 27 <div> 28 <p class="text-center"><strong>点赞文本的读者</strong></p> 29 {% for user in article.users_like.all %} 30 <p class="text-center">{{ user.username }}</p> 31 {% empty %} 32 <p class="text-center">还没有人对此文章表态</p> 33 {% endfor %} 34 </div> 35 <div class="col-md-3"> 36 <p class="text-center"><h3>最受欢迎文章</h3></p> 37 <ol> 38 {% for article_rank in most_viewed %} 39 <li> 40 <a href="{{article_rank.get_url_path}}">{{ article_rank.title }}</a> 41 </li> 42 {% endfor %} 43 </ol> 44 </div> 45 </div>
最终效果如下图所示(在查看最终结果前,请确认Redis数据库的服务和Dajngo服务已经启动)

本节我们用Redis实现了最“热”文章排序。其实,在Django中实现类似功能还有别的方法,后面会陆续讲解。
Redis的用途绝非上面所讲述的这些,在某些项目中,它的作用非常大,比如某博网站,据说在众多业务场景中使用了Redis,如关系、计数、通知提醒等,每天提供了上万亿次的读取访问。
4.4.5 知识点
1、关于Redis
本节中以最简单的方式使用了Redis,实际上在一些大型的网站中,Redis应用广泛。下面首先介绍它的基本特点。
- Redis将其数据库完全保存在内存中,仅使用磁盘进行持久化。
- 与其他键值数据存储相比,Redis有一组相对丰富的数据类型。
- Redis可以将数据复制到任意数量的其他从属服务器。
上述特点使得Redis具有以下优势。
- Redis读取速度非常快:每秒可执行大约110000次的设置(SET)操作,每秒大约可执行81000次的读取/获取(GET)操作。
- 支持丰富的数据类型:Redis支持常用的大多数数据类型,例如列表、集合、排序集和散列等。
- 操作具有原子性:所有Redis操作都是原子操作,如果两个客户端并发访问,那么Redis服务器接收更新的值。
- 多实用工具:Redis是一个多实用工具,可用于多种用例,例如缓存、消息队列等。此外,Web应用程序中的会话、网页访问量计数等也经常使用Redis.
根据特点和优势,可以想象一下Redis的用武之地,比如网站搞活动有限量抢购,如果每次都访问数据库恐怕会对数据库造成很大的压力,这时就可以借助Redis;本节实例也是一种应用场景。
浙公网安备 33010602011771号