既然已經能夠訪問django,那咱們就能夠搞點事情了哦,至少來個helloworld吧。html
有兩個基本的知識點:python
基於這兩個知識點,咱們就改一下urls.py,在請求主頁面時,調用一個函數,而且讓這個函數返回helloworld的內容。linux
urls.py的主要內容以下:nginx
from django.contrib import admin from django.urls import path from django.conf.urls import url from django.http import HttpResponse def dosomething(request): return HttpResponse('<html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><title>你好</title><body>hello world 喂世界 nihao</body><head></html>') urlpatterns = [ #path('admin/', admin.site.urls), url(r'^$', dosomething) ]
這裏定義一個dosomething的函數,注意這個函數是帶一個參數的,由於django會傳遞request給它。而後dosomething返回了一個HttpResponse對象,裏面就是一些簡單的文字了。git
./manage.py runserver啓動django後,在瀏覽器請求一下,能夠看到這樣的效果:
github
這就是一個簡單的helloworld程序,太好改了吧。但這裏有個問題,上面那段python代碼,裏面出現一段html,有什麼問題嗎?html標識的是一個界面,好比用什麼標題、用什麼字體、用幾號大小,等等,這是界面設計的東西,而把界面設計跟代碼邏輯或業務邏輯混在一塊兒,除非你能容忍混亂並且不影響開發效率,不然界面跟代碼邏輯就要分開。那界面提到哪裏去呢,就是模板了,就是一個html文件,這裏演示一下。web
先mkdir建立一個templates文件夾,之後就放html文件了,而後建立一個main.html,這樣設計這個界面(好簡單!):shell
<h1>hello,{{yourname}}</h1>
{{yourname}}表示引用一個變量,變量名叫yourname,注意要用雙符號來引用變量。在界面中使用變量,這太尋常了,那變量的定義還有值從哪裏來的?就是業務邏輯給的呀,這就是界面與邏輯分離的表現,即界面使用邏輯給的變量值,邏輯給界面提供數據。django
好了,而後,天然是要在代碼中定義這個yourname變量了,並且代碼中要展現這個html,代碼以下:後端
from django.contrib import admin from django.urls import path from django.conf.urls import url from django.shortcuts import render def dosomething(request): dict = {} dict['yourname'] = '廣州小程' return render(request, 'main.html', dict) urlpatterns = [ #path('admin/', admin.site.urls), url(r'^$', dosomething) ]
在接到請求時,仍是調用dosomething函數,而後返回一個render,看名字就知道是要渲染繪製一個界面出來,這個界面是什麼呢?就是第二個參數指定的main.html,而後第三個參數就是傳遞給界面的數據,它是一個鍵值對集,明顯,必定要包括yourname這個變量,並且事先給了變量值。
最後要注意一個路徑的問題,就是render怎麼找到main.html的問題,這個要在settings.py中進行設置,而後來看一下如今的目錄結構:
按這個結構,要指定的路徑就是:項目目錄+/myblog/templates
在settings.py中找到 TEMPLATES 這個dict,而後把DIRS的值改爲這樣:
'DIRS': [BASE_DIR+'/myblog/templates',],
ok,一切就緒,瀏覽器請求一下,看到這樣的效果:
好了,界面你也知道怎麼寫了,不就是寫html嘛。可是,我要的博客可沒有這麼簡單,須要一步步來開發嗎?
在你作一個事情,特別是一個常見的事情以前,看看別人是怎麼作的,或許能大大節省你的時間成本。因而,你會發現,博客這種平常操做,在github上有大量的項目。
因而,這裏我直接使用這個項目:https://github.com/liangliangyy/DjangoBlog
按這個地址的介紹來部署便可:https://www.lylinux.net/article/2019/8/5/58.html
這裏有個知識點,爲何有了djangoblog,還要用到nginx跟gunicorn呢?它們是什麼關係呢?
djangoblog,簡單來講就是一個web應用,也能夠說是一個web框架。做爲一個應用,djangoblog固然能夠runserver起來而且佔用80端口等,而後瀏覽器就能夠訪問到他。可是,在實際數據交互的場景中,讓web應用把負載均衡、高併發之類的事情也作了,是不合適的,應用只應該作本身的業務。因此,還須要一個重要的角色,這個角色就是web服務器,而nginx就是一個web服務器,瀏覽器的全部請求先到達nginx,nginx先作一些前置的處理(好比靜態頁面攔截、負載平衡之類),可是,因爲nginx不懂業務啊,因此它仍是要調用到djangoblog(web框架或應用),但這個調用不是直接的調用,而是通過中間件,好比gunicorn。gunicorn或wsgi(網關接口),解決了nginx與django交互的問題,由於web服務器與web框架的通訊,要遵照一種協議,而gunicorn正是實現了這種協議。實際上,gunicorn自己也能作爲web服務器(相似於nginx),但因能力有限,通常會把這個角色讓位於nginx等。因此,簡單來講,一種常見的後端結構就是:nginx+gunicorn+django。
另外,因爲gunicorn支持nginx與django的通訊,不可或缺,若是它退出了,有必要即刻啓動起來,因而引入supervisor。supervisor監控gunicorn,保證後者的拉起,並且後者以子進程掛在supervisor進程內。因而這個結構也能夠說是:nginx+supervisor+gunicorn+django。
最終用瀏覽器訪問,一個網站就出來了:
補充一些知識點。
(a)supervisor與gunicorn
supervisor是監控並管理gunicorn的,若是你想中止gunicorn,你只須要把對應的supervisor服務給stop掉就能夠了,gunicorn進程會自動中止。
用這個命令先看一下supervisor監控了哪些服務:
supervisorctl status
而後就能夠中止這個服務:
supervisorctl stop 服務名
這時服務對應的gunicorn會自動中止,用lsof -i:8000再也不看到進程。 對應於stop,還有start、reload。
固然,若是想直接kill掉gunicorn進程,也能夠,先找到它的根pid:
pstree -ap|grep gunicorn
再kill掉:
kill -9 pid
可是,若是supervisor是運行狀態,kill掉的gunicorn即刻就會被拉起,一個新的pid的gunicorn又會出現。
(b)supervisor的配置
諸多key-value的配置選項,請自行搜索瞭解,這裏簡單說兩個。
command,就是supervisor要執行的命令,好比執行某個程序或腳本,好比執行一句python語句等等,涉及到的文件,你能夠寫完整路徑,若是寫相對路徑則要組合directory這個選項。
directory,在執行command以前,先cd到這個目錄,看狀況使用(也可不用)。
(c)supervisor的日誌
若是遇到supervisor有什麼異常而你一時想不出緣由,這時看一下它的日誌輸出(包括你故意print出來的日誌--由於supervisor是python程序因此你固然能夠print),也許能幫到你,那日誌在哪裏呢? 默認在/var/log/supervisor目錄下面。若是在配置supervisor時指定了標準輸出路徑,好比stdout_logfile字段,那就多了一個日誌。對於分析問題,這兩個日誌都應該關注。
(d)supervisor的進程關係
這樣查看supervisor的進程關係:
service supervisor status
若是已經設置好supervisor的配置,好比指定啓動gunicorn,那就能夠看到在supervisor進程下面掛上了gunicorn進程(通常兩個,一主一從)。
(e)nginx的配置
nginx的全部配置都在:/etc/nginx 目錄,而你新增長的配置應該放在 /etc/nginx/sites-enabled 目錄下,這個目錄已經有一個叫default的默認配置文件,你的新配置能夠任意命名,都將替代default配置,但你須要從新啓動nginx。
能夠這樣重啓nginx:
service nginx reload/restart 或:
/etc/init.d/nginx reload
若是不放心,也能夠先stop(瀏覽器請求一下)再start:
service nginx stop
service nginx start
注意,nginx明明stop掉了,用ps也看不到進程了,這時瀏覽器再請求可能仍是看到頁面,這多是瀏覽器端的緩存。
配置中的error_log字段,指定了nginx出錯時的記錄文件,這個文件能夠幫助你分析nginx的錯誤。默認不設置這個字段的狀況下,錯誤日誌文件是/var/log/nginx/error.log。
若是隻是想驗證nginx是否能夠正常使用,能夠寫一個最簡單的配置,好比這樣:
server { listen 80; server_name www.freep2p.cn; root /root/python; }
而後在/root/python目錄建立一個index.html文件,好比文件內容能夠這麼簡單:
<html><p2>hello world</p2></html>
重啓nginx後用 www.freep2p.cn 訪問它,就能夠看到hello world。
對於nginx的運行狀況,能夠用下面的命令來查看:
systemctl status nginx.service
(f)定位問題的一個關鍵
層級一多,問題定位就變得複雜。除了考慮去除層級,好比直接手動調用gunicorn不經supervisor等,這個辦法有效外,還有一個關鍵的點,就是分析日誌。
有兩個日誌要上心,一個是nginx的輸出日誌(在配置中有寫,或者使用默認的路徑即/var/log/nginx/error.log),另外一個是supervisor的輸出日誌(如上介紹,有兩個),supervisor的日誌,包括了supervisor跟gunicorn的表現,還有請求應答的狀況。
(g)可能遇到的問題
(1)Internal Server Error
對於nginx,若是提示「Internal Server Error」,是什麼緣由呢? 這個提示(對應錯誤碼是500),意思是服務內部出問題了,但至少說明,你訪問到nginx了,只是觸發了錯誤。對於這裏的結構,nginx是要調用supervisor+gunicorn的,而gunicorn要調用djangoblog框架,是哪一步出了問題呢?
用lsof -i:8000,能夠看到gunicorn已經運行起來了,而nginx的配置相對是簡單的,不太像會出問題,那gunicorn到djangoblog那一步怎麼樣?gunicorn的配置是否是有問題呢?
先把supervisor中止掉,按上面介紹的命令便可作到,supervisor給stop掉後,gunicorn也會自動結束(lsof -i:8000看不到進程),若是這時用瀏覽器請求一下,會看到這樣的提示:
502 Bad Gateway
也就是網關接口出問題了,而實際就是gunicorn給中止了。
嘗試用最簡單的nginx的配置,能正常訪問,因此排除是nginx的問題。
先把supervisor給stop掉,也就是不使用supervisor來啓用gunicorn,而是直接執行gunicorn_start.sh腳本,再訪問nginx,發現,正常了!。
因此,從gunicorn到djangoblog沒有問題,問題出在supervisor啓用gunicorn引入了問題。
從理論來看,按這裏使用的supervisor的配置,supervisor解釋執行腳本(不必定用bash),再以exec命令啓動gunicorn,而exec的意思就是不另起進程,而是使用當前進程,只要gunicorn不退出(本意就是不退出的),那麼當前進程聲明的變量以及用source切換至python虛擬環境就是生效的,不用懷疑source不生效。
這時,必定要分析日誌。 在supervisor的標準輸出/var/log/djangoblog.log中,能夠看到這樣的提示:
也就是找不到HOST變量!
根據上面的提示,這個是database的設置,代碼以下圖:
也就是os.environ.get不到環境變量。
手動執行sh腳本,至關在shell中交互執行,實際是bash進程啓動了gunicorn,而supervisor是python程序,它解釋sh腳本啓動了gunicorn,這兩種方式是不一樣的,至少bash跟supervisor使用的環境變量的配置就不一樣,這個下面就來證實。
先來測試一下supervisor當前的環境變量吧。
把supervisor執行的命令設置一下:
command=python3 -c "import os; print(os.environ)"
而後:
tail -10 /var/log/djangoblog.log
你能夠看到已經有一些變量了,可是,沒有代碼裏面的那三個變量,由於尚未設置(設置到~/.bashrc中是無效的)。這樣設置到supervisor,一樣是在supervisor的配置中修改:
environment = DJANGO_MYSQL_USER='root',DJANGO_MYSQL_PASSWORD='xxx',...
也就是增長environment字段,值就是新增的環境變量,以逗號分隔。
再啓supervisor,這個問題就獲得解決。
(2)403 forbidden
若是error的log提示,「xxx」 is forbidden,一個多是在這個目錄下面找不到index.html。
總結一下,本文介紹了怎麼簡單寫helloworld界面,怎麼使用開源的博客項目,也重點介紹了後端的知識點。
至此,解決了後端結構的部署問題,網站框架也好了,接下來就是頁面個性化類的問題了。