Django 从 1.7 升级到 1.8:视图中需要来自上下文处理器的变量
Django upgrade from 1.7 to 1.8: Need variable from contextprocessor in view
许多变量必须在每次页面点击期间确定,但在我的项目的不同地方使用,不仅是模板,而且在视图中。到目前为止,我一直在使用上下文处理器(称为 'globals')来实现此结果。请注意,在上下文处理器中,我正在进行实际的计算和数据库调用,因此我不仅仅需要一个设置变量。
自从 Django 1.7 升级到 1.8 后,上下文处理器返回的变量仍然显示在模板中,这很好,但它们不再显示在视图中,至少我找不到它们。
在我的上下文处理器中,我有以下代码:
def globals(request):
# NOTE: We DON'T simply need a variable from settings - in reality this is computed
if_this_is_true_then_we_alter_text = True
ctx = {
'var_from_contextprocessor': if_this_is_true_then_we_alter_text,
}
return ctx
那么,在我看来,我有:
from django.template import RequestContext
from django.shortcuts import render
def show_globals(request):
ctx = RequestContext(request)
ctx['var_from_view'] = 'YES, we found it!' if ctx.has_key('var_from_contextprocessor') else 'NO, it ain\'t there!'
return render(request, 'show_globals.html', context_instance=ctx)
我的模板,show_globals.html
如下:
var_from_view: {{ var_from_view }}
var_from_contextprocessor: {{ var_from_contextprocessor }}
当 运行 Django 1.7 时,视图模板中的输出将为 "YES, we found it!"。但是,一旦我升级到 1.8,上下文处理器返回的变量似乎可用于视图,因此文本更改为 "NO, it ain't there!"。然而,在这两种情况下,var_from_contextprocessor
都会适当地显示在模板本身中。
还有办法在单个视图中从上下文处理器中检索变量吗?如果没有,关于如何在不使用上下文处理器的情况下获得相同结果的任何建议?
请注意,我试图解决的基本问题只是在每次页面点击期间即时计算变量,然后这些变量可用于视图和模板。我真的不在乎这是否是通过使用上下文处理器完成的。
提前致谢!
1.7 和 1.8 之间的变化是引入了不同的模板后端,以允许 first-class 支持例如 Jinja2。这意味着上下文处理器已经从 top-level 设置转变为与特定模板后端关联的设置;例如,TEMPLATE_CONTEXT_PROCESSORS 设置已弃用,但目前仍受支持。
这样做的结果是 RequestContext 在与实际模板相关联之前不与任何特定的上下文处理器集相关联。默认情况下,当您调用模板的 render
方法(它本身由上面使用的独立 render
快捷方式调用)时会发生这种情况。
但是,您可以自己执行此操作,方法是显式调用 bind_template
并在视图中自己进行渲染:
from django.template import loader
ctx = RequestContext(request)
tpl = loader.get_template('show_globals.html')
with ctx.bind_template(tpl.template):
ctx['var_from_view'] = 'YES, we found it!' if ctx.has_key('var_from_contextprocessor') else 'NO, it ain\'t there!'
return HttpResponse(template.render(ctx))
不过我必须说,这整件事让我觉得是对上下文处理器的误用,出于某种原因将其称为 template 上下文处理器。您应该考虑重新编写代码,以便在视图中不需要此访问权限 - 也许在模板标记中执行此操作?
我发现了一个有帮助的解决方案,至少对我来说是这样。
所以期望的结果是在每次页面加载时都有代码 运行,结果在所有视图和所有模板中都可用。
在 Django 版本 1.7 和 1.8 之间停止使用简单的上下文处理器的技术原因在 Daniel Roseman 的不同答案中得到了很好的解释,所以我不会在这里讨论它们。
长话短说,诀窍是使用 中间件 而不是 上下文处理器 ,然后 contextprocessor 从 middleware.
继承变量
考虑原题中的代码,与新代码对比:
上下文处理器:
def globals(request):
ctx = request.extravars # See example.middleware.ExtraVarsMiddleware
return ctx
中间件:
class ExtraVarsMiddleware():
# For handing certain variables over to the context processor for global display.
def process_view(self, request, view_func, view_args, view_kwargs):
# NOTE: We DON'T simply need a variable from settings
if_this_is_true_then_we_alter_text = True
request.extravars = {
'var_from_contextprocessor': if_this_is_true_then_we_alter_text,
}
"global" 变量挂在一个名为 extravars 的任意命名字典中的请求对象上。请注意,虽然我们的 "global" 变量条目仍称为 var_from_contextprocessor
,但此时用词不当,因为它来自中间件,不再是上下文处理器。
为了激活这个中间件,必须更改设置以包含它,就像这样(包含默认值):
MIDDLEWARE_CLASSES = (
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.auth.middleware.SessionAuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
'example.middleware.ExtraVarsMiddleware',
)
然后模板可以像以前一样访问变量,因为上下文处理器已将整个 request.extravars
添加到其生成的上下文中,然后按照上面的代码返回。
然后,为了访问视图中的变量,我们需要对之前的内容稍作改动:
from django.shortcuts import render
def show_globals(request):
ctx = request.extravars
ctx['var_from_view'] = 'YES, we found it!' if ctx.has_key('var_from_contextprocessor') else 'NO, it ain\'t there!'
return render(request, 'show_globals.html', context=ctx)
我已尽可能少地更改此代码以演示所需的最少更改。只有两件事发生了变化,一个是 ctx
字典的获取方式,这次没有使用 RequestContext
。第二个变化是我们不再将 context_instance
传递给 render
函数,而是简单地传递 context
.
为澄清起见,我的示例设置中相应的文件名是:
example/contextprocessors.py
example/middleware.py
example/views.py
settings.py
许多变量必须在每次页面点击期间确定,但在我的项目的不同地方使用,不仅是模板,而且在视图中。到目前为止,我一直在使用上下文处理器(称为 'globals')来实现此结果。请注意,在上下文处理器中,我正在进行实际的计算和数据库调用,因此我不仅仅需要一个设置变量。
自从 Django 1.7 升级到 1.8 后,上下文处理器返回的变量仍然显示在模板中,这很好,但它们不再显示在视图中,至少我找不到它们。
在我的上下文处理器中,我有以下代码:
def globals(request):
# NOTE: We DON'T simply need a variable from settings - in reality this is computed
if_this_is_true_then_we_alter_text = True
ctx = {
'var_from_contextprocessor': if_this_is_true_then_we_alter_text,
}
return ctx
那么,在我看来,我有:
from django.template import RequestContext
from django.shortcuts import render
def show_globals(request):
ctx = RequestContext(request)
ctx['var_from_view'] = 'YES, we found it!' if ctx.has_key('var_from_contextprocessor') else 'NO, it ain\'t there!'
return render(request, 'show_globals.html', context_instance=ctx)
我的模板,show_globals.html
如下:
var_from_view: {{ var_from_view }}
var_from_contextprocessor: {{ var_from_contextprocessor }}
当 运行 Django 1.7 时,视图模板中的输出将为 "YES, we found it!"。但是,一旦我升级到 1.8,上下文处理器返回的变量似乎可用于视图,因此文本更改为 "NO, it ain't there!"。然而,在这两种情况下,var_from_contextprocessor
都会适当地显示在模板本身中。
还有办法在单个视图中从上下文处理器中检索变量吗?如果没有,关于如何在不使用上下文处理器的情况下获得相同结果的任何建议?
请注意,我试图解决的基本问题只是在每次页面点击期间即时计算变量,然后这些变量可用于视图和模板。我真的不在乎这是否是通过使用上下文处理器完成的。
提前致谢!
1.7 和 1.8 之间的变化是引入了不同的模板后端,以允许 first-class 支持例如 Jinja2。这意味着上下文处理器已经从 top-level 设置转变为与特定模板后端关联的设置;例如,TEMPLATE_CONTEXT_PROCESSORS 设置已弃用,但目前仍受支持。
这样做的结果是 RequestContext 在与实际模板相关联之前不与任何特定的上下文处理器集相关联。默认情况下,当您调用模板的 render
方法(它本身由上面使用的独立 render
快捷方式调用)时会发生这种情况。
但是,您可以自己执行此操作,方法是显式调用 bind_template
并在视图中自己进行渲染:
from django.template import loader
ctx = RequestContext(request)
tpl = loader.get_template('show_globals.html')
with ctx.bind_template(tpl.template):
ctx['var_from_view'] = 'YES, we found it!' if ctx.has_key('var_from_contextprocessor') else 'NO, it ain\'t there!'
return HttpResponse(template.render(ctx))
不过我必须说,这整件事让我觉得是对上下文处理器的误用,出于某种原因将其称为 template 上下文处理器。您应该考虑重新编写代码,以便在视图中不需要此访问权限 - 也许在模板标记中执行此操作?
我发现了一个有帮助的解决方案,至少对我来说是这样。
所以期望的结果是在每次页面加载时都有代码 运行,结果在所有视图和所有模板中都可用。
在 Django 版本 1.7 和 1.8 之间停止使用简单的上下文处理器的技术原因在 Daniel Roseman 的不同答案中得到了很好的解释,所以我不会在这里讨论它们。
长话短说,诀窍是使用 中间件 而不是 上下文处理器 ,然后 contextprocessor 从 middleware.
继承变量考虑原题中的代码,与新代码对比:
上下文处理器:
def globals(request):
ctx = request.extravars # See example.middleware.ExtraVarsMiddleware
return ctx
中间件:
class ExtraVarsMiddleware():
# For handing certain variables over to the context processor for global display.
def process_view(self, request, view_func, view_args, view_kwargs):
# NOTE: We DON'T simply need a variable from settings
if_this_is_true_then_we_alter_text = True
request.extravars = {
'var_from_contextprocessor': if_this_is_true_then_we_alter_text,
}
"global" 变量挂在一个名为 extravars 的任意命名字典中的请求对象上。请注意,虽然我们的 "global" 变量条目仍称为 var_from_contextprocessor
,但此时用词不当,因为它来自中间件,不再是上下文处理器。
为了激活这个中间件,必须更改设置以包含它,就像这样(包含默认值):
MIDDLEWARE_CLASSES = (
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.auth.middleware.SessionAuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
'example.middleware.ExtraVarsMiddleware',
)
然后模板可以像以前一样访问变量,因为上下文处理器已将整个 request.extravars
添加到其生成的上下文中,然后按照上面的代码返回。
然后,为了访问视图中的变量,我们需要对之前的内容稍作改动:
from django.shortcuts import render
def show_globals(request):
ctx = request.extravars
ctx['var_from_view'] = 'YES, we found it!' if ctx.has_key('var_from_contextprocessor') else 'NO, it ain\'t there!'
return render(request, 'show_globals.html', context=ctx)
我已尽可能少地更改此代码以演示所需的最少更改。只有两件事发生了变化,一个是 ctx
字典的获取方式,这次没有使用 RequestContext
。第二个变化是我们不再将 context_instance
传递给 render
函数,而是简单地传递 context
.
为澄清起见,我的示例设置中相应的文件名是:
example/contextprocessors.py
example/middleware.py
example/views.py
settings.py