zoukankan      html  css  js  c++  java
  • Django之使用redis缓存session,历史浏览记录,首页数据实现性能优化

    Redis缓存session

    配置Django缓存数据到redis中

    # diango的缓存配置
    CACHES = {
        "default": {
            "BACKEND": "django_redis.cache.RedisCache",
            # 用户的session信息,历史浏览记录存储在redis数据库9中
            "LOCATION": "redis://127.0.0.1:6379/9",
            "OPTIONS": {
                "CLIENT_CLASS": "django_redis.client.DefaultClient",
            }
        }
    }

    配置session信息缓存在redis中

    # 配置session存储在前面配置的redis数据库中
    SESSION_ENGINE = "django.contrib.sessions.backends.cache"
    SESSION_CACHE_ALIAS = "default"

     保存用户cookie,session信息

    # 与数据库的数据进行校验用户密码正确性
    user = authenticate(request, username=username, password=password)
    # 业务处理:用户登录
    # 返回应答
    if user is not None:
        # 用户名密码正确
        if user.is_active:
            # 用户已激活
            # 记录用户的登录状态
            login(request, user)
            # 获取接下来要访问的地址,默认访问主页
            next_url = request.GET.get("next", reverse("goods:index"))
            response = redirect(next_url)
            # 判断是否记住用户名
            if remember == "on":
                response.set_cookie("username", username, max_age=7*24*3600)
            else:
                response.delete_cookie("username")
            return response

    Redis缓存历史浏览记录 

    链接Redis数据库

    链接redis数据库有两种:

    • 1.使用redis默认的StrictRedis链接
    • 2.使用redis提供的get_redis_connection方法链接default配置;

    方式一:

    # 使用redis默认的方式与django链接
    # from redis import StrictRedis
    # sr = StrictRedis(host="localhost", port=6379, db=9)

    方式二:

    from django_redis import get_redis_connection
    con = get_redis_connection('default')  # 这里的default指的是settings配置中CACHE的default配置

    缓存历史浏览记录

    首先确定我们的需求,是一个用户保存一个浏览商品id集合,然后确定是以redis的hash格式存储,存储类似于

    history_userid:[goods1, goods2, goods3]

    然后我们要考虑情况,比如我们原来浏览过一条商品,现在再浏览一遍,那么就要把这个商品的位置提到最前面去,怎么处理?

    • 在这里我们选择的是如果存在该商品,就先删除,再往最左边插入这条数据,可以使用redis提供的 lrem 方法。
    • 将最新浏览的记录放在最前面,当我们获取缓存中的浏览商品id集合数据,应该是根据id集合的顺序来确定商品顺序的,这里我们可以规定最新的浏览记录放在集合的最左边,使用的是redis的lpush方法。
    • 还有只保存固定条数的浏览记录,过期的就不保存,使用redis的ltrim方法。

    同时下面也例举了如何获取历史浏览记录id集合。

    from django_redis import get_redis_connection
    
    if user.is_authenticated():
        # 用户已登录
        conn = get_redis_connection('default')
        cart_key = 'cart_%d' % user.id
        cart_count = conn.hlen(cart_key)
    
        # 添加历史浏览记录
        conn = get_redis_connection("default")
        history_key = "history_%d" % user.id
        # 移除相同的记录
        conn.lrem(history_key, 0, goods_id)
        # 从左侧添加历史浏览记录
        conn.lpush(history_key, goods_id)
        # 只保留最新的五个历史浏览记录
        conn.ltrim(history_key, 0, 4)
        # 获取历史浏览记录的商品id表
        # sku_ids = conn.lrange(history_key, 0, 4)
        # print("goods.view,历史浏览记录商品id表", sku_ids)

    获取历史浏览记录

    获取用户历史浏览商品id可以使用redis的lrange加上始终索引来获取指定数量数据,
    获取历史浏览商品id后,因为需要根据redis中的顺序来确定商品显示顺序,可以用两种方式来获取商品具体信息:

    • 1.循环从redis获取的商品id列表,根据id获取对应的商品;
    • 2.根据商品id列表获取商品列表,循环从redis获取的商品id列表,在循环中再次循环商品列表,判断如果商品id等于循环的商品列表的id,就添加入商品表中。

    方式一:

    # 从数据库查询用户浏览商品的具体信息
    # goods_li = GoodsSKU.objects.filter(id__in=sku_ids)
    # goods_res = []
    # for a_id in sku_ids:
    #     for goods in goods_li:
    #         if a_id == goods.id:
    #             goods_res.append(goods)

    方式二:

    # 遍历获取用户浏览的商品信息
    goods_li = []
    for id in sku_ids:
        goods = GoodsSKU.objects.filter(id=id)
        goods_li.append(goods)

    获取用户历史浏览记录代码

    class UserInfoView(LoginRequiredMixin, View):
        """用户中心-信息页"""
        def get(self, request):
            """返回用户中心信息页面"""
            user = request.user
            # 获取用户的历史浏览记录
            con = get_redis_connection('default')  # 这里的default指的是settings配置中CACHE的default配置
            history_key = 'history_%d' % user.id
            # 获取用户最新浏览的5个历史记录
            sku_ids = con.lrange(history_key, 0, 4)
    
            # 从数据库查询用户浏览商品的具体信息
            # goods_li = GoodsSKU.objects.filter(id__in=sku_ids)
            # goods_res = []
            # for a_id in sku_ids:
            #     for goods in goods_li:
            #         if a_id == goods.id:
            #             goods_res.append(goods)
            # 遍历获取用户浏览的商品信息
            goods_li = []
            for sku_id in sku_ids:
                goods = GoodsSKU.objects.get(id=sku_id)
                goods.image = settings.MEDIA_PATH + str(goods.image)
                goods_li.append(goods)
            context = {
                "page": "page",
                "address": address,
                "goods_li": goods_li
            }
            return render(request, "user_center_info.html", context)

    Redis缓存网站首页数据

    Django缓存相关文档:https://yiyibooks.cn/xx/django_182/topics/cache.html
    缓存文档中,提供有三种缓存方式,站点级缓存,单个view缓存,模板片段缓存,但都不适合我们,这里我们是直接操作底层缓存api。

    首页数据的缓存:把页面使用的数据存放在缓存中,当要使用这些数据时,就先从缓存中获取,如果获取不到,就再去数据库中获取,减少数据库的查询次数。

    缓存首页数据,使用的还是redis进行缓存,如果你没看前面是独立做这一步的话,要进行如下配置,前面已经配置过的。

    # diango的缓存配置
    CACHES = {
        "default": {
            "BACKEND": "django_redis.cache.RedisCache",
            # 用户的session信息,历史浏览记录存储在redis数据库9中
            "LOCATION": "redis://127.0.0.1:6379/9",
            "OPTIONS": {
                "CLIENT_CLASS": "django_redis.client.DefaultClient",
            }
        }
    }

    缓存首页数据

    缓存数据,我们在这里用的是django自带的cache函数,它会帮我们将数据缓存到一定的地方,我们这里配置的是将数据缓存到redis中,即cache函数会帮我们将数据缓存到redis中。

    cache函数需要三个参数,第一个是缓存的key,即你要给缓存的数据起一个名字,我们可以理解为python中的字典,第二个参数是要缓存的数据,第三个参数是缓存数据过期时间。

    使用cache函数缓存首页数据代码

    class IndexView(View):
        def get(self, request):
            # 从缓存中获取数据
            context = cache.get("index_page_data")
            # 如果缓存中没有数据,就去数据库中获取数据
            if context is None:
                print("缓存数据ing")
                # 获取商品的种类信息
                types = GoodsType.objects.all()
                # 获取首页轮播商品信息
                goods_banners = IndexGoodsBanner.objects.all().order_by("index")
                # 获取首页促销活动信息
                promotions_banners = IndexPromotionBanner.objects.all().order_by("index")
                # 获取首页分类商品展示信息
                for type in types:
                    # 获取type分类首页分类商品的图片展示对象信息
                    image_banners = IndexTypeGoodsBanner.objects.filter(type=type, display_type=1)
                    # 获取type分类首页分类商品的文字展示对象信息
                    title_banners = IndexTypeGoodsBanner.objects.filter(type=type, display_type=0)
                    # 动态给type增加属性,分别保存首页分类商品的图片展示信息和文字展示信息
                    type.image_banners = image_banners
                    type.title_banners = title_banners
                context = {
                    "types": types,
                    "goods_banners": goods_banners,
                    "promotions_banners": promotions_banners,
                }
                # 设置缓存
                cache.set("index_page_data", context, 3600)
    
            # 获取用户购物车中商品的数目
            user = request.user
            cart_count = 0
            if user.is_authenticated:
                # 用户已登录
                conn = get_redis_connection("default")
                cart_key = "cart_%d" % user.id
                cart_count = conn.hlen(cart_key)
            context.update(cart_count=cart_count)
            # 返回应答
            return render(request, "index.html", context)

    同时在这里提醒一下,如果你对Redis不够熟悉的话,不用去拘泥于使用redis的哪种格式缓存首页数据,我们只需要知道redis是一种内存数据库即可,django配置了将缓存放入redis即内容中,在这里django的cache已经帮我们做好了怎么缓存,我们只需要调用即可。

    首页缓存数据的更新

    当管理员在后台修改首页信息对应的数据表中的数据时,我们就需要更新首页的缓存数据了。

    在这里我们实现的方式是直接清空缓存中的首页数据,这样当下一个用户去访问首页时,因为没有从缓存中查到数据,就会从数据库获取数据并且重新存储到缓存中了,清除缓存使用cache.delete()方法。

    下面直接贴代码,置于实现原理,可以参考  https://www.cnblogs.com/yifchan/p/python-1-37.html 最后一节

    from django.contrib import admin
    from django.core.cache import cache
    from goods.models import GoodsType, GoodsSKU, Goods, GoodsImage, IndexGoodsBanner, IndexTypeGoodsBanner, IndexPromotionBanner
    
    
    class BaseModelAdmin(admin.ModelAdmin):
        """当后台数据库数据改动时清空缓存使重新缓存首页数据"""
        def save_model(self, request, obj, form, change):
            """当更新或者新增数据时调用"""
            super().save_model(request, obj, form, change)
            # 清除首页的缓存数据
            cache.delete("index_page_data")
    
        def delete_model(self, request, obj):
            """当删除数据时调用"""
            super().delete_model(request, obj)
            # 清除首页的缓存数据
            cache.delete("index_page_data")
    
    
    class GoodsTypeAdmin(BaseModelAdmin):
        pass
    
    
    class IndexGoodsBannerAdmin(BaseModelAdmin):
        pass
    
    
    class IndexTypeGoodsBannerAdmin(BaseModelAdmin):
        pass
    
    
    class IndexPromotionBannerAdmin(BaseModelAdmin):
        pass
    
    
    admin.site.register(GoodsType, GoodsTypeAdmin)
    admin.site.register(GoodsSKU)
    admin.site.register(Goods)
    admin.site.register(GoodsImage)
    admin.site.register(IndexGoodsBanner, IndexGoodsBannerAdmin)
    admin.site.register(IndexTypeGoodsBanner, IndexTypeGoodsBannerAdmin)
    admin.site.register(IndexPromotionBanner, IndexPromotionBannerAdmin)
    app-goods/admin.py
  • 相关阅读:
    最长上升序列,首尾连接
    带权并查集&&并查集
    开发者的小天地-1
    Binary Tree Maximum Path Sum
    Linked List Cycle II
    动归熟手题单
    java 正则表达式-忽略大小写与多行匹配
    KO之tab栏切换
    Vue中通过属性绑定为元素绑定style
    Vue中通过属性绑定为元素设置class
  • 原文地址:https://www.cnblogs.com/yifchan/p/python-1-38.html
Copyright © 2011-2022 走看看