Сохраняет ли запрос django свой результат после вызова? - PullRequest
2 голосов
/ 03 декабря 2010

Я пытаюсь определить, будет ли полезен простой трюк с кэшированием. Я знаю, что наборы запросов 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 ]

1 голос
/ 03 декабря 2010

Этот запрос не кэшируется 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 с помощью атрибута.)

1 голос
/ 03 декабря 2010

Попробуйте использовать johnny-cache, если вы хотите прозрачное кэширование наборов запросов.

1 голос
/ 03 декабря 2010

Django не будет кешировать его для вас.

Вместо Klass1.objects.filter (k2 = self) вы можете просто сделать self.klass1_set.all (). Потому что Django всегда создает множество во многих отношениях 1-n отношений.

Я думаю, что этот тип кеша сложен, потому что он должен запоминать все используемые фильтры, exclude и 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

Это очень полезно, когда вы многократно повторяете цикл во всех связанных объектах. Для меня это часто случается в шаблоне, когда мне нужно сделать цикл более одного раза.

...