通化网站开发,石家庄有那些网站开发公司,wordpress 获取标签所有文章,网站开发项目计划书一、Django缓存系统概述
Django提供了一个统一的缓存API#xff0c;支持多种缓存后端#xff08;内存、数据库、文件、Redis等#xff09;。你可以在不改动代码的情况下#xff0c;通过配置切换不同的缓存后端。
# 支持的缓存后端
CACHES {default: {BACKEND: django.core…一、Django缓存系统概述Django提供了一个统一的缓存API支持多种缓存后端内存、数据库、文件、Redis等。你可以在不改动代码的情况下通过配置切换不同的缓存后端。# 支持的缓存后端CACHES{default:{BACKEND:django.core.cache.backends.locmem.LocMemCache,# 内存缓存# BACKEND: django.core.cache.backends.db.DatabaseCache, # 数据库缓存# BACKEND: django.core.cache.backends.filebased.FileBasedCache, # 文件缓存# BACKEND: django_redis.cache.RedisCache, # Redis缓存}}二、缓存API基础1. 导入缓存对象# 方式1导入默认缓存最常用fromdjango.core.cacheimportcache# 方式2导入特定缓存fromdjango.core.cacheimportcaches cache_aliascaches[default]# 或 caches[session] 等2. 基本操作方法defbasic_cache_operations():基本缓存操作# 1. set() - 设置缓存# 语法cache.set(key, value, timeoutNone, versionNone)cache.set(username,张三)# 使用默认超时时间cache.set(user_age,25,timeout300)# 5分钟后过期cache.set(permanent_data,重要数据,timeoutNone)# 永不过期# 2. get() - 获取缓存# 语法cache.get(key, defaultNone, versionNone)usernamecache.get(username)usernamecache.get(username,默认值)# 获取不到时返回默认值not_foundcache.get(non_existent_key)# 返回 None# 3. add() - 仅当键不存在时设置# 语法cache.add(key, value, timeoutNone, versionNone)addedcache.add(counter,1)# 第一次设置成功返回Trueadded_againcache.add(counter,2)# 已存在不修改返回False# 4. get_or_set() - 获取或设置# 语法cache.get_or_set(key, default, timeoutNone, versionNone)valuecache.get_or_set(my_key,default_value,timeout60)# 等价于# value cache.get(my_key)# if value is None:# value default_value# cache.set(my_key, value, timeout60)# 5. delete() - 删除缓存# 语法cache.delete(key, versionNone)cache.delete(username)deletedcache.delete(non_existent_key)# 返回False# 6. clear() - 清空所有缓存# 语法cache.clear()# cache.clear() # 谨慎使用return{username:username,counter:cache.get(counter),added_first:added,added_again:added_again,}3. 批量操作方法defbatch_operations():批量缓存操作# 1. set_many() - 设置多个缓存# 语法cache.set_many(dict, timeoutNone, versionNone)data{user:1:name:张三,user:1:age:25,user:1:email:zhangsanexample.com,user:2:name:李四,}cache.set_many(data,timeout300)# 2. get_many() - 获取多个缓存# 语法cache.get_many(keys, versionNone)keys[user:1:name,user:1:age,user:1:email,user:2:name]valuescache.get_many(keys)# 返回字典# 3. delete_many() - 删除多个缓存# 语法cache.delete_many(keys, versionNone)cache.delete_many([user:1:age,user:1:email])returnvalues4. 原子操作方法defatomic_operations():原子操作需要缓存后端支持# 1. incr() - 递增# 语法cache.incr(key, delta1, versionNone)cache.set(counter,1)cache.incr(counter)# 2cache.incr(counter,10)# 12# 2. decr() - 递减# 语法cache.decr(key, delta1, versionNone)cache.decr(counter)# 11cache.decr(counter,5)# 6# 3. touch() - 更新过期时间# 语法cache.touch(key, timeoutNone, versionNone)cache.touch(counter,timeout600)# 重置为10分钟后过期return{counter:cache.get(counter)}三、缓存版本控制defcache_versioning():缓存版本控制# 设置版本cache.set(config,v1_config,version1)cache.set(config,v2_config,version2)# 获取特定版本v1_configcache.get(config,version1)# v1_configv2_configcache.get(config,version2)# v2_config# 递增版本旧版本自动失效cache.incr_version(config)# version从2变为3v3_configcache.get(config)# None默认使用最新版本# 删除特定版本cache.delete(config,version1)return{v1:v1_config,v2:v2_config,v3:v3_config}四、缓存键的生成defcache_key_generation():缓存键的生成# Django会自动处理键的生成# 最终的键 前缀:版本:原始键# 自定义键生成函数defmake_cache_key(model_name,object_id,actiondetail):生成结构化缓存键returnf{model_name}:{object_id}:{action}# 使用示例user_keymake_cache_key(user,123,profile)cache.set(user_key,{name:张三,age:25})# 复杂的键complex_keyfsearch:{hashlib.md5(python tutorial.encode()).hexdigest()}:page:1cache.set(complex_key,[result1,result2])return{user_key:user_key,user_data:cache.get(user_key),complex_key:complex_key}五、实战缓存数据库查询fromdjango.dbimportmodelsfromdjango.core.cacheimportcacheimporttimeclassProduct(models.Model):产品模型namemodels.CharField(max_length100)pricemodels.DecimalField(max_digits10,decimal_places2)stockmodels.IntegerField(default0)categorymodels.CharField(max_length50)created_atmodels.DateTimeField(auto_now_addTrue)def__str__(self):returnself.nameclassProductCacheService:产品缓存服务staticmethoddefget_product(product_id):获取单个产品带缓存cache_keyfproduct:{product_id}# 尝试从缓存获取productcache.get(cache_key)ifproductisNone:print(f缓存未命中从数据库查询产品{product_id})# 模拟数据库查询time.sleep(1)# 假设查询耗时1秒try:product_objProduct.objects.get(idproduct_id)product{id:product_obj.id,name:product_obj.name,price:float(product_obj.price),stock:product_obj.stock,category:product_obj.category,}# 存入缓存有效期1小时cache.set(cache_key,product,timeout3600)exceptProduct.DoesNotExist:# 缓存空结果防止缓存穿透cache.set(cache_key,None,timeout60)productNoneelse:print(f缓存命中从缓存获取产品{product_id})returnproductstaticmethoddefget_products_by_category(category,page1,per_page20):按分类获取产品列表带缓存cache_keyfproducts:category:{category}:page:{page}:per_page:{per_page}productscache.get(cache_key)ifproductsisNone:print(f缓存未命中查询分类{category}的产品)# 模拟数据库查询time.sleep(2)# 假设查询耗时2秒querysetProduct.objects.filter(categorycategory,stock__gt0).order_by(-created_at)# 分页start(page-1)*per_page endstartper_page productslist(queryset.values(id,name,price,stock)[start:end])# 存入缓存有效期5分钟cache.set(cache_key,products,timeout300)returnproductsstaticmethoddefinvalidate_product_cache(product_idNone):使产品缓存失效ifproduct_id:# 删除单个产品缓存cache.delete(fproduct:{product_id})# 删除所有产品列表缓存# 注意实际项目中可能需要更精细的控制# 这里简单删除所有包含products:的键# 实际可以使用更复杂的方法如缓存标签# 示例删除特定模式的键# 注意keys() 命令在生产环境慎用# 更好的方案是使用缓存版本或单独管理缓存键staticmethoddefget_or_set_product_stats():获取或设置产品统计信息cache_keyproduct_statsstatscache.get_or_set(cache_key,lambda:ProductCacheService._calculate_product_stats(),timeout600# 10分钟)returnstatsstaticmethoddef_calculate_product_stats():计算产品统计信息耗时操作print(计算产品统计信息...)time.sleep(3)# 模拟耗时计算return{total_products:Product.objects.count(),total_stock:Product.objects.aggregate(models.Sum(stock))[stock__sum],average_price:Product.objects.aggregate(models.Avg(price))[price__avg],}六、视图缓存fromdjango.views.decorators.cacheimportcache_page,never_cachefromdjango.utils.decoratorsimportmethod_decoratorfromdjango.viewsimportViewfromdjango.httpimportJsonResponseimporttime# 1. 函数视图缓存cache_page(60*5)# 缓存5分钟defexpensive_view(request):缓存整个视图响应time.sleep(2)# 模拟耗时操作returnJsonResponse({data:这是缓存的结果,timestamp:time.time(),message:这个视图被缓存了5分钟})cache_page(60*15)# 缓存15分钟defproduct_list_view(request,category):带参数的视图缓存# 注意不同参数会生成不同的缓存productsProductCacheService.get_products_by_category(category)returnJsonResponse({products:products})# 2. 类视图缓存classCachedView(View):缓存的类视图method_decorator(cache_page(60*10))defdispatch(self,*args,**kwargs):returnsuper().dispatch(*args,**kwargs)defget(self,request):time.sleep(1)returnJsonResponse({message:类视图缓存示例})# 3. 条件缓存defconditional_cached_view(request):根据条件决定是否缓存ifrequest.user.is_staff:# 管理员不缓存returnexpensive_operation(request)# 普通用户缓存returncache_page(60*5)(expensive_operation)(request)# 4. 不缓存装饰器never_cachedefsensitive_data_view(request):敏感数据不缓存returnJsonResponse({token:sensitive_token_123456,timestamp:time.time()})七、模板缓存!--在Django模板中使用缓存--{%load cache%}!DOCTYPE htmlhtmlheadtitle产品详情/title/headbodyh1{{product.name}}/h1!--1.基本模板缓存--{%cache300product_sidebar%}divclasssidebarh3相关产品/h3ul{%forrelatedinrelated_products%}li{{related.name}}/li{%endfor%}/ul/div{%endcache%}!--2.带变量的缓存--{%cache300product_detail product.idproduct.updated_at%}divclasscontentp价格:¥{{product.price}}/pp库存:{{product.stock}}/pp描述:{{product.description}}/p/div{%endcache%}!--3.根据用户缓存--{%cache300user_recommendations request.user.id%}divclassrecommendationsh3为您推荐/h3{%foriteminuser_recommendations%}p{{item}}/p{%endfor%}/div{%endcache%}!--4.多变量组合--{%withcache_keyproduct_|add:product.id|add:_|add:category%}{%cache300cache_key%}divclasscategory-info分类:{{category}}/div{%endcache%}{%endwith%}/body/html八、缓存中间件# settings.pyMIDDLEWARE[django.middleware.cache.UpdateCacheMiddleware,# 必须第一个# ... 其他中间件 ...django.middleware.cache.FetchFromCacheMiddleware,# 必须最后一个]# 全站缓存配置CACHE_MIDDLEWARE_ALIASdefaultCACHE_MIDDLEWARE_SECONDS60*15# 15分钟CACHE_MIDDLEWARE_KEY_PREFIXmysite# views.pyfromdjango.views.decorators.cacheimportcache_controlfromdjango.views.decorators.varyimportvary_on_cookie,vary_on_headers# 控制HTTP缓存头cache_control(publicTrue,max_age300,# 客户端缓存5分钟s_maxage600,# 代理服务器缓存10分钟must_revalidateTrue)defapi_view_with_cache_control(request):控制HTTP缓存的视图returnJsonResponse({data:可缓存的数据})# 根据Cookie变化缓存vary_on_cookiecache_page(300)defuser_specific_view(request):不同用户看到不同的缓存内容returnJsonResponse({user:request.user.username,data:用户特定数据})# 根据请求头变化缓存vary_on_headers(User-Agent,Accept-Language)cache_page(300)defvary_by_header_view(request):根据请求头变化缓存returnJsonResponse({user_agent:request.META.get(HTTP_USER_AGENT),accept_language:request.META.get(HTTP_ACCEPT_LANGUAGE)})九、多缓存配置# settings.pyCACHES{default:{BACKEND:django.core.cache.backends.locmem.LocMemCache,LOCATION:unique-snowflake,TIMEOUT:300,},user_sessions:{BACKEND:django_redis.cache.RedisCache,LOCATION:redis://127.0.0.1:6379/1,OPTIONS:{CLIENT_CLASS:django_redis.client.DefaultClient,},TIMEOUT:60*60*24,# 24小时},fast_cache:{BACKEND:django.core.cache.backends.memcached.MemcachedCache,LOCATION:127.0.0.1:11211,TIMEOUT:60,}}# 使用不同的缓存后端fromdjango.core.cacheimportcachesdefuse_multiple_caches():使用多个缓存后端# 获取不同的缓存default_cachecaches[default]session_cachecaches[user_sessions]fast_cachecaches[fast_cache]# 存储到不同的缓存default_cache.set(site_config,{theme:dark},timeout3600)session_cache.set(fsession:{user_id},session_data,timeout86400)fast_cache.set(hot_data,hot_data,timeout60)# 从不同的缓存获取configdefault_cache.get(site_config)sessionsession_cache.get(fsession:{user_id})hotfast_cache.get(hot_data)return{config:config,session:session,hot:hot}十、缓存模式和最佳实践1. 缓存穿透防护defget_product_safe(product_id): 防止缓存穿透 缓存空值避免大量请求直接打到数据库 cache_keyfproduct:{product_id}# 尝试获取缓存productcache.get(cache_key)ifproductisNone:# 查询数据库try:productProduct.objects.get(idproduct_id)# 缓存1小时cache.set(cache_key,product,timeout3600)exceptProduct.DoesNotExist:# 缓存空值短时间如1分钟cache.set(cache_key,NULL,timeout60)productNoneelifproductNULL:# 空值标记productNonereturnproduct2. 缓存雪崩防护importrandomdefset_with_random_ttl(key,value,base_ttl3600,jitter300): 防止缓存雪崩 设置随机过期时间避免大量缓存同时过期 # 添加随机抖动ttlbase_ttlrandom.randint(-jitter,jitter)cache.set(key,value,timeoutttl)returnttl3. 缓存预热defwarmup_cache():缓存预热print(开始缓存预热...)# 预热热门数据hot_productsProduct.objects.filter(stock__gt0).order_by(-sales)[:100]forproductinhot_products:cache_keyfproduct:{product.id}product_data{id:product.id,name:product.name,price:float(product.price),}cache.set(cache_key,product_data,timeout3600)# 预热分类数据categoriesProduct.objects.values_list(category,flatTrue).distinct()forcategoryincategories:cache_keyfproducts:category:{category}productslist(Product.objects.filter(categorycategory,stock__gt0).values(id,name)[:20])cache.set(cache_key,products,timeout1800)print(缓存预热完成)4. 缓存统计classCacheStats:缓存统计def__init__(self):self.hits0self.misses0defget_with_stats(self,key,defaultNone):带统计的获取valuecache.get(key)ifvalueisnotNone:self.hits1else:self.misses1valuedefaultreturnvaluedefget_hit_rate(self):获取命中率totalself.hitsself.missesiftotal0:return0return(self.hits/total)*100defget_stats(self):获取统计信息return{hits:self.hits,misses:self.misses,total:self.hitsself.misses,hit_rate:f{self.get_hit_rate():.2f}%}十一、常见问题1. 缓存键太长# 解决方法对长键进行哈希importhashlibdefget_hashed_key(key):对长键进行哈希iflen(key)200:returnhashlib.md5(key.encode()).hexdigest()returnkey2. 缓存不一致# 解决方法及时清理缓存defupdate_product_and_clear_cache(product_id,data):更新产品并清理相关缓存# 1. 更新数据库Product.objects.filter(idproduct_id).update(**data)# 2. 清理相关缓存cache.delete(fproduct:{product_id})cache.delete(product_list)# 列表缓存cache.delete_pattern(products:category:*)# 如果有相关分类缓存# 3. 可选重新设置缓存new_productProduct.objects.get(idproduct_id)cache.set(fproduct:{product_id},new_product,timeout3600)3. 缓存序列化问题# Django模型对象需要序列化才能缓存fromdjango.coreimportserializersdefcache_model_object(model_obj):缓存模型对象# 方法1转换为字典data{id:model_obj.id,name:model_obj.name,# ... 其他字段}cache.set(fmodel:{model_obj.id},data)# 方法2使用Django序列化serializedserializers.serialize(json,[model_obj])cache.set(fmodel_serialized:{model_obj.id},serialized)# 方法3使用values()查询dataModel.objects.filter(idmodel_obj.id).values().first()cache.set(fmodel_values:{model_obj.id},data)总结Django的标准缓存API提供了统一的接口相同API操作不同后端丰富的功能基本CRUD、批量操作、原子操作灵活的配置支持多种缓存策略集成良好与视图、模板无缝集成最佳实践选择合适的缓存粒度设置合理的过期时间及时清理无效缓存监控缓存命中率处理缓存异常情况掌握这些API你就能在Django项目中高效地使用缓存来提升应用性能了。