When rendering a template, you need a context. This can be an instance of django.template.Context, but Django also comes with a subclass, django.template.RequestContext, that acts slightly differently.
RequestContext adds a bunch of variables to your template context by default – things like the HttpRequest object or information about the currently logged-in user.
The render() shortcut creates a RequestContext unless it’s passed a different context instance explicitly. For example, consider these two views:
from django.template import loader, Context
def view_1(request):
# …
t = loader.get_template(‘template1.html’)
c = Context({
‘app’: ‘My app’,
‘user’: request.user,
‘ip_address’: request.META[‘REMOTE_ADDR’],
‘message’: ‘I am view 1.’
})
return t.render(c)
def view_2(request):
# …
t = loader.get_template(‘template2.html’)
c = Context({
‘app’: ‘My app’,
‘user’: request.user,
‘ip_address’: request.META[‘REMOTE_ADDR’],
‘message’: ‘I am the second view.’
})
return t.render(c)
(Note that I’m deliberately not using the render() shortcut in these examples – we’re manually loading the templates, constructing the context objects and rendering the templates. I’m “spelling out” all of the steps for the purpose of clarity.)
Each view passes the same three variables – app, user and ip_address – to its template. Wouldn’t it be nice if we could remove that redundancy? RequestContext and context processors were created to solve this problem. Context processors let you specify a number of variables that get set in each context automatically – without you having to specify the variables in each render() call.
The catch is that you have to use RequestContext instead of Context when you render a template. The most low-level way of using context processors is to create some processors and pass them to RequestContext. Here’s how the above example could be written with context processors:
from django.template import loader, RequestContext
def custom_proc(request):
# A context processor that provides ‘app’, ‘user’ and ‘ip_address’.
return {
‘app’: ‘My app’,
‘user’: request.user,
‘ip_address’: request.META[‘REMOTE_ADDR’]
}
def view_1(request):
# …
t = loader.get_template(‘template1.html’)
c = RequestContext(request,
{‘message’: ‘I am view 1.’},
processors=[custom_proc])
return t.render(c)
def view_2(request):
# …
t = loader.get_template(‘template2.html’)
c = RequestContext(request,
{‘message’: ‘I am the second view.’},
processors=[custom_proc])
return t.render(c)
Let’s step through this code:
- First, we define a function custom_proc. This is a context processor – it takes an HttpRequest object and returns a dictionary of variables to use in the template context. That’s all it does.
- We’ve changed the two view functions to use RequestContext instead of Context. There are two differences in how the context is constructed. One, RequestContext requires the first argument to be an HttpRequest object – the one that was passed into the view function in the first place (request). Two, RequestContext takes an optional processors argument, which is a list or tuple of context processor functions to use. Here, we pass in custom_proc, the custom processor we defined above.
- Each view no longer has to include app, user or ip_address in its context construction, because those are provided by custom_proc.
- Each view still has the flexibility to introduce any custom template variables it might need. In this example, the message template variable is set differently in each view.
- The render() shortcut, which saves you from having to call loader.get_template(), then create a Context, then call the render() method on the template.
In order to demonstrate the lower-level workings of context processors, the above examples didn’t use render(). But it’s possible – and preferable – to use context processors with render(). Do this with the context_instance argument, like so:
from django.shortcuts import render
from django.template import RequestContext
def custom_proc(request):
# A context processor that provides ‘app’, ‘user’ and ‘ip_address’.
return {
‘app’: ‘My app’,
‘user’: request.user,
‘ip_address’: request.META[‘REMOTE_ADDR’]
}
def view_1(request):
# …
return render(request, ‘template1.html’,
{‘message’: ‘I am view 1.’},
context_instance=RequestContext(
request, processors=[custom_proc]
)
)
def view_2(request):
# …
return render(request, ‘template2.html’,
{‘message’: ‘I am the second view.’},
context_instance=RequestContext(
request, processors=[custom_proc]
)
)
Here, we’ve trimmed down each view’s template rendering code to a single (wrapped) line. This is an improvement, but, evaluating the conciseness of this code, we have to admit we’re now almost overdosing on the other end of the spectrum. We’ve removed redundancy in data (our template variables) at the cost of adding redundancy in code (in the processors call).
Using context processors doesn’t save you much typing if you have to type processors all the time. For that reason, Django provides support for global context processors. The context_processors setting (in your settings.py) designates which context processors should always be applied to RequestContext. This removes the need to specify processors each time you use RequestContext.
By default, context_processors is set to the following:
‘context_processors’: [
‘django.template.context_processors.debug’,
‘django.template.context_processors.request’,
‘django.contrib.auth.context_processors.auth’,
‘django.contrib.messages.context_processors.messages’,
],
This setting is a list of callables that use the same interface as our custom_proc function above – functions that take a request object as their argument and return a dictionary of items to be merged into the context. Note that the values in context_processors are specified as strings, which means the processors are required to be somewhere on your Python path (so you can refer to them from the setting).
Each processor is applied in order. That is, if one processor adds a variable to the context and a second processor adds a variable with the same name, the second will override the first. Django provides a number of simple context processors, including the ones that are enabled by default:
auth
django.contrib.auth.context_processors.auth
If this processor is enabled, every RequestContext will contain these variables:
- user – An auth.User instance representing the currently logged-in user (or an AnonymousUser instance, if the client isn’t logged in).
- perms – An instance of django.contrib.auth.context_processors.PermWrapper, representing the permissions that the currently logged-in user has.
debug
django.template.context_processors.debug
If this processor is enabled, every RequestContext will contain these two variables – but only if your DEBUG setting is set to True and the request’s IP address (request.META[‘REMOTE_ADDR’]) is in the INTERNAL_IPS setting: - debug – True. You can use this in templates to test whether you’re in DEBUG mode.
- sql_queries – A list of {‘sql’: …, ‘time’: …} dictionaries, representing every SQL query that has happened so far during the request and how long it took. The list is in order by query and lazily generated on access.
i18n
django.template.context_processors.i18n
If this processor is enabled, every RequestContext will contain these two variables:
- LANGUAGES – The value of the LANGUAGES setting.
- LANGUAGE_CODE – request.LANGUAGE_CODE, if it exists. Otherwise, the value of the LANGUAGE_CODE setting.
media
django.template.context_processors.media
If this processor is enabled, every RequestContext will contain a variable MEDIA_URL, providing the value of the MEDIA_URL setting.
static
django.template.context_processors.static
If this processor is enabled, every RequestContext will contain a variable STATIC_URL, providing the value of the STATIC_URL setting.
csrf
django.template.context_processors.csrf
This processor adds a token that is needed by the csrf_token template tag for protection against cross site request forgeries.
request
django.template.context_processors.request
If this processor is enabled, every RequestContext will contain a variable request, which is the current HttpRequest.
messages
django.contrib.messages.context_processors.messages
If this processor is enabled, every RequestContext will contain these two variables:
- messages – A list of messages (as strings) that have been set via the messages framework.
- DEFAULT_MESSAGE_LEVELS – A mapping of the message level names to their numeric value.