2016-11-21 4 views
0

Я смущен тем, что запрос времени использует его _result_cache или он напрямую попадает в базу данных.Когда набор запросов использует свой _result_cache, не попадая в базу данных?

Например (в оболочке Python):

user = User.objects.all() # User is one of my models 
print(user) # show data in database (hitting the database) 
print(user._result_cache) # output is None 
len(user) # output is a nonzero number 
print(user._result_cache) # this time, output is not None 

Итак, мои вопросы:

  1. Почему _result_cache является None после удара базы данных?
  2. Выполнено ли задание запроса, что _result_cache не None?
  3. Когда набор запросов использует его _result_cache, не попадая в базу данных?

ответ

4

Запрос будет кэшировать свои данные в self._result_cache всякий раз, когда вычисляется запрос . Это включает итерацию по набору запросов, вызывая bool(), len() или list(), или травление набора запросов.

Функция print() косвенно вызывает repr() на запрос. repr() будет оценивать набор запросов для включения данных в строковое представление, но он не будет оценивать полный набор . Вместо этого он будет get a slice набора запросов и использовать его в представлении. Это предотвращает огромные запросы, когда все, что вам нужно, - это простое строковое представление. Поскольку оценивается только срез, он не будет кэшировать результаты.

Когда кеш заполнен, каждый метод, который не создает новый объект запроса, будет использовать кеш вместо создания нового запроса. В вашем конкретном примере, если вы переключитесь заявление print() и len(), ваш QuerySet только попал в базу данных один раз:

user = User.objects.all() 
len(user) # complete queryset is evaluated 
print(user._result_cache) # cache is filled 
print(user) # slicing an evaluated queryset will not hit the database 
print(user._result_cache) 
+0

Спасибо большое !!!!Эта функция 'print()' меня озадачивает в течение длительного времени. – hochun

+0

извините, у меня вопрос. В «repr() будет оценивать набор запросов для включения данных в строковое представление», что означает «строковое представление»? и что это ? (is '_result_cache'?) – hochun

+0

Строковое представление объекта - это то, что вы видите напечатанным на консоли всякий раз, когда вы запускаете' print (obj) '. В случае набора запросов, '' QuerySet [...]> ', где' ... 'содержит фактические данные из отдельных экземпляров модели. – knbk

1

Существует объяснение такого поведения:

При использовании User.objects.all(), база данных не hit.When вы не перебирать набор запроса, _result_cache не всегда Нет. Но когда вы вызываете функцию len(). Итерация будет выполняться с помощью набора запросов, база данных будет удалена, а итоговый результат также установит result_cahce для этого набора запросов. Вот исходный код функции LEN() Джанго:

def __len__(self): 
    # Since __len__ is called quite frequently (for example, as part of 
    # list(qs), we make some effort here to be as efficient as possible 
    # whilst not messing up any existing iterators against the QuerySet. 
    if self._result_cache is None: 
     if self._iter: 
      self._result_cache = list(self._iter) 
     else: 
      self._result_cache = list(self.iterator()) 
    elif self._iter: 
     self._result_cache.extend(self._iter) 
    return len(self._result_cache) 

Надеется, что это проясняет все ваши вопросы. Благодарю.

+0

QuerySet ленивы, и просто 'User.objects.all()', безусловно, _not_ попал в базу данных , Только оценка набора запросов, например, при вызове 'print()' или 'len()', попадет в базу данных. – knbk

+0

@knbk Что .. ?? User.objects.all() не попадет в базу данных .. ?? –

+0

Правильно. Прочитайте [при запросе запросов] (https://docs.djangoproject.com/en/1.10/ref/models/querysets/#when-querysets-are-evaluated). В частности: _ «Внутренне, QuerySet может быть сконструирован, отфильтрован, разрезан и вообще передан без фактического попадания в базу данных. На самом деле активность базы данных не происходит, пока вы не сделаете что-то для оценки набора запросов». _ – knbk