Django: Можете ли вы сказать, была ли предварительно полезна соответствующая область, не получая ее?
Мне было интересно, есть ли способ в Django определить, связано ли связанное поле, в частности "много" части отношения "один-ко-многим", через, скажем, prefetch_related()
, не выбирая его?
Итак, в качестве примера предположим, что у меня есть эти модели:
class Question(Model):
"""Class that represents a question."""
class Answer(Model):
"""Class the represents an answer to a question."""
question = ForeignKey('Question', related_name='answers')
Обычно, чтобы получить количество ответов на вопрос, наиболее эффективным способом получить это было бы сделать следующее (поскольку в документах Django указано, что count()
более эффективен, если вам просто нужен счетчик):
# Note: "question" is an instance of class Question.
answer_count = question.answers.count()
Однако в некоторых случаях ответы могли быть получены с помощью вызова prefetch_related()
(или каким-то образом, например, ранее повторяющегося в ответах). Поэтому в таких ситуациях было бы более эффективно это делать (потому что мы пропустили дополнительный счетчик):
# Answers were fetched via prefetch_related()
answer_count = len(question.answers.all())
То, что я действительно хочу сделать, это что-то вроде:
if question.answers_have_been_prefetched: # Does this exist?
answer_count = len(question.answers.all())
else:
answer_count = question.answers.count()
Я использую Django 1.4, если это имеет значение. Спасибо заранее.
Изменить: добавлено разъяснение, что prefetch_related()
- это не единственный способ получить ответы.
Ответы
Ответ 1
Да, Django сохраняет предварительно выбранные результаты в атрибуте _prefetched_objects_cache
экземпляра родительской модели.
Итак, вы можете сделать что-то вроде:
instance = Parent.objects.prefetch_related('children').all()[0]
try:
instance._prefetched_objects_cache[instance.children.prefetch_cache_name]
# Ok, it pefetched
child_count = len(instance.children.all())
except (AttributeError, KeyError):
# Not prefetched
child_count = instance.children.count()
См. соответствующее использование в исходной магистрали django или эквивалент в версии 1.4.9