Ошибка обработчика контекста в Django 1.11: Ошибка типа: контекст должен быть dict, а не 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))

Жесткое кодирование шаблона путем переопределения Template отлично работает, но импорт его с помощью django.template.loader.get_loader не дает??? Я действительно в растерянности здесь.

Что я делаю неправильно? Шаблоны делают то же самое. Это действительно возвращает меня к 1.11. Раньше вы могли передавать context_instance в Django 1.8, и это просто работало. Кажется, я не могу запустить ни одного Context Procesers в версии 1.11, даже используя пример, описанный на docs.djangoproject.com. Это работает только тогда, когда я вызываю Template и передаю свой шаблон через него путем жесткого кодирования.

2 ответа

Как сказал The_Cthulhu_Kid в комментарии, Django 1.11 не одобряет переход в недиктивный контекст:

https://docs.djangoproject.com/en/1.11/releases/1.11/

Я придумал быстрый пример, если кто-нибудь подумает, как бы вы работали с обработчиками контента в 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))

Похоже, главное здесь - просто накормить его диктовкой, и он счастлив.

По сути, проблема, с которой вы сталкиваетесь, заключается в том, что в Django 1.11 запрещен недиктивный контекст.

Для совместимости с несколькими шаблонными движками, django.template.backends.django.Template.render() должен получить словарь контекста, а не Context или же RequestContext, Если вы передавали один из двух классов, вместо этого передайте словарь - это обратно совместимо со старыми версиями 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 перед возвращением. (для более подробной информации проверьте этот вопрос и его ответы)

Попробуй это:

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(). Затем вам нужно преобразовать его в обычный словарь Python, используя.dict(). Вrender() иначе метод не примет.

Другие вопросы по тегам