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
  • 相关阅读:
    118/119. Pascal's Triangle/II
    160. Intersection of Two Linked Lists
    168. Excel Sheet Column Title
    167. Two Sum II
    172. Factorial Trailing Zeroes
    169. Majority Element
    189. Rotate Array
    202. Happy Number
    204. Count Primes
    MVC之Model元数据
  • 原文地址:https://www.cnblogs.com/yifchan/p/python-1-38.html
Copyright © 2011-2022 走看看