上篇寫了幾個簡單的閱讀計數功能實現,其缺點都是沒法統計某一天的閱讀數量,也就沒法根據日期來對熱門博客進行排行。因此最好仍是重建一個帶有日期字段名的模型表,這就能夠根據日期條件來篩選博客的閱讀次數了,比較方便統計。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