本文作者:Eric
作者 Github : https://github.com/Ratherman
自由團隊將從0到1 手把手教各位讀者學會(1)Python基礎語法、(2)Python Web 網頁開發框架 – Django 、(3)Python網頁爬蟲 – 周易解夢網、(4)Tensorflow AI語言模型基礎與訓練 – LSTM、(5)實際部屬AI解夢模型到Web框架上。
AI . FREE Team 讀者專屬福利 → Python Basics 免費學習資源
探討 Models, Views, 與 Urls 之間的交互。
我們在昨天利用了 Django Shell Command 做了一連串的資料庫的增刪改查,而在前幾天,我們也有看到 urls.py 和 views.py 之間的互動,不過我們在當時因為資料庫不存在,所以在呈現上就只有用到已經被決定的字串。我們今天,將以前兩天的內容做為基底,繼續延伸,看看該如隨著資料庫的內容,做到頁面內容的動態調整。
先從 demo_app/ urls.py 開始看,如果沒有大家沒有特別去做改動的話,這是我們在第六天的成果。
from django.urls import path from demo_app import views urlpatterns = [ path("Confucianism", views.confucianism_detail, name="confucianism"), path("Taoism", views.taoism_detail, name="taosim") ]
在 runserver 之後(i.e. 於虛擬環境中執行 python manage.py runserver
),開啟瀏覽器並點選下方兩個 URL,就可以看到對應的頁面顯示:
Confucianism 是儒家的英文
Taoism 是道家的英文。
在 urlpatterns 裡面,我們用了 path 的第一個 argument 來做到導引至特定位置的功能,不過其實我們可以對第一個 argument 多做一些事情,我們可以利用它傳變數,假設我們想要透過 path 幫我們把學派的幸運數字傳給 view 的話,我們需要對 path 的 argument 動一點手腳。
from django.urls import path from demo_app import views urlpatterns = [ path("Confucianism/<int:lucky_number>", views.confucianism_detail, name="confucianism"), path("Taoism/<int:lucky_number>", views.taoism_detail, name="taosim") ]
我們在學派名後面,多加了 <int:lucky_number>
,urls.py 在接收到 HttpRequest 之後,就會連同 HttpRequest 和型別為int的 lucky_number 傳給對應的 view。注意,我們目前的 view 還沒有新增額外的 input variable 來接受 lucky_number 這個 integer,所以我們需要將 demo_app/ views.py 的 input variable 擴充為兩個(原本只有一個專門用來接受 HttpRequest 的),特別針對 int 的變數在這邊必須命名為 lucky_number,這樣才能和 view.py 串在一起。
from django.shortcuts import render from django.http import HttpResponse # Create your views here. def taoism_detail(request, lucky_number): #擴充 input variable return HttpResponse(f"Taoism 是道家的英文。道家的學派的幸運數字是{lucky_number}") def confucianism_detail(request, lucky_number): #擴充 input variable return HttpResponse(f"Confucianism 是儒家的英文。儒家的學派幸運數字是{lucky_number}")
如果 server 有 run 起來,就可以看到類似的結果。於 http://127.0.0.1:8000/demo_app/Confucianism/12 看到的畫面如下。
除了上面提到的方式可以傳沒有什麼實質用處的 luncky number 之外(笑),跟資料庫最直觀的操作就是將 lucky number 所代表的數字當作是資料表格 primary key (主鍵),大家不需要覺得這個很陌生喔,因為其實我們已經有在昨天的 Django Command Shell 就算是看過它了,只是後來覺得它的呈現有點不直覺,所以很快地就把它換成其他種呈現方式,
>>> School.objects.all() # 更改前 <QuerySet [<School: School object (1)>, <School: School object (2)>]> >>> School.objects.all() # 更改後,詳情請參考第七天的內容 <QuerySet [<School: Taoism>, <School: Confucianism>]>
上面的 (6) 和 (7) 表示的就是那筆資料的 primary key (主鍵),主鍵代表的是在資料表格中,可以用來獨一無二地代表該筆完整的資料的數值,而針對 school,完整的資料有: school_name,core_value, num_member, 也就是我們在 models.py 所定義的那些 field。
接下來會需要用到資料庫的資料,包含學派(School)、以及古人(Ancient People),所以如果目前大家發現自己的資料庫沒有像是下方的回傳值的話,先請大家 create 一下資料喔。
... / ... / DI_project>python manage.py shell Python 3.7.4 (default, Aug 9 2019, 18:34:13) [MSC v.1915 64 bit (AMD64)] on win32 Type "help", "copyright", "credits" or "license" for more information. (InteractiveConsole) >>> from demo_app.models import Ancient_People, School >>> School.objects.all() #學派的回傳值 <QuerySet [<School: Confucianism>, <School: Taoism>]> >>> Ancient_People.objects.all() #古人的回傳值 <QuerySet [<Ancient_People: Confucius>, <Ancient_People: Mencius>, <Ancient_People: Xunzi>, <Ancient_People: Lao Tzu>, <Ancient_People: Zhuangzi>]>
觀察下會發現與昨天提供的表格是相符合的。下方正式進入今日重點。
內容:
調整 urls.py
新增 template 及 html
調整 views.py
Run Server
在上面,為了顯示 url 可以用來傳變數,所以將命名設為 lucky_number,但我們等一下想要做的事情是,透過這個變數,幫我們找到特定學派裡面的某位古人資料,我們需要這個變數作為那位古人的 id,所以把 lucky_number 換成更適合的名字,改成 id。
打開 demo_app/ urls.py,並修改成以下內容。
from django.urls import pathfrom demo_app import views urlpatterns = [ path("Confucianism/<int:id>", views.confucianism_detail, name="confucianism"), path("Taoism/<int:id>", views.taoism_detail, name="taosim") ]
這邊修成 id 之後,views.py 裡面兩個class的 input argument 也要從 lucky_number 變成 id(兩邊的變數名稱需要一致)。這個我們待會兒會再做,大家也可以先修改喔!
這邊需要 html 檔案幫我們做網頁的呈現,原因是 html 可以讓畫面豐富度的呈現上,大於原先的字串使用。我們需要先新增此檔案,而如果要在 Django Project 使用 html 作為畫面上的呈現,有一套預設的規則:
html 的檔案路徑需要是 APP_NAME/ templates/ APP_NAME/ test.html
簡單來說,就是要在 APP Folder 內(i.e. demo_app)新增一個資料夾,資料夾必須叫做 templates
templates 之下需要再建立一個 APP_NAME(i.e. demo_app) 的資料夾
最後再最裡面的資料夾內新增一個 html 檔
這邊我們建立 2 個 html 檔,一個是 ancient_people.html,另一個是 not_found.html,這裡的命名就可以任意,這邊可以取自己喜歡的名字。建立完之後,整個專案的結構會長得像是這樣:
DI_project/
DI_project/...
demo_app/ # APP Folder
apps.py
views.py
urls.py
...
templates/
demo_app/ # APP_NAME
ancient_people.html
not_found.html
manage.py
manage.py
建立了兩個檔案之後,先將下面的內容分別寫到 ancient_people.html,和 not_found.html 內。
demo_app/ templates/demo_app/ancient_people.html
<h1>{{name}}</h1> <h3>Age: {{age}}</h3> <h2>Statement</h2> <p>{{statement}}</p>
demo_app/ templates/demo_app/not_found.html
<h1>{{message}}</h1>
微介紹下 html 檔案的特性,html 檔案其實也算是個文字檔,只是它可以透過給予不同文字區塊不同的 (標籤),來讓文字有不一樣的呈現方式,我們之後會更詳細地來建立一個完整的html檔,因為我們今天的目的是串接資料庫內的資料,所以就只說明有用到的 tag 的功能吧。
<h1></h1>
將內容以一號大小的字體顯示出來,字會比一般沒有調整的字大。
字的大小 h1 > h2 > h3
<p></p>
*paragraph 的意思,文字不會有特別的變化,在這邊只是單純的一段文字
在 html 檔案裡面可以設定那些希望能夠動態調整的內容,既然我們要使用的資料是來自於 Ancient People 這個 model,那我們希望會自動調整的內容,自然就會是「古人名字」、「古人歲數」、和「古人言論」在 html 裡面,針對這種需求,我們只需要在變數外面多加上兩層大括號(i.e. {{ variable }}),這些變數就會變成這個 html 設定好的 input variables,所以我們等等在處理 views.py 的時候就要記得把這些變數傳出去(給 html)。
特別再寫一個 not found 的 html 是因為並不是每個任意的數字都可以對應到一個古人(極端一些的例子就是,id=100的情況),所以算是用一個蠻簡單的方式去避免掉找不到古人資料所以錯誤的情況。當然,還有更好的方式可以處理,這個我們就有機會再去處理吧!
根據上方在 urls.py 和 html 的設計,我們的 views.py 需要有以下的處理:
改變 input variable 的命名,用來接收來自 url 的變數
調整 output 給 html 的內容,需要包含 name, age, statement
將以下內容加到 demo_app/ views.py
from django.shortcuts import render from django.http import HttpResponse from .models import School # Create your views here. def taoism_detail(request, id): #return HttpResponse(f"Taoism 是道家的英文。道家的學派的幸運數字是{lucky_number}") school = School.objects.get(school_name="Taoism") ancient_person = school.ancient_people_set.filter(id=id) if len(ancient_person) == 1: result = school.ancient_people_set.get(id=id) return render(request, "demo_app/ancient_people.html", {"name":result.name, "statement":result.statement, "age":result.age}) elif len(ancient_person) != 1: return render(request, "demo_app/not_found.html", {"message": "Person not found"}) def confucianism_detail(request, id): #return HttpResponse(f"Confucianism 是儒家的英文。儒家的學派幸運數字是{lucky_number}") school = School.objects.get(school_name="Confucianism") ancient_person = school.ancient_people_set.filter(id=id) if len(ancient_person) == 1: result = school.ancient_people_set.get(id=id) return render(request, "demo_app/ancient_people.html", {"name":result.name, "statement":result.statement, "age":result.age}) elif len(ancient_person) != 1: return render(request, "demo_app/not_found.html", {"message": "Person not found"})
兩個方法的內容大同小異,我們看儒家(def confucianism_detail
)這個方法,首先確認 input argument 這邊有調整成可以接收來自 url 的變數內容(id),再來看看 return 的內容。我們在這邊使用到了 render
的方法,render 內會需要包含三個變數:
HttpRequest: 這部分的機制Django 幫我們處理的很好了,在這只需要提供 request 就好了
Template 位址: 還有印象在建立 html 檔案的時候,我們有先新增 templates 這個資料夾嗎? Django 在 render
的時候預設會找 templates/ 內部的 html 檔案,所以我們在這邊就只需要寫 demo_app/ ancient_people.html
就可以了。
傳給 template 的變數內容: 型別為 dictionary
。我們就是在這邊將資料傳給 html 的,在這個 dictionary
的資料結構裡面,key (鍵值)需要和 html 裡面被兩層大括號(i.e. {{variable}})包住的變數名稱一致。
至於要把什麼樣的值放在 key 後面,就是 confucianism_detail
裡面要處理的事情了,這邊和前幾天在 Django Shell Command 用到的方法其實很像,我們先用 School.objects.get() 的方法,將儒家的 School Object 取到,再來才透過關聯的方式(ancient_people_set),取到特定id的古人 Object。
再這邊我們多追加一個上次在 Django Shell Command 沒有特別提到的內容。
School.objects.filter()
和 School.objects.get()
的區別filter()
出來的東西
型別是 queryset
概念上可以當作是 object 構成的陣列,所以在上面的程式碼中有看到條件判斷處,使用了 len(queryset)
,其結果即表示 queryset 內部有幾個 object。
想要看到 data 的特定欄位資訊,要先指定 queryset 的第幾個 object。舉例而言,將利用 filter() 的方式得到的 queryset 給一個變數(ex: query_set_demo
), 然後我們再指定一個 object,如第一個object 就會是 query_set_demo[0],剩下的操作就和一般 object 一樣了,可以參考下面的內容。
get()
出來的東西
型別是 object
如果想要看到 data 的特定欄位資訊,只能用 object,舉例而言,我們想看到學派的名稱,就需要先用 get()
的方式把 object 取到並給一個變數(ex: school_demo),school_demo.school_name 才會是我們的目標。
在最後,我們就來看看今天的成果吧。先把 server run 起來,然後再打開瀏覽器至對應的url看看結果。
$ python manage.py runserver
Note: 大家可以換換url最後的數字(id),這邊的 id 和最初 create 的順序相關,和同樣的 id 看到的結果沒有相同是正常的喔。
儒家學派的某位古人(id = 1)
道家學派的某位古人(id = 5)
沒有此人的 case:
在今天我們將資料庫的資料串接到頁面的呈現上,我們也建立了最基本但堪用的html作為我們的render時的template,另外,在現在有用到 html 的部分,我們未來都會用到 bootstrap 這個常見的網頁前端框架做一個升級版本,預計會和大家一起設計一個美美又好用的頁面(template)。明天的部分,我們會深入網頁後端的部分,目標為做出資料的增刪改查端口(API),然後再用 Django rest framework 發出 HTTP Request,詳情我們就明天再看看吧!
自由團隊 官方網站:https://aifreeblog.herokuapp.com/
自由團隊 Github:https://github.com/AI-FREE-Team/
自由團隊 粉絲專頁:https://www.facebook.com/AI.Free.Team/
自由團隊 IG:https://www.instagram.com/aifreeteam/
自由團隊 Youtube:https://www.youtube.com/channel/UCjw6Kuw3kwM_il39NTBJVTg/
文章同步發布於:第十二屆 IT 挑戰賽部落格