2011-05-12 76 views
5

我爲我的CSS/Javascript設置了far-future expires頭文件,以便瀏覽器在獲取緩存後不再請求文件。我也有一個簡單的版本機制,如果文件改變,客戶端就會知道。使用Django進行靜態文件版本控制

基本上我有一個模板標籤,我這樣做

<script type="text/javascript" src="{{ MEDIA_URL }}{% versioned "javascript/c/c.js" %}"></script>

這將成爲

<script type="text/javascript" src="http://x.com/media/javascript/c/c.min.js?123456"></script>

模板標記將打開一個文件javascript/c/c.js.v,在該文件中查找版本號並將其附加到查詢字符串。該版本由shell腳本(現在手動運行,可能會添加預先提交掛鉤)生成,該腳本檢查文件是否已更改(使用git diff)。

這都是做工精細,除了:

我想要實現同一種版本的圖像,以及。但圖像可以從CSS引用 - 這是一個靜態文件(由nginx提供) - 因此沒有模板標籤。

什麼是文件版本控制的更好方法?

或者,我正在考慮用返回響應之前更改所有鏈接的中間件替換模板標記。這比模板標籤要好,可能會被誤刪。但仍然不能解決CSS引用的圖像問題。

此外,我知道將版本作爲查詢字符串的一部分可能會導致某些代理不緩存文件,從而導致出現問題 - 因此我考慮將版本部分作爲文件名 - 例如javascript/c/c.123456.js

注意:看起來像使用Django無法解決這個問題(很明顯 - 因爲我甚至沒有通過Django服務於CSS)。但必須有一個解決方案,可能涉及一些nginx技巧。

+1

回答@paluh下面是你最好的選擇。在Django中從文件中提取文件的時間並不會節省您直接檢查Django中文件的時間。它只是增加了一層額外的複雜性和另一個失敗點(shell腳本作爲cron作業運行)。 – 2011-05-12 15:18:37

+0

的確,mtimes可以讓我的設置更簡單 - 減少運行腳本和依賴git的需要。我通常不信任mtimes(當它複製到另一個文件系統或備份時,它們可能會發生變化,或者......) - 但在這種情況下,我認爲它並不重要,因爲源代碼樹總是在同一個地方。另外,如果由於某種原因m次真的發生變化,那麼發生的最糟糕的情況是緩存失效。不可怕。 – ibz 2011-05-13 02:11:14

+1

如何處理CSS文件的預部署步驟?我做了類似的事情,但沒有與Django做類似的事。這是一些自定義的PHP。 – 2011-05-15 11:24:37

回答

0

將向我的預先提交腳本添加另一個步驟來將所有直接鏈接替換爲鏈接t o最小化CSS中的版本化文件。

似乎沒有更好的方法來做到這一點。如果您想到任何問題,請告訴我,我會考慮將其標記爲已接受的答案。

感謝您的意見!

0

我們正在利用這個簡單的templatetag基於文件的修改時間,生成版本號:

import os 
import posixpath 
import stat 
import urllib 

from django import template 
from django.conf import settings 
from django.contrib.staticfiles import finders 

register = template.Library() 

@register.simple_tag 
def staticfile(path): 
    normalized_path = posixpath.normpath(urllib.unquote(path)).lstrip('/') 
    absolute_path = finders.find(normalized_path) 
    if not absolute_path and getattr(settings, 'STATIC_ROOT', None): 
     absolute_path = os.path.join(settings.STATIC_ROOT, path) 
    if absolute_path: 
     return '%s%s?v=%s' % (settings.STATIC_URL, path, os.stat(absolute_path)[stat.ST_MTIME]) 
    return path 

對於預1.3 Django的有這個標記的更簡單的版本:

@register.simple_tag 
def staticfile(path): 
    file_path = os.path.join(settings.MEDIA_ROOT, path) 
    url = '%s%s?v=%s' % (settings.MEDIA_URL, path, os.stat(file_path)[stat.ST_MTIME]) 
    return url 

用法:

<link rel="stylesheet" href="{% staticfile "css/style.css" %}" type="text/css" media="screen" /> 
+0

與我的原始解決方案有相同的問題。無法處理在CSS內引用的圖像(除非我通過Django提供CSS)。希望我能找到更好的方法。 – ibz 2011-05-13 02:04:40

+0

是的,如何最好地處理CSS文件中的圖像的問題是一個常年。你不能利用'MEDIA_URL',就像你的情況一樣,你不能添加查詢字符串等來實現緩存。也就是說,除非你通過Django提供文件,但是這是一個或多個其他蠕蟲。 – 2011-05-13 16:14:06

+0

但是,由於您的問題是對修改後的文件無效的緩存之一,因此可以推定,CSS引用的圖像在修改時會對應於CSS文件中的編輯。這不一定總是如此,但可以想象,在這裏自我管理緩存失效不應該太困難。 – 2011-05-13 16:16:57

0

我認爲一個簡單的解決方案可能是:

  1. 寫你的CSS文件作爲Django模板。
  2. 編寫一個Django命令來呈現您的css模板(並將它們存儲在某處可訪問)
  3. 在您的部署腳本中調用此命令。
1

樣式表資產

對於你的樣式表中引用的資產,你好得多使用薩斯&羅盤。 Compass有一個mixin,它會自動將版本查詢參數添加到樣式表中引用的靜態資產的末尾。版本號僅在您重新生成樣式表時發生變化(在本地開發時,這與compass watch並不重要)。

模板資產

對於其他文件,我真的使用某種用於重寫一個Python模塊,其唯一目的是遏制當前版本的上拉後掛機。

/var/www/aweso.me/ 
    ./files/ 
    ./private-files/ 
    ./static/ 
    ./project/ 
     ./manage.py 
     ./fabfile.py 
     ./.gitignore 
     ./base/ 
      ./__init__.py 
      ./wsgi.py 
      ./settings/ 
       ./__init__.py 
       ./modules 
        ./__init__.py 
        ./users.py 
        ./email.py 
        ./beta.py 
        ./redis.py 
        ./haystack.py 
       ./version.py 
       ./default.py 
       ./local.py 
       ./live.py 

您的文章拉鉤將創建:

/var/www/aweso.me/project/base/settings/version.py 

這將包含最新的(先前)git的承諾哈希:你settings.live

__version__ = "0763j34bf" 

然後用一個簡單的from .version import __version__ as ApplicationVersion,您的模板標籤可以簡單地使用from settings import ApplicationVersion將該查詢參數寫爲緩存中斷器。