博客閱讀數(shù)的統(tǒng)計三部曲【一】-3種方式中講到的3種方式扼仲,其模型都是在blog應(yīng)用下models.py里面寫的,這樣耦合性太強渠缕,不利于以后給其他應(yīng)用的拓展
這節(jié)講的是將閱讀計數(shù)的功能單獨創(chuàng)建出一個app應(yīng)用,打包發(fā)后便于其他項目的拓展使用
app應(yīng)用的分離
Github源碼地址:請點這里
1.此方法是將閱讀計數(shù)功能分離出來,獨立作為一個app引用趋距,便于打包在線安裝供其他項目中的使用
其中使用的功能方法詳見Django官方文檔“The contenttypes framework”(內(nèi)容類型框架)
具體頁面鏈接地址:Django官網(wǎng)文檔
2.首先使用命令新建獨立應(yīng)用
python manage.py startapp read_statistics
接下來將read_statistics應(yīng)用添加到settings.py的apps里面,如下圖:
3.創(chuàng)建read_statistics應(yīng)用下的models.py模型
具體參照Django官方文檔: https://docs.djangoproject.com/en/2.0/ref/contrib/contenttypes/
from django.db import models
from django.contrib.contenttypes.fields import GenericForeignKey
from django.contrib.contenttypes.models import ContentType
class ReadNum(models.Model):
read_num=models.IntegerField(default=0,verbose_name='閱讀數(shù)')
content_type = models.ForeignKey(ContentType, on_delete=models.DO_NOTHING)
object_id = models.PositiveIntegerField()
content_object = GenericForeignKey('content_type', 'object_id')
class Meta:
verbose_name='閱讀數(shù)'
verbose_name_plural=verbose_name
4.同步更新數(shù)據(jù)庫操作
python manage.py makemigrations
python manage.py migrate
5.配置read_statistics應(yīng)用下的admin.py
from django.contrib import admin
from .models import ReadNum
class ReadNumAdmin(admin.ModelAdmin):
list_display=('id','read_num','content_object')
admin.site.register(ReadNum,ReadNumAdmin)
添加完成后Django登錄管理界面
6.下面在blog應(yīng)用下的models.py模型里面添加獲取閱讀數(shù)的方法get_read_num()
注意:添加這個方法是為了在Django管理界面的blog應(yīng)用下越除,將get_read_num添加到list_display展示列表节腐,從而可以在博客頁面直接看到該篇文章所對應(yīng)的閱讀數(shù)
記得引用
from django.db.models.fields import exceptions
from django.contrib.contenttypes.models import ContentType
from read_statistics.models import ReadNum
from django.db import models
from django.db.models.fields import exceptions
from django.contrib.auth.models import User
from django.contrib.contenttypes.models import ContentType
from ckeditor_uploader.fields import RichTextUploadingField
from read_statistics.models import ReadNum
class Blog(models.Model):
title=models.CharField(max_length=50,verbose_name=u'標題')
blog_type=models.ForeignKey(Blog_type,on_delete=models.DO_NOTHING)
content=RichTextUploadingField()
author=models.ForeignKey(User,on_delete=models.DO_NOTHING,verbose_name='作者')
created_time=models.DateTimeField(auto_now_add=True,verbose_name=u'創(chuàng)建時間')
last_update_time=models.DateTimeField(auto_now=True,verbose_name=u'修改時間')
is_delete=models.BooleanField(default=False,verbose_name=u'是否刪除')
# 添加方法,添加的get_read_num方法,用于在admin管理后臺的blog頁面顯示閱讀數(shù)摘盆。即在admin.py的 BlogAdmin類的list_display添加read_num
def get_read_num(self):
# 返回該篇文章的閱讀數(shù),此處如果該文章還沒有閱讀數(shù)翼雀,會有個異常,該異常是的默認閱讀數(shù)不是0孩擂,而是-
try:
ct=ContentType.objects.get_for_model(Blog)
readnum=ReadNum.objects.get(content_type=ct,object_id=self.pk)
return readnum.read_num
except exceptions.ObjectDoesNotExist:
return 0
class Meta:
ordering=['-created_time']
verbose_name='博客'
verbose_name_plural=verbose_name
def __str__(self):
return self.title
7.再將上面get_read_num()方法添加到blog應(yīng)用下面的admin.py的list_display列表
完成后狼渊,打開Django管理頁面的博客,便可以看到每篇文章get_read_num的閱讀數(shù)类垦,如下圖:
8.在bolg應(yīng)用下的views.py狈邑,處理用于前臺頁面閱讀數(shù)展示的邏輯關(guān)系
from django.contrib.contenttypes.models import ContentType
from read_statistics.models import ReadNum
def blog_detail(request,blog_pk):
"""博客詳情頁"""
blog=get_object_or_404(Blog,pk=blog_pk) # 根據(jù)傳入blog_pk的ID來找到具體對應(yīng)博客文章
# 獲取cookie:根據(jù)獲取cookie的key值'blog_%s_readed' % blog_pk,判斷是否存在蚤认,不存在則閱讀數(shù) +1
if not request.COOKIES.get('blog_%s_read' % blog_pk):
ct=ContentType.objects.get_for_model(Blog)
if ReadNum.objects.filter(content_type=ct,object_id=blog.pk).count():
# 記錄存在,則查詢并閱讀數(shù)+1米苹,保存
readnum=ReadNum.objects.get(content_type=ct,object_id=blog.pk)
else:
# 對應(yīng)記錄不存在,則創(chuàng)建并閱讀數(shù)+1砰琢,保存(這樣就會在閱讀數(shù)管理頁面點擊后保存對應(yīng)文章以及閱讀數(shù))
readnum=ReadNum(content_type=ct,object_id=blog.pk)
readnum.read_num += 1 #點擊該篇文章蘸嘶,閱讀數(shù)自增1
readnum.save()
pre_blog=Blog.objects.filter(id__gt=blog.id).last() # 博客的上一篇文章
next_blog=Blog.objects.filter(id__lt=blog.id).first() # 博客的下一篇文章
response=render(request,'blog/blog_detail.html',{'blog':blog,'pre_blog':pre_blog,'next_blog':next_blog}) #響應(yīng)
# 設(shè)置cookie,打開過這篇文章即寫入cookie,key是'blog_%s_readed' % blog_pk,value是'true'
response.set_cookie('blog_%s_read' % blog_pk,'true')
return response
9.最后在html頁面,使用get_read_num方法獲取閱讀數(shù)的數(shù)據(jù)