我正在尝试确定一个简单的缓存技巧是否真的有用。我知道Django查询集很懒惰以提高效率,但我想知道他们是否在调用数据后保存了查询结果。
例如,如果我有两个模型:
class Klass1(models.Model):
k2 = models.ForeignKey('Klass2')
class Klass2(models.Model):
# Model Code ...
@property
def klasses(self):
self.klasses = Klass1.objects.filter(k2=self)
return self.klasses
我在某处调用klass_2_instance.klasses[:]
,然后访问数据库并返回查询。我想知道我是否再次呼叫klass_2_instance.klasses
,是否会再次访问数据库,或者django查询是否会保存第一次呼叫的结果?
答案 0 :(得分:1)
Django不会为你缓存它。
而不是Klass1.objects.filter(k2 = self),你可以做self.klass1_set.all()。 因为Django总是在1-n关系的许多方面创建一个集合。
我猜这种缓存很复杂,因为它应该记住所有过滤器,排除和使用order_by。虽然可以使用任何设计良好的哈希来完成,但至少应该有一个参数来禁用缓存。
如果你想要任何缓存,你可以这样做:
class Klass2(models.Model): def __init__(self, *args, **kwargs): self._klass1_cache = None super(Klass2, self).__init__(*args, **kwargs) def klasses(self): if self._klass1_cache is None: # Here you can't remove list(..) because it is forcing query execution exactly once. self._klass1_cache = list(self.klass1_set.all()) return self._klass1_cache
当您在所有相关对象中循环多次时,这非常有用。对我来说,它经常发生在模板中,当我需要循环多次时。
答案 1 :(得分:1)
Django不会缓存此查询。
转发 FK关系 - 即给定Klass
对象klass
,在第一次查找后缓存klass.k2
- 。但反过来,你在这里做的 - 实际上通常是拼写klass2.klass_set.all()
- 是不缓存。
您可以轻松记住它:
@property
def klasses(self):
if not hasattr(self, '_klasses'):
self._klasses = self.klass_set.all()
return self._klasses
(请注意,您的现有代码无效,因为您使用属性覆盖方法klasses
。)
答案 2 :(得分:1)
如果要对查询集进行透明缓存,请尝试使用johnny-cache。