【问题标题】:Django templatetag "order of processing"Django模板标签“处理顺序”
【发布时间】:2010-05-25 23:57:10
【问题描述】:

我正在尝试编写一组模板标签,让您可以轻松地从模板文件本身中指定 js 和 css 文件。类似于{% requires global.css %} 的内容,以及稍后在请求中的{% get_required_css %}

这主要是我的工作,但有几个问题。我们将从“时间”问题开始。

每个模板标签由两个步骤组成,调用/初始化和渲染。每个调用/初始化都发生在调用任何渲染过程之前。为了保证所有文件都在{% get_required_css %} 被渲染之前排队,我需要自己在调用/初始化过程中建立我的所需文件列表。

所以,我需要每个请求将所有文件收集到一个包中。 context dict 显然是这个地方,但不幸的是, call/init 无权访问上下文变量。

这有意义吗?任何人都可以解决这个问题(无需求助于 hack-y 全局 request 对象)?

另一种将这些存储在本地字典中的可能性,但它们仍然需要以某种方式绑定到请求......可能是某种{% start_requires %} 标签?但我也不知道如何让它发挥作用。

【问题讨论】:

  • 在简要检查了“中间件”的功能之后,我正在考虑使用它来插入生成的 html。这样做的问题是,让各种静态压缩应用程序中的任何一个无缝工作变得更加困难。
  • 如果有人感兴趣,我在 github 上有一个应用程序,它是解决这个特定问题的一个相当不优雅的解决方案 - github.com/pappy74/django-requires_js_css。这有点类似于 Jack 在下面的回答,但打包成一个漂亮、整洁的应用程序。

标签: django django-templates


【解决方案1】:

我想出了一种更适合您需求的方法。它将在服务器上增加一点负载,但适当的缓存可以帮助减轻大部分负载。下面我概述了一种方法,如果每个路径的 CSS 包含相同,则该方法应该有效。您需要创建一个视图来包含所有这些文件,但您实际上可以使用此方法优化您的 CSS,每个页面只需调用一次 CSS。

import md5
class LoadCss(template.Node):
    def __init__(self, tag_name, css):
        self.css = css
        self.tag_name = tag_name
    def render(self, context):
        request = context['request']
        md5key = md5.new(request.path).hexdigest()
        if md5key not in request.session:
            request.session[md5key] = list()
        ## This assumes that this method is being called in the correct output order.
        request.session[md5key].append(self.css)
        return '<!-- Require %s -->' % self.css
def do_load_css(parser, token):
    tag_name, css = token.split_contents()
    return LoadCss(tag_name, key)
register.tag('requires', do_load_css)

class IncludeCss(template.Node):
    def __init__(self, tag_name):
        self.tag_name = tag_name
    def render(self, context):
        request = context['request']
        md5key = md5.new(request.path).hexdigest()
        return '<link rel="stylesheet" href="/path/to/css/view/%s">' % md5key
def do_include_css(parser, token):
    return IncludeCss(token)
register.tag('get_required_css', do_include_css)

views.py:

from django.conf import settings
from django.views.decorators.cache import cache_page
import os

@cache_page(60 * 15) ## 15 Minute cache.
def css_view(request, md5key):
    css_requires = request.session.get(md5key, list())
    output = list()
    for css in css_requires:
        fname = os.path.join(settings.MEDIA_ROOT, 'css', css) ## Assumes MEDIA_ROOT/css/ is where the CSS files are.
        f = open(fname, 'r')
        output.append(f.read())
    HttpResponse(''.join(output), mimetype="text/css")

这允许您将 CSS 信息存储在上下文中,然后存储在会话中,并提供来自视图的输出(通过缓存使其更快)。当然,这会产生更多的服务器开销。

如果您需要改变的不仅仅是路径上的 CSS,那么您可以简单地修改 md5 行以满足您的需要。您可以访问整个请求对象和上下文,因此几乎所有内容都应该在其中。

注意:在第二次审核中,如果浏览器在填充会话之前获取 CSS,这可能会导致竞争条件。我不相信 Django 是这样工作的,但我现在不想查找它。

【讨论】:

  • 这就是我最初实现它的方式,但问题在于订购。这样,您必须确保在解析“get_required”之前解析所有“requires”。当包含模板标签本身“需要”一个 css 文件时,这一点尤其明显。如果您实际上可以在 init 期间添加文件,那么您就可以解决这个问题。
  • 我添加了另一种可能的方式来实现这一点,它不依赖于内部排序。这有点令人费解,但它应该可以工作。
猜你喜欢
  • 2020-04-12
  • 2011-10-06
  • 2013-06-18
  • 2021-02-18
  • 1970-01-01
  • 2011-02-09
  • 2016-06-09
  • 1970-01-01
  • 2012-10-31
相关资源
最近更新 更多