从上下文处理器中 "懒加载 "数据。

问题描述 投票:10回答:2

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

但我不想在每个视图中重复。我猜想,最好的地方是在我自己的上下文处理器中准备菜单。于是我确实写了一个,但我注意到,即使我不使用上下文处理器的数据,用来准备菜单的查询也会被执行。有没有办法从CP中 "懒加载 "这样的数据,或者我必须在CP中使用 "低级 "缓存?或者也许有更好的办法解决我的问题?

django caching django-views lazy-loading
2个回答
19
投票

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)

3
投票

如果你把一个可调用的对象传递到模板上下文中,当它在模板中被使用时,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 因为后者可以产生一些 怪胎.

(我是最初实施 LazyObjectSimpleLazyObject我自己也发现,任何被标示为 简单的.)

© www.soinside.com 2019 - 2024. All rights reserved.