You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何验证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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.28 06:36:27