来自上下文处理器的数据的"延迟加载"

szy*_*ond 9 django caching lazy-loading django-views

在我的应用程序的每个视图中,我需要准备导航菜单.所以现在在每个视图中我执行复杂的查询并将菜单存储在传递给模板的字典中.在模板中,我拥有数据的变量被"缓存"包围,所以即使查询成本很高,也不会打扰我.

但我不想在每一种观点中重复自己.我猜想准备菜单的最佳位置是在我自己的上下文处理器中.所以我写了一个,但我注意到即使我不使用来自上下文处理器的数据,也会执行用于准备菜单的查询.有没有办法从CP"延迟加载"这样的数据,还是我必须在CP中使用"低级"缓存?或者也许有更好的解决方案来解决我的问题?

Ala*_*air 18

Django有一个SimpleLazyObject.在Django 1.3中,auth上下文处理器使用它(源代码).这使得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)
Run Code Online (Sandbox Code Playgroud)


spo*_*key 9

如果将可调用对象传递到模板上下文中,Django 将在模板中使用它时对其进行评估。这提供了一种实现懒惰的简单方法——只需传入可调用对象:

def my_context_processor(request):
    def complicated_query():
        do_stuff()
        return result                      
    return {'my_info': complicated_query}
Run Code Online (Sandbox Code Playgroud)

这样做的问题是它不会记住调用——如果你在模板中多次使用它,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}
Run Code Online (Sandbox Code Playgroud)

你现在可以my_info在你的模板中使用,它会被懒惰地评估一次。

或者,如果函数已经存在,你可以这样做:

from somewhere import complicated_query

def my_context_processor(request):        
    return {'my_info': lru_cache()(complicated_query)}
Run Code Online (Sandbox Code Playgroud)

我更喜欢这种方法,SimpleLazyObject因为后者有时会产生一些奇怪的错误

(我是最初实现LazyObjectand 的人SimpleLazyObject,并为自己发现任何标记为simple 的代码人工制品都存在诅咒。)