Django是python web框架中,最popular的一個(gè),關(guān)于model/view/controller/模版等,各種教程非常多,現(xiàn)用現(xiàn)查即可,推薦:http://www.ziqiangxuetang.com/django/django-tutorial.html
django最麻煩的地方,反而是部署,下面詳細(xì)聊聊。
1.協(xié)議:wsgi
wsgi相當(dāng)于是python定制版的cgi,通用于所有的python web框架。wsgi/cgi的存在意義在于,確立了一套服務(wù)端腳本模式的標(biāo)準(zhǔn),讓服務(wù)器支持動(dòng)態(tài)頁(yè)面。之所以稱之為協(xié)議,是因?yàn)槠渲兄欢x了接口標(biāo)準(zhǔn),而沒(méi)有規(guī)定實(shí)現(xiàn)方法,你可以基于任何語(yǔ)言/平臺(tái)去實(shí)現(xiàn)它。
2.web容器
用戶訪問(wèn)網(wǎng)站的行為,實(shí)際上是從服務(wù)器取得一個(gè)html文本,然后在本地瀏覽器進(jìn)行解析。這些文本文件,就存放在服務(wù)端的web容器中,等待被用戶請(qǐng)求。然而現(xiàn)代的網(wǎng)站,體量都很大,數(shù)據(jù)量巨大,且應(yīng)用場(chǎng)景也多,安全性隱患也多,因此不可能全都使用靜態(tài)文件來(lái)存儲(chǔ)?,F(xiàn)在仍然活著的web容器,都是支持cgi族協(xié)議的,也就是可以通過(guò)server腳本,實(shí)現(xiàn)網(wǎng)頁(yè)動(dòng)態(tài)化。
比較流行的web容器,有:apache,nginx,IIS等。雖然都是通用web容器,但是設(shè)計(jì)之初的區(qū)別,導(dǎo)致各自的應(yīng)用場(chǎng)景不同。對(duì)wsgi最友好的是nginx,所以django最簡(jiǎn)便的部署方式就是做nginx映射。
3.gunicorn+nginx+django快捷部署
以下為具體操作:
1)環(huán)境準(zhǔn)備:安裝django,nginx,gunicore
sudo brew install nginx(sudo apt-get install nginx)
sudo pip install django
sudo pip install gunicorn
2)配置nginx
在/etc/nginx/sites-available/目錄下創(chuàng)建 配置文件(文件名不限)
mac下是:/usr/local/etc/nginx/nginx.conf
server {
listen 9600;監(jiān)聽(tīng)的服務(wù)器端口號(hào),小于1024的端口號(hào),需要sudo權(quán)限。由于做了gunicore映射,這里隨便用個(gè)port就可以,用戶實(shí)際訪問(wèn)時(shí),請(qǐng)求的是gunicore綁定的端口。
server_name localhost;
server_name 127.0.0.1;此處應(yīng)該改為公網(wǎng) IP地址
access_log /opt/logs/nginx/wasp_ticket_stat.log;
error_log /opt/logs/nginx/wasp_ticket_stat_error.log;
? ? location / {
? ? ? ? proxy_pass http://127.0.0.1:8000;此處填寫(xiě)轉(zhuǎn)發(fā)到的gunicorn綁定的服務(wù)器端口
? ? ? ? proxy_set_header Host $host;
? ? ? ? proxy_set_header X-Real-IP $http_x_real_ip;
? ? ? ? proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
? ? }
}配置結(jié)束
保存后,啟動(dòng)nginx:sudo nginx
3)配置gunicorn
cd到django工程目錄,gunicore project.wsgi –bind 0.0.0.0:8000 –deamon或者nohup gunicore project.wsgi –bind 0.0.0.0:8000
這么做是要保證,從部署服務(wù)器logout之后,gunicorn進(jìn)程仍然活動(dòng)。
gunicore第一個(gè)輸入,就是要找到你project的wsgi,“.”表示目錄級(jí),可以挨個(gè)文件夾去找著自帶的wsgi.py在哪里,默認(rèn)在project內(nèi)的project同名文件夾里。
如果成功了,則可以通過(guò)server公網(wǎng)ip:8000來(lái)訪問(wèn)網(wǎng)站。如果綁定80端口,則可以直接使用ip來(lái)訪問(wèn)。注意綁定小于1024的端口號(hào)時(shí),需要sudo權(quán)限。
4.靜態(tài)文件處理
如上的部署方式,做了兩次web容器映射,最容易出bug的就是路徑。web的開(kāi)發(fā)環(huán)境肯定跟生產(chǎn)環(huán)境是隔離的,使用絕對(duì)路徑非常蠢,運(yùn)維很容易出錯(cuò)。且django對(duì)絕對(duì)路徑進(jìn)行了重定向,使用的絕對(duì)路徑和系統(tǒng)路徑并不完全一致。
相對(duì)路徑由于多次映射的原因,很容易找不到/找錯(cuò)了,反復(fù)試驗(yàn)后,覺(jué)得如下配置比較輕便:
settings.py:末尾加上
STATIC_URL = '/static/'
STATICFILES_DIRS = (os.path.join(BASE_DIR, 'static').replace('\\', '/'),)
urls.py末尾加上
from django.contrib.staticfiles.urls import staticfiles_urlpatterns
from django.contrib import staticfiles
urlpatterns += staticfiles_urlpatterns()
在項(xiàng)目根目錄建立static/文件夾,各處用/static/images/test.jpg訪問(wèn)文件即可。
ps:從django腳本訪問(wèn)文件,與從模版訪問(wèn)是不同的。腳本訪問(wèn)文件的根目錄是就是django項(xiàng)目的根目錄,在views.py打印一下執(zhí)行目錄,一目了然:
for item in os.walk('.'):
? ? print item
5.跨域訪問(wèn)
在有些linux上,由于安全策略的關(guān)系,需要指定可用的安全ip。在settings.py里面,KNOWN_HOSTS這個(gè)list里面加上server ip
5.django for QA進(jìn)階
在測(cè)試/質(zhì)量保證過(guò)程中,常常會(huì)用到基于web的任務(wù)托盤(pán),來(lái)支撐持續(xù)集成之類的工作。當(dāng)具體需求需要對(duì)大路貨jekins進(jìn)行深度定制時(shí),可以考慮改用django來(lái)做任務(wù)托盤(pán),可擴(kuò)展性要強(qiáng)得多,對(duì)python也更友好。
1.并發(fā)
manage.py是for debug的,性能不適合用于生產(chǎn)環(huán)境,因此一般基于其他容器來(lái)部署。這里舉gunicorn為例,根據(jù)具體業(yè)務(wù)來(lái)決定子進(jìn)程個(gè)數(shù)。然后gunicorn -w 12代表建立一個(gè)12個(gè)子進(jìn)程的進(jìn)程池。
現(xiàn)代web容器都是自帶排隊(duì)的,建立子進(jìn)程池是for 長(zhǎng)效任務(wù)需要較長(zhǎng)時(shí)間獨(dú)占進(jìn)程的情況。
2.長(zhǎng)效任務(wù)
在任務(wù)托盤(pán)的深度定制中,很可能某個(gè)任務(wù)是要長(zhǎng)時(shí)間運(yùn)行后輸出結(jié)果的。在托盤(pán)模型中,對(duì)任務(wù)的管理需要是反饋式的,且各個(gè)任務(wù)的代碼完全異構(gòu),并不方便跟一般的PC腳本一樣做多進(jìn)程交互。
因此service上可以直接不做多進(jìn)程/線程,直接在一個(gè)viess.py的接口響應(yīng)里,調(diào)用一個(gè)長(zhǎng)效任務(wù),多個(gè)任務(wù)多次請(qǐng)求即可。
但是這樣做會(huì)觸碰到gunicorn的timeout瓶頸,導(dǎo)致任務(wù)中斷。這時(shí)需要借助eventlet插件,來(lái)協(xié)助處理子進(jìn)程阻塞的情況。
安裝eventlet:sudo easy_install eventlet
部署時(shí)加參數(shù)-k ‘eventlet’
3.時(shí)間
django有個(gè)非常微弱的小坑,就是有獨(dú)立的時(shí)區(qū),并不和server時(shí)區(qū)進(jìn)行同步。所以需要在setting里面手工設(shè)置一下:
TIME_ZONE = ‘Asia/Shanghai’