【问题标题】:Django templatetag scope forcing me to do extra queriesDjango templatetag 范围迫使我做额外的查询
【发布时间】:2011-01-05 19:56:03
【问题描述】:

问题是,如果我将模板标签调用到块中 它用通常的 context[varname]=something 填充了我一个变量, 然后如果我需要将该变量放入另一个块中,我必须调用 再次模板标签。这对我来说意味着额外的数据库查询,这真的是 我试图避免的事情。

这个模板标签在一个基础模板中被调用,它被扩展 许多其他模板,所以我不能只更改所有视图以通过 根据上下文,这没有任何意义(WET 原则?)

即使是上下文处理器也不好,因为我不想 为站点中呈现的每个页面调用它,即使是那些不基于的页面 在那个模板上。

我正在考虑编写一个模板标签,它会使用 内部上下文结构将变量放在全局上下文中, 但这样做我会感到内疚。

你会如何解决这个问题?

【问题讨论】:

    标签: django scope templatetags


    【解决方案1】:

    你说,“这个模板标签是在一个基础模板中调用的,该模板由许多其他模板扩展。”

    问题是:这个标签是从命名块中调用的吗?如果是,那么您有几个潜在的问题。

    1. {% block %} 将一个新的 dict 压入 Context 堆栈,并在它到达匹配的 `{% endblock %}' 时将其弹出。这意味着在块中创建的任何上下文值在块退出时基本上已经超出了范围。

    2. 如果此块被其他扩展基本模板的模板覆盖,则该值可能根本不可用,除非您执行{{block.super}},即使那样我也不确定该值是否可用到模板进行扩展。

    如果标签 不是{% block %} 中调用,那么上下文值应该可用于其后面的所有代码,无论是在基本模板中、任何包含的模板中还是(I想想)任何扩展模板。

    在这种情况下,构建一组仔细的测试可能会节省您的时间和精力。

    或者,如果您总是访问此值,则可以将其放入 context processor 中,以保证其可用性。

    cmets 更新:好的,是时候引入大炮了! Django 模板中最烦人、长期存在的错误之一是作为顶级上下文值的可调用对象(即函数)(与作为 dict-values/methods of 上下文值的函数相反) 没有被调用!这张票已经超过 2 年了,大约需要 10 行代码来修复。我们有几个重量级的 DB 调用,我们只希望在模板缓存已过期时发生 。所以我们 a) MonkeyPatched 模板 _resolve_lookup() 代码以修复可调用问题,然后 b) curry 函数以具有所有必要的参数如果需要,因为你不能将参数传递给函数模板“语言”。

    【讨论】:

    • 如果他在其中调用标签的模板也扩展了另一个模板,那么在块外调用上下文修改模板标签实际上对任何东西的影响为零。我猜这就是他的情况。
    • 是的,在块外调用它是行不通的。这是因为我正在扩展另一个模板。
    【解决方案2】:

    我认为您已经准确地描述了这种情况下的局限性。最可维护的解决方案可能会涉及到模板继承链的一些重组,尽管在不了解细节的情况下很难说。您能否在继承层次结构中引入一个新模板,可能在金字塔顶部附近的某个地方,但它仅由需要此数据的模板继承,并且单个块包含您需要此数据的整个区域?然后可以将该大块细分为继承模板将覆盖的较小块。如果您在该块的开头调用模板标签,则其中的所有块(包括继承模板中的块)都可以访问数据。

    更新:如果没有看到您的模板,我不能说太多,但是在继承链中间引入新模板很少涉及“更改所有模板”,在合理的继承结构中,通常可以通过更改来完成仅适用于一两个其他模板。而且我认为我的建议实际上不是黑客,它只是更好的设计。如果您在网站的某些部分而不是其他部分需要某条数据,应该有一个特定的单一模板,您可以指向并说“这个模板代表了该部分所在的逻辑层引入了数据,并包含需要该数据的站点部分。”

    【讨论】:

    • 谢谢你,卡尔,不幸的是,这两个块是 1) 左侧边栏,2) 右侧边栏。考虑到模板的当前布局,将它们放在一个公共块下将非常具有挑战性,而且我不喜欢仅仅因为我无法在两个块中读取一个变量而不得不更改所有模板,我认为这是一种 hack。感谢您的建议!
    【解决方案3】:

    您只是想减少数据库查询的数量,还是在寻找聪明的解决方案?

    如果是前者,我肯定会使用缓存。在您的情况下,片段缓存会起作用吗?如果没有,也许您可​​以将缓存放在模板标签代码中(假设它不是您使用的 Django 自己的模板标签之一)?

    【讨论】:

    • 在这里缓存看起来就像用机关枪射蝴蝶一样!
    【解决方案4】:

    刚刚从Liviu, Agile Bear 发现了这个技巧(所有功劳归他所有)

    而不是做

    context['some_var']='some value'
    

    context.dicts[0]['some_var']='some value'
    

    可能不是按部就班的编码实践,但效果很好

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-10-07
      • 2014-12-17
      • 2012-04-16
      • 2015-01-05
      • 2015-07-20
      • 2016-02-21
      • 1970-01-01
      相关资源
      最近更新 更多