Могу ли я получить доступ к объекту контекста в декораторе поверх представления django

#python #django #python-2.7 #django-views #python-decorators

#python #django #python-2.7 #django-views #python-декораторы

Вопрос:

У меня есть несколько представлений django, к которым я хочу добавить некоторый контекст на основе их ответа и кода состояния. Прямо сейчас у меня есть код, который выглядит примерно так:

 def my_decor(func):
    def wrapper(*args, **kwargs):
        response = func(*args, **kwargs)
        if response.status_code == 200:  # It will be changed to manipulate 2XX reponses only
            new_data = foo()
            response.context['some_new_data'] = new_data
        return response
    return wrapper


@my_decor
def view1(request):
    # some logic
    context = {'some_data': 'some_value'}
    return render(request, 'some_template.html', context)


@my_decor
def view2(request):
    # more logic
    return render(request, 'another_template.html')
  

Итак, по сути, я хочу создать декоратор, который можно использовать с представлениями, которые прикрепляют контекст при возврате, и с теми, которые этого не делают.
Прямо сейчас я получаю AttributeError: 'HttpResponse' object has no attribute 'context' .
Что я делаю не так?

Python 2.7.13 и Django 1.7.11

Комментарии:

1. Какое преимущество или использование вы хотите получить, добавив что-то в HTTP-ответ?

2. Будет удобно не изменять существующие представления return render(request, 'tmp.html') , а добавлять к ним декоратор, чтобы их HttpResponse имел контекст, к которому мне нужно получить доступ в шаблоне. Самым простым способом было бы ввести foo() в каждую функцию и изменить каждый возврат на return render(request, 'tm.html', context)

3. «таким образом, их HttpResponse будет иметь контекст, к которому мне нужно получить доступ в шаблоне» …. Это то HttpResponse , что имеет «визуализированный вывод» , то есть результат render(request, 'some_template.html', context) . В этом случае вы не можете манипулировать данными контекста

4. Более того, я бы рекомендовал использовать CBV, чтобы у вас было больше контроля над контекстными данными

Ответ №1:

После того, как вы вызовете func(*args, **kwargs) свой декоратор, вы отрисовали шаблон, и менять шаблон уже слишком поздно.

Вы можете переключиться на TemplateResponse , что позволяет изменять контекст перед отображением шаблона. Получите доступ к контексту, используя атрибут ответа context_data .

 from django.template.response import TemplateResponse

@my_decor
def view1(request):
    # some logic
    context = {'some_data': 'some_value'}
    return TemplateResponse(request, 'some_template.html', context)
  

В вашем декораторе измените response.context на response.context_data :

     if response.status_code == 200:  # n.b. this is only for 200 responses, not 2XX as you say in your comment
        new_data = foo()
        response.context_data['some_new_data'] = new_data