2020年11月24日 星期二

程式員的區塊鏈好書

最近注意到一則關於數位貨幣的新聞, 說中國人行正緊鑼密鼓準備讓人民幣數位化, 其長遠戰略目標是擺脫美元束縛, 並企圖建立起人民幣支付的數位金融霸權云云, 參考 : 


這就挑起了我對區塊鏈的興趣, 數位貨幣底層的技術是區塊鏈, 看來這已經是非常成熟且正在運行的金融科技, 我好奇是否有哪些書可讓程式員實際參考學習的區塊鏈實作書籍? 今天花了點時間調查了一下, 發現下面這幾本值得一讀 : 

1. Hands-On Blockchain for Python Developers (2019, Packt)


Source : 天瓏


與傳統使用類似 Javascript 的 Solidity 語言不同, 此書使用與 Python 語法極為類似的 Vyper 語言來撰寫智慧合約, 此語言是以太坊共同創辦人布特林 (Vitalik Buterin) 以 Python 為藍本為智慧合約開發的語言. Vyper 與 Solidity 的差異參考 : 

類 Python 的合約語言 Vyper 開發入門:與 Solidity 差異、用 Truffle 部署、ERC20 賣幣合約實做


2. Learn Blockchain Programming with JavaScript  (2019, Packt) :

這本書是我認為最適合熟悉 Javascript 的網頁程式設計師看的區塊鏈入門書, 介紹如何使用 Javascript 與 Node.js 建構自己的區塊鏈原型與去中心化網路, 在此網路中不僅可挖掘新的區塊, 也可以建立不可變更的交易, 透過書中範例可以徹底了解區塊鏈技術的底層是如何運作的. 


Source : 天瓏

3. Beginning Ethereum Smart Contracts Programming: With Examples in Python, Solidity, and JavaScript (Apress, 2019)

此書作者是新加坡知名區塊鏈技術訓練機構 Developer Learning Solution 創辦人李孟韋, 也是 Oreilly 多本暢銷書作家. 此書使用 Python, Javascript, 以及 Solidity 語言為例介紹如何撰寫乙太幣的智慧契約, 可讓讀者不需閱讀大批文件而能快速上手. 


Source : 天瓏

2020年11月23日 星期一

好書 : Building a websie with Django 3

此書為澳洲出版商 NGW 出版的 Django 3 書籍, 作者以淺顯的範例說明 Django 3 架站的步驟, 我覺得是目前寫得最好的一本 Python Web 入門書, 例如為什麼 Django 會有上下兩層專案目錄 (Ans :下層才是真正的專案目錄, 上層只是容器可以隨意改名)? 為什麼用 startapp 建立 App 時不會在其目錄下自動產生 App 的路由器程式 urls.py (Ans : 不是每個 App 都需要 View) ? 這些問題應該都曾掠過每個學習者心頭, 但答案我在別本書上從來沒讀過, 所以這是非常不錯的一本書 :


Source : Amazon


此書副標題 "Go from zero knowledge to your own website using the easiest to learn programming language on the Internet (讓門外漢以最簡單的方式在互聯網學習程式語言並建立自己的網站)" 確實所言不虛. 

2020年11月22日 星期日

市圖還書 1 本

本周市圖還書一本 (有人預約) : 

  1. 最聽話的人最先被淘汰 : 當學校所教的九成都是洗腦, 「渾然忘我力」才是網路世代的關鍵競爭力! /

但早上去還一本, 卻借回兩本 Python 的書 (GUI + 機器學習), 反而越借越多了. 


2020 年第 47 周記事

今天下午突然接到老張電話, 說剛協助南屏別院童軍活動來鄉下拔蘿蔔, 想來坐一下聊天, 我想那真是太好了, 趕緊切好水果恭候大駕, 昨日本來與大帥老張等約好見面, 卻因為周五接到養護中心電話說吾妹阿蘭發燒送醫, 所以下午就請假回鄉下處理住院事宜, 並通知大帥我無法赴約. 

阿蘭因反覆尿路感染住院此次為今年第五次, 同樣一對多無床位改健保房, 打給上回木棉花的看護潘大姊, 她說在忙就推薦另一位同鄉鍾大姊, 雖然第一次做看護較無經驗, 但人挺好. 

週五晚上上二樓書房找東西, 在抽屜裡找到以前的信件, 坐在地上一封封打開來看, 有許多以前我離開旭青後同事寄來的信, 後來不知為何疏於連絡都斷了音訊, 有些名字都已經忘了, 看了信才回想起那些快要遺忘的過往青澀歲月. 還有那個常寫字條給我的國中女同學年年寄來的賀卡, 唉, 看完突然覺得欠了很多債. 旭青的室友周宗榮給我的信也讓我很感傷, 他是真正可以結交的朋友, 但卻這麼早就走了. 

昨日下午去跑步, 跑完經過南側登山口看到有人上山, 我看時間還早就順路爬上去, 等於是往日兩倍運動量, 結果今天下午剛跑出去就覺得肌肉痠痛, 只好折返. 昨日回程剛好遇到國中同學劉老師剛辦完拔蘿蔔活動, 跟他聊了一下, 原來已從老師崗位退休五年改為務農, 令我羨慕不已, 真後悔當初沒聽外婆的勸告去讀屏師, 要不然我現在也跟他一樣爽退了, 哈哈哈. 

昨天早上起來發現洗衣機似乎沒正常洗完, 正納悶時才聽爸說好像自來水沒進樓上水塔, 趕緊從備用水池抽水, 原來水壓不足, 洗衣機也罷工. 今天早上跟爸去對面張家伙房門口查看自來水表, 發現果然有漏水, 門口的柏油是新鋪的, 據阿清伯母說上周有人來施工鋪新柏油路面, 恐怕是壓路機把水管壓壞了, 連榮彩伯也說他們家自來水水量變少, 要找當水電工姪子來勘查一下了. 

傍晚取消跑步改到樓上鑽水桶, 前年為了儲存雨水在資材行買的 "天x" 牌大儲水桶不中用, 上個月爸發現中間出現一個口字型破口, 應該是塑膠不耐熱裂開所致 :



剛好佃耕的阿正兄載了好幾個中型水桶放在我家後院, 我就跟他要了兩個, 上個月抬上頂樓後一直沒空施工, 今天早上去小漢買了出水口接頭, 趁著天黑前把洞鑽好 : 





我還沒買鑽孔器, 所以只好用電鑽附的小鑽頭鑽很多洞, 再慢慢打穿. 下周再把出水接頭安裝上去, 然後改接管路. 我覺得以後在設計智慧家居時要把水塔水量也納入監控對象, 避免水塔沒水都不知道. 

住家大樓的電梯原訂本周一到五施工更換鋼索主機板等, 上下班, 買東西, 倒垃圾等出入麻煩, 要搭別棟電梯到頂樓, 越過頂樓曬衣場再走樓梯下到我家樓層真的好不方便, 所幸工程提早於周四完成, 下班回到樓下發現已可使用, 全新的控制板有開延長對拿信, 搬東西都很方便. 

本周沒在追韓劇了, 努力學習 Django 中 .... 

好書 : 最聽話的人最先被淘汰

這本書借了很久了, 但都斷斷續續地看, 最近發現有人預約此書, 所以就認真看完並做了簡單的筆記摘要. 真的, 如果沒有人跟我搶書, 還不知要放到何時才真的算看完.



Source : 博客來


此書作者是日本商業怪才崛江貴文, 也是日本知名入口網站活力門 (東京證券交易所上市公司) 的前老闆. 雖然他後來因不實財報事件遭到判刑, 但行事作風總是異於日本社會常軌的他, 其實許多想法還蠻值得參考的. 讀後摘要如下 :
  1. 在網路時代 G (Global) 人才比 L (Local) 人才更具優勢. G 人才以存取的能力來豐富自己的生活, 重視的是資訊判讀; 而 L 人才則是以擁有為基礎, 重視的是具體可見的東西. G 人才最大的特徵是從擁有的思維中解放, 不把價值寄託於擁有之中. 當人們掙脫金錢, 學歷, 地位的束縛時, 就邁向了 G 人才的世界.  
  2. 學校與公司都是洗腦機關, 是讓人變成聽話的笨蛋的場所, 會徹底扼殺人們渾然忘我學習的能力. 學習的可能性其實海闊天空, 不需要學校, 老師, 教科書, 網路的時代每個人都可以更自由, 更渾然忘往地開拓自己的視野, 不要畏懼握住方向盤, 勇敢地踩下油門就對了, 想做的事盡管去做就對了, 不想做的不要勉強去做. 
  3. 希望讀者都能丟掉為了以備不時之需, 應當儲蓄金錢, 學歷, 證照, 技術的錯誤觀念. 以忍耐, 節約為基礎的儲蓄型思考不會為你帶來好處. 儲蓄型思考懶得做價值思考; 而投資型思考則努力於決斷對未來之預測. 投資型思考的人重視的是時間與費用的性價比.
  4. 在公司工作到 65 歲, 然後就靠年金過生活, 這樣的人生設計圖已經太陳舊了. 人生班表應該調整為 "開心持續喜愛的工作, 一直工作到沒幹勁為止" 比較好, 從十歲到九十歲都能工作. 
  5. 不浪費時間與勞力是投資自我的基本. 浪費了金錢還有補救挽回的機會, 浪費了時間則一去不復返, 因為生命有限, 要把勞力與腦袋花在更有益的事情上面. 
  6. 學歷, 職業, 出身, 證照, 這些都是可以拿掉的標籤而已. 如果我現在是十五歲, 根本不會想去讀高中大學, 我應該會利用網路學習, 結交朋友, 早早創業. 
  7. 抱持 "總之先做點甚麼" 想法的人絕對無法勝過 "很想做" 同樣事情的人.
  8. 以 "工作與生活平衡" 的方式來度過人生其實並無法讓人開心, 應該劃分成 "想做" 與 "不想做" 才對, 人生最開心的是把百分之百的人生投注在想做的事情上, 而非去想著如何平衡, 人生過得極端沒關係, 不平衡也沒關係.  
  9. 做喜愛的事是玩樂不是工作, 做不想做的事那才是工作. 應該把遊戲, 工作, 學習視為一體, 最開心的人生是徹底在工作中玩樂的人生. 

2020年11月19日 星期四

Python 學習筆記 : Django 3 測試 (六) : 應用程式

距離年初學習 Django 已近一年, Django 也從 2 版躍升到 3 版, 最近因為要所借的書被預約了必須在還書前看完, 所以暫時重回 Django 學習軌道, 希望這次能一舉搞定 Django. 以下測試改用最新版的 Django 3, 其實新版最大的亮點是支援非同步, 整體架構並無改變, 只有專案設定檔的絕對路徑用法改變而已. 

本系列之前的筆記參考 : 


Django 2 官方文件參考 :

在之前的測試中, 我們使用 django-admin startproject mysite 指令自動建立了一個名為 mysite 的 Django 網站, 其基本結構如下 :

mysite (上層專案目錄)

     |____ manage.py
     |____ mysite  (下層案目錄)
                   |_____ __init__.py
                   |_____ settings.py
                   |_____ urls.py
                   |_____ wsgi.py

接著在上層專案目錄下添加模版目錄 (templates) 與靜態檔案目錄 (static), 這個 templates 目錄就是 Django MTV 架構中的 T (Template) :

(venv) D:\django\venv\mysite>mkdir templates 
(venv) D:\django\venv\mysite>mkdir static   
(venv) D:\django\venv\mysite>cd static   
(venv) D:\django\venv\mysite\static>mkdir images    
(venv) D:\django\venv\mysite\static>mkdir css     
(venv) D:\django\venv\mysite\static>mkdir js     

然後在下層專案目錄下添加處理呼叫與回應處理程式 views.py (對應 Django MTV 架構中的 V), 最後修改路由器程式 urls.py 即可讓網頁應用程式網站運作起來, 完整之檔案結構如下 : 

mysite (上層專案目錄)
     |____ manage.py
     |____ templates                 (模版目錄)
     |____ static                        (靜態檔案)
     |             |____ css              (存放 CSS 樣式檔)
     |             |____ js                (存放 Javascript 檔)
     |             |____ images        (存放圖檔)
     |____ mysite                       (下層專案目錄)
                   |____ __init__.py
                   |____ settings.py
                   |____ urls.py         (專案路由器)
                   |____ wsgi.py
                   |____ views.py      (HTTP 請求處理器)

但是直接將網頁應用程式建在專案目錄下的結構不符合軟體工程的要求, 因為由 urls.py 與 views.py 組成的服務控制邏輯與專案緊密結合, 使得應用程式無法重複使用於其他專案. 完整的 Django 網站架構是由是由上層的專案 (Project) 與下層的多個應用程式 (App) 組成, 專案負責設定, App 負責特定之服務邏輯, 且與抽象化的 ORM 資料庫存取機制結合以建立動態網站. 

App 是 Django 專案中具有獨立功能的可插拔元件, 亦即可將網頁專案的服務邏輯按照功能切割為數個 App 以符合軟體工程中元件可重用 (reusable) 之要求, 每一個 App 可以在最小程度的調整後移植到其他專案中使用. 例如一個購物網站的功能可以由會員登入, 商品列表, 購物車以及結帳等 App 組成. 

建立一個 App 可在第一層專案目錄下輸入如下指令 : 

python manage.py startapp <AppName>

例如 :

(venv) D:\django\venv\mysite>python manage.py startapp helloworld
(venv) D:\django\venv\mysite>dir  
 D:\django\venv\mysite 的目錄

2020/11/18  下午 04:47    <DIR>          .
2020/11/18  下午 04:47    <DIR>          ..
2020/11/14  下午 10:55                 0 db.sqlite3
2020/11/16  下午 03:25    <DIR>          helloworld
2020/11/14  下午 08:52               684 manage.py
2020/11/14  下午 10:55    <DIR>          mysite
2020/11/18  下午 04:48    <DIR>          static
2020/11/18  下午 04:47    <DIR>          templates

注意, App 與 static 與 templates 是第一層專案目錄下平行的子目錄. 此外, 建立 App 會在第一層專案目錄下建立一個 db.sqlite3 檔案與一個 helloworld 目錄, 前者為 Django 預設使用的單一檔案關聯式資料庫; 後者則是 App 的目錄, 其底下檔按結構為 : 




可見建立 App 時會自動在該 App 目錄自動產生 views.py 程式檔, 而以前直接在專案下建立應用程式時則須自行在第二層專案目錄 mysite 底下手動建立 views.py, 使用 App 架構的話就不需要了. App 目錄底下的檔案與子目錄之用途如下 :


 App 檔案目錄 說明
 migrations 紀錄與資料庫版本與資料模型變更相關之檔案 (用來同步模型與資料庫)
 __init__.py 空檔案, 使 App 目錄形式上符合 Python 套件要求
 admin.py 用來註冊資料模型以便能於管理網頁中管理資料表
 apps.py 儲存與此 App 相關之設定
 models.py 儲存 App 資料模型定義以及資料間之關係
 test.py 儲存測試程式碼
 views.py 為 urls.py 處理 HTTP 要求與回應之程式檔


其中有需要動手去修改的只有 admin.py, models.py, 以及 views.py 這三個檔案. 加入 App 後完整的 Django 網站之檔案結構如下 : 

mysite                                      (上層專案目錄)
     |____ manage.py                (管理程式)
     |____ templates                  (模版目錄)
     |____ static                         (靜態檔案)
     |             |____ css               (存放 CSS 樣式檔)
     |             |____ js                 (存放 Javascript 檔)
     |             |____ images         (存放圖檔)
     |____ mysite                        (下層專案目錄)
     |             |____ __init__.py   (形成套件)
     |             |____ settings.py    (專案設定檔)
     |             |____ urls.py           (專案路由器)
     |             |____ wsgi.py         (伺服器佈署設定檔)
     |____ myapp                         (應用程式目錄)
                   |____ migrations     (資料庫同步)
                   |____ __init__.py    (形成套件)
                   |____ admin.py       (註冊資料模型)
                   |____ apps.py         (App 設定檔)
                   |____ models.py     (資料模型定義)
                   |____ test.py           (測試用程式)
                   |____ views.py        (HTTP 請求處理器)

注意, 此結構是所有 App 都使用專案路由器來將 URL 映射到請求處理器, 

建立 App 後須先如下設定與程式修改才能正常運行 :


1. 修改 settings.py 設定檔 :   

建立 App 後須先修改第二層專案目錄下的 settings.py (專案設定檔), 需要改的地方基本上有四個 :
  • INSTALLED_APPS : 註冊所建立之 App 名稱
  • LANGUAGE_CODE : 將預設英文 en-us 改為繁體中文的 zh-Hant
  • TIME_ZONE : 將預設 UTC 改為 Asia/Taipei
  • TEMPLATES : 指定網頁模板路徑
INSTALLED_APPS 是一個串列變數, 其中 django.contrib 開頭的是 Django 內建的應用程式, 自訂的 App 名稱就直接加到最後面即可 : 

# Application definition
INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'helloworld',
]

在 INSTALLED_APPS 中註冊 helloworld 這個 App 後, Django 才會載入這個應用程式. 

其次是修改 LANGUAGE_CODE 與 TIME_ZONE 變數, 修改如下 : 

LANGUAGE_CODE = 'zh-Hant'
TIME_ZONE = 'Asia/Taipei'

修改模版變數 TEMPLATES, 把原先空白的 'DIR' 屬性設為 templates 子目錄之絕對路徑 :

'DIRS': [BASE_DIR / 'templates')],

最後在 STATIC_URL 變數底下添加一行指定靜態目錄之絕對路徑 : 

STATIC_URL = '/static/'
STATICFILES_DIRS = [BASE_DIR / 'static'),]   

注意, 在 Django 2.x 的 settings.py 中使用 os.path.dirname() 來取得網站根目錄絕對位址, 然後用 os.path.join() 組合出檔案之絕對路徑, 但在 Django 3 已經不需要這麼做了, 直接用 BASE_DIR 串接即可, 參考 :


最後將 settings.py 存檔即完成設定.  


2. 修改路由器 urls.py : 

第二層專案目錄下的 urls.py 負責處理 HTTP 請求的路由 (routing), 將來自客戶端的 URL 請求指配給 App 目錄下的 views.py 處理並做出回應. 建立專案後預設的 urls.py 內容如下 :

from django.contrib import admin
from django.urls import path

urlpatterns = [
    path('admin/', admin.site.urls),
]

這個預設的 urls.py 已經幫我們匯入兩個內建 App : 後台管理模組 admin 以及路由指派模組 django.urls 的 path(), 後台管理程式的 URL 在本機為 127.0.0.1/admin, 對應到 path() 的第一參數 'admin/', 它被指派給 admin.site.urls 這個內建 App 處理. 

對於我們新建的應用程式 helloworld 來說, 只要在串列變數 urlpatterns 中為此 App 添加路由指派即可, 例如 :

from django.contrib import admin
from django.urls import path
from helloworld.views import helloworld

urlpatterns = [
    path('admin/', admin.site.urls),
    path('helloworld/', helloworld),  
]

首先從 helloworld 目錄下的 views.py 匯入其 helloworld() 函數, 然後將 URL 'helloworld/' 指派給 helloworld() 函數去處理 (即回應此請求), 如果在本機要請求此 App 服務需使用 127.0.0.1:8000/helloworld 這個網址. 


3. 修改請求處理程式 views.py : 

開啟 App 目錄底下的 views.py 檔, 其預設內容如下 : 

from django.shortcuts import render

# Create your views here.

可見它已預先從內建的捷徑模組 django.shortcuts 匯入渲染方法 render(), 但此 render() 方法是用來渲染模版的, 如果只是要回應 Hello World 字串, 其實只要用 django.http.HttpResponse() 方法即可, 因此可將 views.py 修改為 : 

#views.py
from django.shortcuts import render
from django.http import HttpResponse

def helloworld(request): 
    return HttpResponse('<b>Hello World! <i>您好</i></b>')

此處定義一個呼叫 HttpResponse() 方法並傳回其結果的函數 helloworld(), 此函數即專案目錄下的路由器程式 urls.py 中 URL='helloworld' 所對應之處理函數, 當收到這個 URL 請求時就由 helloworld 函數回應. 

這樣就完成 App 的設定了, 將 views.py 以 utf-8 編碼存檔 (因為用到中文) 存檔後用 python manage.py runserver 指令運行測試伺服器, 這時會顯示有 18 個 migration (資料模型變更) 沒有執行, 由於這個簡單的 App 沒有用到資料庫, 所以還不執行變更也沒關係 :

(venv) D:\django\venv\mysite>python manage.py runserver    
Watching for file changes with StatReloader
Performing system checks...

System check identified no issues (0 silenced).

You have 18 unapplied migration(s). Your project may not work properly until you apply the migrations for app(s): admin, auth, contenttypes, sessions.
Run 'python manage.py migrate' to apply them.
November 18, 2020 - 23:52:23
Django version 3.1.3, using settings 'mysite.settings'
Starting development server at http://127.0.0.1:8000/
Quit the server with CTRL-BREAK.

在瀏覽器網址列輸入 127.0.0.1:8000/helloworld 即可看到網頁輸出結果 :



以上是在 App 架構下使用 django.http.HttpResponse() 方法輸出網頁的基本步驟, 測試專案壓縮檔存放於 GitHub :




不過當網頁內容複雜時用 HttpResponse() 輸出網頁會顯得很雜亂, 實務上 Django 網站使用捷徑方法 django.shortcuts.render() 搭配模版來輸出網頁, 例如可將上面的應用程式 helloworld 輸出的網頁改成如下可傳遞參數的模版網頁 hello.htm :

<!-- hello.htm -->
<!DOCTYPE html>
<html>
<head>
  <title>Hello</title>
  <meta charset="utf-8">
</head>
<body>
  <p class="msg">Hello, {{ name }}, 現在的時間是 {{ now }}</p>
</body>
</html>

將此模版檔案以 utf-8 編碼存檔於第一層專案目錄下的 templates 子目錄下, 然後修改路由器程式 urls.py, 添加 hello 這個附帶參數 name 的 URL :

#urls.py
from django.contrib import admin
from django.urls import path
from helloworld.views import helloworld, hello

urlpatterns = [
    path('admin/', admin.site.urls),
    path('helloworld/', helloworld),
    path('hello/<name>/', hello),
]

然後修改請求處理程式 views.py, 添加 hello 函式, 利用 django.shortcuts.render() 方法將名字 name 與現在時間 now 兩個參數以字典物件傳給模版網頁 hello.htm, 模版引擎會將參數插入網頁中 :

#views.py
from django.shortcuts import render
from django.http import HttpResponse
from datetime import datetime

def helloworld(request): 
    return HttpResponse('<b>Hello World! <i>您好</i></b>')
    
def hello(request, name):
    now=datetime.now()
    dict1={'name': name, 'now': now}
    return render(request, 'hello.htm', dict1)

然後在網址列輸入 127.0.0.1/hello/trump 結果如下 :



修改後的專案壓縮檔存放於 GitHub :


上面的測試雖然把 views.py 放在 App 目錄下, 但路由器卻統一使用專案路由器 (即第二層專案目錄下的 urls.py), 亦即專案中的每個 App 之路由指派全部都集合在專案路由器內, 如果一個專案包含了 App 很多, 則專案路由器就會顯得很雜亂, 而且削弱了 App 的獨立性. 

為了進一步讓 App 更具有可插拔性, 較好的做法是將各 App 的路由指派放在各自的 App 目錄下, 然後在專案路由器中用 django.urls.include() 將其含括進來, 這樣專案路由器內容就很清爽, 專案內有哪些 App 在此檔案中也一目了然, 當 App 要移植到別的專案中使用時也不需要到原始的專案路由器中複製貼上, 只要將 App 目錄複製過去, 然後於新專案的專案路由器中 include 進來即可, 架構如下 : 




可知此架構下會有兩層路由器檔案 urls.py, 即專案路由器與 App 路由器, 前者位於第二層專案目錄下, 後者則位於各 App 之目錄下, 但這個 App 路由器 urls.py 在建立 App 時並不會自動建立, 必須手動從專案路由器 urls.py 複製一份到 App 目錄下修改. 

其次, 對於 URL 的路徑也要加入 App 這一層, 路徑分配如下所示 :

Protocol://Host address/AppName/AppURL/param1/param2/param3...

協定 (Protocol) 為 http 或 https, 主機位址是 IP (例如 127.0.0.1) 或域名 (localhost, www.abc.com 等), 接下來是 App 名稱, App 位址 (在 App 的 urls.py 中映射到 views.py 中的函數), 最後跟著的是可能的參數. 

完整的 URL 會由左至右被一層一層剝掉 (striping), 當 HTTP 伺服器收到請求時, 首先協定與位址會先被伺服器剝除, 剩下 AppName/AppURL/param1/param2/param3... 被送到 Django 的專案路由器處理, 它會在取出 AppName 後將剩下的路徑送給該 App 的路由器, 取出的 AppURL (圖中的 url1) 會被映射到 views.py 中的函數 fun1 處理 (同時將剩下的參數傳入該函數) :




以修改上面的測試 2 為例, 第一步先根據上面的新架構修改 App 的請求處理器 views.y 如下 :

#views.py of App "helloworld"
from django.shortcuts import render
from django.http import HttpResponse
from datetime import datetime

def hello1(request): 
    return HttpResponse('<b>Hello World! <i>您好</i></b>')
    
def hello2(request, name):
    now=datetime.now()
    dict1={'name': name, 'now': now}
    return render(request, 'hello.htm', dict1)

事實上這與上面測試 2 內容一樣, 只是為了讓 URL 路徑更清楚而修改了函數名稱, 原來的 hellowworld() 改為 hello1(); 而 hello() 則改為 hello2() 而已. 

第二步是將第二層專案目錄 mysite 底下的專案路由器程式 urls.py 複製到 App 目錄 helloworld 下, 去除 admin (這屬於專案, App 不需要) 只保留 path 模組即可, 然後定義 App 名稱變數 app_name, 最後在 path() 函數中將 AppURL 映射到 views.py 中的處理函數就完成了, 修改後內容如下 :

#App router : urls.py
from django.urls import path
from helloworld import views

app_name="helloworld"

urlpatterns = [
    path('hello1/', views.hello1),
    path('hello2/<name>/', views.hello2),
]

注意, 此處匯入請求處理器的方式與上面測試 2 不同, 這裡是匯入整個 views 模組而非模組內的函數, 因此映射到函數時前面必須帶上模組名稱. 

最後第三步是修改專案路由器 urls.py, 用 include 把 App 路由器含括進來 :

#Project router: urls.py
from django.contrib import admin
from django.urls import path
from django.urls import include

urlpatterns = [
    path('admin/', admin.site.urls),
    path('helloworld/', include('helloworld.urls')),
]

這樣就全部完成了, 完整的檔案結構如下 :

mysite                                      (上層專案目錄)
     |____ manage.py                (管理程式)
     |____ templates                  (模版目錄)
     |____ static                         (靜態檔案)
     |             |____ css               (存放 CSS 樣式檔)
     |             |____ js                 (存放 Javascript 檔)
     |             |____ images         (存放圖檔)
     |____ mysite                        (下層專案目錄)
     |             |____ __init__.py   (形成套件)
     |             |____ settings.py    (專案設定檔)
     |             |____ urls.py           (專案路由器)
     |             |____ wsgi.py         (伺服器佈署設定檔)
     |____ helloworld                  (應用程式目錄)
                   |____ migrations     (資料庫同步)
                   |____ __init__.py    (形成套件)
                   |____ admin.py       (註冊資料模型)
                   |____ apps.py         (App 設定檔)
                   |____ models.py     (資料模型定義)
                   |____ test.py           (測試用程式)
                   |____ urls.py           (應用程式路由器)
                   |____ views.py        (HTTP 請求處理與回應)


於瀏覽器輸入如下網址 127.0.0.1:8000/helloworld/hello1 結果如下 :



輸入網址 127.0.0.1:8000/helloworld/hello2/trump 結果如下 :



修改後的專案壓縮檔可從 GitHub 下載 :


綜合上述測試總結如下 :
  • Django 3 除了新增非同步功能外, 基本用法與第二版並無差異, 只有在專案設定檔 settings.py 的絕對路徑指派方式不同而已. 
  • 使用 App 在架構上只是將 views.py 從第二層專案目錄移到 App 目錄下, 以及增加資料同步動作而已. 
  • 路由器 urls.py 分離為專案路由器與 App 路由器有助於提升 App 可重用性.
如果是沒有用到資料庫的小型專案, 直接把應用程式寫在專案目錄下 (即不用 App, 控制邏輯 urls.py 與 views.py 都在第二層專案目錄下) 是最簡單的實作方式; 如果要用到資料庫, 則必須使用 App 架構, 功能不複雜只有少數 App 可以直接使用專案路由器; 但若 App 很多且考慮 App 可移植需求的話, 每一個 App 的路由器最好獨立出來, 與專案路由器分開. 

由於篇幅太長, 資料庫存取部分留到下一篇測試. 

2020年11月18日 星期三

2020 年第 46 周記事

時序已過了 46 周, 令人惶惶不安的 2020 只剩 6 周就要掰掰囉. 

姊姊週五回到高雄, 週日晚上回台北, 原本說因為水某生日要去吃飯, 但時間沒喬好就延到下個月. 主要是週六姊姊要燙頭髮, 我要參加公司體育活動. 幸運的是這次在大東公園我又抽到首獎 2000 元, 因為組頭也抽中大獎, 這回沒有人敢起鬨要捐公積金, 哈哈哈! 真爽! 這個大東公園我第一次來, 面積不大, 大概 15 分鐘就可以繞一圈, 園中有人造溪流, 還有幾個生態池, 池邊種了一種藤蔓類開白色花的植物, 本想用形色掃看看名稱, 可惜形色現在要收錢了 : 






周日是小學母校創校 100 周年校慶, 原本在二月底 (228) 要舉辦的, 因為疫情延宕至今. 周六中午爸打電話說他們那班 (28 屆) 寥寥可數, 已無人來邀, 問我是否要去, 趕緊聯繫班長問是否還能報名, 還好班長與現任校長非常熟識, 說沒問題可排入臨時桌. 八點半到校門口不遠處就發現兩旁停車已停到庄口, 只好開到舅公家附近停放. 表演節目蠻豐富, 尤其是金曲獎的得主羅文裕為校慶創作的歌還蠻好聽的. 中午在大操場辦桌, 估計約 200 多桌左右, 因為是臨時報名, 沒辦法跟國小同學同桌, 殘念 ~~~ 






最近鄉下家會有一隻灰色的大貓跑來偷吃小雖貓的糧食而且咬它, 我聽到哀哀叫出去追趕都被它跑掉. 小雖貓吃我在家樂福超市買回去的貓食越長越大, 縱身一躍就能輕鬆爬上屋前的龍眼樹 :




本周看完 16 集韓劇 "大家的謊言" 與 10 集的 "非武裝救援 (Search)", "大家的謊言" 由李宥英 (飾演金議員) 與李民基 (飾演趙泰植警官) 主演, 描述 JQ 財團會長透過政商勾結, 藉推動新能源法搜購土地掩飾之前經營鋼鐵廠時因為污染造成民眾罹患癌症之犯罪行為, 但在趙警官與金議員合作追查下, 終於水落石出. 此劇非常懸疑, 我原先以為的罪魁到最後才發現並不是. "非武裝救援" 由張東潤 (飾演軍犬兵長龍東振) 與鄭秀晶 (飾演化生放司令部特遣隊中尉) 主演, 描述發生在南北韓非軍事區的軍人遇襲失蹤案, 經特種兵組成的北極星特遣隊搜索, 最終揭開 1997 年越北軍官事件的真相. 此劇據說是少有的以 DMZ 為背景之韓劇 (另一部是孫藝珍主演的愛的迫降). 這個月花太多時間看電視了, 看完這兩部要休息一下, 要專心學習啦. 

2020年11月14日 星期六

在虛擬環境安裝 Django 3.1

這幾天在複習 Django 時發現它已升版至 3.1.3 版, 所以把筆電的 Django 也提升至最新版, 以下是在虛擬環境 virtualenv 中安裝, 參考 : 



D:\>cd django  
D:\django>virtualenv venv
created virtual environment CPython3.7.2.final.0-64 in 5360ms
  creator CPython3Windows(dest=D:\django\venv, clear=False, global=False)
  seeder FromAppData(download=False, pip=bundle, setuptools=bundle, wheel=bundle, via=copy, app_data_dir=C:\Users\User\AppData\Local\pypa\virtualenv)
    added seed packages: pip==20.2.4, setuptools==50.3.2, wheel==0.35.1
  activators BashActivator,BatchActivator,FishActivator,PowerShellActivator,PythonActivator,XonshActivator

這會建立一個虛擬環境目錄 venv, 進入其下子目錄 Scripts 執行 activate 程式進入虛擬環境, 然後安裝 Django 最新版 : 

D:\django>cd venv  
D:\django\venv>Scripts\activate  

(venv) D:\django\venv>pip install django    
Collecting django
  Downloading Django-3.1.3-py3-none-any.whl (7.8 MB)
Collecting sqlparse>=0.2.2
  Downloading sqlparse-0.4.1-py3-none-any.whl (42 kB)
Collecting pytz
  Downloading pytz-2020.4-py2.py3-none-any.whl (509 kB)
Collecting asgiref<4,>=3.2.10
  Downloading asgiref-3.3.1-py3-none-any.whl (19 kB)
Installing collected packages: sqlparse, pytz, asgiref, django
Successfully installed asgiref-3.3.1 django-3.1.3 pytz-2020.4 sqlparse-0.4.1

可見除了安裝 Django 3 之外, 還會安裝 pytz, sqlparse, asgiref 這三個相依套件. 用 pip list 檢視虛擬環境中已安裝套件 :

(venv) D:\django\venv>pip3 list   
Package    Version
---------- -------
asgiref    3.3.1
Django     3.1.3
pip        20.2.4
pytz       2020.4
setuptools 50.3.2
sqlparse   0.4.1
wheel      0.35.1

查詢 Django 版本 :

(venv) D:\django\venv>python -m django --version   
3.1.3

Django 3.1 版的新功能參考發布版本通知 :


Django 3 新增了非同步功能, 主要支援 WebSocket, 目的是解決執行緒執行效能低落問題, 將逐步改寫 MTV 架構與中介軟體, 取代原先的阻塞式作業使其原生支援非同步, 最終會在 3.2 版完成全部功能, 參考 :


所以其實若不是寫大型高流量網頁應用, 使用 Django 2 就可以了. 

我查詢了 Pythonanywhere 的 Django 版本, 它預設還是 2.1 版 : 


Django 2.1 django-blog-zinnia 0.20 django-bootstrap-form 3.4 django-classy-tags 0.8.0 django-contrib-comments 1.8.0 django-formtools 2.1 django-js-asset 1.1.0 django-mptt 0.9.0 django-object-tools 1.11.0 django-sekizai 0.10.0 django-tagging 0.4.6 django-treebeard 4.3 django-xmlrpc 0.1.8 djangocms-admin-style 1.2.8


GitHub 上有一個很不錯的 Django 3.1 線上教學網站可參考 :


2020年11月13日 星期五

昊瀚資訊的 Python 基礎教學

今天在臉書程式交易社團看到一篇文章, 作者是高雄一家財金資訊公司昊瀚資訊的工程師, 查了一下發現這是設立於高雄苓雅區的公司, 有名的下單機軟體 GOrder 原來就是該公司的產品 (之前在所買的一本 Python 書上看過此軟體之介紹). 

瀏覽網站時發現它的知識專區提供了很棒的 Python 程式教學, 值得參考 : 

# PYTHON基礎教學

2020年11月12日 星期四

露天購買 USB 蒸氣眼罩

今天在露天找到一款蒸氣眼罩, 因為每天寫程式看電腦眼睛容易疲勞, 這可在午睡時戴著既可遮光, 又可以熱敷眼睛, 先買一個試試看好用否, 老闆在 FAQ 說老顧客回購免運費 : 

【GooDay】原廠正品 USB蒸氣眼罩 控溫定時 蒸汽眼罩 熱敷 紓壓 $270

今天這個也是露天還有一張免運券而免運. 

2020-11-25 補充 :

其實這並非用蒸氣, 我覺得應該是小型發熱片, 有一個線控可以調整溫度與持續加熱時間, 接 5V1A 以上充電頭 (須自備), PC 的 USB 槽也可以. 我現在都是午休時用來遮光順便熱敷眼睛.