【问题标题】:Django 1.11 context processor error: TypeError: context must be a dict rather than RequestContext'Django 1.11 上下文处理器错误:TypeError: context must be a dict 而不是 RequestContext'
【发布时间】:2018-01-15 14:54:18
【问题描述】:

我无法弄清楚为什么我会遇到 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 并通过硬编码传递我的模板时,它才会起作用。

【问题讨论】:

  • 这是 django 1.11 中的一个变化。不向后兼容。 docs.djangoproject.com/en/1.11/releases/1.11/…
  • 你也可以参考这张票code.djangoproject.com/ticket/27722
  • 哦不 :( !您有任何资源在 1.11 中执行上下文处理器的正确方法吗?我想定义一个返回字典值的函数并将其传递为上下文。
  • @user1601871,我已经为您的问题添加了答案。我认为您的问题是从 Django 1.8 更新到更新版本(在我的情况下为 1.11)的用户所面临的,所以 +1。

标签: python django requestcontext


【解决方案1】:

试试这个:

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() 方法否则不会接受它。

【讨论】:

    【解决方案2】:

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

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

    您应该使用render 而不是返回HttpResponse,因此您可以按如下方式更新您的代码。请注意,它传递的是 dict 作为上下文而不是 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

    【讨论】:

      【解决方案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))
      

      看起来这里的关键是只给它一个 dict 并且它很高兴。

      【讨论】:

      • 我尝试了您的解决方案。但它抛出“dict对象没有属性'render_context'。”。
      猜你喜欢
      • 2017-10-02
      • 2018-10-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-08-22
      • 1970-01-01
      相关资源
      最近更新 更多