手順 2: ビューおよびページ テンプレートを使用して Flask アプリを作成する

前の手順:Visual Studio プロジェクトとソリューションを作成する

このチュートリアルの手順 1 では、 1 つのファイルに 1 つのページとすべてのコードをまとめた Flask アプリを作成しました。 今後の開発を可能にするために、コードをリファクタリングし、ページ テンプレートの構造体を作成することをお勧めします。 特に、アプリのビューのコードを、スタートアップ コードなど、他の側面と切り離すことが望まれます。

この手順では、次の方法を学習します。

  • アプリのコードをリファクタリングし、ビューとスタートアップ コードを切り離す (手順 2-1)
  • ページ テンプレートを使用してビューを表示する (手順 2-2)

手順 2-1: 将来の開発のためにプロジェクトをリファクタリングする

"空の Flask Web プロジェクト" テンプレートで作成されたコードには、シングル ビューと共にスタートアップ コードが含まれる app.py ファイルが 1 つ与えられます。 今後、複数のビューとテンプレートでアプリを開発するためには、このような重要な項目を切り離すことをお勧めします。

  1. プロジェクト フォルダーで、HelloFlask という名前のアプリ フォルダーを作成します (ソリューション エクスプローラーでプロジェクトを右クリックし、 [追加][新しいフォルダー] の順に選択します)。

  2. HelloFlask フォルダーで、__init__.py という名前のファイルを次の内容で作成します。Flask インスタンスが作成され、(次の手順で作成された) アプリのビューが読み込まれます。

    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. HelloFlasktemplates という名前のサブフォルダーを作成します。今のところは空のままです。

  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 キー) の順に選択するか、ツール バーの [Web サーバー] ボタンを使用して (表示されるブラウザーは異なる場合があります)、アプリを起動し、ブラウザーを開きます。 URL ルートには / と /home の両方を試してください。

  8. コードのさまざまな部分にブレークポイントを設定し、アプリを再開し、スタートアップ シーケンスを続行することもできます。 たとえば、runserver.py と HelloFlask_init_.py の最初の行と views.pyreturn "Hello Flask!" 行にブレークポイントを設定します。 その後、アプリを再起動し ( [デバッグ]>[再開]Ctrl+Shift+F5 キー、または下のツール バーのボタン)、コードをステップ実行する (F10 キー) か、F5 キーを使って各ブレークポイントから実行します。

    Restart button on the debugging toolbar in Visual Studio

  9. 完了したら、アプリを停止します。

ソース管理へのコミット

コードに変更を加え、テストが正常に行われたら、確認してソース管理にコミットできます。 このチュートリアルの後半の手順で、再びソース管理について触れた場合は、このセクションを参照してください。

  1. Visual Studio の下部にある変更ボタン (下の丸印) を選択すると、チーム エクスプローラーに移動します。

    Source control changes button on the Visual Studio status bar

  2. チーム エクスプローラーで "Refactor code" などのコミット メッセージを入力し、 [すべてコミット] を選択します。 コミットが完了すると、"<hash> のコミットがローカルで作成されました。変更をサーバーと共有するには、同期を使用してください。" というメッセージが表示されます。リモート リポジトリに変更をプッシュする場合は、[同期] を選択して、[出力方向のコミット] にある [プッシュ] を選択します。 リモートにプッシュする前に、複数のローカル コミットを蓄積しておくことも可能です。

    Push commits to remote in Team Explorer

質問: ソース管理にはどのくらいの頻度でコミットすべきですか。

回答:ソース管理に変更をコミットすると、変更ログにレコードが作成され、必要に応じてリポジトリを元に戻すためのポイントが作成されます。 各コミットはその特定の変更について調べることもできます。 Git のコミットは高コストではないため、大量の変更を蓄積して 1 回でコミットするより頻繁にコミットすることをお勧めします。 個々のファイルの細かな変更を逐一コミットする必要はありません。 一般的に、この手順で行ったように機能を追加したとき、構造を変更したとき、または一部のコードをリファクタリングしたときにコミットします。 また、コミットの詳細度について、皆にとって最適になるよう、チームの全員に確認します。

コミットする頻度とリモート リポジトリにコミットをプッシュする頻度の 2 つが重要な項目となります。 リモート リポジトリにプッシュする前にローカル リポジトリに複数のコミットを蓄積することもできます。 コミットの頻度は、チームがリポジトリを管理する方法によって異なります。

手順 2-2: テンプレートを使用してページをレンダリングする

views.py に既にある home 関数では、ページに対するプレーンテキストの HTTP 応答以外は生成されません。 ただし、現実のほとんどの Web ページは、ライブ データを頻繁に取り込む豊富な 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. render_template を利用してテンプレートを読み込み、"コンテンツ" の値を入力するように home 関数を変更します。値は、プレースホルダーの名前に一致する名前付き引数を使用することで入力されます。 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 ファイルの拡張子を使用する必要がありますか。

回答: render_template 関数の最初の引数にファイルへの正確な相対パスを常に指定するため、ページ テンプレート ファイルの .html 拡張子は完全にオプションです。 ただし、Visual Studio (および、その他のエディター) では通常、 .html ファイルにより、コード補完や構文の色付けなどの機能が提供されており、これは、ページ テンプレートが HTML ではないという事実よりも重要です。

Flask プロジェクトを操作していると、Visual Studio により、編集中の HTML ファイルが実際には Flask テンプレートである場合は自動検出され、特定のオートコンプリート機能が提供されます。 たとえば、Flask ページ テンプレートのコメント {# の入力を開始すると、Visual Studio では終了の #} 文字を自動的に提示します。 また、 [選択範囲のコメント] および [選択範囲のコメントを解除] コマンド ( [編集]>[詳細] メニューおよびツールバー上にある) では、HTML コメントではなく、テンプレート コメントを使用します。

質問:サブフォルダーをさらに追加してテンプレートを整理できますか。

回答: はい。サブフォルダーを使用し、render_template の呼び出しで templates 下の相対パスを参照できます。 これは、テンプレートの名前空間を効果的に作成する方法として優れています。

次の手順

詳しい説明