王 祎,賈文雅,尹雪婷,白艷明,張亮明
(1.山西藥科職業(yè)學(xué)院工商管理系,太原 030031;2.山西藥科職業(yè)學(xué)院器械工程系,太原 030031;3.山西藥科職業(yè)學(xué)院電教中心,太原 030031)
Django 是一個(gè)廣受歡迎的Web 框架,用于開(kāi)發(fā)現(xiàn)代的Web 應(yīng)用程序。它為開(kāi)發(fā)者提供了許多有用的功能,包括靜態(tài)文件管理。雖然靜態(tài)文件管理是一項(xiàng)相對(duì)簡(jiǎn)單的任務(wù),但如果不理解Django 的靜態(tài)文件管理機(jī)制,可能會(huì)導(dǎo)致在使用靜態(tài)文件時(shí)遇到各種問(wèn)題。本文將結(jié)合項(xiàng)目開(kāi)發(fā)實(shí)踐及相關(guān)文檔研究,對(duì)Django 的靜態(tài)文件管理機(jī)制進(jìn)行深入解析,以幫助開(kāi)發(fā)者更好地使用靜態(tài)文件,并在此基礎(chǔ)上提出了一種Django 靜態(tài)文件的使用策略,實(shí)現(xiàn)開(kāi)發(fā)狀態(tài)和部署狀態(tài)的自由切換。
Django 在開(kāi)發(fā)狀態(tài)(DEBUG=True)和部署狀態(tài)(DEBUG=False)下對(duì)靜態(tài)文件的處理方式有所不同。在開(kāi)發(fā)狀態(tài)下,Django 使用django.contrib.staticfiles 進(jìn)行靜態(tài)文件管理,靜態(tài)文件可以存放在應(yīng)用的static 子目錄中,也可以存放在STATICFILES_DIRS 指定的目錄中,Django 會(huì)自動(dòng)掃描并管理這些目錄中的文件。
而在部署狀態(tài)下,所有的靜態(tài)文件都需要放置到一個(gè)單獨(dú)的目錄中,再由專(zhuān)業(yè)的靜態(tài)文件服務(wù)器進(jìn)行管理。開(kāi)發(fā)者需要使用命令將開(kāi)發(fā)狀態(tài)下的所有靜態(tài)文件收集到該文件夾中,并提供正確的靜態(tài)文件路徑給專(zhuān)業(yè)的服務(wù)器,以便服務(wù)器能夠正確地找到并管理這些文件[1]。
一般來(lái)講,在使用Django 框架建立網(wǎng)站時(shí),可以通過(guò)以下步驟來(lái)設(shè)置使用靜態(tài)文件[2]。
第一步:?jiǎn)⒂胐jango.contrib.staticfiles
在項(xiàng)目的settings.py文件中找到INSTALLED_APPS 設(shè)置項(xiàng),保持其原有內(nèi)容不變,在列表的最后加入‘django.contrib.staticfiles’,代碼如下:
一般在創(chuàng)建項(xiàng)目時(shí)默認(rèn)已加入該項(xiàng),所以通常不需要修改。
第二步:設(shè)置訪問(wèn)靜態(tài)文件時(shí)使用的基礎(chǔ)URL
在項(xiàng)目的settings.py 文件中找到STATIC_URL(若找不到,則新建一個(gè)),將其值設(shè)置為‘/staticFiles/’,代碼如下:
其中的‘/staticFiles/’可以修改為你想要使用的任何字符串,最后一個(gè)字符必須是斜線‘/’。
第三步:在應(yīng)用文件夾下建立static文件夾
每一個(gè)項(xiàng)目通常都會(huì)有多個(gè)應(yīng)用,假設(shè)在項(xiàng)目中存在一個(gè)名為myapp1 的應(yīng)用,要實(shí)現(xiàn)該應(yīng)用靜態(tài)文件的正確引用,需要在myapp1 目錄下建立static 文件夾,這個(gè)文件夾的名稱(chēng)不可以更改,因?yàn)檫@是Django 默認(rèn)查找的目錄。靜態(tài)文件需要存放在該static 文件夾下。該文件夾下還可以建立子文件夾。
第四步:使用static標(biāo)簽引用靜態(tài)文件
在應(yīng)用的模板文件中,首先使用{% load static %}導(dǎo)入static 標(biāo)簽,然后通過(guò){% static“靜態(tài)文件相對(duì)路徑”%}就可以訪問(wèn)到需要的靜態(tài)文件。
下面以圖片為例,演示靜態(tài)文件的使用。假設(shè)有一個(gè)名稱(chēng)為myWebSite 的Django 項(xiàng)目,該項(xiàng)目有兩個(gè)應(yīng)用myapp1 和myapp2。要實(shí)現(xiàn)圖片的正確引用,需要完成以下四個(gè)步驟:
第一步:修改項(xiàng)目的設(shè)置,編輯myWeb-Site/settings.py文件,在其中加入如下代碼:
這一步中除‘django.contrib.staticfiles’之外,‘myapp1’‘myapp2’也不可少,只有在這里聲明了應(yīng)用名稱(chēng),Django 才會(huì)到它們的目錄下去尋找static文件夾。
第二步:編輯myWebSite/settings.py 文件,在其中加入如下代碼:
這一步設(shè)定了訪問(wèn)靜態(tài)文件的基礎(chǔ)URL。
第三步:在應(yīng)用文件夾下建立static 文件夾。建好之后的目錄結(jié)構(gòu)如圖1 所示(隱藏了與靜態(tài)文件引用無(wú)關(guān)的內(nèi)容)。
圖1 目錄結(jié)構(gòu)示例1
在myapp1 中有一張圖片‘錢(qián)學(xué)森.jpg’,存放位置是myWebSite/myapp1/static。為了能正常訪問(wèn)這張圖片,static 文件夾必須要在應(yīng)用目錄myapp1 之下,且名稱(chēng)必須是static。類(lèi)似的,myapp2要用到的靜態(tài)文件,需要放置到myWeb-Site/myapp2/static 文件夾之下。若有其它應(yīng)用,與此類(lèi)似。
第四步:在模板文件中引用‘錢(qián)學(xué)森.jpg’,可以通過(guò)以下代碼實(shí)現(xiàn):
其中static 標(biāo)簽對(duì)應(yīng)的是STATIC_URL 的值,{%static“錢(qián)學(xué)森.jpg”%} 對(duì)應(yīng)的URL是:‘/static-Files/錢(qián)學(xué)森.jpg’,在模板中直接使用該地址也可以訪問(wèn)到圖片文件。
Django 將每個(gè)應(yīng)用的static 文件夾下的所有內(nèi)容都對(duì)應(yīng)到了‘/staticFiles/’這個(gè)URL 之下。若以‘python manage.py runserver 127.0.0.1:8000’啟動(dòng)網(wǎng)站,則在瀏覽器中可以通過(guò)‘http://127.0.0.1:8000/staticFiles/錢(qián)學(xué)森.jpg’來(lái)訪問(wèn)該圖片文件。
(1)不使用{%load static%}能否引用圖片?
不使用{% load static %}也能引用圖片,方法如下[3]:
修改settings.py 文件,在其中加入如下代碼,原有代碼保持不變:
以上設(shè)置完成之后重啟網(wǎng)站,就可以通過(guò){{STATIC_URL}}來(lái)引用STATIC_URL 中的值。在模板中構(gòu)建靜態(tài)文件地址的代碼為:‘{{STATIC_URL}}錢(qián)學(xué)森.jpg’,其對(duì)應(yīng)的URL為‘/static_url/錢(qián)學(xué)森.jpg’。
(2)在項(xiàng)目中存在多個(gè)應(yīng)用的時(shí)候,有些應(yīng)用的靜態(tài)文件可能會(huì)使用相同的名稱(chēng),同名靜態(tài)文件在引用時(shí)出現(xiàn)沖突怎么辦?
是的,同名靜態(tài)文件確實(shí)會(huì)存在沖突。Django 在查找靜態(tài)文件時(shí),以先找到者為準(zhǔn),所以如果存在同名文件,返回的地址對(duì)應(yīng)的是首先找到的文件,可能導(dǎo)致文件引用錯(cuò)誤。
為了解決這個(gè)問(wèn)題,一般采用的方法是,在每個(gè)應(yīng)用的static 文件夾下再以應(yīng)用名稱(chēng)建立一個(gè)文件夾,該應(yīng)用的所有的靜態(tài)文件都存放在該文件夾下,為了便于使用,一般會(huì)以js、css、imgs 等文件夾來(lái)區(qū)分靜態(tài)文件的類(lèi)型,目錄結(jié)構(gòu)如圖2所示。
圖2 目錄結(jié)構(gòu)示例2
如圖2 所示,在myapp1/static 文件夾下再建立一個(gè)myapp1 文件夾,在myapp2/static 文件夾之下再建立一個(gè)myapp2 文件夾。這樣在引用myapp1 中的靜態(tài)文件‘錢(qián)學(xué)森.jpg’時(shí),其引用地址是:
而在應(yīng)用myapp2 中存在的同名文件,其引用地址是:
如此一來(lái),就不會(huì)出現(xiàn)地址沖突的問(wèn)題了。
(3)有一些靜態(tài)文件在很多應(yīng)用中都會(huì)用到,放到某一個(gè)應(yīng)用的static 文件夾下好像不太合適,該怎么辦?
可以使用公共靜態(tài)文件夾,將公用文件存放在該文件夾下。公共靜態(tài)文件夾可以通過(guò)STATICFILES_DIRS 進(jìn)行設(shè)定。編輯settings.py文件中,增加如下代碼:
STATICFILES_DIRS=(‘common_static’,)
將公共靜態(tài)文件存放到‘common_static’文件夾下即可。這里指定的文件夾可以使用絕對(duì)地址,也可以使用相對(duì)地址,相對(duì)地址是相對(duì)項(xiàng)目主目錄的地址。上面的代碼設(shè)置的就是一個(gè)相對(duì)地址。這里可以指定多個(gè)文件夾,文件夾名稱(chēng)可以由用戶(hù)自行設(shè)定。這里的文件夾可以位于項(xiàng)目文件夾之外。絕對(duì)地址一般使用os. path. join(BASE_DIR,‘common_static’)這樣的方式來(lái)生成,避免硬編碼,具有更高的可移植性。Django 查找文件的順序是先查找STATICFILES_DIRS 中指定的文件夾,后查找應(yīng)用下的static文件夾。
對(duì)公共靜態(tài)文件夾中的文件的引用方式與前面相同。
(4)將settings.py 文件中的‘DEBUG=True’改為‘DEBUG=False’后,靜態(tài)文件訪問(wèn)不了了,該怎么辦?(在部署狀態(tài)下如何使用靜態(tài)文件?)
在網(wǎng)站開(kāi)發(fā)時(shí)我們會(huì)將DEBUG 設(shè)置為T(mén)rue,以方便錯(cuò)誤調(diào)試;在網(wǎng)站部署時(shí),需要將DEBUG設(shè)置為False,以停止顯示詳細(xì)錯(cuò)誤信息,提高網(wǎng)站的安全性。但在將DEBUG 設(shè)置為False之后,Django就由開(kāi)發(fā)狀態(tài)轉(zhuǎn)為部署狀態(tài),其不再自動(dòng)支持對(duì)靜態(tài)文件的訪問(wèn)。此時(shí)需要使用第三方文件服務(wù)器提供靜態(tài)文件服務(wù)。
開(kāi)發(fā)者需要在settings.py 文件中設(shè)定STATIC_ROOT參數(shù),代碼如下:
設(shè)定之后,運(yùn)行python manage.py collectstatic 命令,它會(huì)將所有的靜態(tài)文件收集到staticRoot 文件夾之下。staticRoot 文件夾的名稱(chēng)可以由用戶(hù)自定義,收集命令會(huì)自動(dòng)建立該文件夾。該文件夾地址可以是絕對(duì)地址,也可以是相對(duì)地址,相對(duì)地址是相對(duì)項(xiàng)目主目錄的地址。該文件夾可以位于項(xiàng)目目錄之外。
因?yàn)镈jango 的靜態(tài)文件服務(wù)在效率和安全性方面不夠成熟,不建議在部署時(shí)使用。需要改為使用其它專(zhuān)業(yè)的靜態(tài)文件服務(wù)器,一般比較常用的是Nginx。在靜態(tài)文件服務(wù)器軟件中將根目錄設(shè)置為STATIC_ROOT指定的目錄即可。
不使用第三方靜態(tài)文件服務(wù)器,而是用Django 自身也可以在部署狀態(tài)下提供靜態(tài)文件服務(wù),詳見(jiàn)后文。
(5)不使用django.contrib.staticfiles 能否訪問(wèn)靜態(tài)文件?
可以。以下方法適用于開(kāi)發(fā)狀態(tài)。
首先在settings.py 中設(shè)置DEBUG=True,然后將所有的靜態(tài)文件存放在STATIC_ROOT 指定的文件夾中,最后修改項(xiàng)目的根路由文件urls.py,代碼如下:
該方法只有技術(shù)上的可行性,并沒(méi)有實(shí)用價(jià)值,因?yàn)樵诜奖阈陨纤蝗纭畇taticfiles’,并且也僅適用于開(kāi)發(fā)狀態(tài),列出僅供參考。
(6)STATIC_URL 設(shè)置為‘static/’和‘/static/’有何區(qū)別?
如果STATIC_URL 設(shè)置為‘static/’,那么它將以服務(wù)器提供的SCRIPT_NAME 的值為前綴,如果服務(wù)器沒(méi)有設(shè)置SCRIPT_NAME,則以‘/’為前綴,最終STATIC_URL 值為‘/static/’。因此,若服務(wù)器沒(méi)有提供SCRIPT_NAME 的話,這兩種設(shè)置的結(jié)果是一樣的。如果沒(méi)有特別的需要,為避免不確定性,建議設(shè)置為‘/static/’。
Django 在開(kāi)發(fā)狀態(tài)和部署狀態(tài)使用了不同的方式來(lái)處理靜態(tài)文件,增加了復(fù)雜性。開(kāi)發(fā)者開(kāi)發(fā)過(guò)程中經(jīng)常需要在開(kāi)發(fā)狀態(tài)和部署狀態(tài)之間進(jìn)行切換,此時(shí)可能需要反復(fù)進(jìn)行靜態(tài)文件的收集操作,否則可能導(dǎo)致有些靜態(tài)文件無(wú)法正確顯示。有沒(méi)有一種方法可以避免這種反復(fù)的收集操作呢?
有!由于‘django.contrib.staticfiles’在由開(kāi)發(fā)狀態(tài)轉(zhuǎn)為部署狀態(tài)后,不再提供靜態(tài)文件服務(wù)。所以我們要放棄使用它,轉(zhuǎn)而通過(guò)手動(dòng)設(shè)置提供靜態(tài)文件服務(wù),從而實(shí)現(xiàn)開(kāi)發(fā)狀態(tài)和部署狀態(tài)的自由切換。具體實(shí)現(xiàn)步驟如下:
第一步:修改項(xiàng)目設(shè)置文件settings.py,刪除‘django. contrib. staticfiles’和STATICFILES_DIRS,設(shè)置STATIC_URL=‘/static/’,STATIC_ROOT=‘staticRoot’。
這一步停止了‘django.contrib.staticfiles’對(duì)靜態(tài)文件的自動(dòng)管理,并將靜態(tài)文件的文件夾設(shè)定為項(xiàng)目根文件夾下的‘staticRoot’文件夾。
第二步:在項(xiàng)目根路由文件urls.py 中增加以下代碼[4]:
以上代碼設(shè)置了對(duì)‘staticRoot’目錄下的所有文件的訪問(wèn)路由。使這些文件可以被正常訪問(wèn)到。
這些代碼放在根路由文件的末尾,在項(xiàng)目真正需要部署的時(shí)候?qū)⑵渥⑨尩艏纯伞?/p>
第三步:由于不再使用‘django.contrib.staticfiles’管理靜態(tài)文件,所以也不能再使用應(yīng)用下的static 文件夾和公共靜態(tài)文件夾存放靜態(tài)文件。而是必須把所有的靜態(tài)文件統(tǒng)一放置到一個(gè)文件夾下。在第一步中我們?cè)O(shè)置了STATIC_ROOT=‘staticRoot’,是一個(gè)相對(duì)于項(xiàng)目根目錄的路徑,所以需要在項(xiàng)目根文件夾下建立static-Root文件夾,在其中建立應(yīng)用文件夾和分類(lèi)文件夾以便于管理靜態(tài)文件,目錄結(jié)構(gòu)如圖3所示。
圖3 目錄結(jié)構(gòu)示例3
第四步在模板文件中使用如下代碼進(jìn)行圖片文件引用:
使用這種方式,我們?cè)陂_(kāi)發(fā)狀態(tài)和部署狀態(tài)之間進(jìn)行切換時(shí),靜態(tài)文件均可以正常顯示,不需要進(jìn)行其他處理,對(duì)于網(wǎng)站開(kāi)發(fā)過(guò)程中的運(yùn)行測(cè)試提供了極大的便利。
但在網(wǎng)站正式部署的時(shí)候,還是需要使用專(zhuān)業(yè)的文件服務(wù)器來(lái)管理靜態(tài)文件,以保證效率和安全性。這時(shí)需要將第二步中跟路由文件urls.py 中增加的代碼刪除或注釋掉,其它代碼無(wú)需修改。
上傳文件也屬于靜態(tài)文件,Django 對(duì)它們的管理方式和以上方式類(lèi)似。這里僅探討File-Field 字段對(duì)應(yīng)的文件的上傳方式。要實(shí)現(xiàn)文件的正確上傳,僅需在settings.py 文件中增加以下一條語(yǔ)句:
該文件夾地址可以是絕對(duì)地址,也可以是相對(duì)地址,相對(duì)地址是相對(duì)項(xiàng)目主目錄的地址。該文件夾可以位于項(xiàng)目目錄之外。這里設(shè)置的是相對(duì)地址,因此需要在項(xiàng)目根目錄下建立uploadFiles 文件夾。之后使用Django 提供的admin管理頁(yè)面就可以正常上傳文件了。
如果要訪問(wèn)已上傳的文件,需要設(shè)置MEDIA_URL 和添加已上傳文件的路由。首先編輯settings.py文件,增加以下語(yǔ)句:
接著修改項(xiàng)目的根路由文件urls.py,在其中添加以下語(yǔ)句:
之后就可以實(shí)現(xiàn)對(duì)已上傳文件的正常訪問(wèn)。這種方式同時(shí)適用于開(kāi)發(fā)狀態(tài)和部署狀態(tài),在兩種狀態(tài)之間切換時(shí)不需要進(jìn)行其它修改。同樣建議在項(xiàng)目正式部署時(shí),改為由其它正式的靜態(tài)文件服務(wù)器提供服務(wù),同時(shí)將該條語(yǔ)句注釋或刪除。
本文對(duì)Django 靜態(tài)文件管理機(jī)制進(jìn)行了較為全面的解析,在此基礎(chǔ)上使用手動(dòng)配置文件服務(wù)和單一文件夾管理靜態(tài)文件的方式,實(shí)現(xiàn)了Django 項(xiàng)目靜態(tài)文件管理的優(yōu)化,使開(kāi)發(fā)者在進(jìn)行網(wǎng)站開(kāi)發(fā)測(cè)試時(shí)不需要手動(dòng)進(jìn)行靜態(tài)文件的收集操作及其他文件服務(wù)器的配置,簡(jiǎn)化了開(kāi)發(fā)者的操作,提高了Django 網(wǎng)站開(kāi)發(fā)測(cè)試的便利性和工作效率。