Django之使用redis快取session,歷史瀏覽記錄,首頁數據實現性能優化
- 2019 年 10 月 8 日
- 筆記
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