【问题标题】:Django upgrade from 1.7 to 1.8: Need variable from contextprocessor in viewDjango 从 1.7 升级到 1.8:需要上下文处理器中的变量
【发布时间】:2016-04-02 17:49:51
【问题描述】:

在每个页面点击期间必须确定许多变量,但在我的项目中的不同位置使用,不仅是模板,而且在视图中。到目前为止,我一直在使用上下文处理器(称为“全局”)来实现此结果。请注意,在上下文处理器中,我正在执行实际计算和数据库调用,因此我不仅需要设置变量。

自从从 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,我们找到它!”。但是,一旦我升级到 1.8,上下文处理器返回的变量似乎对视图可用,因此文本更改为“不,它不存在!”。然而,在这两种情况下,var_from_contextprocessor 都会适当地显示在模板本身中。

还有没有办法在单个视图中从上下文处理器中检索变量?如果没有,关于如何在不使用上下文处理器的情况下获得相同结果的任何建议?

请注意,我试图解决的基本问题是在每次页面点击期间动态计算变量,然后视图和模板都可以使用这些变量。我真的不在乎这是否通过使用上下文处理器来完成。

提前致谢!

【问题讨论】:

    标签: django django-templates django-1.8


    【解决方案1】:

    1.7 和 1.8 之间的变化是引入了不同的模板后端,以允许一流的支持,例如 Jinja2。这意味着上下文处理器已经从顶级设置转变为与特定模板后端相关联的设置;例如,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))
    

    我必须说,这整件事让我觉得是对上下文处理器的误用,出于某种原因,它们被称为 模板 上下文处理器。您应该考虑修改您的代码,以便您不需要在视图中进行此访问 - 也许在模板标签中进行?

    【讨论】:

    • 感谢您提供的信息!您已经阐明了这背后的原因。 :) 我不太确定什么是误用,但我的确切问题是我在视图函数和模板中都需要东西,但这些是我在每个页面上使用的变量,所以我觉得很恶心在每个视图函数中做一些事情来完成这个。一般来说,我不喜欢编写另一个视图函数需要重复。但是,我已经发现了如何达到预期的结果,并将其发布在另一个回复中以供其他人使用。 :) 长话短说,请改用中间件。
    【解决方案2】:

    我发现了一个有帮助的解决方案,至少对我来说是这样。

    因此,期望的结果是生成代码,该代码在每次页面加载时运行,结果在所有视图和所有模板中都可用。

    Daniel Roseman 在另一个答案中很好地解释了为什么在 Django 版本 1.7 和 1.8 之间停止使用简单的上下文处理器的技术原因,所以我不会在这里讨论它们。

    长话短说,诀窍是使用 middleware 而不是 contextprocessor,然后让 contextprocessor 从中间件。

    考虑原题中的代码,与新代码对比:

    上下文处理器:

    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,
            }
    

    “全局”变量挂在名为 extravars 的任意命名字典中的请求对象上。请注意,虽然我们的“全局”变量条目仍称为 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
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-07-17
      • 2020-05-17
      • 2018-06-14
      • 2014-08-11
      • 1970-01-01
      • 2021-09-07
      相关资源
      最近更新 更多