Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Django: add context to response using decorator

Given the following scenario:

from django.shortcuts import render


def decorator(view):
    def wrapper(request, *args, **kwargs):
        context = {'foo': 'bar'}
        # Logic ...
        return view(request, *args, **kwargs)
    return wrapper


@decorator
def index(request):
    return render(request, 'index.html')

I'd like to have the decorator add a context dictionary to the view, so that the decorated function that is returned looks like this:

return render(request, 'index.html', context)

Is this possible?

like image 894
Jeremy Swinarton Avatar asked Jun 18 '13 18:06

Jeremy Swinarton


2 Answers

After a bunch of searching, I've figured out how to do this in a way that requires no extra cruft in the original function, keeping things DRY. The key is Django's TemplateResponse object, which defers rendering of the template until just before the response is sent to the user, opening up opportunities for processing by decorators (and middleware, FWIW).

Here's what it looks like now:

from django.template.response import TemplateResponse    

def decorator(view):
    def wrapper(request, *args, **kwargs):
        r = view(request, *args, **kwargs)
        r.context_data = {'foo': 'bar'}
        return r.render()
    return wrapper

@decorator
def index(request):
    return TemplateResponse(request, 'index.html')
like image 181
Jeremy Swinarton Avatar answered Oct 19 '22 19:10

Jeremy Swinarton


This isn't possible the way you currently have your function written, but you could do something like the following for the same behavior:

from django.shortcuts import render    

def decorator(view):
    def wrapper(request, *args, **kwargs):
        context = {'foo': 'bar'}
        args = args + (context,)
        return view(request, *args, **kwargs)
    return wrapper    

@decorator
def index(request, *args):
    return render(request, 'index.html', *args)

This will cause the decorator to add your context dictionary to the end of the positional arguments that are passed into index(), which are then passed onto render().

like image 37
Andrew Clark Avatar answered Oct 19 '22 18:10

Andrew Clark