欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

django中使用redis做缓存中间件

程序员文章站 2024-03-15 19:59:06
...

由于电商后台的首页,客户要求的数据特别多,都是从各个表中查出来的,我大致算了一下,大概要查30多个表,我想这不行啊,于是决定使用使用redis作为缓存使用

  1. 客户要求的首页展示数据,这只是一小小部分
    django中使用redis做缓存中间件

  2. 我决定写一个脚本,每天晚上凌晨时查询db,放入redis,

# -*- coding: utf-8 -*-
#!/usr/bin/python3
import os
import sys
import datetime

BASE_DIR = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))

sys.path.append(os.path.join(BASE_DIR,'one_fashion'))
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "one_fashion.settings.settings")
import django
django.setup()

import datetime
import logging
from django_redis import get_redis_connection
from users.models import User, UserInfo, VIPInfo
from orders.models import OrderInfo
from payment.models import Recharge
from management.utils import Public_func
from message.models import Message
from django.db.models import Q, Count, F, Case, When, Value


logger = logging.getLogger('django')

if __name__ == "__main__":
    """每日凌晨执行定时任务,存入缓存"""

    now_time = datetime.datetime.now()
    time = now_time - datetime.timedelta(days=1)

    # 网站概览/用户
    accumulated = User.objects.filter(is_staff=False).count()  # 累计用户
    yesterday_increased = User.objects.filter(date_joined__range=(time, now_time)).count() # 昨日新增数
    # 昨日付费人数(下单用户和开vip用户)
    pay_user_ord = OrderInfo.objects.filter(create_time__range=(time, now_time), status=2).count()
    pay_user_vip = VIPInfo.objects.filter(create_time__range=(time, now_time)).count()
    pay_user_count = pay_user_ord + pay_user_vip
    # todo 昨日活跃数(登录人数 User表中的last_login)
    login_count = User.objects.filter(last_login__range=(time, now_time)).count()
    
    # 网站概览/付费收入
    # 昨天收入
    before_conclude_actual_amount = 0
    ord_query = OrderInfo.objects.filter(create_time__range=(time, now_time), status=2)  # 订单收入
    for ord_obj in ord_query:
        before_conclude_actual_amount += int(ord_obj.actual_amount)
        
    vip_list = VIPInfo.objects.filter(create_time__range=(time, now_time)).values_list('level', flat=True) # vip收入
    for level in vip_list:
        rec_obj = Recharge.objects.filter(level=level).first()
        before_conclude_actual_amount += int(rec_obj.price)

    # 本月收入
    first_day = Public_func().month_first_day(now_time) # 返回当月的第一天的零点零分
    month_conclude_actual_amount = 0
    ord_query = OrderInfo.objects.filter(create_time__range=(first_day, now_time), status=2)  # 订单收入
    for ord_obj in ord_query:
        month_conclude_actual_amount += int(ord_obj.actual_amount)

    vip_list = VIPInfo.objects.filter(create_time__range=(first_day, now_time)).values_list('level', flat=True)  # vip收入
    for level in vip_list:
        rec_obj = Recharge.objects.filter(level=level).first()
        month_conclude_actual_amount += int(rec_obj.price)

    # 存入缓存
    try:
        conn = get_redis_connection('admin_home')
        pl = conn.pipeline(True)
        pl.multi()
        pl.hmset('user', {'accumulated': accumulated, 'yesterday_increased': yesterday_increased, 'pay_user_count':pay_user_count, 'login_count':login_count})
        pl.hmset('pay', {'before_conclude_actual_amount': before_conclude_actual_amount, 'month_conclude_actual_amount': month_conclude_actual_amount,})

        pl.execute()

    except Exception as e:
        logger.error(e)
  1. 由于查询数据较为固定,所以我没有考虑db和redis数据不一致,因为这个场景根本不需要,接口代码
import datetime
import logging
from django_redis import get_redis_connection
from rest_framework.generics import CreateAPIView, ListAPIView, UpdateAPIView, RetrieveAPIView, DestroyAPIView, GenericAPIView
from rest_framework.permissions import IsAuthenticated
from one_fashion.utils.permissions import AdminUserPermission
from one_fashion.utils.api_response import APIResponse
from management.utils import Public_func

from users.models import User, UserInfo, VIPInfo
from django.db.models import Q, Count, F, Case, When, Value
from message.models import Message

logger = logging.getLogger('django')


class WebsiteOverviewView(GenericAPIView):
    """首页网站概览模块"""
    permission_classes = [IsAuthenticated, AdminUserPermission]

    def get(self, request, *args, **kwargs):
        try:
            conn = get_redis_connection('admin_home')
            pl = conn.pipeline(True)
            pl.watch('user')
            pl.multi()

            pl.hgetall('user')

            user_dict = pl.execute()[0]
            pl.unwatch()

            # 如果事务没有执行
            if not user_dict:
                return APIResponse.fail(message='获取数据失败,请刷新重试')

            data = {'data':user_dict}

        except Exception as e:
            logger.error(e)
            return APIResponse.fail(message='服务器错误,请刷新重试')

        return APIResponse.success(data=data)
  1. 由于代码内容没有写完,所以接口代码应该还有一段就是如果redis数据不存在,那么应该再查询db返回数据的,不能导致如果redis出现状况,数据不存在,给前端返回的数据为空
  2. settin代码:
# 用来缓存后台首页数据
    "admin_home": {
                "BACKEND": "django_redis.cache.RedisCache",
                "LOCATION": "redis://127.0.0.1:6379/6",
                "OPTIONS": {
                    "CLIENT_CLASS": "django_redis.client.DefaultClient",
                    "CONNECTION_POOL_KWARGS": {"max_connections": 20, "decode_responses": True}
                }
            },
  1. 接口返回数据:
{
    "data": {
        "data": {
            "accumulated": "43",
            "yesterday_increased": "0",
            "pay_user_count": "1",
            "login_count": "0"
        }
    },
    "code": 0,
    "message": ""
}