4

我无法弄清楚为什么我在 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))

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

我究竟做错了什么?模板正在做同样的事情。这真的让我从 1.11 回来了。以前你可以在 Django 1.8 中传递一个 context_instance ,它就可以工作了。即使使用 docs.djangoproject.com 上记录的示例,我似乎也无法在 1.11 中运行任何上下文处理器。只有当我调用 Template 并通过硬编码传递我的模板时,它才会起作用。

4

3 回答 3

3

正如The_Cthulhu_Kid 在评论中所说,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))

看起来这里的关键是只喂它一个字典,它很高兴。

于 2017-08-08T07:32:24.747 回答
1

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

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

您应该使用render而不是返回一个HttpResponse,因此您可以按如下方式更新您的代码。请注意,它将 dict 作为上下文而不是 type 的对象传递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带有渲染主体的 an。

HttpResponse不会在幕后做 Django 的事情,所以如果你想返回一个渲染的 Django 模板,你需要手动执行此操作并将结果传递给HttpResponse返回之前。(更多检查这个问题及其答案

于 2018-07-13T03:28:39.190 回答
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(). render()否则该方法将不接受它。

于 2019-10-15T23:53:39.753 回答