博客阅读数的统计三部曲【一】-3种方式中讲到的3种方式,其模型都是在blog应用下models.py里面写的,这样耦合性太强,不利于以后给其他应用的拓展
这节讲的是将阅读计数的功能单独创建出一个app应用,打包发后便于其他项目的拓展使用
app应用的分离
Github源码地址:请点这里

1.此方法是将阅读计数功能分离出来,独立作为一个app引用,便于打包在线安装供其他项目中的使用
其中使用的功能方法详见Django官方文档“The contenttypes framework”(内容类型框架)
具体页面链接地址:Django官网文档


2.首先使用命令新建独立应用
python manage.py startapp read_statistics
接下来将read_statistics应用添加到settings.py的apps里面,如下图:

3.创建read_statistics应用下的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='阅读数')
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='阅读数'
verbose_name_plural=verbose_name
4.同步更新数据库操作
python manage.py makemigrations
python manage.py migrate
5.配置read_statistics应用下的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应用下的models.py模型里面添加获取阅读数的方法get_read_num()
注意:添加这个方法是为了在Django管理界面的blog应用下,将get_read_num添加到list_display展示列表,从而可以在博客页面直接看到该篇文章所对应的阅读数
记得引用
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'创建时间')
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页面显示阅读数。即在admin.py的 BlogAdmin类的list_display添加read_num
def get_read_num(self):
# 返回该篇文章的阅读数,此处如果该文章还没有阅读数,会有个异常,该异常是的默认阅读数不是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应用下面的admin.py的list_display列表

完成后,打开Django管理页面的博客,便可以看到每篇文章get_read_num的阅读数,如下图:

8.在bolg应用下的views.py,处理用于前台页面阅读数展示的逻辑关系

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) # 根据传入blog_pk的ID来找到具体对应博客文章
# 获取cookie:根据获取cookie的key值'blog_%s_readed' % blog_pk,判断是否存在,不存在则阅读数 +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():
# 记录存在,则查询并阅读数+1,保存
readnum=ReadNum.objects.get(content_type=ct,object_id=blog.pk)
else:
# 对应记录不存在,则创建并阅读数+1,保存(这样就会在阅读数管理页面点击后保存对应文章以及阅读数)
readnum=ReadNum(content_type=ct,object_id=blog.pk)
readnum.read_num += 1 #点击该篇文章,阅读数自增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}) #响应
# 设置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方法获取阅读数的数据

网友评论