iT邦幫忙

第 12 屆 iThome 鐵人賽

DAY 8
0
自我挑戰組

零基礎成為 AI 解夢大師秘笈系列 第 8

【零基礎成為 AI 解夢大師秘笈】Day08 - Django V

  • 分享至 

  • xImage
  •  

斜槓學習 – 零基礎成為 AI 解夢大師秘笈

前言

系列文章簡介

大家好,我們是 AI . FREE Team - 人工智慧自由團隊,這一次的鐵人賽,自由團隊將從0到1 手把手教各位讀者學會 (1)Python基礎語法 (2)Python Web 網頁開發框架 – Django (3)Python網頁爬蟲 – 周易解夢網 (4)Tensorflow AI語言模型基礎與訓練 – LSTM (5)實際部屬AI解夢模型到Web框架上。

為什麼技術要從零開始寫起

自由團隊的成立宗旨為開發AI/新科技的學習資源,提供各領域的學習者能夠跨域學習資料科學,並透過自主學習發展協槓職涯,結合智能應用到各式領域,無論是文、法、商、管、醫領域的朋友,都可以自由的學習AI技術。

資源

AI . FREE Team 讀者專屬福利 → Python Basics 免費學習資源

今日目標

  • 探討 Models, Views, 與 Urls 之間的交互。

教學開始

我們在昨天利用了 Django Shell Command 做了一連串的資料庫的增刪改查,而在前幾天,我們也有看到 urls.py 和 views.py 之間的互動,不過我們在當時因為資料庫不存在,所以在呈現上就只有用到已經被決定的字串。我們今天,將以前兩天的內容做為基底,繼續延伸,看看該如隨著資料庫的內容,做到頁面內容的動態調整。

1 傳變數的 url

先從 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,就可以看到對應的頁面顯示:

在 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 看到的畫面如下。https://ithelp.ithome.com.tw/upload/images/20200923/201307122UYXCVPnB7.png

2 確認資料庫資料齊全

除了上面提到的方式可以傳沒有什麼實質用處的 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>]>

觀察下會發現與昨天提供的表格是相符合的。下方正式進入今日重點。

下方目標: 將某位古人的資料以 html 呈現在網頁上。

內容:

  • 調整 urls.py
  • 新增 template 及 html
  • 調整 views.py
  • Run Server

3 調整 urls.py

在上面,為了顯示 url 可以用來傳變數,所以將命名設為 lucky_number,但我們等一下想要做的事情是,透過這個變數,幫我們找到特定學派裡面的某位古人資料,我們需要這個變數作為那位古人的 id,所以把 lucky_number 換成更適合的名字,改成 id。

打開 demo_app/ urls.py,並修改成以下內容。

from django.urls import path
from 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(兩邊的變數名稱需要一致)。這個我們待會兒會再做,大家也可以先修改喔!

4 新增 template 及 html

這邊需要 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

建立了兩個檔案之後,先將下面的內容分別寫到 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的情況),所以算是用一個蠻簡單的方式去避免掉找不到古人資料所以錯誤的情況。當然,還有更好的方式可以處理,這個我們就有機會再去處理吧!

5 調整 views.py

根據上方在 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 才會是我們的目標。

6 Runserver

在最後,我們就來看看今天的成果吧。先把 server run 起來,然後再打開瀏覽器至對應的url看看結果。

$ python manage.py runserver

Note: 大家可以換換url最後的數字(id),這邊的 id 和最初 create 的順序相關,和同樣的 id 看到的結果沒有相同是正常的喔。

https://ithelp.ithome.com.tw/upload/images/20200923/20130712LHxdDx9VQo.png

7 邁向 AI 解夢大師 - 第八天

在今天我們將資料庫的資料串接到頁面的呈現上,我們也建立了最基本但堪用的html作為我們的render時的template,另外,在現在有用到 html 的部分,我們未來都會用到 bootstrap 這個常見的網頁前端框架做一個升級版本,預計會和大家一起設計一個美美又好用的頁面(template)。明天的部分,我們會深入網頁後端的部分,目標為做出資料的增刪改查端口(API),然後再用 Django rest framework 發出 HTTP Request,詳情我們就明天再看看吧!

8 參考連結

想更深入認識 AI . FREE Team ?

自由團隊 官方網站: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/

文章同步發布於:自由團隊部落格
(想看更多文章?學習更多AI知識?敬請鎖定自由團隊的頻道!)


上一篇
【零基礎成為 AI 解夢大師秘笈】Day07 - Django IV
下一篇
【零基礎成為 AI 解夢大師秘笈】Day09 - Django VI
系列文
零基礎成為 AI 解夢大師秘笈30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言