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;本节实例也是一种应用场景。

 

posted @ 2019-05-23 11:31  taoziya  阅读(256)  评论(0)    收藏  举报