【发布时间】:2013-10-29 16:21:30
【问题描述】:
我想知道 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() 不是获取答案的唯一方法。
【问题讨论】:
-
这里使用包装库的全部意义在于,事实上,您不必担心这样的事情。除非您认为这是一个真正的瓶颈,否则只需使用简单的方法,不要增加不必要的复杂性。但是,在 Django 源代码中稍微戳了一下之后,我发现了一些提示。如果您仍然坚持尝试此 hack,您可以尝试
obj._prefetched_objects_cache,或者您也可以尝试print dir(question.answers),看看您是否在其中看到任何与缓存相关的外观参数。 -
这不是一个巨大的瓶颈,不。我只是想真正优化应用程序并将查询数量降至最低限度。同意如果唯一的方法是hacky,那么它是不值得的。我应该澄清一下:prefetch_related 只是一个例子。也可以通过其他方式获取结果(例如,迭代代码中之前的 question.answers),这就是为什么我希望有一些通用的解决方案。
-
如果 Django 可以让你选择对预取关系进行自动内存过滤,那就太好了,这样你就不会仅仅通过使用他们的 DSL 来调查你已经拥有的数据来生成新的查询有。
-
请注意,关系的“一”侧存储在 obj._{{field_name}}_cache 中
-
自动内存过滤会很不错,尽管随着 Prefetch 对象的出现不太必要。