博客閱讀數(shù)的統(tǒng)計(jì)三部曲【二】-閱讀計(jì)數(shù)的分離

博客閱讀數(shù)的統(tǒng)計(jì)三部曲【一】-3種方式中講到的3種方式,其模型都是在blog應(yīng)用下models.py里面寫(xiě)的,這樣耦合性太強(qiáng),不利于以后給其他應(yīng)用的拓展
這節(jié)講的是將閱讀計(jì)數(shù)的功能單獨(dú)創(chuàng)建出一個(gè)app應(yīng)用,打包發(fā)后便于其他項(xiàng)目的拓展使用

app應(yīng)用的分離

Github源碼地址:請(qǐng)點(diǎn)這里

image.png

1.此方法是將閱讀計(jì)數(shù)功能分離出來(lái),獨(dú)立作為一個(gè)app引用,便于打包在線安裝供其他項(xiàng)目中的使用

其中使用的功能方法詳見(jiàn)Django官方文檔“The contenttypes framework”(內(nèi)容類型框架)

具體頁(yè)面鏈接地址:Django官網(wǎng)文檔

image.png

image.png

2.首先使用命令新建獨(dú)立應(yīng)用

python manage.py startapp read_statistics

接下來(lái)將read_statistics應(yīng)用添加到settings.py的apps里面,如下圖:

image.png

3.創(chuàng)建read_statistics應(yīng)用下的models.py模型

具體參照Django官方文檔: https://docs.djangoproject.com/en/2.0/ref/contrib/contenttypes/

image.png
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ù)庫(kù)操作

python manage.py makemigrations

python manage.py migrate

5.配置read_statistics應(yīng)用下的admin.py

image.png
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登錄管理界面

image.png
image.png

6.下面在blog應(yīng)用下的models.py模型里面添加獲取閱讀數(shù)的方法get_read_num()

注意:添加這個(gè)方法是為了在Django管理界面的blog應(yīng)用下,將get_read_num添加到list_display展示列表,從而可以在博客頁(yè)面直接看到該篇文章所對(duì)應(yīng)的閱讀數(shù)

記得引用
from django.db.models.fields import exceptions
from django.contrib.contenttypes.models import ContentType
from read_statistics.models import ReadNum

image.png
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'標(biāo)題')
    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)建時(shí)間')
    last_update_time=models.DateTimeField(auto_now=True,verbose_name=u'修改時(shí)間')
    is_delete=models.BooleanField(default=False,verbose_name=u'是否刪除')

    # 添加方法,添加的get_read_num方法,用于在admin管理后臺(tái)的blog頁(yè)面顯示閱讀數(shù)。即在admin.py的                                                                                        BlogAdmin類的list_display添加read_num
    def get_read_num(self):
        # 返回該篇文章的閱讀數(shù),此處如果該文章還沒(méi)有閱讀數(shù),會(huì)有個(gè)異常,該異常是的默認(rèn)閱讀數(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列表

image.png

完成后,打開(kāi)Django管理頁(yè)面的博客,便可以看到每篇文章get_read_num的閱讀數(shù),如下圖:

image.png

8.在bolg應(yīng)用下的views.py,處理用于前臺(tái)頁(yè)面閱讀數(shù)展示的邏輯關(guān)系

image.png
from django.contrib.contenttypes.models import ContentType
from read_statistics.models import ReadNum

def blog_detail(request,blog_pk):
    """博客詳情頁(yè)"""
    blog=get_object_or_404(Blog,pk=blog_pk) # 根據(jù)傳入blog_pk的ID來(lái)找到具體對(duì)應(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:
            # 對(duì)應(yīng)記錄不存在,則創(chuàng)建并閱讀數(shù)+1,保存(這樣就會(huì)在閱讀數(shù)管理頁(yè)面點(diǎn)擊后保存對(duì)應(yīng)文章以及閱讀數(shù))
            readnum=ReadNum(content_type=ct,object_id=blog.pk)
        readnum.read_num += 1    #點(diǎn)擊該篇文章,閱讀數(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,打開(kāi)過(guò)這篇文章即寫(xiě)入cookie,key是'blog_%s_readed' % blog_pk,value是'true'
    response.set_cookie('blog_%s_read' % blog_pk,'true')
    return response

9.最后在html頁(yè)面,使用get_read_num方法獲取閱讀數(shù)的數(shù)據(jù)

image.png
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容