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

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM