處理靜態(tài)文件,尤其是在開發(fā)時(shí)馅精,是一件很頭疼的事情严嗜。在這篇文章中,我們將會(huì)討論一些設(shè)置洲敢,目錄結(jié)構(gòu)和他們之間的相互影響漫玄。設(shè)置好 DEBUG = True 然后我們開始開發(fā)吧。
我們將會(huì)創(chuàng)建一個(gè) Django 項(xiàng)目压彭,這樣可以讓我們更好的了解我們討論的這些這些文件在什么目錄中睦优。我們將會(huì)使用 Django1.4,這些都也能在 Django1.3 中工作壮不,因?yàn)闆]有在 Django1.2 下進(jìn)行測試汗盘,所以對1.2版本下是否有問題不是很清楚。
創(chuàng)建項(xiàng)目
如果你不需要這部分询一,可以直接跳到處理靜態(tài)文件這一節(jié)隐孽。只要保證你看過了這節(jié)底部的目錄結(jié)構(gòu)并對其有了解,這樣你閱讀后面的內(nèi)容會(huì)更舒服健蕊。
我們將在命名為 staticvirt 的虛擬環(huán)境中做所有事情菱阵,所以我們需要命令
~$ virtualenv staticvirt
接下來我們需要在這個(gè)虛擬環(huán)境中創(chuàng)建一個(gè) Django 項(xiàng)目。確保你進(jìn)入了虛擬環(huán)境的目錄缩功,并且激活了該環(huán)境晴及。同時(shí)也要保證在這個(gè)虛擬環(huán)境中安裝了 Django,因?yàn)槲覀儾幌胛廴鞠到y(tǒng)的包環(huán)境嫡锌。
~$ cd staticvirt/
~/staticvirt$ source bin/activate
(staticvirt)~/staticvirt$ pip install django==1.4
創(chuàng)建一個(gè) Django 項(xiàng)目抗俄。
django-admin.py startproject test_project
進(jìn)入項(xiàng)目所在系統(tǒng)脆丁。
cd test_project/
讓我們看看現(xiàn)在的目錄結(jié)構(gòu)。
(staticvirt)~/staticvirt/test_project$ tree
.
|-- manage.py
*-- test_project |-- __init__.py
|-- settings.py
|-- urls.py
*-- wsgi.py 1 directory, 5 files
現(xiàn)在查看下 test_project/settings.py 的內(nèi)容动雹。搜索所有包括 static 的行槽卫,下面我列出所有包括 static 的行。
STATIC_ROOT = ''
STATIC_URL = '/static/'
STATICFILES_DIRS = ()
STATICFILES_FINDERS = ( 'django.contrib.staticfiles.finders.FileSystemFinder',
'django.contrib.staticfiles.finders.AppDirectoriesFinder',
'django.contrib.staticfiles.finders.DefaultStorageFinder',
)
INSTALLED_APPS = (
....
....
'django.contrib.staticfiles',
....
)
然而胰蝠,這里所看到的都是 Django 提供的默認(rèn)設(shè)置歼培,我們沒有做任何的設(shè)置。
我們創(chuàng)建一個(gè) app茸塞,我們將會(huì)在里面創(chuàng)建一個(gè) template躲庄,然后會(huì)寫一些靜態(tài)文件,比如樣式文件钾虐,然后在模板中使用這個(gè)樣式文件噪窘。
python manage.py startapp some_app
將 some_app 添加進(jìn) test_project/settings.py 中的INSTALLED_APPS。
我們需要一個(gè) urls.py 文件來為 some_app 定制路由效扫。項(xiàng)目的 urls.py應(yīng)該包括 some_app 中的 urls.py倔监。所以,我們在 test_project/urls.py 中添加以下一行菌仁。
url(r'^some_app/', include('some_app.urls'))
在 some_app 的 urls.py 文件中添加以下內(nèi)容浩习。
url(r'^home$', direct_to_template, {"template": "some_app/home.html"})
創(chuàng)建一個(gè)名為 templates 的目錄,然后將其添加進(jìn)TEMPLATE_DIRS济丘。我在 manage.py 同級目錄下創(chuàng)建 templates谱秽。
將 templates 添加進(jìn) TEMPLATE_DIRS 我需要做以下設(shè)定,如果你也使用跟我一樣的目錄結(jié)構(gòu)摹迷,你也需要同樣的設(shè)定疟赊。
PROJECT_DIR = os.path.dirname(__file__)
TEMPLATE_DIRS = (
os.path.join(PROJECT_DIR, '../templates'),
)
我們需要為 some_app 創(chuàng)建 home.html 文件,然后你需要進(jìn)入templates 目錄峡碉。所以創(chuàng)建 templates/come_app/home.html听绳,在文件中寫入以下內(nèi)容。
<html>
<body>
<h1>This is home for some_app</h1>
</body>
</html>
現(xiàn)在查看一下項(xiàng)目的目錄結(jié)構(gòu)异赫,便于消除一些不清楚的地方。
~/staticvirt/test_project$ tree -I *.pyc
.
|-- manage.py
|-- some_app
| |-- __init__.py
| |-- models.py
| |-- tests.py
| |-- urls.py
| *-- views.py
|-- templates
| *-- some_app
| *-- home.html
*-- test_project
|-- __init__.py
|-- settings.py
|-- urls.py
*-- wsgi.py
4 directories, 11 files
我們不想想是 .pyc 文件头岔,所以將他們做了過濾塔拳。
啟動(dòng)服務(wù)。請確保你做好了你的數(shù)據(jù)庫設(shè)定峡竣。
(staticvirt)~/staticvirt/test_project$ python manage.py runserver
在瀏覽器中打開 http://127.0.0.1:8000/some_app/home靠抑。從現(xiàn)在開始,我們稱這個(gè)頁面為 some_app 的 home适掰,你應(yīng)該能夠看到你剛寫下的 html 的內(nèi)容颂碧。
處理靜態(tài)文件
讓我們編輯下 some_app 中的 home.html 文件荠列,并且在其中添加樣式,現(xiàn)在還不存在任何樣式文件载城,我們將在編輯好 home.html 中的代碼后添加肌似。
<html>
<head>
<link href="{{STATIC_URL}}styles.css" rel="stylesheet" type="text/css">
</head>
<body>
<h1>This is home for some_app</h1>
</body>
</html>
刷新 some_app 的 home 頁面。你將不會(huì)看到任何變化诉瓦,因?yàn)槲覀冞€沒有創(chuàng)建樣式文件川队。
同樣,訪問 http://127.0.0.1/static/style.css睬澡,你將會(huì)看到一個(gè)404頁面固额。
現(xiàn)在開始創(chuàng)建樣式文件。因?yàn)槲覀兿胍?some_app 的 template 中使用這個(gè)樣式煞聪,所以我們將在 some_app 的 static/ 的子目錄中創(chuàng)建斗躏。所以創(chuàng)建 some_app/static/style.css,添加以下內(nèi)容昔脯。
body
{ background-color: red; }
再刷新 some_app 的 home 頁面啄糙,你將會(huì)看到頁面背景變成了紅色。同樣栅干,訪問 http://127.0.0.1/static/style.css迈套,你看到的不再是404頁面,而是樣式文件的內(nèi)容碱鳞。如果你看到這些變化桑李,請確認(rèn)你將
some_app 添加進(jìn)了 INSTALLED_APPS,并且重啟了服務(wù)窿给。
需要注意的地方
我們沒有對 Django 的默認(rèn)靜態(tài)文件設(shè)置做任何改變贵白。我們完全保留了 Django 的 settings.py 中關(guān)于靜態(tài)文件的設(shè)置。
在開發(fā)中崩泡,你不需要在 urls.py 中關(guān)于靜態(tài)文件做任何改變禁荒,不需要添加 staticfiles_urlpatterns(),我經(jīng)常對此感到疑惑角撞。
在開發(fā)中呛伴,你不需要執(zhí)行 python manage.py collectstatic。
內(nèi)部是怎么工作的
首先谒所,檢索 settings.py 中所有關(guān)于靜態(tài)文件的設(shè)置热康。
他們是 STATIC_URL, STATIC_ROOT, STATICFILES_FINDERS, STATICFILES_DIRS。
同樣我們已經(jīng)將 'django.contrib.staticfiles' 添加進(jìn)了INSTALLED_APPS劣领。
現(xiàn)在先不管 STATIC_ROOT 和 STATICFILES_DIRS姐军。即使你將他們注釋或者刪除,你的項(xiàng)目依然能夠像現(xiàn)在一樣工作。
我們需要將 'django.contrib.staticfiles' 添加進(jìn) INSTALLED_APPS奕锌,如果我們想要使用 Django 默認(rèn)的靜態(tài)文件處理服務(wù)著觉。
所謂的 Django 默認(rèn)的靜態(tài)文件處理服務(wù)就相當(dāng)于需要使用 Django提供的 python manage.py runserver。
Django 默認(rèn)會(huì)在 STATIC_URL 下處理靜態(tài)文件惊暴。注意STATIC_URL 已經(jīng)設(shè)置為 '/static/' 饼丘。這就是為什么我們獲取到了我們的靜態(tài)文件,舉個(gè)例子缴守,樣式文件在這個(gè) url 下http://127.0.0.1:8000/static/styles.css葬毫。如果你訪問http://127.0.0.1:8000/static_changed/styles.css,你將會(huì)得到一個(gè)404頁面屡穗。如果你想要在http://127.0.0.1:8000/static_changed/styles.css提供贴捡,需要設(shè)置STATIC_URL = '/static_changed/'。現(xiàn)在動(dòng)手試試吧村砂。這只是為了舉例說明 STATIC_URL 的用處把篓,現(xiàn)在都改回默認(rèn)設(shè)置袒餐,即STATIC_URL = '/static/'拴魄。
下一個(gè)問題是路星,Django 是怎么知道從哪里去讀取靜態(tài)文件的,或者說怎么知道去哪里找到靜態(tài)文件呢评腺?這就
STATICFILES_FINDERS 的作用了帘瞭。在 STATICFILES_FINDERS 中我們有兩條記錄:
'django.contrib.staticfiles.finders.FileSystemFinder', 'django.contrib.staticfiles.finders.AppDirectoriesFinder'
現(xiàn)在你可以先不管 FileSystemFinder,如果你愿意蒿讥,你可以先注釋掉這一行蝶念。
AppDirectoriesFinder 告訴 Django 從 INSTALLED_APPS
中每一個(gè) app下的 static/ 子目錄下去尋找靜態(tài)文件。記住芋绸,我們是將style.css 放在了 some_app
中 static/ 子目錄下媒殉,這就是為什么 Django 能夠找到它,并且進(jìn)行正確的處理摔敛。如果你將 'static/' 子目錄修改為其他名字廷蓉,你的靜態(tài)文件就不能被正確處理了。動(dòng)手試一試吧马昙。注釋掉 AppDirectoriesFinder 這一行桃犬,然后訪問 http://127.0.0.1:8000/static/styles.css,現(xiàn)在樣式文件不能被正確地處理了行楞。好攒暇,嘗試過后去掉注釋。
現(xiàn)在敢伸,我們知道了 STATIC_URL 和 STATICFILES_FINDERS
的作用。我們現(xiàn)在仍然不需要用到 STATIC__ROOT 和STATICFILES_DIRS恒削。
為了了解一些其他的事情關(guān)于靜態(tài)文件的處理池颈,我們需要另一個(gè)app尾序。
創(chuàng)建一個(gè)。
python manage.py startapp other_app
修改項(xiàng)目的 urls.py躯砰,將 other_app 包括進(jìn)去∶勘遥現(xiàn)在項(xiàng)目的 urls.py 包括兩行。
url(r'^some_app/', include('some_app.urls')),
url(r'^other_app/', include('other_app.urls')),
我們需要在 other_app 的 urls.py 中添加幾行琢歇,比如兰怠,在other_app/urls.py中:
url(r'^home$', direct_to_template, {"template": "other_app/home.html"})
現(xiàn)在在 templates 目錄下創(chuàng)建 other_app/home.html。
<html>
<body>
<h1>This is home for other_app</h1>
</body>
</html>
查看一下現(xiàn)在的目錄結(jié)構(gòu)李茫。
~/staticvirt/test_project$ tree -I *.pyc
.
|-- manage.py
|-- other_app
| |-- __init__.py
| |-- models.py
| |-- tests.py
| |-- urls.py
| *-- views.py
|-- some_app
| |-- __init__.py
| |-- models.py
| |-- static
| | *-- styles.css
| |-- tests.py
| |-- urls.py
| *-- views.py
|-- templates
| |-- other_app
| | *-- home.html
| *-- some_app
| *-- home.html
*-- test_project
|-- __init__.py
|-- settings.py
|-- urls.py
*-- wsgi.py
將 other_app 添加進(jìn) INSTALLED_APPS揭保。
現(xiàn)在訪問 url:http://127.0.0.1:8000/other_app/home。
為 other_app 的 home 頁面添加樣式魄宏。假設(shè)我們想讓它的背景顏色為藍(lán)色秸侣,我們創(chuàng)建 other_app/static/other_style.css
body{ background-color: blue; }
將樣式文件添加進(jìn) other_app 的 home 頁面的模板中,將templates/other_app/home.html
改為:
<html>
<head>
<link href="{{STATIC_URL}}other_style.css" rel="stylesheet" type="text/css">
</head>
<body>
<h1>This is home for other_app</h1>
</body>
</html>
刷新 http://127.0.0.1:8000/other_app/home宠互,你將會(huì)看到藍(lán)色背景味榛。你也許需要重啟服務(wù)才能看到變化。同樣予跌,我們能夠在http://127.0.0.1:8000/static/other_style.css 中看到樣式文件的內(nèi)容搏色。
同時(shí),訪問 http://127.0.0.1:8000/some_app/home券册,驗(yàn)證下some_app 的 home 頁面依然是紅色背景频轿。
這里發(fā)生了什么
當(dāng)我們發(fā)起一個(gè) /static/other_style.css 的請求,Django 知道STATIC_URL 設(shè)置為 '/static/' 汁掠,這跟 url 提供的第一個(gè)部分相匹配略吨,因此它推斷我們想要將其作為靜態(tài)文件處理,所以它進(jìn)入所有 app 的 static/ 子目錄中進(jìn)行查找考阱,因?yàn)?STATICFILES_FINDERS 包含了 'django.contrib.staticfiles.finders.AppDirectoriesFinder'翠忠。當(dāng)它在other_app 中的 static/ 目錄下找到一個(gè)名為 other_style.css 的文件,就對它進(jìn)行處理乞榨。
然而秽之,這帶來了另一個(gè)問題,你一定注意到了我們將 other_app
中的樣式文件命名為 other_style.css吃既。如果我們想要它的名稱也為style.css 會(huì)發(fā)生什么呢考榨?試試看。
mv other_app/static/other_style.css other_app/static/styles.css
同時(shí)鹦倚,我們需要修改 other_app 的 home 文件來引入這個(gè)樣式文件河质。我們必須做這個(gè),因?yàn)槲覀儗?other_style.css
改名為了 style.css。other_app 的 home 文件修改如下:
<html>
<head>
<link href="{{STATIC_URL}}styles.css" rel="stylesheet" type="text/css">
</head>
<body>
<h1>This is home for other_app</h1>
</body>
</html>
現(xiàn)在查看兩個(gè)我們創(chuàng)建的頁面掀鹅。
http://127.0.0.1:8000/some_app/home
http://127.0.0.1:8000/other_app/home
你會(huì)發(fā)現(xiàn)現(xiàn)在兩個(gè)頁面的背景都變成了紅色散休。這依賴于INSTALLED_APPS 中 app 的排列順序。如果 some_app 在other_app 的前面乐尊,兩個(gè)頁面都會(huì)是紅色背景戚丸。如果 other_app
在 some_app 的前面,那么兩個(gè)頁面背景都是藍(lán)色扔嵌。在我的設(shè)置中限府,some_app 在 other_app 之前,所以背景都是紅色的痢缎。
為什么這會(huì)發(fā)生
兩個(gè)頁面都想引用一個(gè)名為 style.css 的靜態(tài)文件胁勺。Django 嘗試在INSTALLED_APPS 中列出的所有 app 中的 static/ 子目錄下尋找這個(gè)文件。一旦它在 some_app 的 static/ 子目錄中找到了牺弄,就會(huì)進(jìn)行處理并且不再繼續(xù)在 other_app 中進(jìn)行尋找姻几。因此,some_app
中 static/ 子目錄下將背景設(shè)置為紅色势告,那么兩個(gè)頁面都被設(shè)置為紅色背景了蛇捌。
怎么避免
那么,如果我們想在兩個(gè) app 中樣式文件都叫做 style.css 怎么做咱台?這時(shí)候络拌,我們需要在沒一個(gè) app 下的 static/ 目錄下增加一層目錄,將其命名為各自 app 的名稱回溺。像下面這么做:
mkdir some_app/static/some_app
mv some_app/static/styles.css some_app/static/some_app
mkdir other_app/static/other_app
mv other_app/static/styles.css other_app/static/other_app/
我們在每一個(gè) app 下的 static/ 子目錄下創(chuàng)建一個(gè)與各自 app 相同的目錄春贸。然后將樣式文件移到這個(gè)目錄下。
同理遗遵,也需要修改各自的模板文件萍恕。
修改 templates/some_app/home.html 中的 stylesheet 路徑,新的內(nèi)容如下:
<html>
<head>
<link href="{{STATIC_URL}}some_app/styles.css" rel="stylesheet" type="text/css">
</head>
<body>
<h1>This is home for some_app</h1>
</body>
</html>
對 templates/other_app/home.html 做相似的改動(dòng)车要。
<html>
<head>
<link href="{{STATIC_URL}}other_app/styles.css" rel="stylesheet" type="text/css">
</head>
<body>
<h1>This is home for other_app</h1>
</body>
</html>
現(xiàn)在再次查看兩個(gè)頁面允粤。
http://127.0.0.1:8000/some_app/home
http://127.0.0.1:8000/other_app/home
你將會(huì)發(fā)現(xiàn)一個(gè)背景是紅色,另一個(gè)是藍(lán)色翼岁。
這里發(fā)生了什么
some_app 的模板需要引用http://127.0.0.1:8000/static/some_app/styles.css类垫。
Django 發(fā)現(xiàn)這個(gè) url 以 '/static/' 開頭,這跟 STATIC_URL
匹配琅坡,推測這需要處理靜態(tài)文件 some_app/style.css悉患。它開始在所有 app 的 static/ 子目錄中尋找文件 some_app/style.css。
它最終在 some_app 的 static/ 子目錄中找到了它榆俺,并進(jìn)行處理售躁。
other_app 的模板需要引用http://127.0.0.1:8000/static/other_app/styles.css坞淮。
Django 開始在所有 app 的 static/ 子目錄中尋找文件other_app/style.css。
它最終在 other_app 的 static/ 子目錄中找到了它陪捷,并進(jìn)行處理碾盐。
希望你現(xiàn)在對于 STATIC_URL, STATICFILES_FINDERS 和靜態(tài)文件是怎么處理的更加清楚了。
關(guān)于 STATICFILES_DIRS
到現(xiàn)在我們假定我們在 some_app 和 other_app是需要各自獨(dú)立的靜態(tài)文件揩局,所以我們?yōu)樗麄儗懥瞬煌瑯邮轿募?/p>
假定我們項(xiàng)目中一些樣式需要保持一致,沒一個(gè) app 都沒有特殊掀虎。這也的話凌盯,我們不需要將這些樣式文件放進(jìn)任何一個(gè) app 的 static/ 子目錄中。我們在 manage.py 的同級目錄中創(chuàng)建一個(gè)目錄烹玉,然后將項(xiàng)目共同的靜態(tài)資源放在這個(gè)目錄中驰怎。
然我們看看是怎么做的。
在 manage.py 的同一級下創(chuàng)建一個(gè)名為 project_static 的目錄二打。
mkdir project_static
創(chuàng)建一個(gè)名為 base.css 的文件县忌,放進(jìn)去。
touch project_static/base.css
編輯這個(gè)頁面继效,包含以下內(nèi)容:
h1
{
font-style: italic;
}
我們想讓項(xiàng)目中所有h1標(biāo)簽中的內(nèi)容斜體顯示症杏。
Django 現(xiàn)在還不知道這個(gè)文件,也不知道怎么進(jìn)行處理瑞信。要讓Django 知道它厉颤,需要將包含這個(gè)文件的目錄添加進(jìn)STATICFILES_DIRS。所以編輯 test_project/settings.py
,將需要的目錄添加進(jìn) STATICFILES_DIRS凡简。
STATICFILES_DIRS = (
os.path.join(PROJECT_DIR, '../project_static'),
)
試著訪問http://127.0.0.1:8000/static/base.css
逼友,你應(yīng)該能看到剛才寫的樣式。請確保在STATICFILES_FINDERS
中你設(shè)置了:
'django.contrib.staticfiles.finders.FileSystemFinder'
否則你將得到一個(gè)404頁面秤涩。
這里發(fā)生了什么
Django 服務(wù)器收到一個(gè)關(guān)于靜態(tài)文件的請求帜乞,因?yàn)槭且灰?'/static/' 開頭的 url。
它開始在 STATICFILES_DIRS 設(shè)定的所有目錄中尋找這個(gè)靜態(tài)文件筐眷,比如 base.css黎烈。
由于我們在 STATICFILES_DIRS 中指定了一個(gè)目錄,即
project_static浊竟,Django 服務(wù)器在這個(gè)目錄中嘗試尋找這個(gè)文件怨喘。它在這個(gè)目錄中進(jìn)行搜索時(shí)找到了這個(gè)文件,然后進(jìn)行處理振定。如果沒有在 STATICFILES_DIRS 指定的目錄中找到這個(gè)文件必怜,它將會(huì)在 INSTALLED_APPS 下所有 app 的 static/ 子目錄嘗試尋找。
注意后频,這時(shí)候依然沒有不需要添加 staticfiles_urlpatterns()梳庆。
為了在模板中使用這個(gè)文件暖途,我們需要引用這個(gè)樣式。在所有模板中添加進(jìn)下面這行膏执。
<link href="{{STATIC_URL}}base.css" rel="stylesheet" type="text/css">
刷新兩個(gè)頁面的url驻售,你將會(huì)看到這些頁面中h1標(biāo)簽中的字體都為斜體。
讓我們查看最終的目錄結(jié)構(gòu)更米,如果你有什么問題可以有幫助欺栗。
(staticvirt)~/staticvirt/test_project$ tree -I *.pyc
.
|-- manage.py
|-- other_app
| |-- __init__.py
| |-- models.py
| |-- static
| | *-- other_app
| | *-- styles.css
| |-- tests.py
| |-- urls.py
| *-- views.py
|-- project_static
| *-- base.css
|-- some_app
| |-- __init__.py
| |-- models.py
| |-- static
| | *-- some_app
| | *-- styles.css
| |-- tests.py
| |-- urls.py
| *-- views.py
|-- templates
| |-- other_app
| | *-- home.html
| *-- some_app
| *-- home.html
*-- test_project
|-- __init__.py
|-- settings.py
|-- urls.py
*-- wsgi.py
11 directories, 20 files
關(guān)于 STATIC_ROOT
如果在開發(fā)階段你使用 Django 的 runserver,你將永遠(yuǎn)不會(huì)需要STATIC_ROOT征峦。
一旦你需要進(jìn)入生產(chǎn)迟几,你能在服務(wù)器中使用它。Django 提供了一個(gè)靜態(tài)文件管理的命令叫做 collectstatic栏笆,它將收集所有的靜態(tài)資源类腮,(如在 STATICFILES_DI
![Uploading 0_005091.jpg . . .]
RS 中找到的和在所有 app 下的 static/子目錄中找到的靜態(tài)資源),將它們放進(jìn)一個(gè) STATIC_ROOT
定義的位置蛉加。STATIC_ROOT 只有在你使用 collectstatic 命令的時(shí)候才會(huì)有用處蚜枢。
讓我們驗(yàn)證一下,創(chuàng)建一個(gè)名為 static_resources 的目錄.
mkdir static_resources
修改settings.py针饥,添加以下幾行.
STATIC_ROOT = os.path.join(PROJECT_DIR, '../static_resources')
現(xiàn)在運(yùn)行命令:
python manage.py collectstatic
它會(huì)請求你確認(rèn)厂抽,輸入 'yes',然后你將會(huì)看見所有的靜態(tài)資源被收集進(jìn)一個(gè)你在 STATIC_ROOT 定義的目錄中丁眼。
然后在生產(chǎn)服務(wù)器中你可以設(shè)置所有的靜態(tài)文件請求都進(jìn)入STATIC_ROOT 定義的目錄中進(jìn)行查找修肠。
再說一次,關(guān)于 STATIC_ROOT 的部分只是附帶著說說户盯。在開發(fā)階段你都不需要用到它嵌施。
原文:http://agiliq.com/blog/2013/03/serving-static-files-in-django/