Краткий ответ : здесь вы используете разные QuerySet
с, поэтому вы, создав копию, сделаете еще один запрос. Если вы используете тот же QuerySet
, Django удалит кеш, и поэтому пересмотрит QuerySet
. Однако возможно позволить объектам временно пережить вызов .delete()
из-за кэширования в другом QuerySet
, который был оценен до .
- это questions
объект переоценивается, когда мы запускаем delete()
на его подмножестве del_questions
questions
с никогда оценивается в первую очередь. QuerySet
является итеративным, и в случае, если вы перебираете его (или извлекаете длину, или что-то еще), результатом будет запрос. Но если вы напишите Model.objects.all().filter(foo=3)
, тогда Django не сначала "оценит" .all()
, извлекая все Model
объекты в память.
A QuerySet
по сути является инструментом для создания запроса, объединяя операции и каждый раз создавая новый набор запросов. В конце концов вы можете оценить один из наборов запросов.
Здесь примените .filter(..)
для двух вызовов. Таким образом, мы построили два разных QuerySet
с, и поэтому, если вы оцените первое, то это не приведет к кешированию во втором.
Вторым важным примечанием является то, что .delete()
не оценивает набор запросов и, следовательно, не кэширует результаты. Если мы проверим метод .delete()
[GitHub] , мы увидим:
def delete(self):
"""Delete the records in the current QuerySet."""
assert self.query.can_filter(), \
"Cannot use 'limit' or 'offset' with delete."
if self._fields is not None:
raise TypeError("Cannot call delete() after .values() or .values_list()")
<b>del_query = self._chain()</b>
# The delete is actually 2 queries - one to find related objects,
# and one to delete. Make sure that the discovery of related
# objects is performed on the same database as the deletion.
del_query._for_write = True
# Disable non-supported fields.
del_query.query.select_for_update = False
del_query.query.select_related = False
del_query.query.clear_ordering(force_empty=True)
collector = Collector(using=del_query.db)
collector.collect(del_query)
deleted, _rows_count = collector.delete()
# Clear the result cache, in case this QuerySet gets reused.
<b>self._result_cache = None</b>
return deleted, _rows_count
При self._chain()
создается копия кверсета. Таким образом, даже если это изменит состояние QuerySet
, оно не изменит состояние QuerySet
.
Другая интересная часть - self._result_cache = None
, здесь Django сбрасывает кеш. Таким образом, если набор запросов уже был оценен за до , который вы вызывали .delete()
(например, вы материализовали набор запросов перед вызовом .delete()
), то он удалит этот кеш. Так что если вы переоцените QuerySet
, это приведет к другому запросу на выборку элементов.
Однако существует сценарий, в котором данные все еще могут быть устаревшими. Например, следующее:
questions = Question.objects.all() # create a queryset
list(questions) # materialize the result
questions2 = questions.all() # create a copy of this queryset
questions2.delete() # remove the entries
Если мы сейчас назовем list(questions)
, мы получим элементы в кеше questions
, и это QuerySet
означает не недействительными, поэтому элементы "выживают" в .delete()
из другого набора запросов (копия этого запроса, хотя в этом нет необходимости, просто Questions.objects.all().delete()
также поможет).