首發於Python與Web
關注專欄寫文章
【記錄】Django學習34
以後的每一天。
關注她
對文章的閱讀次數進行記錄與統計,另外數據庫在原來的基礎上加一個Redis。
1、安裝Reids,然後改掉默認端口號。
vim redis.conf
root@Grace:/opt/redis-5.0.0/src# ./redis-server ../redis.conf #按配置啓動
./redis-cli -p port_number
redis雖然是root安裝的,所屬權也歸root,但對其他用戶是r-x權限,執行還是沒問題的。
2、REDIS相關配置(HOST PORT DB)放settings。
在views.py中引入settings的方法:
from django.conf import settings
注意導入的這個路徑並不是物理路徑。看看這裏怎麼回事?
3、在views.py裏,首先一次性構造連接對象,然後在視圖函數裏執行它的方法。
這樣,全程只有一個連接對象,但是視圖函數的每調用一次就操作一次數據庫。
r = redis.StrictRedis(host=settings.REDIS_HOST, port=settings.REDIS_PORT, db=settings.REDIS_DB)
total_views = r.incr("article:{}:views".format(article.id))
每篇文章的瀏覽次數是redis裏面的value,它的key就是"article:{}:views".format(article.id)。
r.incr,用到的是redis字符串類型,如果沒有定義,變量的值從從0開始。
redis命令:【筆記】Redis練習
4、至於閱讀數的最終呈現,只要變量傳進模板就和點贊數的呈現沒什麼區別:
<span style="margin-left:20px">{{ total_views }}view{{ total_views | pluralize:"s" }}</span>
下面來顯示訪問最多的文章。
1、這個結果肯定從數據庫取:
38 def article_detail(request, id, slug):
39 article = get_object_or_404(ArticlePost, id=id, slug=slug)
40 total_views = r.incr("article:{}:views".format(article.id))
41 r.zincrby("article_ranking", article.id, 1)
42
43 article_ranking = r.zrange("article_ranking", 0, -1, desc=True)[:10]
44 article_ranking_ids = [int(id) for id in article_ranking]
45 most_viewed = list(ArticlePost.objects.filter(id__in=article_ranking_ids))
46 most_viewed.sort(key=lambda x: article_ranking_ids.index(x.id))
47
48 return render(request, "article/list/article_detail.html", {"article": article, "total_views": total_views, "most_viewed": most_viewed})
1)redis五大類型之一是sorted-set,sorted-set中的每一個元素除了本身的值還有score作爲排序依據。zincrby就是其中一個方法,用於增加某個元素的socre。
同incr一樣,如果這個sorted-set根本不存在……也是可以用的,會算成新建。
[redis中的例子]
zincrby mysset 5 one
這裏用一個sorted-set來保存文章的排名情況,其中的元素是article.id,得分自然從0開始,每次有訪問(視圖函數被調用)就給得分加1。(其實不明白爲什麼不將就"article:1:views"的取值呢?)
r.zincrby("article_ranking", article.id, 1)
2)article_ranking = r.zrange("article_ranking", 0, -1, desc=True)[:10]
[redis中的例子]
redis 127.0.0.1:6379> zrange mysset 0 -1
1) "one"
2) "two"
3) "three"
4) "four"
desc=True,從"articleranking"這個sorted_set中從大到小取出元素。
3)most_viewed = list(ArticlePost.objects.filter(id__in=article_ranking_ids))
id__in是filter的語法,id在xx區間內。
4)most_viewed.sort(key=lambda x: article_ranking_ids.index(x.id))
是python sort的用法,傳入排序依據的關鍵字,這裏是用article.id找到他在article_ranking_ids中的位置,也就是名詞作爲排序依據。
2、用有序列表<ol>配合for標籤展示most_viewed的每一項。
<ol>
{% for article_rank in most_viewed %}
<li>
<a href="{{ article_rank.get_url_path }}">{{ article_rank.title }}</a>
</li>
{% endfor %}
</ol>
article_rank其實就是ArticlePost的實例,所以具有這2個特性。
3、最後回顧一下,取出閱讀數最大的十篇文章爲什麼用到4條語句:
44 article_ranking = r.zrange("article_ranking", 0, -1, desc=True)[:10]
45 article_ranking_ids = [int(id) for id in article_ranking]
46 most_viewed = list(ArticlePost.objects.filter(id__in=article_ranking_ids))
47 most_viewed.sort(key=lambda x: article_ranking_ids.index(x.id))
- 從sorted_set裏面取出排名前10的10個對象,列表返回,列表的元素是articleid,而不是article本身
- article_id是str,把str轉成int。
- 拿着10個article_id組成的列表篩選出10個article的列表,filter返回的結果又成亂序。
- 對10個article的列表按閱讀量重新排序。
[Redis的優點]
- 讀取速度快
- 豐富的數據類型
- 操作具有原子性
【之後的思考】
以上是照着書上做的,感覺書上這麼操作應該是爲了練習使用Redis,否則是有更簡單的實現方法。
比如這裏就想增加文章的瀏覽數,那麼大可以在ArticlePost裏面加一個字段比如viewcount,然後顯示和修改這個變量就行,找出top10瀏覽量文章也可以把所有文章取出來用sort排序,取key=view_count就行。
但這篇文章的實現脫離了原來的dblite,把每個文章的瀏覽量作爲一個字符串類型的數據存儲在redis裏面;爲了找出top10瀏覽量的文章,在redis裏面又另外開闢了一個sorted-set,其中的元素就是article_id,元素的score表示瀏覽量。 這樣瀏覽量其實被保存了兩次,在我看來是冗餘的,不知道爲什麼要這樣。
編輯於 2018-10-20
贊同添加評論
分享
收藏
文章被以下專欄收錄
主要學習資料:《跟老齊學Python Django實戰》。代碼提交於:https://github.com/tianwei1992/mysite 不對之處請多指教~
關注專欄
推薦閱讀
django框架結構
關於Django,我想推薦這樣一本書給你
揣着Django做項目2:組隊
pyecharts + Flask&Django,該來的總是要來的
還沒有評論
寫下你的評論...
發佈