«Ленивая загрузка» данных из контекстного процессора - PullRequest
9 голосов
/ 19 декабря 2011

В каждом представлении моего приложения мне нужно подготовить меню навигации. Так что сейчас в каждом представлении я выполняю сложный запрос и сохраняю меню в словаре, который передается шаблону В шаблонах переменная, в которой у меня есть данные, окружена «кешем», поэтому, несмотря на то, что запросы довольно дорогие, меня это не беспокоит.

Но я не хочу повторяться во всех взглядах. Я догадался, что лучшее место для подготовки меню - это мой собственный контекстный процессор. И поэтому я написал один, но заметил, что даже когда я не использую данные из контекстного процессора, выполняются запросы, используемые для подготовки меню. Есть ли способ «ленивой загрузки» таких данных из CP или мне нужно использовать «низкоуровневый» кэш в CP? Или, может быть, есть лучшее решение моей проблемы?

Ответы [ 2 ]

18 голосов
/ 19 декабря 2011

Джанго имеет 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 голосов
/ 26 января 2015

Если вы передадите вызываемый объект в контекст шаблона, Django оценит его, когда он будет использован в шаблоне.Это обеспечивает один простой способ сделать лень - просто передать вызываемые объекты:

def my_context_processor(request):
    def complicated_query():
        do_stuff()
        return result                      
    return {'result': complicated_query}

Проблема в том, что он не запоминает вызов - если вы используете его несколько раз, complicated_query вызывается несколько раз.

Исправление состоит в том, чтобы использовать что-то вроде SimpleLazyObject, как в другом ответе, или использовать что-то вроде этого декоратора памятки:

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, поскольку последний может иногда вызывать странных ошибок .

(я был однимкоторый первоначально реализовал LazyObject и SimpleLazyObject и обнаружил для себя, что на любом артефакте кода, помеченном simple .)

, есть проклятие.
...