2010-05-25 41 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