Django 1.11上下文处理器错误:TypeError:context必须是dict而不是RequestContext'

时间:2017-08-08 07:07:26

标签: python django requestcontext

我无法弄清楚为什么我遇到了Django 1.11和RenderContext的问题。我真的需要帮助。这是我从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))

我的简单模板:

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

这会导致以下错误:

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

这对我来说很奇怪,因为以下代码有效:

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))

通过覆盖模板对模板进行硬编码工作正常,但使用django.template.loader.get_loader导入它不会???我真的很茫然。

我做错了什么?模板正在做同样的事情。这真的让我从1.11回来。过去你可以在Django 1.8中传递一个context_instance,它就可以了。我似乎无法在1.11中运行任何Context Processers,即使使用docs.djangoproject.com上记录的示例也是如此。它只有在我调用模板并通过硬编码传递我的模板时才有效。

3 个答案:

答案 0 :(得分:3)

作为The_Cthulhu_Kid said in a comment,Django 1.11弃用了非字典上下文:

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

我想出了一个简单的例子,如果有人想知道你在1.11中如何做内容处理器

我将上面的示例代码更改为:

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))

模板:

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

您也可以这样做,以避免必须使用ip_address_processor函数对齐密钥:

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))

看起来这里的关键是给它一个字母,它很开心。

答案 1 :(得分:1)

基本上,您面临的问题是在Django 1.11中禁止非字典上下文。

  

为了与多个模板引擎兼容,django.template.backends.django.Template.render()必须接收上下文词典,而不是ContextRequestContext如果您要传递这两个类中的任何一个,请改为传递字典-这样做与旧版本的Django向后兼容。

您应该使用render而不是返回HttpResponse,以便可以按以下方式更新代码。请注意,它正在将字典作为上下文而不是RequestContext类型的对象。

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


def view_2(request):
    context = ip_address_processor(request)
    context.update({'title': 'test2'})
    return render(request, 'template2.html', context)

render是一种快捷方式,它将使用模板名称作为参数,然后使用给定的参数渲染此模板,然后使用渲染的正文返回HttpResponse

HttpResponse不会在后台执行Django的工作,因此,如果要返回渲染的Django模板,则需要手动执行此操作并将结果传递给HttpResponse,然后再返回。 (有关更多检查,this question and its answers

答案 2 :(得分:0)

尝试一下:

from django.http import HttpResponse
from django.template import 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 = request.GET.copy().dict()
    ctx.update({
        'title': 'Your IP Address',
    })
    ctx.update(ip_address_processor(request))
    return HttpResponse(template.render(ctx))

request.GET现在返回一个只读的QueryDict对象。为了使其可修改,您必须使用.copy()获得读写副本。然后,您必须使用.dict()将其转换为常规的Python字典。 render()方法不会接受它。