在我的应用程序的每个视图中,我需要准备导航菜单。所以现在在每个视图中,我都会执行复杂的查询,并将菜单存储在一个字典中,然后传递给一个模板。在模板中,我有数据的变量是用 "缓存 "包围的,所以即使查询的成本很高,也不会影响我。
但我不想在每个视图中重复。我猜想,最好的地方是在我自己的上下文处理器中准备菜单。于是我确实写了一个,但我注意到,即使我不使用上下文处理器的数据,用来准备菜单的查询也会被执行。有没有办法从CP中 "懒加载 "这样的数据,或者我必须在CP中使用 "低级 "缓存?或者也许有更好的办法解决我的问题?
Django有一个 SimpleLazyObject
. 在Django 1.3中,这是由 认证背景处理器 (源码). 这使得 user
在模板上下文中,每个查询都可以使用,但只有当模板含有 {{ user }}
.
你应该可以在你的上下文处理器中做类似的事情。
from django.utils.functional import SimpleLazyObject
def my_context_processor(request):
def complicated_query():
do_stuff()
return result
return {
'result': SimpleLazyObject(complicated_query)
如果你把一个可调用的对象传递到模板上下文中,当它在模板中被使用时,Django会对它进行评估。这提供了一个简单的方法来实现懒惰--只需传递可调用对象。
def my_context_processor(request):
def complicated_query():
do_stuff()
return result
return {'my_info': complicated_query}
这样做的问题是,如果你在一个模板中多次使用它,它就不会对调用进行记忆。complicated_query
被多次调用。
解决方法是使用类似 SimpleLazyObject
如同其他答案一样,或者使用类似于 functools.lru_cache
:
from functools import lru_cache:
def my_context_processor(request):
@lru_cache()
def complicated_query():
result = do_stuff()
return result
return {'my_info': complicated_query}
您现在可以使用 my_info
在你的模板中,它将被懒惰地评估,只评估一次。
或者,如果函数已经存在,你可以这样做。
from somewhere import complicated_query
def my_context_processor(request):
return {'my_info': lru_cache()(complicated_query)}
我更喜欢这个方法,而不是 SimpleLazyObject
因为后者可以产生一些 怪胎.
(我是最初实施 LazyObject
和 SimpleLazyObject
我自己也发现,任何被标示为 简单的.)