Django开发博客5——访问量统计

文章访问量的统计

涉及知识点:

  • 自定义中间件
  • 缓存读写
  • F

实现方式:

  1. 基于当此访问后端实时处理
    为防止竞争,使用F表达式来实现数据库层面的+1,但是每次访问都会产生一次写入操作,写入的操作会影响页面的响应速度,尤其是并发量比较高的时候
  2. 基于当此访问后端延时处理——celery
    通过celery(分布式任务队列)使用异步化的方式处理访问统计
  3. 前端通过js埋点或img标签来统计
    大规模系统常用的统计方式,需要一个独立的系统来完成统计业务
  4. 基于Nginx日志分析来统计

解决方法:对每一个用户生成唯一的id,保存在cookie中,用户访问时将访问数据存入缓存中,以便后续具体的统计操作
1.创建中间件生成唯一id
在app下创建middleware文件夹,新建__init__.py和user_id.py

import uuid

USER_KEY = 'uid'
TEN_YEARS = 60 * 60 * 25 * 365 * 10

class UserIDMiddleware:
    def __init__(self, get_response):
        self.get_response = get_response

    def __call__(self, request):
        uid = self.generate_uid(request)
        # 给request对象添加uid属性,也就是说request对象是在访问后创建的
        request.uid = uid
        response = self.get_response(request)
        # 给响应对象设置cookie,httponly:只能在服务端访问
        response.set_cookie(USER_KEY, uid, max_age=TEN_YEARS, httponly=True)
        return response

    # 先从cookie中取uid,取不到则生成一个
    def generate_uid(self, request):
        try:
            uid = request.COOKIES[USER_KEY]
        except KeyError:
            uid = uuid.uuid4().hex
        return uid

django中的middleware在项目启动时会被初始化,等接收到请求后依次调用中间件,传递request作为参数
2.配置中间件

MIDDLEWARE = [
	# 添加在第一行,则后面的流程中request对象就多了一个uid属性
    'blog.middleware.user_id.UserIDMiddleware',    
    # 省略
    ]

3.完善视图层,进行访问统计:判断是否有缓存,没有则加1

from datetime import date
from django.db.models import Q, F
from django.core.cache import cache

class PostDetailView(CommonViewMixin, DetailView):
    queryset = Post.latest_posts()
    template_name = 'blog/detail.html'
    context_object_name = 'post'    # 设置模板中使用的变量名
    pk_url_kwarg = 'post_id'    # 设置url中的参数名,默认为pk

    # 重写get方法,在其中处理访问统计
    def get(self, request, *args, **kwargs):
    	# 在调用父类的get方法前进行访问统计,则可以获得实时的数据
    	self.handle_visited()
        response = super().get(request, *args, **kwargs)
        return response

    def handle_visited(self):
        increase_pv = False
        increase_uv = False
        uid = self.request.uid
        # 在对象中获取url中的参数
        post_id = self.kwargs.get('post_id')
        # 生成针对每篇文章的key值
        pv_key = 'pv:%s:%s' % (uid, self.request.path)
        uv_key = 'uv:%s:%s:%s' % (uid, str(date.today()), self.request.path)
        # 判断缓存中是否有pv_key,没有则创建,有效期1分钟,并将标志位改为True
        if not cache.get(pv_key):
            increase_pv = True
            cache.set(pv_key, 1, 1*60)
        if not cache.get(uv_key):
            increase_uv = True
            cache.set(uv_key, 1, 24*60*60)

        # 根据标志位判断是否执行写入操作
        # 此条件可避免出现两次写入操作
        if increase_pv and increase_uv:
            Post.objects.filter(pk=post_id).update(pv=F('pv')+1, uv=F('uv')+1)
        elif increase_pv:
            Post.objects.filter(pk=post_id).update(pv=F('pv') + 1)
        elif increase_uv:
            Post.objects.filter(pk=post_id).update(uv=F('uv') + 1)

django的缓存在未配置时使用的时内存缓存,内存缓存是进程间独立的
因此如果是多进程时就会出现问题

参考:《django企业开发实战》

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值