共用方式為


步驟 2:使用檢視與頁面範本來建立 Flask 應用程式

上一個步驟:建立 Visual Studio 專案和解決方案

在本教學課程步驟 1,您會建立一個 Flask 應用程式。此應用程式為單一檔案,其中包含單一頁面與所有程式碼。 若要考慮進一步開發,最好是將程式碼重構,並為頁面範本建立結構。 特別是,您會想要將應用程式檢視程式碼與其他方面 (例如起始程式碼) 分開。

在這個步驟中,您現在將了解如何:

  • 重構應用程式的程式碼以將檢視與起始程式碼分割 (步驟 2-1)
  • 使用頁面範本來轉譯檢視 (步驟 2-2)

步驟 2-1:重構專案以支援進一步的開發

在「空白 Flask Web 專案」範本所建立的程式碼中,會有單一 app.py 檔案,其中除了單一檢視,還包含啟動程式碼。 若要考慮使用多個檢視和範本來進一步開發應用程式,建議將這些考量重點分開。

  1. 在您的專案資料夾中,建立一個名為 HelloFlask 的應用程式資料夾 (在 [方案總管] 中的專案上按一下滑鼠右鍵,然後選取 [新增]>[新增資料夾])。

  2. HelloFlask 資料夾中,使用下列會建立 Flask 執行個體並載入應用程式檢視 (在下一個步驟中建立) 的內容,來建立名為 __init__.py 的檔案:

    from flask import Flask
    app = Flask(__name__)
    
    import HelloFlask.views
    
  3. HelloFlask 資料夾中,使用下列內容來建立名為 views.py 的檔案。 名稱 views.py 很重要,因為您已在 __init__.py 內使用 import HelloFlask.views ;如果名稱不相符,在執行階段將會顯示錯誤。

    from flask import Flask
    from HelloFlask import app
    
    @app.route('/')
    @app.route('/home')
    def home():
        return "Hello Flask!"
    

    除了將函式重新命名並路由傳送至 home 之外,此程式碼還包含來自 app.py 的頁面轉譯程式碼,並且會匯入 __init__.py 中所宣告的 app 物件。

  4. HelloFlask 中建立名為 templates 的子資料夾,此子資料夾目前會維持空白。

  5. 在專案的根資料夾中,將 app.py 重新命名為 runserver.py,並讓內容符合下列程式碼:

    import os
    from HelloFlask import app    # Imports the code from HelloFlask/__init__.py
    
    if __name__ == '__main__':
        HOST = os.environ.get('SERVER_HOST', 'localhost')
    
        try:
            PORT = int(os.environ.get('SERVER_PORT', '5555'))
        except ValueError:
            PORT = 5555
    
        app.run(HOST, PORT)
    
  6. 您的專案結構應該看起來如下圖:

    Project structure after refactoring the code

  7. 選取 [偵錯]> [開始偵錯] (F5),或使用工具列上的 [網頁伺服器] 按鈕 (您看到的瀏覽器可能會有所不同),以啟動應用程式並開啟瀏覽器。 同時嘗試 / 和 /home URL 路由。

  8. 您也可以在程式碼的各個不同部分設定中斷點,然後重新啟動應用程式以依照該啟動順序。 例如,在 runserver.py 和 *HelloFlask_*init_.py 的前幾行,以及 views.py 中的第 return "Hello Flask!" 行上設定中斷點。 接著,重新啟動應用程式 ([偵錯]> [重新啟動]Ctrl+Shift+F5 或以下所示的工具列按鈕),然後逐步執行 (F10) 程式碼,或使用 F5 從每個中斷點執行。

    Restart button on the debugging toolbar in Visual Studio

  9. 完成時,請停止應用程式。

認可至原始檔控制

對程式碼進行變更並成功測試之後,您就可以檢閱並認可對原始檔控制所做的變更。 在稍後的步驟中,當本教學課程提醒您再次認可原始檔控制時,您可以參閱本節。

  1. 選取位於 Visual Studio 底部的變更按鈕 (下面圈起處),這會瀏覽至 [Team Explorer]

    Source control changes button on the Visual Studio status bar

  2. 在 [Team Explorer] 中,輸入 "Refactor code" (重構程式碼) 之類的訊息,然後選取 [全部認可]。 當認可完成時,您會看到下列訊息:認可於本機建立的 <雜湊>。同步以將您的變更與伺服器共用。如果您想要將變更推送至遠端存放庫,請選取 [同步],然後選取 [傳出的認可] 底下的 [推送]。 您也可以在累積多個本機認可之後,再推送至遠端。

    Push commits to remote in Team Explorer

問題:認可至原始檔控制的頻率應該有多高?

回答:將變更認可至原始檔控制會在變更記錄檔中建立記錄,以及可供您視需要還原存放庫的點。 您也可以檢查每個認可來了解其特定的變更。 由於在 Git 中進行認可並不會耗費太多資源,因此最好是經常進行認可,而不要累積大量變更再一次進行認可。 您並不需要認可對個別檔案所做的每個微小變更。 通常,您會在新增功能、變更結構 (就像在此步驟中所做的) 或已完成一些程式碼重構時,才進行認可。 此外,也請與您小組中的其他人進行確認,以找出最適合每個人的認可細微性。

進行認可的頻率與將認可推送至遠端存放酷的頻率,是兩個不同的考量重點。 您可以先在本機存放庫中累積多個認可,然後再將其推送到遠端存放庫。 認可的頻率取決於小組想要管理存放庫的方式。

步驟 2-2:使用範本來轉譯頁面

目前您在 views.py 中已有的 home 函式,只會針對網頁產生純文字 HTTP 回應。 不過,大多數真實世界的網頁都是以通常含有即時資料的豐富 HTML 網頁來回應。 使用函式來定義檢視的主要原因就是為了動態產生內容。

因為檢視的傳回值只是一個字串,所以您可以使用動態內容,視需要在字串內建置任何 HTML。 不過,由於最好是將標記與資料分開,因此理想的做法是將標記放在範本中,而將資料保留在程式碼中。

  1. 對於初學者來說,請編輯 views.py 來包含下列程式碼,這些程式碼會針對頁面使用內嵌 HTML 搭配某些動態內容:

    from datetime import datetime
    from flask import render_template
    from HelloFlask import app
    
    @app.route('/')
    @app.route('/home')
    def home():
        now = datetime.now()
        formatted_now = now.strftime("%A, %d %B, %Y at %X")
    
        html_content = "<html><head><title>Hello Flask</title></head><body>"
        html_content += "<strong>Hello Flask!</strong> on " + formatted_now
        html_content += "</body></html>"
    
        return html_content
    
  2. 執行應用程式並將頁面重新整理幾次,以查看日期/時間是否更新。 完成時,請停止應用程式。

  3. 若要將頁面轉譯轉換成使用範本,請使用下列內容在 templates 資料夾中建立名為 index.html 的檔案,其中 {{ content }} 是您在程式碼中為其提供值的預留位置或取代權杖 (也稱為「範本變數」):

    <html>
      <head>
        <title>Hello Flask</title>
      </head>
    
      <body>
        {{ content }}
      </body>
    </html>
    
  4. 修改 home 函式以使用 render_template 來載入範本及為 "content" 提供值,這會使用符合預留位置名稱的具名引數來完成。 Flask 會自動在 templates 資料夾中尋找範本,因此範本路徑會是該資料夾的相對路徑:

    def home():
        now = datetime.now()
        formatted_now = now.strftime("%A, %d %B, %Y at %X")
    
        return render_template(
            "index.html",
            content = "<strong>Hello, Flask!</strong> on " + formatted_now)
    
  5. 執行應用程式並查看結果。 觀察 content 值中的內嵌 HTML 並未轉譯成 HTML,因為範本化引擎 (Jinja) 會自動逸出 HTML 內容。 自動逸出可防止意外的插入式攻擊弱點。 開發人員通常會從某個頁面收集輸入,並透過範本預留位置,將其作為另一個頁面的值使用。 逸出也可作為一種提醒,就是最好將 HTML 放在程式碼外。

    因此,請檢閱 templates\index.html,以在標記內針對每個資料片段包含不同的預留位置:

    <html>
      <head>
        <title>{{ title }}</title>
      </head>
      <body>
        <strong>{{ message }}</strong>{{ content }}
      </body>
    </html>
    

    接著,更新 home 函式來為所有預留位置提供值:

    def home():
        now = datetime.now()
        formatted_now = now.strftime("%A, %d %B, %Y at %X")
    
        return render_template(
            "index.html",
            title = "Hello Flask",
            message = "Hello, Flask!",
            content = " on " + formatted_now)
    
  6. 重新執行應用程式並查看正確轉譯的輸出。

    Running app using the template

  7. 您可以將變更認可至原始檔控制,並更新遠端存放庫。 如需相關資訊,請參閱步驟 2-1

問題:頁面範本是否一定要位於個別檔案中?

回答:雖然範本通常會維護於個別的 HTML 檔案中,您也可以使用內嵌範本。 建議使用不同的檔案,以維持標記和程式碼之間的全新分隔。

問題:範本一定要使用 .html 副檔名嗎?

回答:頁面範本檔案的 .html 副檔名完全是選用的,因為您一律是在 render_template 函式的第一個引數中識別檔案的確切相對路徑。 不過,Visual Studio (與其他編輯器) 通常會針對 .html 檔案,為您提供程式碼完成和語法色彩等功能,其重要性比頁面範本不是 HTML 的事實更高。

當您在處理 Flask 專案時,Visual Studio 會自動偵測出您正在編輯的 HTML 檔案實際上是 Flask 範本,然後提供一些自動完成功能。 例如,當您開始鍵入 Flask 頁面範本註解 ({#) 時,Visual Studio 會自動提供結尾的 #} 字元。 [註解選取範圍] 與 [取消註解選取範圍] 命令 (位在 [編輯]>[進階] 功能表和工具列上) 也會使用範本註解,而不是 HTML 註解。

問題:是否可以將範本組織成進一步的子資料夾?

回答:是,您可以使用子資料夾,然後在對 render_template 的呼叫中參考 templates 底下的相對路徑。 這樣做是一個可有效地為範本建立命名空間的絕佳方式。

下一步

深入了解