2010-05-25 43 views
10

我正在尝试编写一套模板标签,允许您从模板文件本身轻松指定js和css文件。一些沿着{% requires global.css %}的行,以及稍后的请求{% get_required_css %}Django templatetag“处理顺序”

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

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

所以,我需要收集所有的文件到一个包每个请求context字典显然是这个地方,但不幸的是,调用/ init不能访问上下文变量。

这是有道理的吗?任何人都可以看到解决这个问题的方法(而不是诉诸全球性的request对象)?

另一种将它们存储在本地字典中的可能性,但它们仍然需要以某种方式与请求绑定...可能是某种{% start_requires %}标记?但我不知道如何做这件事。

+0

在简单检查'中间件'的能力后,我正在考虑使用它来插入生成的html。问题在于让任何各种静态压缩应用程序无缝工作更加困难。 – 2010-05-26 17:01:51

+0

如果任何人有兴趣,我有一个应用程序在github上,这是一个相当不雅的解决方案,这个特定的问题 - http://github.com/pappy74/django-requires_js_css。这与Jack的答案有点类似,但是打包成一个漂亮,整洁的应用程序。 – 2010-09-07 22:15:55

回答

2

我想出了一个更适合您的需求的方法。它在服务器上会有更多的负载,但适当的缓存可以帮助减轻大部分负担。下面我已经概述了一种方式,如果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是这样工作的,但我现在不想看到它。

+0

这就是我最初实施的方式,但问题在于订购。有了这个,你必须*确保在'get_required'被解析之前解析所有的'require'。当一个包含模板标签本身“需要”一个css文件时,这一点尤其明显。 如果您实际上可以在__init__期间添加文件,那么您可以解决该问题。 – 2010-05-26 17:00:12

+0

我添加了另一种可能的方式来完成这不依赖于内部排序。这有点复杂,但它应该工作。 – 2010-06-07 20:01:39