上篇写了几个简单的阅读计数功能实现,其缺点都是没法统计某一天的阅读数量,也就没法根据日期来对热门博客进行排行。因此最好仍是重建一个带有日期字段名的模型表,这就能够根据日期条件来筛选博客的阅读次数了,比较方便统计。ReadNum继续保留,再建一个ReadDetail模型类html
from django.db import models from django.contrib.contenttypes.fields import GenericForeignKey from django.contrib.contenttypes.models import ContentType class ReadDetail(models.Model): """ 根据日期计数的模型类 继承model.Model模型类 """ read_num = models.IntegerField(default=0) date = models.DateField(default=timezone.now) content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE) object_id = models.PositiveIntegerField() content_object = GenericForeignKey('content_type', 'object_id') class Meta: verbose_name = '阅读记录' verbose_name_plural = '阅读记录' ordering = ['-date']
作到这一步,就应该对read_num的数值进行计数了。这个计数还不能每次点击进入read_num都会增长,不然这个数值就没有意义了,应当是只要是同一个用户在段时间重复进入屡次,数值只会变化+1,而不是每次进入都会增长。由于这个状态是不涉及重要信息的,因此直接用cookie来进行状态保持的记录就能够了,经过request.COOKIES.get(key)来获取key的值,若是获取不到,则说明用户还未点击这篇博客,能够对read_num进行+1逻辑处理。同时当没有ReadNum或ReadDetail的实例对象时,就要建立,这里可使用get_or_create方法,返回两个参数python
from django.contrib.contenttypes.models import ContentType def read_statistics_once_read(request, obj): """ 做用:阅读+1的处理逻辑功能 request:请求对象 obj:post实例对象 """ ct = ContentType.objects.get_for_model(obj) key = "%s_%s_read" % (ct.model, obj.pk) if not request.COOKIES.get(key): # 若是使用get_or_create就能省略上面一大段,能够简化 readnum, created = ReadNum.objects.get_or_create(content_type=ct, object_id=obj.pk) # 总阅读计数+1 readnum.read_num += 1 readnum.save() # 当天阅读数+1 date = timezone.now().date() readdetail, created = ReadDetail.objects.get_or_create(content_type=ct, object_id=obj.pk, date=date) readdetail.read_num += 1 readdetail.save() return key
上面是对每篇博客阅读+1的处理,能够看到该函数返回了一个key,经过对key赋值能够实现状态保持。下面代码还有上一篇和下一篇博客的逻辑部分,这里也顺便贴出来了django
def detail(request, pk): """ 做用:显示当前选择文章内容 request:请求对象 pk:每篇文章的pk值 """ # 接收了一个pk值,这个值是在url中传递的主键,利用该主键能够找到文章的对象 # get_object_or_404的用法是(模型名,get方法) post = get_object_or_404(Post, pk=pk) post_all_list = Post.objects.all() # read_statistics_once_read是在read_statistics应用中的方法,表示计数+1 read_cookie_key = read_statistics_once_read(request, post) # 在django中不能使用>=或<=,因此django自定义了__gt和__lt # 目的:得出建立时间比当前博客建立时间较晚的全部博客列表的最后一篇博客,也就是当前博客的上一篇 # 由于博客是按照建立时间的前后来排序的:即先建立的靠后,那么上一篇博客建立时间晚于当前博客 previous_post = Post.objects.filter(created_time__gt=post.created_time).last() # 目的:得出建立时间比当前博客建立时间较早的全部博客列表的第一篇博客,也就是当前博客的下一篇 # 由于博客是按照建立时间的前后来排序的:即先建立的靠后,那么上一篇博客建立时间早于当前博客 next_post = Post.objects.filter(created_time__lt=post.created_time).first() context = ({'article': post.body, 'title': post.title, 'author': post.author, 'created_time': post.created_time, 'category': post.category, 'previous_post': previous_post, 'next_post': next_post, 'read_num': post.get_read_num, 'user': request.user, 'post_id': post.id, 'post': post, }) response = render(request, 'blog/detail.html', context) # 第一个参数是键,键值,和过时时间 response.set_cookie(read_cookie_key, 'true') # 阅读cookie标记 return response
到这里就基本就是阅读计数优化的所有内容。cookie