Django 1.11 context processor error: TypeError: context must be a dict rather than RequestContext'

user1601871 picture user1601871 · Aug 8, 2017 · Viewed 8.7k times · Source

I cannot figure out why I'm encountering a problem with Django 1.11 and RenderContext. I really need help here. This is the code I've been playing with from the official documentation for 1.11:

from django.http import HttpResponse
from django.template import RequestContext, Template
from django.template import loader

def ip_address_processor(request):
    return {'ip_address': request.META['REMOTE_ADDR']}


def view_2(request):
    template = loader.get_template('template2.html')
    ctx = RequestContext(request, {
        'title': 'Your IP Address',
    }, [ip_address_processor])
    return HttpResponse(template.render(ctx))

And my simple template:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
Test
{{ title }}: {{ ip_address }}
</body>
</html>

This results in the following error:

Internal Server Error: /view2/
Traceback (most recent call last):
  File "C:\Python27\lib\site-packages\django\core\handlers\exception.py", line 41, in inner
    response = get_response(request)
  File "C:\Python27\lib\site-packages\django\core\handlers\base.py", line 187, in _get_response
    response = self.process_exception_by_middleware(e, request)
  File "C:\Python27\lib\site-packages\django\core\handlers\base.py", line 185, in _get_response
    response = wrapped_callback(request, *callback_args, **callback_kwargs)
  File "C:\Users\null\PycharmProjects\project1\project1\views.py", line 48, in view_2
    return template.render(c)
  File "C:\Python27\lib\site-packages\django\template\backends\django.py", line 64, in render
    context = make_context(context, request, autoescape=self.backend.engine.autoescape)
  File "C:\Python27\lib\site-packages\django\template\context.py", line 287, in make_context
    raise TypeError('context must be a dict rather than %s.' % context.__class__.__name__)
TypeError: context must be a dict rather than RequestContext.
[07/Aug/2017 23:52:49] "GET /view2/ HTTP/1.1" 500 72701

Which is just odd to me because the following code works:

from django.http import HttpResponse
from django.template import RequestContext, Template
from django.template import loader

def ip_address_processor(request):
    return {'ip_address': request.META['REMOTE_ADDR']}


def view_2(request):

    template = Template('{{ title }}: {{ ip_address }}')
    ctx = RequestContext(request, {
        'title': 'Your IP Address',
    }, [ip_address_processor])
    return HttpResponse(template.render(ctx))

Hard coding a template by overriding Template works fine, but importing it with django.template.loader.get_loader does not??? I'm really at a loss here.

What am I doing wrong? The templates are doing exactly the same thing. This is really putting me back from 1.11. It used to be you could pass a context_instance in Django 1.8 and it just worked. I can't seem to get any Context Processers running in 1.11, even using the example as documented on docs.djangoproject.com. It only ever works if I call Template and pass in my template through that by hard coding it.

Answer

user1601871 picture user1601871 · Aug 8, 2017

As The_Cthulhu_Kid said in a comment, Django 1.11 deprecated passing in non-dict Contexts:

https://docs.djangoproject.com/en/1.11/releases/1.11/#django-template-backends-django-template-render-prohibits-non-dict-context

I came up with a quick example, if anyone is figuring how you'd do content processors in 1.11

I changed the example code above to:

def ip_address_processor(request):
    return {'ip_address': request.META['REMOTE_ADDR'], 'ua': request.META['HTTP_USER_AGENT']}


def view_2(request):
    template = loader.get_template('template2.html')
    proc_ex = ip_address_processor(request)
    context = {'ua': proc_ex.get('ua'),
               'ip_address': proc_ex.get('ip_address'),
               'title': 'TEST'}
    return HttpResponse(template.render(context))

And the template:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
{{ title }}: {{ ip_address }}
User-Agent: {{ ua }}
</body>
</html>

You could also do this, to save from having to align keys up with the ip_address_processor function:

def ip_address_processor(request):
    return {'ip_address': request.META['REMOTE_ADDR'], 'ua': request.META['HTTP_USER_AGENT']}


def view_2(request):
    template = loader.get_template('template2.html')
    proc_ex = ip_address_processor(request)
    proc_ex.update({'title': 'test2'})
    return HttpResponse(template.render(proc_ex))

Looks like the key thing here is to just feed it a dict and it's happy.