django查询在调用后是否保存其结果?

时间:2010-12-03 01:40:27

标签: python django django-models django-queryset

我正在尝试确定一个简单的缓存技巧是否真的有用。我知道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查询是否会保存第一次呼叫的结果?

3 个答案:

答案 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。