如何验证Django @cached_property装饰器的缓存是否正常生效
问题解答
1. listing 属性是否会被缓存
会被缓存。django.utils.functional.cached_property 的缓存逻辑和方法内部执行的操作无关:首次访问实例上的该属性时,装饰器会执行对应方法拿到返回值,之后直接把返回值存储到当前实例的内存空间中,后续所有对这个属性的访问都会直接读取预存的值,不会再次执行方法内部代码,自然也不会重复触发.get()对应的数据库查询。
注意:如果首次访问时方法内部抛出异常(比如未保存的空
MyModel实例调用self.products.get()会触发DoesNotExist异常、数据库连接错误等),异常结果不会被缓存,下次访问时依然会重新执行方法逻辑。
你给出的调用示例中,只要第一次instance.listing成功拿到了匹配的Product对象,第二次访问就会直接从内存读取缓存结果,不会再查库。
2. 缓存生效的验证方法
你之前查看__dict__没找到缓存字段,核心原因是cached_property是惰性写入的:在你从未成功访问过这个属性之前,实例的__dict__里根本不会生成对应的缓存键,自然看不到内容。
可以通过以下两种方式验证:
方法1:通过数据库查询计数验证(最准确)
用Django测试框架自带的assertNumQueries上下文管理器就能精准判断查询次数,示例测试代码:
from django.test import TestCase from myapp.models import MyModel, Product class CacheTest(TestCase): def test_listing_cache(self): # 构造测试数据 my_model_instance = MyModel.objects.create(...) Product.objects.create( my_model=my_model_instance, product_type=Product.ProductType.LISTING ) # 首次访问,预期触发1次数据库查询 with self.assertNumQueries(1): first_get = my_model_instance.listing # 第二次访问,预期触发0次数据库查询,直接读缓存 with self.assertNumQueries(0): second_get = my_model_instance.listing # 可选校验:两次拿到的是内存中同一个对象 self.assertIs(first_get, second_get)
跑通这个用例就证明缓存正常生效。
方法2:查看__dict__验证
你需要在首次成功访问listing属性之后再打印实例的__dict__,就能看到对应的缓存键值对:
instance = MyModel.objects.get(pk=1) # 访问前打印,__dict__里没有listing键 print("before access:", "listing" in instance.__dict__) # 输出False _ = instance.listing # 首次成功访问 # 访问后打印,__dict__里已经存在listing对应的缓存值 print("after access:", "listing" in instance.__dict__) # 输出True print(instance.__dict__["listing"]) # 打印缓存的Product实例
内容的提问来源于stack exchange,提问作者Jarad
相关产品推荐
相关产品推荐

