在我的应用程序的每个视图中,我需要准备好导航菜单。所以现在在每个视图中我执行复杂的查询并将菜单存储在传递给模板的字典中。在模板中,我拥有数据的变量被“缓存”包围,所以即使查询成本很高,也不会打扰我。
但我不想在每一种观点中重复自己。我猜想准备菜单的最佳位置是在我自己的上下文处理器中。所以我写了一个,但我注意到即使我不使用来自上下文处理器的数据,也会执行用于准备菜单的查询。有没有办法从CP“延迟加载”这样的数据,还是我必须在CP中使用“低级”缓存?或者可能有更好的解决方案来解决我的问题?
答案 0 :(得分:18)
Django有SimpleLazyObject
。在Django 1.3中,auth context processor(source code)使用了它。这使得每个查询的模板上下文中都可以使用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)
答案 1 :(得分:3)
如果将可调用对象传递给模板上下文,Django将在模板中使用它时对其进行评估。这提供了一种简单的方法来做懒惰 - 只需传入callables:
def my_context_processor(request):
def complicated_query():
do_stuff()
return result
return {'result': complicated_query}
问题在于它没有记住调用 - 如果你多次使用它,complicated_query
会被多次调用。
修复是使用SimpleLazyObject
之类的东西,就像在另一个答案中一样,或者使用像memoize decorator这样的东西:
def memoize_nullary(f):
"""
Memoizes a function that takes no arguments.
"""
def func():
if not hasattr(func, 'retval'):
func.retval = f()
return func.retval
return func
def my_context_processor(request):
@memoize_nullary
def complicated_query():
do_stuff()
return result
return {'result': complicated_query}
或者,如果该功能已经存在,您可以这样做:
from somewhere import complicated_query
def my_context_processor(request):
return {'result': memoize_nullary(complicated_query)}
我希望这种方法优于SimpleLazyObject
,因为后者可以产生一些strange bugs sometimes。
(我是最初实施LazyObject
和SimpleLazyObject
的人,并为自己发现任何标有simple的代码人工制品都存在诅咒。)