[譯]Django中對靜態文件的支持

原文地址:[http://agiliq.com/blog/2013/03/serving-static-files-in-django/]css

處理靜態文件,尤爲是在開發時,是一件蛋疼的事情。在這篇文章中,咱們將會討論一些設置,目錄結構和他們之間的相互影響。設置好DEBUG = True而後咱們開始開發吧。html

咱們將會建立一個Django項目,這樣可讓咱們更好的瞭解咱們討論的這些這些文件在什麼目錄中。咱們將會使用Django1.4,這些都也能在Django1.3中工做,由於沒有在Django1.2下進行測試,因此對1.2版本下是否有問題不是很清楚。python

建立項目

若是你不須要這部分,能夠直接跳到處理靜態文件這一節。只要保證你看過了這節底部的目錄結構並對其有了解,這樣你閱讀後面的內容會更舒服。數據庫

咱們將在命名爲staticvirt的虛擬環境中作全部事情,因此咱們須要命令django

~$ virtualenv staticvirt

接下來咱們須要在這個虛擬環境中建立一個Django項目。確保你進入了虛擬環境的目錄,而且激活了該環境。同時也要保證在這個虛擬環境中安裝了Django,由於咱們不想污染系統的包環境。瀏覽器

~$ cd staticvirt/  
~/staticvirt$ source bin/activate  
(staticvirt)~/staticvirt$ pip install django==1.4

建立一個Django項目。bash

django-admin.py startproject test_project

進入項目所在系統。服務器

cd test_project/

讓咱們看看如今的目錄結構。app

(staticvirt)~/staticvirt/test_project$ tree  
. 
|-- manage.py   
*-- test_project   
|-- __init__.py 
|-- settings.py   
|-- urls.py   
*-- wsgi.py    
1 directory, 5 files

如今查看下test_project/settings.py的內容。搜索全部包括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提供的默認設置,咱們沒有作任何的設置。

咱們建立一個app,咱們將會在裏面建立一個template,而後會寫一些靜態文件,好比樣式文件,而後在模板中使用這個樣式文件。

python manage.py startapp some_app

some_app添加進test_project/settings.py中的INSTALLED_APPS

咱們須要一個urls.py文件來爲some_app定製路由。項目的urls.py應該包括some_app中的urls.py。因此,咱們在test_project/urls.py中添加如下一行。

url(r'^some_app/', include('some_app.urls'))

some_app的urls.py文件中添加如下內容。

url(r'^home$', direct_to_template, {"template": "some_app/home.html"})

建立一個名爲templates的目錄,而後將其添加進TEMPLATE_DIRS。我在manage.py同級目錄下建立templates

templates添加進TEMPLATE_DIRS我須要作如下設定,若是你也使用跟我同樣的目錄結構,你也須要一樣的設定。

PROJECT_DIR = os.path.dirname(__file__)  

TEMPLATE_DIRS = (
os.path.join(PROJECT_DIR, '../templates'),  
)

咱們須要爲some_app建立home.html文件,而後你須要進入templates目錄。因此建立templates/come_app/home.html,在文件中寫入如下內容。

<html>  
<body>  
<h1>This is home for some_app</h1>   
</body>  
</html>

如今查看一下項目的目錄結構,便於消除一些不清楚的地方。

~/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文件,因此將他們作了過濾。

啓動服務。請確保你作好了你的數據庫設定。

(staticvirt)~/staticvirt/test_project$ python manage.py runserver

在瀏覽器中打開http://127.0.0.1:8000/some_app/home。從如今開始,咱們稱這個頁面爲some_app的home,你應該可以看到你剛寫下的html的內容。

處理靜態文件

讓咱們編輯下some_app中的home.html文件,而且在其中添加樣式,如今還不存在任何樣式文件,咱們將在編輯好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頁面。你將不會看到任何變化,由於咱們尚未建立樣式文件。

一樣,訪問http://127.0.0.1/static/style.css,你將會看到一個404頁面。

如今開始建立樣式文件。由於咱們想要在some_app的template中使用這個樣式,因此咱們將在some_appstatic/的子目錄中建立。因此建立some_app/static/style.css,添加如下內容。

body  
{  
background-color: red;  
}

再刷新some_app的home頁面,你將會看到頁面背景變成了紅色。一樣,訪問http://127.0.0.1/static/style.css,你看到的再也不是404頁面,而是樣式文件的內容。若是你看到這些變化,請確認你將some_app添加進了INSTALLED_APPS,而且重啓了服務。

須要注意的地方

  • 咱們沒有對Django的默認靜態文件設置作任何改變。咱們徹底保留了Django的settings.py中關於靜態文件的設置。
  • 在開發中,你不須要在urls.py中關於靜態文件作任何改變,不須要添加staticfiles_urlpatterns(),我常常對此感到疑惑。
  • 在開發中,你不須要執行python manage.py collectstatic

內部是怎麼工做的

  • 首先,檢索settings.py中全部關於靜態文件的設置。
  • 他們是STATIC_URL, STATIC_ROOT, STATICFILES_FINDERS, STATICFILES_DIRS
  • 一樣咱們已經將'django.contrib.staticfiles'添加進了INSTALLED_APPS
  • 如今先無論STATIC_ROOTSTATICFILES_DIRS。即便你將他們註釋或者刪除,你的項目依然可以像如今同樣工做。
  • 咱們須要將'django.contrib.staticfiles'添加進INSTALLED_APPS,若是咱們想要使用Django默認的靜態文件處理服務。
  • 所謂的Django默認的靜態文件處理服務就至關於須要使用Django提供的python manage.py runserver
  • Django默認會在STATIC_URL下處理靜態文件。注意STATIC_URL已經設置爲'/static/'。這就是爲何咱們獲取到了咱們的靜態文件,舉個例子,樣式文件在這個url下http://127.0.0.1:8000/static/styles.css
    若是你訪問http://127.0.0.1:8000/static_changed/styles.css,你將會獲得一個404頁面。若是你想要在http://127.0.0.1:8000/static_changed/styles.css提供,須要設置STATIC_URL = '/static_changed/'。如今動手試試吧。這只是爲了舉例說明STATIC_URL的用處,如今都改回默認設置,即STATIC_URL = '/static/'
  • 下一個問題是,Django是怎麼知道從哪裏去讀取靜態文件的,或者說怎麼知道去哪裏找到靜態文件呢?這就是STATICFILES_FINDERS的做用了。
    STATICFILES_FINDERS中咱們有兩條記錄:
'django.contrib.staticfiles.finders.FileSystemFinder',  
'django.contrib.staticfiles.finders.AppDirectoriesFinder'

如今你能夠先無論FileSystemFinder,若是你願意,你能夠先註釋掉這一行。AppDirectoriesFinder告訴Django從INSTALLED_APPS中每個app下的static/ 子目錄下去尋找靜態文件。記住,咱們是將style.css放在了some_app中static/子目錄下,這就是爲何Django可以找到它,而且進行正確的處理。若是你將'static/'子目錄修改成其餘名字,你的靜態文件就不能被正確處理了。動手試一試吧。註釋掉AppDirectoriesFinder這一行,而後訪問http://127.0.0.1:8000/static/styles.css,如今樣式文件不能被正確地處理了。好,嘗試事後去掉註釋。

如今,咱們知道了STATIC_URLSTATICFILES_FINDERS的做用。咱們如今仍然不須要用到STATIC__ROOTSTATICFILES_DIRS

爲了瞭解一些其餘的事情關於靜態文件的處理,咱們須要另外一個app。

建立一個。

python manage.py startapp other_app

修改項目的urls.py,將other_app包括進去。如今項目的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"})

如今在templates目錄下建立other_app/home.html

<html>   
<body>   
<h1>This is home for other_app</h1>    
</body>   
</html>

查看一下如今的目錄結構。

~/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添加進INSTALLED_APPS

如今訪問url:http://127.0.0.1:8000/other_app/home

爲other_app的home頁面添加樣式。假設咱們想讓它的背景顏色爲藍色,咱們建立other_app/static/other_style.css

body{  
background-color: blue;  
}

將樣式文件添加進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,你將會看到藍色背景。你也許須要重啓服務才能看到變化。一樣,咱們可以在http://127.0.0.1:8000/static/other_style.css中看到樣式文件的內容。

同時,訪問http://127.0.0.1:8000/some_app/home,驗證下some_app的home頁面依然是紅色背景。

這裏發生了什麼

當咱們發起一個/static/other_style.css的請求,Django知道STATIC_URL設置爲'/static/',這跟url提供的第一個部分相匹配,所以它推斷咱們想要將其做爲靜態文件處理,因此它進入全部app的static/子目錄中進行查找,由於STATICFILES_FINDERS包含了'django.contrib.staticfiles.finders.AppDirectoriesFinder'。當它在other_app中的static/目錄下找到一個名爲other_style.css的文件,就對它進行處理。

然而,這帶來了另外一個問題,你必定注意到了咱們將other_app中的樣式文件命名爲other_style.css。若是咱們想要它的名稱也爲style.css會發生什麼呢?試試看。

mv other_app/static/other_style.css other_app/static/styles.css

同時,咱們須要修改other_app的home文件來引入這個樣式文件。咱們必須作這個,由於咱們將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>

如今查看兩個咱們建立的頁面。

http://127.0.0.1:8000/some_app/home  
http://127.0.0.1:8000/other_app/home

你會發現如今兩個頁面的背景都變成了紅色。這依賴於INSTALLED_APPS中app的排列順序。若是some_appother_app的前面,兩個頁面都會是紅色背景。若是other_appsome_app的前面,那麼兩個頁面背景都是藍色。在個人設置中,some_appother_app以前,因此背景都是紅色的。

爲何這會發生

兩個頁面都想引用一個名爲style.css的靜態文件。Django嘗試在INSTALLED_APPS中列出的全部app中的static/子目錄下尋找這個文件。一旦它在some_app的static/子目錄中找到了,就會進行處理而且再也不繼續在other_app中進行尋找。所以,some_app中static/子目錄下將背景設置爲紅色,那麼兩個頁面都被設置爲紅色背景了。

怎麼避免

那麼,若是咱們想在兩個app中樣式文件都叫作style.css怎麼作?這時候,咱們須要在沒一個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/

咱們在每個app下的static/子目錄下建立一個與各自app相同的目錄。而後將樣式文件移到這個目錄下。

同理,也須要修改各自的模板文件。

修改templates/some_app/home.html中的stylesheet路徑,新的內容以下:

<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作類似的改動。

<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>

如今再次查看兩個頁面。

http://127.0.0.1:8000/some_app/home  
http://127.0.0.1:8000/other_app/home

你將會發現一個背景是紅色,另外一個是藍色。

這裏發生了什麼

  • some_app的模板須要引用http://127.0.0.1:8000/static/some_app/styles.css
  • Django發現這個url以'/static/'開頭,這跟STATIC_URL匹配,推測這須要處理靜態文件some_app/style.css
  • 它開始在全部app的static/子目錄中尋找文件some_app/style.css
  • 它最終在some_app的static/子目錄中找到了它,並進行處理。
  • other_app的模板須要引用http://127.0.0.1:8000/static/other_app/styles.css
  • Django開始在全部app的static/子目錄中尋找文件other_app/style.css
  • 它最終在other_app的static/子目錄中找到了它,並進行處理。

但願你如今對於STATIC_URL, STATICFILES_FINDERS和靜態文件是怎麼處理的更加清楚了。

關於STATICFILES_DIRS

到如今咱們假定咱們在some_appother_app是須要各自獨立的靜態文件,因此咱們爲他們寫了不一樣樣式文件。

假定咱們項目中一些樣式須要保持一致,沒一個app都沒有特殊。這也的話,咱們不須要將這些樣式文件放進任何一個app的static/子目錄中。咱們在manage.py的同級目錄中建立一個目錄,而後將項目共同的靜態資源放在這個目錄中。

然咱們看看是怎麼作的。

在manage.py的同一級下建立一個名爲project_static的目錄。

mkdir project_static

建立一個名爲base.css的文件,放進去。

touch project_static/base.css

編輯這個頁面,包含如下內容:

h1  
{  
font-style: italic;  
}

咱們想讓項目中全部h1標籤中的內容斜體顯示。

Django如今還不知道這個文件,也不知道怎麼進行處理。要讓Django知道它,須要將包含這個文件的目錄添加進STATICFILES_DIRS。因此編輯test_project/settings.py,將須要的目錄添加進STATICFILES_DIRS。

STATICFILES_DIRS = (  
os.path.join(PROJECT_DIR, '../project_static'),  
)

試着訪問http://127.0.0.1:8000/static/base.css,你應該能看到剛纔寫的樣式。請確保在STATICFILES_FINDERS中你設置了:

'django.contrib.staticfiles.finders.FileSystemFinder'

不然你將獲得一個404頁面。

這裏發生了什麼

  • Django服務器收到一個關於靜態文件的請求,由於是一個以'/static/'開頭的url。
  • 它開始在STATICFILES_DIRS設定的全部目錄中尋找這個靜態文件,好比base.css。
  • 因爲咱們在STATICFILES_DIRS中指定了一個目錄,即project_static,Django服務器在這個目錄中嘗試尋找這個文件。它在這個目錄中進行搜索時找到了這個文件,而後進行處理。
  • 若是沒有在STATICFILES_DIRS指定的目錄中找到這個文件,它將會在INSTALLED_APPS下全部app的static/子目錄嘗試尋找。
  • 注意,這時候依然沒有不須要添加staticfiles_urlpatterns()

爲了在模板中使用這個文件,咱們須要引用這個樣式。在全部模板中添加進下面這行。

<link href="{{STATIC_URL}}base.css" rel="stylesheet" type="text/css">

刷新兩個頁面的url,你將會看到這些頁面中h1標籤中的字體都爲斜體。

讓咱們查看最終的目錄結構,若是你有什麼問題能夠有幫助。

(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

關於STATIC_ROOT

  • 若是在開發階段你使用Django的runserver,你將永遠不會須要STATIC_ROOT。
  • 一旦你須要進入生產,你能在服務器中使用它。Django提供了一個靜態文件管理的命令叫作collectstatic,它將收集全部的靜態資源,(如在STATICFILES_DIRS中找到的和在全部app下的static/子目錄中找到的靜態資源),將它們放進一個STATIC_ROOT定義的位置。
  • STATIC_ROOT只有在你使用collectstatic命令的時候纔會有用處。

讓咱們驗證一下,建立一個名爲static_resources的目錄.

mkdir static_resources

修改settings.py,添加如下幾行.

STATIC_ROOT = os.path.join(PROJECT_DIR, '../static_resources')

如今運行命令:

python manage.py collectstatic

它會請求你確認,輸入'yes',而後你將會看見全部的靜態資源被收集進一個你在STATIC_ROOT定義的目錄中。

而後在生產服務器中你能夠設置全部的靜態文件請求都進入STATIC_ROOT定義的目錄中進行查找。

再說一次,關於STATIC_ROOT的部分只是附帶着說說。在開發階段你都不須要用到它。

相關文章
相關標籤/搜索