title: 利用Django實現一個能與使用者互動的初級框架
author: Sun-Wind
date: September 1, 2021
Django實現基本的框架
- 此框架的功能是搭建伺服器,使得伺服器和客戶端互動
- 此框架可以接受客戶端的請求,並返回根據請求所得到的結果
這裡列舉一個垃圾識別分類的例子
Django簡介
Django 是一個由 Python 編寫的一個開放原始碼的 Web 應用框架。
使用 Django,只要很少的程式碼,Python 的程式開發人員就可以輕鬆地完成一個正式網站所需要的大部分內容,並進一步開發出全功能的 Web 服務
MVC模型
Django 本身基於 MVC 模型,即 Model(模型)+ View(檢視)+ Controller(控制器)設計模式,MVC 模式使後續對程式的修改和擴充套件簡化,並且使程式某一部分的重複利用成為可能。
MVT模型
Django 的 MTV 模式本質上和 MVC 是一樣的,也是為了各元件間保持鬆耦合關係,只是定義上有些許不同,Django 的 MTV 分別是指:
M 表示模型(Model):編寫程式應有的功能,負責業務物件與資料庫的對映(ORM)。
T 表示模板 (Template):負責如何把頁面(html)展示給使用者。
V 表示檢視(View):負責業務邏輯,並在適當時候呼叫 Model和 Template。
除了以上三層之外,還需要一個 URL 分發器,它的作用是將一個個 URL 的頁面請求分發給不同的 View 處理,View 再呼叫相應的 Model 和 Template,MTV 的響應模式如下所示:
簡易圖:
建立垃圾分類專案
注意:博主使用的是windows系統,不同系統使用的指令不一樣
<django-admin startproject rub>
使用以上指令建立專案
此時Django會形成一個專案框架,以下會一一解釋說明
- rub:專案的容器
- manage.py:作為一個實用的命令列工具,能夠讓你和專案進行互動
- init.py:此空檔案告訴python是一個python包
- asgi.py: ASGI相容的web伺服器入口,以便執行專案
- settings.py:該專案的配置,比如資料庫配置,訪問配置,連結配置
- urls.py:該專案的url(路由)宣告
- wsgi.py: WSGI相容的web伺服器入口,以便執行專案
執行我們的專案
<py manage.py runserver 0.0.0.0:8000>
通過以上命令來執行我們的專案
此命令需要在rub資料夾裡命名
其中0.0.0.0能夠讓區域網的其他電腦訪問到我們的網站,8000是埠號,也可以改成其他埠號,如果不寫埠號預設是8000
此時命令列會生成對應的本地伺服器的http,訪問後如下所示
如果無法訪問,請檢視是否是端口占用的問題,可以考慮更換一個埠號
悄悄說一句,8000端口占用多半是酷狗音樂什麼的[]( ̄▽ ̄)*
建立app
Django規定,如果要使用模型層,必須要建立一個app(雖然我們這個專案裡面不用,但還是教一下)
<django-admin.py startapp app>
然後Django就會自動生成app的框架
<py manage.py migrate>
# 建立表結構
< py manage.py makemigrations app>
# 讓 Django 知道我們在我們的模型有一些變更
<py manage.py migrate app>
# 建立表結構
執行以上指令可以完成資料庫表單的建立
這裡只是額外引入一下,實際上本專案實現比較簡單,可以無需使用
配置路由
路由簡單的來說就是根據使用者請求的 URL 連結來判斷對應的處理程式,並返回處理結果,也就是 URL 與 Django 的檢視建立對映關係。
我們在rub的主路由中新增如下配置
<path('',include('app.urls')),>
利用include語句可以將app的路由對映進來,這樣我們直接配置app的路由即可
include指的是路由的分發
Django 專案裡多個app目錄共用一個 urls 容易造成混淆,後期維護也不方便。
使用路由分發(include),讓每個app目錄都單獨擁有自己的 urls。
在app的路由當中加入如下的配置
< path('',views.index,name = 'index'),>
<path('upload1',views.upload1,name = 'upload1'),>
path方法
Django path() 可以接收四個引數,分別是兩個必選引數:route、view 和兩個可選引數:kwargs、name。
- route:字串,表示URL規則,與之匹配的URL會執行第二個引數view
- view:用來執行匹配的URL請求
- kwargs:字典引數(通過此引數可以實現網頁變數的解析操作,後續會有解釋)
- name:用來反向獲取URL
檢視層
在app的檢視層中加入如下程式碼
def index(request):
return render(request,'app/index.html')
def upload1(request):
myfile = request.FILES.get('pic',None)
if not myfile:
return HttpResponse("沒有上傳的檔案資訊:")
filename = str(time.time()) + "." + myfile.name.split('.').pop()#這裡是對檔名進行預處理操作,時間函式可以隨機化一個值,用str方法轉換為字串,然後用split拆分字尾名,可以實現任意圖片形式的儲存
destination = open("./static/pic/" + filename,"wb+")#利用open函式和chunks流寫入static資料夾
for chunk in myfile.chunks(): # 分塊寫入檔案
destination.write(chunk)
destination.close()
label = predict_img(path="static/pic/" + filename)#此處是垃圾分類識別函式,因為競賽相關,就不放出具體的識別程式碼了,讀者可以參考相關資料自行補充此函式
print(label)
os.remove("./static/pic/"+filename)#這裡刪除檔案,防止使用者傳入檔案佔用記憶體的問題
context = {}
context['result'] = label # 將result變數對應的鍵值設為lable,這樣可以讓html檔案解析lable變數
return render(request,'app/result.html',context)
接下來我們進行逐一解讀
render(): 返回文字,第一個引數為 request,第二個引數為字串(頁面名稱),第三個引數為字典(可選引數,向頁面傳遞的引數:鍵為頁面引數名,值為views引數名)。
簡而言之就是根據路徑返回我們需要的頁面
注意這裡要寫成app/index而不是rub/index,雖然index的網頁檔案在rub的templates下創立
Request是一個物件,其屬性簡述如下
- path 請求頁面的全路徑,不包括域名—例如, "/hello/"。
- method 請求中使用的HTTP方法的字串表示。全大寫表示。如
if request.method == 'GET':
do_something()
elif request.method == 'POST':
do_something_else()
- FILES
包含所有上傳檔案的類字典物件。FILES中的每個Key都是<input type="file" name="" />
標籤中name屬性的值. FILES中的每個value 同時也是一個標準Python字典物件,包含下面三個Keys:
filename: 上傳檔名,用Python字串表示
content-type: 上傳檔案的Content type
content: 上傳檔案的原始內容
注意:只有在請求方法是POST,並且請求頁面中有enctype="multipart/form-data"屬性時FILES才擁有資料。否則,FILES 是一個空字典。
FILE的get方法,第一個引數來源於所收到請求的html檔案,裡面包含有圖片名.第二個引數是如果沒有接收到檔案,就返回None
HttpResponse(): 返回文字,引數為字串,字串中寫文字內容。如果引數為字串裡含有 html 標籤,也可以渲染。
static是Django的靜態檔案儲存處,需要在rub目錄當中建立,可以儲存文字檔案,css,js檔案
模板
模板是一個文字,用於分離文件的表現形式和內容
在rub目錄下建立templates資料夾,屆時Django在通過URL尋找時會直接在此資料夾中找到對應的網頁檔案,在template資料夾下新建一個app資料夾
建立的index.html檔案如下
<!DOCTYPE html>
<html lang="cn">
<head>
<meta charset="UTF-8">
<title>垃圾分類管理</title>
</head>
<body>
<h2>垃圾分類管理</h2>
{% include 'app/upload.html' %}
</body>
</html>
{% include %} 標籤允許在模板中包含其它的模板的內容。
upload.html檔案如下:
<!DOCTYPE html>
<html lang = "en">
<head>
<meta charset = "UTF-8">
<meta name = "viewport" content = "width = device-width,initial-scale=1.0">
<title> Document </title>
</head>
<body>
<h2>檔案上傳 </h2>
<form action = "{% url 'upload1' %}" method = "post" enctype="multipart/form-data">
{% csrf_token %}
圖片序號:<input type = "text" name = "title"/><br/><br/>
請上傳需要識別的圖片:<input type = "file" name = "pic"/><br/><br>
<input type = "submit" value = "上傳"/>
</form>
</body>
</html>
這裡只講解一下csrf
csrf_token 用於form表單中,作用是跨站請求偽造保護。
如果不用{% csrf_token %}標籤,在用 form 表單時,要再次跳轉頁面會報403許可權錯誤。
用了{% csrf_token %}標籤,在 form 表單提交資料時,才會成功。
至於其他的就是html語言的學習了,這裡只簡要講解一下
在表單當中,input標籤後面跟對應的type屬性,可以上傳相關的資料到後面的name鍵位當中
{% url 'upload1' %}是反方向解析URL,這裡會直接將我們輸入的資訊提交到uoload1URL當中,然後會啟用對應的檢視層,也就是說我們提交的圖片最終會傳到upload1函式中.
我們在上文當中提到的配置path路徑中的name就是這樣的作用,這裡圖片上傳的name是'pic'對應於我們在上文方法中引用的FILE.get中的引數
最後一個result介面
<html>
<div>
<p>垃圾分類的結果是:{{ result }}</p>
</div>
</html>
這裡對應檢視層當中upload1方法,大家不妨轉到檢視層當中再看一下upload1函式
最後其返回的是render方法,然後返回的是result介面
在這裡{{result}}是在html'中定義的一個變數,我們通過render方法可以用lable文字來代替
最後實現的結果如圖所示
我們只需要上傳圖片,然後提交利用我們自己寫的垃圾分類識別程式碼即可得到對應的結果
這裡我們提交上我們想要識別的圖片
結果
今天的教程就到這裡,創作不易,謝謝大家的鼓勵和支援╰(°▽°)╯