ウェブサイト検索

FlaskのBlueprintとFlask-SQLAlchemyを使用して大規模なFlaskアプリケーションを構築する方法


著者は、Write for DOnationsプログラムの一環として寄付を受けるために、Free and Open Source Fundを選びました。

紹介

Flaskは、PythonでWebアプリケーションを作成するための便利なツールと機能を備えた軽量のPythonウェブフレームワークです。SQLAlchemyは、リレーショナルデータベースのための効率的で高性能なデータベースアクセスを提供するSQLツールキットです。これは、SQLite、MySQL、PostgreSQLなどのさまざまなデータベースエンジンと対話する方法を提供し、データベースのSQL機能へのアクセスを可能にします。このツールキットはまた、オブジェクトリレーショナルマッパー(ORM)を提供し、簡単なPythonオブジェクトとメソッドを使用してクエリを作成し、データを処理することを可能にします。Flask-SQLAlchemyは、Flaskと一緒にSQLAlchemyを使用するのを容易にするFlask拡張であり、Flaskアプリケーション内でデータベースと対話するためのツールとメソッドを提供します。

Flaskは、1つのPythonファイルで迅速に小さなウェブアプリケーションを構築する方法を提供します。しかし、小さなアプリケーションは、複数のデータベーステーブルや数百のルート、複雑な機能を持つ大規模なアプリケーションに成長する可能性があります。大規模なアプリケーションのコードを1つのファイルに書くことは、すぐに混乱し、管理が難しくなります。Flaskは、アプリケーションの主要な部分を特定のディレクトリとファイルに分けて、より整理されたアプリケーションのコードベースを構築することを可能にします。

例えば、ソーシャルメディアアプリケーションでは、usersというディレクトリ内のroutes.pyというファイルにユーザーのためのルートを持っているかもしれません。そして、modelsディレクトリ内のusers.pyというモジュールにユーザーのためのデータベースモデルを集めることができます。次に、投稿、フォロワー、ハッシュタグ、質問、回答、広告、マーケットプレイス、支払い、そして大規模なソーシャルメディアアプリケーションの他の機能に対しても同じことを行うことができます。支払いのコードにビジネスロジックを編集したい場合は、mysocialapp/models/paymentにあるファイル内の支払いのデータベースコードを変更できます。 次に、mysocialapp/payments/routes.pyにあるファイルでビジネスロジックを変更します。アプリケーションの各部分は異なるファイルとディレクトリにコードを分離しており、実質的にアプリケーションを管理しやすいコンポーネントに分割しています。この構造は、新しい開発者がアプリケーションに慣れるのに役立ち、問題をトラブルシューティングする場所や新しい機能を追加する場所を理解するのに役立ちます。

Flaskは、アプリケーションコンポーネントを作成するためのブループリントという機能を提供しています。前の例では、ブループリントを使用して、ユーザーのブループリント、投稿用のブループリント、フォロワー用のブループリントなど、異なるブループリントで大規模なソーシャルメディアアプリケーションを構造化できます。

このチュートリアルでは、Flaskのブループリントを使用して、ホームページや他の主要なルートを含むメインブループリント、ブログ投稿を管理するための投稿ブループリント、質問と回答のための質問ブループリントという3つのコンポーネントを持つWebアプリケーションの構造を作成します。

前提条件

  • ローカルのPython 3プログラミング環境をセットアップするには、Python 3の環境をローカルにインストールして設定するためのチュートリアルに従ってください。このチュートリアルでは、プロジェクトディレクトリをflask_appと呼びます。

  • ルート、ビュー関数、テンプレートなどの基本的なFlaskの概念を理解すること。Flaskに不慣れな場合は、『FlaskとPythonを使って最初のWebアプリケーションを作成する方法』や『Flaskアプリケーションでテンプレートを使用する方法』をチェックしてください。

  • 基本的なHTMLの概念についての理解。背景知識のために、私たちの「HTMLでウェブサイトを構築する方法」チュートリアルシリーズを確認できます。

  • データベースの設定、データベースモデルの作成、データベースへのデータの挿入など、基本的なFlask-SQLAlchemyの概念を理解すること。Flaskアプリケーションでデータベースと対話するためにFlask-SQLAlchemyを使用する方法を参照して、背景知識を得てください。

ターゲットアプリケーションの構造

チュートリアルの終わりまでに、次の構造を持つFlaskアプリケーションを構築することになります:

.
└── flask_app
    ├── app
    │   ├── extensions.py
    │   ├── __init__.py
    │   ├── main
    │   │   ├── __init__.py
    │   │   └── routes.py
    │   ├── models
    │   │   ├── post.py
    │   │   └── question.py
    │   ├── posts
    │   │   ├── __init__.py
    │   │   └── routes.py
    │   ├── questions
    │   │   ├── __init__.py
    │   │   └── routes.py
    │   └── templates
    │       ├── base.html
    │       ├── index.html
    │       ├── posts
    │       │   ├── categories.html
    │       │   └── index.html
    │       └── questions
    │           └── index.html
    ├── app.db
    └── config.py

あなたのflask_appディレクトリ内には、app.dbデータベースファイルと、Flaskアプリケーション用のconfig.py設定ファイルがあります。メインのFlaskアプリケーションはappディレクトリ内にあり、インポートが正しく動作するように__init__.pyという特別なファイルが含まれており、Flaskアプリケーションインスタンスを作成するための関数が含まれています。

このappディレクトリには、アプリケーションで使用するFlask拡張機能を管理するためのextensions.pyファイルが含まれています(このチュートリアルでは、Flask拡張機能の使用例としてFlask-SQLAlchemyを示しています)。また、次のディレクトリも含まれます。

  • main: ホームページなどの主要なルートのためのメインブループリントです。
  • posts: ブログ投稿を管理するための投稿ブループリント。
  • 質問: 質問と回答を管理するための質問のブループリント。
  • models: Flask-SQLAlchemyモデルを含むディレクトリ.
  • templates: メインブループリント用のファイルと各ブループリント用のディレクトリを含むテンプレートディレクトリ。

ステップ1 — FlaskとFlask-SQLAlchemyのインストール

このステップでは、アプリケーションに必要なパッケージをインストールします。

あなたの flask_app ディレクトリで、仮想環境をアクティブにしてください。

  1. source my_env/bin/activate

仮想環境がアクティブな状態で、pipを使ってFlaskとFlask-SQLAlchemyをインストールします:

  1. pip install Flask Flask-SQLAlchemy

インストールが完了すると、出力に次のような行が表示されます。

Successfully installed Flask-2.1.2 Flask-SQLAlchemy-2.5.1 Jinja2-3.1.2 MarkupSafe-2.1.1 SQLAlchemy-1.4.39 Werkzeug-2.1.2 click-8.1.3 greenlet-1.1.2 itsdangerous-2.1.2

必要なPythonパッケージがインストールされたら、次のステップでFlaskアプリケーションの設定を管理するための設定ファイルを作成します。

ステップ 2 — 設定ファイルの作成

このステップでは、Flaskアプリケーションの設定ファイルを作成します。これにより、アプリケーションの設定をアプリケーションの残りの部分から分離し、設定を変更しやすくなります。設定ファイルでは、シークレットキー、SQLAlchemyデータベースURIなどの設定を行います。

あなたのflask_appディレクトリで、config.pyという新しいファイルを開いてください。このファイルには、Flaskアプリケーションの設定が含まれます。

  1. nano config.py

次のコードを追加してください:

import os

basedir = os.path.abspath(os.path.dirname(__file__))


class Config:
    SECRET_KEY = os.environ.get('SECRET_KEY')
    SQLALCHEMY_DATABASE_URI = os.environ.get('DATABASE_URI')\
        or 'sqlite:///' + os.path.join(basedir, 'app.db')
    SQLALCHEMY_TRACK_MODIFICATIONS = False

ファイルを保存して閉じてください。

ファイルシステムにアクセスするためにosモジュールをインポートします。データベースファイルのパスを正しく設定するために、os.path.abspath(os.path.dirname(__file__))を使用して基本ディレクトリを確立します。

あなたはConfigというクラスを使用し、クラス変数を使って設定値を設定します。ここでは、3つの設定を行います:

  • SECRET_KEY: Flaskが秘密鍵として使用する長いランダムな文字列であり、リクエストからリクエストへ情報を記憶するセッションを保護するための鍵です。ユーザーはセッションに保存された情報にアクセスできますが、秘密鍵を持っていない限り、情報を変更することはできません。そのため、誰にも秘密鍵へのアクセスを許可してはいけません。詳細については、Flaskのセッションに関するドキュメントを参照してください。他のFlask拡張機能も、データを保護するためにこの秘密鍵を使用することがよくあります。安全な秘密鍵の作成方法についての詳細は、「FlaskアプリケーションにおけるWebフォームの使用方法」のステップ3を参照してください。 Flaskアプリケーションを開発する際は、SECRET_KEYという環境変数を使って秘密鍵を設定するべきです。このconfig.pyファイルでその値を取得し、SECRET_KEYというクラス変数に保存するためには、os.environオブジェクトを介してその環境変数の値にアクセスし、get()メソッドを使用します。(このチュートリアルを進めるために秘密鍵を設定する必要はありませんが、リストの最後に秘密鍵の設定方法についての指示がありますので、ご確認ください。)

  • SQLALCHEMY_DATABASE_URI: データベースURIは、SQLAlchemyを使用して接続したいデータベースを指定します。この場合、DATABASE_URI 環境変数から取得するか、デフォルト値を設定します。ここでのデフォルトURIの形式は sqlite:///path/to/app.db に従います。os.path.join() 関数を使用して、構築してbasedir変数に保存した基準ディレクトリとapp.dbファイル名を結合します。これにより、DATABASE_URI 環境変数を設定せずにFlaskアプリケーションを作成すると、デフォルトでflask_appディレクトリ内のapp.dbデータベースファイルに接続します。このファイルはデータベーステーブルを作成するときに作成されます。異なるSQLエンジンのデータベースURIを設定したい場合は、Flaskアプリケーションでデータベースと対話するためにFlask-SQLAlchemyを使用する方法のステップ2を参照してください。

  • SQLALCHEMY_TRACK_MODIFICATIONS: オブジェクトの変更追跡を有効または無効にする設定です。追跡を無効にし、メモリの使用量を減らすために、Falseに設定します。さらに詳しい情報は、Flask-SQLAlchemyのドキュメントの設定ページを参照してください。

注意:このチュートリアルではシークレットキーを設定しないため、シークレットキーが必要な機能は使用しません。ただし、シークレットキーを設定する必要がある場合は、以下のように設定できます(Windowsの場合はexportの代わりにsetを使用して下さい):

  1. export SECRET_KEY="your secret key"

同様に、データベースURIを次のように設定できます(Windowsではsetを使用してください):

  1. export DATABASE_URI="postgresql://username:password@host:port/database_name"

あなたは今、アプリケーションのための設定ファイルを設定しました。次に、Flaskアプリケーションのインスタンスを設定し、Flaskアプリケーションの異なるコンポーネントを表すいくつかのブループリントを作成します。

ステップ3 — Flaskアプリケーションファクトリの作成

このステップでは、Flaskアプリケーションインスタンスを設定するPython関数であるFlaskアプリケーションファクトリを作成します。

このチュートリアルのこの時点で、あなたのflask_appディレクトリ構造は次のようになっています(仮想環境のディレクトリを除く)。

.
├── flask_app
   └── config.py

あなたのアプリケーションのコアコードはプロジェクトディレクトリ内に存在し、これはPythonパッケージになります。このチュートリアルではそれをappと呼びますが、あなたのプロジェクト名やsrc、coreなどの他の一般的なディレクトリ名を使っても構いません。

アプリケーションのコアコードを含むフォルダーをPythonパッケージにして、コードベース全体でインポートが正しく機能するようにし、保守性を高めます。

appプロジェクトディレクトリをPythonパッケージにするには、その中に特別な__init__.pyファイルを作成します。これにより、ディレクトリがPythonパッケージとしてマークされます。この__init__.pyファイルには、Flaskファクトリー関数のコードが含まれます。この関数は、Flaskアプリケーションインスタンスを設定し作成するために使用し、すべてのFlaskブループリントを一緒にリンクします。ファクトリー関数は、すべてのFlaskコンポーネント(ブループリント)を1つのアプリケーションに統合する中心的な関数と考えてください。また、異なる用途や異なる設定のために、さまざまなFlaskアプリケーションインスタンスを作成するために使用できます。たとえば、テストのために適切な設定でFlaskアプリケーションインスタンスを作成するためにファクトリー関数を使用することができます。

flask_app ディレクトリ内に、次の app ディレクトリを作成します:

  1. mkdir app

それから、app ディレクトリの中に新しい __init__.py ファイルを開いてください:

  1. nano app/__init__.py

次のコードを追加してください:

from flask import Flask

from config import Config

def create_app(config_class=Config):
    app = Flask(__name__)
    app.config.from_object(config_class)

    # Initialize Flask extensions here

    # Register blueprints here

    @app.route('/test/')
    def test_page():
        return '<h1>Testing the Flask Application Factory Pattern</h1>'

    return app

ファイルを保存して閉じてください。

このファイルでは、flaskパッケージからFlaskクラスをインポートします。その後、前のステップでflask_appディレクトリに作成したconfig.pyファイルからConfig設定クラスをインポートします。

create_app()関数は、Flaskアプリケーションファクトリ関数です。これは、Flask()クラスからappと呼ばれるアプリケーションインスタンスを作成します。この作成は、よく知られているapp=Flask(__name__)という行を使用します。アプリケーションは、app.config.from_object()メソッドを使用してオブジェクトから設定値をインポートすることで構成します。このとき、config_classパラメーターの値を渡します。これは、デフォルト値としてConfigクラスを保持します。Flask拡張機能は、# Initialize Flask extensions hereコメントの下に初期化し、アプリケーションのブレークポイントは、作成したら# Register blueprints hereコメントの下に登録します。

あなたは、アプリケーションファクトリ内でルートを登録する方法を示すために、ファクトリ関数内のapp.route()デコレーターを使用してテストルートを作成します。この場合、test_page()ビューファンクションは、Flaskアプリケーションファクトリパターンのテストという見出しを返します。

最後に、create_app()ファクトリ関数は、return appの行で構築したアプリケーションインスタンスを返します。

Flaskは自動的にあなたのappパッケージ内のcreate_app()ファクトリ関数を検出し、それを使用してアプリケーションインスタンスを作成します。しかし、まずFlaskアプリケーションを開発モードで実行するために必要な環境変数を設定する必要があります。

仮想環境が有効な状態でflask_appディレクトリにいる間に、FLASK_APP環境変数にコアアプリケーションのディレクトリ名appを値として渡すことによって、Flaskにファクトリ関数の場所を教えます。次に、FLASK_ENV環境変数をdevelopmentに設定して、開発モードでアプリケーションを実行し、デバッガにアクセスできるようにします。Flaskデバッガについての詳細は、「Flaskアプリケーションでのエラー処理方法」を参照してください。

まず、appパッケージをFlaskがcreate_app()ファクトリ関数を探す場所として設定します:

  1. export FLASK_APP=app

Flaskアプリケーションを単一のPythonファイルであるapp.pyに構築することに慣れているかもしれません。その場合、Flaskにアプリケーションの場所を指示するために同じコマンドを使用します。ここでの違いは、前述のコマンドのappがプロジェクトのコアディレクトリに関連していることです。そこには__init__.pyファイルがあります。

FLASK_ENV 環境変数を設定して、アプリケーションを開発モードで実行します:

  1. export FLASK_ENV=development

次にアプリケーションを実行します:

  1. flask run

開発サーバーが動作している状態で、ブラウザを使用して次のURLにアクセスしてください:

http://127.0.0.1:5000/test/

サイトは Flaskアプリケーションファクトリパターンのテスト 見出しで読み込まれます。

あなたは今、Flaskアプリケーションファクトリ関数を作成しました。次に、Flaskブループリントを作成し、このファクトリ関数に登録します。

ステップ4 — Flaskブループリントの作成

このステップでは、Flaskアプリケーションの主要なコンポーネントを管理するためのメインルートのブループリントを作成し、その後、ファクトリ関数にブループリントを登録します。ブログ投稿、質問、回答のそれぞれのために別のブループリントを作成します。それぞれのブループリントにいくつかのルートを追加し、各ルートのために `templates` ディレクトリを使用してテンプレートをレンダリングします。

このチュートリアルのこの時点で、あなたのflask_appディレクトリ構造は次のようになっています(仮想環境のディレクトリを除く)。

.
├── flask_app
    ├── app
    │   └── __init__.py
    └── config.py

メインの青写真を作成し、そのテンプレートをレンダリングする

これからアプリケーションの主要な設計図を作成し、そのテンプレートをレンダリングします。

前のステップで開始した開発サーバーをそのまま動かしておき、新しいターミナルを開いてください。

新しいターミナルであなたのflask_appディレクトリに移動してください。それから、appディレクトリ内にメインブループリント用のmainという名前のディレクトリを作成してください:

  1. mkdir app/main

次に、新しい main ディレクトリ内に新しい __init__.py メインファイルを開きます:

  1. nano app/main/__init__.py

ここがあなたの主な設計図を作成する場所です。このファイルに次のコードを追加してください:

from flask import Blueprint

bp = Blueprint('main', __name__)

ファイルを保存して閉じてください。

ここでは、flaskパッケージからBlueprintクラスをインポートします。そして、このクラスを使って、名前(この場合は'main')と現在のPythonモジュールの名前を保持する__name__特別変数を渡して、ブループリントオブジェクトbpを作成します。

今、あなたは青写真オブジェクトを持っています。これは後で、あなたが前のステップで書いたcreate_app()ファクトリー関数を使用して作成するFlaskアプリケーションに差し込むことができるルートや関数を持つことになります。

次に、メインブループリントディレクトリ内にroutes.pyファイルを作成します。このファイルは、メインブループリントのルートを保持します。メインブループリントディレクトリ内に新しいroutes.pyファイルを開いてください:

  1. nano app/main/routes.py

あなたはbpオブジェクトを使ってルートを作成します。新しいファイルの中に次のルートを追加してください:

from app.main import bp


@bp.route('/')
def index():
    return 'This is The Main Blueprint'

ファイルを保存して閉じてください。

ここでは、app.mainを通じてアクセスするメインブループリントからbpブループリントオブジェクトをインポートします。インポート行では、appはプロジェクトのパッケージ、mainはメインブループリントパッケージ、bpはメインブループリントの__init__.pyファイル内で宣言したオブジェクトです。

あなたは bp オブジェクトを使用して、/ ルートと index() ビュー関数を bp.route() デコレーターで作成します。これは、馴染みのある app.route() デコレーターと似ています。

Flaskがこれらのルートを使用し、ブループリントから直接インポートできるようにするには、このroutes.pyファイルをブループリントの__init__.pyファイルにインポートする必要があります。編集のために開いてください:

  1. nano app/main/__init__.py

ファイルの最後にハイライトされたインポート行を追加してください:

from flask import Blueprint

bp = Blueprint('main', __name__)

from app.main import routes

ファイルを保存して閉じてください。

この追加により、青写真を登録するとそのルートも登録されます。

今、新しいブループリントを作成し、ルートを追加したので、この新しいブループリントについてFlaskに知らせる必要があります。これにより、Flaskアプリケーションの一部として扱われるようになります。そのために、Flaskアプリケーションファクトリ関数の中でブループリントを登録します。

app/__init__.pyファイルを開いてファクトリ関数を編集します:

  1. nano app/__init__.py

create_app()ファクトリ関数を以下のブロックに合わせて編集し、強調された行を追加してください:

...
def create_app(config_class=Config):
    app = Flask(__name__)
    app.config.from_object(config_class)

    # Initialize Flask extensions here

    # Register blueprints here
    from app.main import bp as main_bp
    app.register_blueprint(main_bp)

    @app.route('/test/')
    def test_page():
        return '<h1>Testing the Flask Application Factory Pattern</h1>'

    return app

ファイルを保存して閉じてください。

あなたは、メインブループリントからbpブループリントオブジェクトをインポートし、可読性のためにそれをmain_bpに名前を変更します。そして、app.register_blueprint()メソッドを使用して、Flaskがアプリケーションの一部として扱うようにこのメインブループリントを登録します。

開発サーバーが実行中の状態で、以下のURLに移動してください:

http://127.0.0.1:5000/

ページはこれがメインの青写真ですというテキストで読み込まれます。これは、メインルートで返されたテキストです。

あなたは現在、アプリケーションにルートを持つブループリントを持っています。次に、Flaskのブループリントでのテンプレートのレンダリング方法を示すHTMLテンプレートをレンダリングするために、メインブループリントのメインルートを編集します。

メインブループリントのroutes.pyファイルを開いて修正してください:

  1. nano app/main/routes.py

ハイライトされた行を含むファイルを編集してください:

from flask import render_template
from app.main import bp

@bp.route('/')
def index():
    return render_template('index.html')

ファイルを保存して閉じてください。

ここでは、render_template() 関数をインポートし、それをルートで使用して index.html というテンプレートファイルをレンダリングします。

これから、コードの重複を避けるために、すべてのテンプレートが共有するテンプレートディレクトリと基本テンプレートを作成する必要があります。

app ディレクトリの中にテンプレート用のディレクトリを作成してください:

  1. mkdir app/templates

新しいファイル base.html を開いて、ベーステンプレートとして使用します:

  1. nano app/templates/base.html

新しいファイルに次のコードを追加してください:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>{% block title %} {% endblock %} - FlaskApp</title>
    <style>
        h2 {
            width: 100%;
        }

        .title {
            margin: 5px;
            width: 100%;
        }

        .content {
            margin: 5px;
            width: 100%;
            display: flex;
            flex-direction: row;
            flex-wrap: wrap;
        }

        .post {
            flex: 20%;
            padding: 10px;
            margin: 5px;
            background-color: #f3f3f3;
            inline-size: 100%;
        }

        .title a {
            color: #00a36f;
            text-decoration: none;
        }

        nav a {
            color: #d64161;
            font-size: 3em;
            margin-left: 50px;
            text-decoration: none;
        }

    </style>
</head>
<body>
    <nav>
        <a href="{{ url_for('main.index') }}">FlaskApp</a>
        <a href="#">Posts</a>
        <a href="#">Categories</a>
        <a href="#">Questions</a>
    </nav>
    <hr>
    <div class="content">
        {% block content %} {% endblock %}
    </div>
</body>
</html>

ファイルを保存して閉じてください。

この基本テンプレートには、他のテンプレートで再利用するHTMLのひな型が含まれています。

基本テンプレートには、タイトルブロック、いくつかのCSS、アプリケーションの異なる部分にリンクするためのナビゲーションバー、およびコンテンツブロックがあります。基本テンプレートの詳細については、『Flaskアプリケーションでのテンプレートの使い方』を参照してください。

ブループリントを使用して url_for() 関数でルートにリンクするには、構文 blueprint_name.view_function_name を使用します。インデックスページはメインブループリントの index() ビュー関数によって処理されるため、リンクを構築するには main.index を url_for() 関数に渡します。

では、メインブループリントのindex()ビュー関数で生成したindex.htmlファイルを作成しましょう:

  1. nano app/templates/index.html

新しく作成したファイルに以下のコードを追加してください:

{% extends 'base.html' %}

{% block content %}
    <span class="title"><h1>{% block title %} The Home Page of FlaskApp {% endblock %}</h1></span>
    <div class="content">
        <h2>This is the main Flask blueprint</h2>
    </div>
{% endblock %}

ファイルを保存して閉じてください。

ここでは、基本テンプレートを拡張します。コンテンツブロックを置き換え、<h1> 見出しを使用してタイトルとしても機能し、<h2> 見出しを使用してインデックスページがメインのFlaskブループリントの一部であることを示します。

開発サーバーが実行中の状態で、ブラウザを使ってインデックスページにアクセスするか、すでに開いている場合はリフレッシュしてください。

http://127.0.0.1:5000/

次の画像に似たページが読み込まれます:

あなたは今、ブループリントを設定し、そのroutes.pyファイルにルートを追加し、アプリケーションに登録し、それに対してテンプレートをレンダリングしました。次に、ブログ投稿用の別のブループリントを作成します。

投稿のブループリントを作成し、そのテンプレートをレンダリングする

これからブログ投稿の設計図を作成し、それを登録し、テンプレートをレンダリングします。

このチュートリアルのこの時点で、あなたのflask_appディレクトリ構造は次のようになっています(仮想環境のディレクトリを除く)。

.
├── flask_app
    ├── app
    │   ├── __init__.py
    │   ├── main
    │   │   ├── __init__.py
    │   │   └── routes.py
    │   └── templates
    │       ├── base.html
    │       └── index.html
    └── config.py

ブログ投稿の新しいブループリントを作成するには、前のセクションと同じ手順に従います。

まず、新しいpostsディレクトリを作成して、ブループリントのファイルを保存します:

  1. mkdir app/posts

次に、新しいpostsディレクトリ内に新しい__init__.pyファイルを開きます:

  1. nano app/posts/__init__.py

bp ブループリントオブジェクトを作成し、作成するルートをブループリントの routes.py ファイルにインポートします:

from flask import Blueprint

bp = Blueprint('posts', __name__)


from app.posts import routes

ファイルを保存して閉じてください。

前のコードブロックでは、postsをブループリントの名前として使用しています。また、まだ作成していないroutes.pyファイルからルートをインポートしています。

次に、新しい routes.py ファイルを開きます。そこで投稿のブループリントのルートを設定します:

  1. nano app/posts/routes.py

次のルートをこのファイルに追加してください:

from flask import render_template
from app.posts import bp

@bp.route('/')
def index():
    return render_template('posts/index.html')

@bp.route('/categories/')
def categories():
    return render_template('posts/categories.html')

ファイルを保存して閉じてください。

ここでは、アプリケーションの投稿コンポーネントのインデックスページのルートと、投稿コンポーネントの一部であるカテゴリのルートという2つのルートがあります。

index ルートでは、パス posts/index.html のテンプレートファイルをレンダリングします。これは、Flask が templates ディレクトリ内の posts というディレクトリを探して、その中にある index.html ファイルを探すことを意味します。

categories ルートでは、categories.html テンプレートをレンダリングします。このテンプレートは、templates フォルダ内の posts ディレクトリの中にもあります。

今、テンプレートディレクトリ内に新しいpostsディレクトリを作成してください:

  1. mkdir app/templates/posts

次に、posts ディレクトリ内に新しい index.html ファイルを作成します。これは、posts ブループリントの index() ビュー関数でレンダリングするファイルです。

  1. nano app/templates/posts/index.html

新しく作成したファイルに以下のコードを追加してください:

{% extends 'base.html' %}

{% block content %}
    <span class="title"><h1>{% block title %} The Posts Page {% endblock %}</h1></span>
    <div class="content">
        <h2>This is the posts Flask blueprint</h2>
    </div>
{% endblock %}

ファイルを保存して閉じてください。

ここでは、基本テンプレートを拡張します。また、<h1>見出しをタイトルとして設定し、<h2>見出しでページが投稿の青写真の一部であることを示します。

次に、posts ディレクトリ内に新しい categories.html ファイルを作成します。これは、posts ブループリントの categories() ビュー関数でレンダリングされたファイルです。

  1. nano app/templates/posts/categories.html

新しく作成したファイルに以下のコードを追加してください:

{% extends 'base.html' %}

{% block content %}
    <span class="title"><h1>{% block title %} Categories {% endblock %}</h1></span>
    <div class="content">
        <h2>This is the categories page within the posts blueprint</h2>
    </div>
{% endblock %}

ファイルを保存して閉じてください。

基本テンプレートを拡張し、<h1>見出しをタイトルとして設定し、<h2>見出しを使ってページを投稿のブループリントの一部としてマークします。

あなたは投稿のブループリントを作成し、ルートを追加し、レンダリングされたテンプレートを作成しました。これから、このブループリントをファクトリー関数に登録して、Flaskにアプリケーションの一部として認識させます。

ファクトリー関数を編集するためにapp/__init__.pyファイルを開いてください。

  1. nano app/__init__.py

create_app()ファクトリ関数を編集して、ハイライトされた行を追加してください:

def create_app(config_class=Config):
    app = Flask(__name__)
    app.config.from_object(config_class)

    # Initialize Flask extensions here

    # Register blueprints here
    from app.main import bp as main_bp
    app.register_blueprint(main_bp)

    from app.posts import bp as posts_bp
    app.register_blueprint(posts_bp, url_prefix='/posts')

    @app.route('/test/')
    def test_page():
        return '<h1>Testing the Flask Application Factory Pattern</h1>'

    return app

ファイルを保存して閉じてください。

ここで、posts ブループリントパッケージから bp ブループリントオブジェクトをインポートし、可読性のためにそれを posts_bp に名前を変更しました。

あなたは、posts_bp ブループリントオブジェクトを渡すことで、app.register_blueprint() メソッドを使用してポストブループリントを登録します。また、url_prefix パラメータに '/posts' の値を渡し、ブループリントのルートにこの文字列をプレフィックスとして付加します。例えば、ポストブループリントのメイン / ルートは /posts/ でアクセス可能になり、/categories ルートは /posts/categories/ でアクセスできるようになります。

新しい投稿のブループリントが登録され、開発サーバーが稼働しているので、ブラウザを使って以下のURLにアクセスしてください。

http://127.0.0.1:5000/posts/
http://127.0.0.1:5000/posts/categories/

投稿ページの見出しは http://127.0.0.1:5000/posts/ ページに読み込まれます。カテゴリの見出しは http://127.0.0.1:5000/posts/categories/ ページに読み込まれます。

ナビゲーションバーの投稿とカテゴリーのリンクを機能させるために、基本テンプレートを開いて修正してください:

  1. nano app/templates/base.html

<nav> タグを強調表示された表現で修正してください:

    <nav>
        <a href="{{ url_for('main.index') }}">FlaskApp</a>
        <a href="{{ url_for('posts.index') }}">Posts</a>
        <a href="{{ url_for('posts.categories') }}">Categories</a>
        <a href="#">Questions</a>
    </nav>

ファイルを保存して閉じてください。

あなたは、url_for('posts.index') 関数呼び出しを使って投稿のインデックスにリンクし、url_for('posts.categories') を使ってカテゴリーのページにリンクします。

アプリケーション内の任意のページをリフレッシュして、投稿 および カテゴリ リンク機能を有効にしてください。

あなたのアプリケーションに投稿のブループリントが登録されました。次に、質問と回答のブループリントを追加します。

質問の青写真を作成し、そのテンプレートをレンダリングする

これから質問の設計図を作成し、それを登録し、テンプレートを表示します。

このチュートリアルのこの時点で、あなたのflask_appディレクトリ構造は次のようになっています(仮想環境のディレクトリを除く)。

.
├── flask_app
    ├── app
    │   ├── __init__.py
    │   ├── main
    │   │   ├── __init__.py
    │   │   └── routes.py
    │   ├── posts
    │   │   ├── __init__.py
    │   │   └── routes.py
    │   └── templates
    │       ├── base.html
    │       ├── index.html
    │       └── posts
    │           ├── categories.html
    │           └── index.html
    └── config.py

質問と回答のための新しい青写真を作成するには、新しいquestionsディレクトリを作成して、青写真のファイルを保管します。

  1. mkdir app/questions

次に、新しいquestionsディレクトリ内に新しい__init__.pyファイルを開きます:

  1. nano app/questions/__init__.py

青写真オブジェクトを作成し、後で青写真のroutes.pyファイルで作成するルートをインポートします。

from flask import Blueprint

bp = Blueprint('questions', __name__)

from app.questions import routes

ファイルを保存して閉じてください。

前のコードブロックでは、questionsをブループリントの名前として使用しています。また、まだ作成していないroutes.pyファイルからルートをインポートしています。

次に、新しい routes.py ファイルを開きます。そこで質問のブループリントのルートを設定します:

  1. nano app/questions/routes.py

次のルートをこのファイルに追加してください:

from flask import render_template
from app.questions import bp

@bp.route('/')
def index():
    return render_template('questions/index.html')

ファイルを保存して閉じてください。

あなたは、questions ブループリントオブジェクトを使用して / ルートを作成し、テンプレートフォルダー内に作成する questions というディレクトリ内の index.html というテンプレートファイルをレンダリングします。

テンプレートディレクトリ内にquestionsディレクトリを作成し、その中にindex.htmlファイルを開きます:

  1. mkdir app/templates/questions
  2. nano app/templates/questions/index.html

新しいファイルに次のコードを追加してください:

{% extends 'base.html' %}

{% block content %}
    <span class="title">
        <h1>{% block title %} Questions {% endblock %}</h1>
    </span>
    <div class="questions">
        <h2>Questions Blueprint</h2>
    </div>
{% endblock %}

ファイルを保存して閉じてください。

ここでは、他の設計書にある以前のインデックステンプレートに似て、タイトルとサブヘッディングを設定します。

次に、app/__init__.pyを開いて、create_app()ファクトリ関数に質問ブループリントを登録してください:

  1. nano app/__init__.py

create_app()ファクトリ関数を編集して、ハイライトされた行を追加してください:

def create_app(config_class=Config):
    app = Flask(__name__)
    app.config.from_object(config_class)

    # Initialize Flask extensions here

    # Register blueprints here
    from app.main import bp as main_bp
    app.register_blueprint(main_bp)

    from app.posts import bp as posts_bp
    app.register_blueprint(posts_bp, url_prefix='/posts')

    from app.questions import bp as questions_bp
    app.register_blueprint(questions_bp, url_prefix='/questions')

    @app.route('/test/')
    def test_page():
        return '<h1>Testing the Flask Application Factory Pattern</h1>'

    return app

ファイルを保存して閉じてください。

あなたは、投稿のブループリントと同様に、質問のブループリントを登録し、そのルートに/questionsプレフィックスを追加します。

開発サーバーが起動している状態で、ブラウザを使用して以下のURLにアクセスしてください:

http://127.0.0.1:5000/questions/

質問および質問のブループリント見出しがページに表示されます。

これから質問リンクを機能させます。ナビゲーションバーを編集するためにベーステンプレートを開いてください:

  1. nano app/templates/base.html

<nav> タグを強調表示された表現で修正してください:

    <nav>
        <a href="{{ url_for('main.index') }}">FlaskApp</a>
        <a href="{{ url_for('posts.index') }}">Posts</a>
        <a href="{{ url_for('posts.categories') }}">Categories</a>
        <a href="{{ url_for('questions.index') }}">Questions</a>
    </nav>

ファイルを保存して閉じてください。

ここでは、url_for('questions.index') 関数呼び出しを使用して質問のインデックスページにリンクします。

アプリケーションの任意のページをリフレッシュして、ナビゲーションバーの質問リンク機能を有効にしてください。

あなたはアプリケーションの異なるコンポーネントを管理するためにいくつかのブループリントを作成しました。ブループリントをファクトリ関数に登録し、各ルートのテンプレートをレンダリングしました。次に、Flaskアプリケーション内の大規模なデータベースを管理し、整理するためにFlask-SQLAlchemyをアプリケーションに追加します。

ステップ5 — FlaskアプリケーションにFlask-SQLAlchemyモデルを追加する

このステップでは、Flask-SQLAlchemyをアプリケーションに統合し、データベースモデル用のディレクトリを追加し、投稿用のモデルと質問用のモデルを作成します。投稿テーブルにいくつかのブログ投稿を挿入し、データベース内のすべての投稿を表示するために投稿のインデックスルートを編集します。また、質問テーブルにいくつかの質問と回答も挿入し、新しいウェブフォームとともに質問のインデックスページに表示します。これにより、データベースにさらに質問と回答を追加することができます。

このチュートリアルのこの時点で、あなたのflask_appディレクトリ構造は次のようになっています(仮想環境のディレクトリを除く)。

.
├── flask_app
    ├── app
    │   ├── __init__.py
    │   ├── main
    │   │   ├── __init__.py
    │   │   └── routes.py
    │   ├── posts
    │   │   ├── __init__.py
    │   │   └── routes.py
    │   ├── questions
    │   │   ├── __init__.py
    │   │   └── routes.py
    │   └── templates
    │       ├── base.html
    │       ├── index.html
    │       ├── posts
    │       │   ├── categories.html
    │       │   └── index.html
    │       └── questions
    │           └── index.html
    └── config.py

Flask拡張を管理し、Flask-SQLAlchemyを統合するためのファイルの作成

Flask-SQLAlchemy拡張機能をアプリケーションに追加するには、まず、さまざまなFlask拡張機能を設定するためのextensions.pyというPythonモジュールをappディレクトリに追加します。

あなたのappディレクトリの中に新しいextensions.pyファイルを作成します:

  1. nano app/extensions.py

新しく作成したファイルに以下のコードを追加してください:

from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy()

ファイルを保存して閉じてください。

ここでは、Flask-SQLAlchemyパッケージからSQLAlchemy()クラスをインポートし、引数なしでdbデータベースオブジェクトを作成するために使用します。

この db オブジェクトを使用して、工場関数で構築する Flask アプリケーションと SQLAlchemy を統合します。 app/__init__.py ファイルを開いて工場関数を編集してください:

  1. nano app/__init__.py

ファイルを編集してデータベースオブジェクトをインポートおよび初期化します:

from flask import Flask

from config import Config
from app.extensions import db

def create_app(config_class=Config):
    app = Flask(__name__)
    app.config.from_object(config_class)

    # Initialize Flask extensions here
    db.init_app(app)

    # Register blueprints here
    from app.main import bp as main_bp
    app.register_blueprint(main_bp)

    from app.posts import bp as posts_bp
    app.register_blueprint(posts_bp, url_prefix='/posts')

    from app.questions import bp as questions_bp
    app.register_blueprint(questions_bp, url_prefix='/questions')

    @app.route('/test/')
    def test_page():
        return '<h1>Testing the Flask Application Factory Pattern</h1>'

    return app

ここでは、以前作成した app.extensions モジュールから db データベースオブジェクトをインポートします。ブループリントを登録する前に、db オブジェクトを app アプリケーションインスタンスに db.init_app() メソッドを使用して接続します。これにより、アプリケーション内で db オブジェクトを使用して Flask-SQLAlchemy モデルを作成し、操作することができます。

Flask-SQLAlchemyは、あなたのflask_appディレクトリ内のconfig.pyファイルにあるConfigオブジェクトを使用して設定したことを思い出してください。このファイルを開いて、確認することができます。

  1. nano config.py
import os

basedir = os.path.abspath(os.path.dirname(__file__))

class Config:
    SECRET_KEY = os.environ.get('SECRET_KEY')
    SQLALCHEMY_DATABASE_URI = os.environ.get('DATABASE_URI')\
        or 'sqlite:///' + os.path.join(basedir, 'app.db')
    SQLALCHEMY_TRACK_MODIFICATIONS = False

もしDATABASE_URI環境変数を設定しない場合、dbオブジェクトはデフォルトでapp.dbというSQLiteファイルに接続します。このファイルは、データベーステーブルを作成するとflask_appディレクトリに表示されます。レビューが終了したら、このファイルを閉じてください。

Flaskシェルを使用して、データベースが正しく登録されたか確認できます。まず、仮想環境が有効になっている状態で、flask_appディレクトリにFlask環境変数を設定していることを確認してください:

  1. export FLASK_APP=app
  2. export FLASK_ENV=development

Flaskシェルを開いてください:

  1. flask shell

app.extensionsモジュールからdbオブジェクトをインポートし、それを出力します:

  1. from app.extensions import db
  2. print(db)

あなたは次のようなデータベースのパスを受け取ります:

<SQLAlchemy engine=sqlite:///your_path_to_flask_app/app.db>

この出力は、db オブジェクトが正しく登録されたことを意味します。Flask シェルでコードを実行中にエラーが発生した場合は、次のセクションに進む前にファクトリ関数内でdb オブジェクトが正しく登録されていることを確認してください。Flask シェルを終了するには、exit() と入力します。

投稿モデルの作成と相互作用

大規模なアプリケーションでは、何百ものデータベーステーブルが存在する可能性があり、それに伴いそれらを管理するために何百ものSQLAlchemyモデルを書く必要があります。すべてのモデルを1つのファイルにまとめると、アプリケーションのメンテナンスが困難になるため、モデルをmodelsディレクトリ内の別々のPythonファイルに分割します。各ファイルは、アプリケーションの特定の部分に関連するモデルと関数を保持します。例えば、投稿を管理するためのモデルと関数をpost.pyというファイルに、appディレクトリ内のmodelsというディレクトリに置くことができます。

このチュートリアルのこの時点で、あなたのflask_appディレクトリ構造は次のようになっています(仮想環境のディレクトリを除く)。

.
├── flask_app
    ├── app
    │   ├── extensions.py
    │   ├── __init__.py
    │   ├── main
    │   │   ├── __init__.py
    │   │   └── routes.py
    │   ├── posts
    │   │   ├── __init__.py
    │   │   └── routes.py
    │   ├── questions
    │   │   ├── __init__.py
    │   │   └── routes.py
    │   └── templates
    │       ├── base.html
    │       ├── index.html
    │       ├── posts
    │       │   ├── categories.html
    │       │   └── index.html
    │       └── questions
    │           └── index.html
    └── config.py

自分のファイル内に投稿のためのデータベースモデルを作成するには、まずappディレクトリ内にmodelsというディレクトリを作成します:

  1. mkdir app/models

次に、モデルディレクトリ内にpost.pyという新しいファイルを開きます:

  1. nano app/models/post.py

新しく作成したファイルに以下のコードを追加してください:

from app.extensions import db

class Post(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    title = db.Column(db.String(150))
    content = db.Column(db.Text)

    def __repr__(self):
        return f'<Post "{self.title}">'

ファイルを保存して閉じてください。

あなたはapp.extensionsモジュールからdbデータベースオブジェクトをインポートします。そして、db.Modelクラスを使用してPostと呼ばれるFlask-SQLAlchemyデータベースモデルを作成します。このモデルには、主キーとしてのID整数列(id)、投稿タイトルの文字列を保持するための列(title)、およびコンテンツ用のテキスト列(content)があります。特別な__repr__()メソッドを使って、各投稿オブジェクトのタイトルを使用して文字列表現を提供します。Flask-SQLAlchemyの詳細については、「Flaskアプリケーションでデータベースと対話するためのFlask-SQLAlchemyの使い方」をレビューできます。

次に、Flaskシェルを開いて、投稿モデルに基づいて投稿テーブルを作成します。

  1. flask shell

次のコードを実行して、postsテーブルを作成します:

  1. from app.extensions import db
  2. from app.models.post import Post
  3. db.create_all()

あなたは、app.extensions モジュールから db オブジェクトをインポートし、app.models.post モジュールから Post モデルをインポートします。次に、create_all() メソッドを使用して posts テーブルを作成します。

コードは出力なしで実行する必要があります。エラーが発生した場合は、app/extensions.pyとapp/models/post.pyファイルを確認し、手順が正しく実行されていることを確認してください。

注: db.create_all() 関数は、テーブルが既に存在している場合、再作成または更新しません。例えば、新しい列を追加することでモデルを修正したい場合、db.create_all() 関数を実行すると、モデルに対する変更は、テーブルがデータベースに既に存在している場合にはテーブルには適用されません。解決策は、db.drop_all() 関数を使用して既存のデータベーステーブルをすべて削除し、その後 db.create_all() 関数で再作成することです:

  1. db.drop_all()
  2. db.create_all()

これらのコマンドは、モデルに対する変更を適用し、データベース内の既存のデータをすべて削除します。データベースを更新し、既存のデータを保持するには、テーブルを変更し、データを保持できるスキーママイグレーションを使用する必要があります。Flaskコマンドラインインターフェースを通じてSQLAlchemyのスキーママイグレーションを実行するために、Flask-Migrate拡張機能を使用できます。

次に、以下のコードを実行して10個のランダムな投稿を作成してください:

  1. import random
  2. for i in range(0, 10):
  3. random_num = random.randrange(1, 1000)
  4. post = Post(title=f'Post #{random_num}',
  5. content=f'Content #{random_num}')
  6. db.session.add(post)
  7. print(post)
  8. print(post.content)
  9. print('--')
  10. db.session.commit()

あなたはdbデータベースオブジェクト、Postデータベースモデル、およびrandom Pythonモジュールをインポートします。このモジュールを使用して、異なるタイトルと内容を持つサンプル投稿を作成するためにランダムな数を生成します。forループとrange() Python関数を使用して、コードブロックを10回繰り返します。

forループ内で、random.randrange()メソッドを使用して、1と1000の間のランダムな整数を生成し、それをrandom_numという変数に保存します。次に、Postモデルを使用して投稿オブジェクトを作成し、random_num変数内のランダムな数を使用してサンプルの投稿タイトルと内容を生成します。

次に、投稿オブジェクトをデータベースセッションに追加し、オブジェクト自体とその内容を表示し、トランザクションをコミットします。

以下のような出力を受け取りますが、数値は異なります:

<Post "Post #58">
Content #58
--
<Post "Post #55">
Content #55
--
<Post "Post #994">
Content #994
--
<Post "Post #394">
Content #394
--
<Post "Post #183">
Content #183
--
<Post "Post #633">
Content #633
--
<Post "Post #790">
Content #790
--
<Post "Post #883">
Content #883
--
<Post "Post #259">
Content #259
--
<Post "Post #581">
Content #581
--

各投稿にはランダムに生成された番号が付いています。これらの投稿は、あなたのデータベースに今後保存されます。

Flaskシェルを実行したままにしておき、新しいターミナルウィンドウを開いてください。環境をソースし、アプリケーションフォルダーに移動します。

テーブルにいくつかのサンプル投稿があるので、それらを投稿のインデックスページに表示できます。まず、インデックスルートを変更するために投稿ルートファイルを開いてください:

  1. nano app/posts/routes.py

インポートとインデックスルートを編集して、ハイライトされた行を追加してください:

from flask import render_template
from app.posts import bp
from app.extensions import db
from app.models.post import Post


@bp.route('/')
def index():
    posts = Post.query.all()
    return render_template('posts/index.html', posts=posts)

ファイルを保存して閉じてください。

あなたは db データベースオブジェクトと Post モデルをインポートします。データベース内のすべての投稿を取得し、それを投稿のインデックステンプレートに渡します。

表示するために、渡された投稿を修正するために投稿のインデックステンプレートを開いてください:

  1. nano app/templates/posts/index.html

強調表示された行を追加してファイルを編集してください。

{% extends 'base.html' %}

{% block content %}
    <span class="title"><h1>{% block title %} The Posts Page {% endblock %}</h1></span>
    <div class="content">
        <h2>This is the posts Flask blueprint</h2>
        {% for post in posts %}
            <div class="post">
                <p><b>#{{ post.id }}</b></p>
                <p class="title">
                    <b>
                        <a href="#">
                            {{ post.title }}
                        </a>
                    </b>
                </p>
                <div class="content">
                    <p>{{ post.content }}</p>
                </div>
                <hr>
            </div>
        {% endfor %}
    </div>
{% endblock %}

ファイルを保存して閉じてください。

ここでは、投稿をループしてそれぞれの投稿のID、タイトル、および内容を表示します。

開発サーバーが実行中の状態で、投稿のインデックスページにアクセスするか、すでに開いている場合は更新してください:

http://127.0.0.1:5000/posts/

生成したサンプル投稿は、次の画像のようにインデックスページに表示されます。

あなたは今、投稿のためのデータベースモデルを持っています。これで、投稿の作成、編集、削除などの新しいルートやテンプレートを使って、アプリケーションに機能を追加できるようになります。

質問モデルの作成と対話

あなたは投稿モデルを作成し、それを投稿のブループリント内で操作しました。これから質問と回答を管理するための質問データベースモデルを追加します。

このチュートリアルのこの時点で、あなたのflask_appディレクトリ構造は次のようになっています(仮想環境のディレクトリを除く)。

.
├── flask_app
    ├── app
    │   ├── extensions.py
    │   ├── __init__.py
    │   ├── main
    │   │   ├── __init__.py
    │   │   └── routes.py
    │   ├── models
    │   │   └── post.py
    │   ├── posts
    │   │   ├── __init__.py
    │   │   └── routes.py
    │   ├── questions
    │   │   ├── __init__.py
    │   │   └── routes.py
    │   └── templates
    │       ├── base.html
    │       ├── index.html
    │       ├── posts
    │       │   ├── categories.html
    │       │   └── index.html
    │       └── questions
    │           └── index.html
    ├── app.db
    └── config.py

質問データベースモデルを作成するには、モデルディレクトリ内に question.py という新しいファイルを開いてください:

  1. nano app/models/question.py

次のコードを追加してください:

from app.extensions import db

class Question(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    content = db.Column(db.Text)
    answer = db.Column(db.Text)

    def __repr__(self):
        return f'<Question {self.content}>'

ファイルを保存して閉じてください。

ここでは、app.extensionsモジュールからdbデータベースオブジェクトをインポートします。次に、db.Modelクラスを使用してQuestionというモデルを作成します。モデルには、主キーとしてのID整数カラム(id)、質問の内容のためのテキストカラム(content)、およびその回答のためのテキストカラム(answer)があります。次に、特別な__repr__()メソッドを使用して、各質問をその内容を用いて表現します。

Flaskシェルを実行しているターミナルセッションで、次のコードを実行してquestionsモデルに基づいてquestionsテーブルを作成します:

  1. flask shell

次のコードを実行して、質問テーブルを作成し、いくつかの質問と回答を追加します:

  1. from app.extensions import db
  2. from app.models.question import Question
  3. db.create_all()
  4. q1 = Question(content='Why is the sky blue?', answer='Because... Why not?')
  5. q2 = Question(content='What is love?', answer='A portal to the underworld.')
  6. db.session.add_all([q1, q2])
  7. db.session.commit()

コードは出力なしで実行される必要があります。エラーが発生した場合は、app/models/question.pyファイルを確認して、コードが正しい構文で書かれているかを確認してください。

データベースオブジェクトと質問モデルをインポートし、次に db.create_all() を使用してテーブルを作成し、最後に2つの質問オブジェクトをデータベースセッションに追加してトランザクションをコミットします。

Flaskシェルを終了する:

  1. exit()

新しい質問モデルと対話できるようになりました。それを行うには、質問のブループリントのroutes.pyファイルを開いて、質問テーブルにある質問をクエリして表示するための変更を加えてください:

  1. nano app/questions/routes.py

強調表示された行を追加してファイルを編集してください。

from flask import render_template
from app.questions import bp
from app.models.question import Question

@bp.route('/')
def index():
    questions = Question.query.all()
    return render_template('questions/index.html', questions=questions)

ファイルを保存して閉じてください。

ここでは、質問モデルをインポートし、データベース内のすべての質問を取得し、それらを質問のインデックステンプレートに渡します。

次に、渡した質問を質問のインデックステンプレートに表示し、ユーザーが新しい質問を追加できるようにウェブフォームを追加します。質問のテンプレートディレクトリ内のindex.htmlファイルを開いてください。

  1. nano app/templates/questions/index.html

強調表示された行を追加してファイルを編集してください。

{% extends 'base.html' %}

{% block content %}
    <span class="title">
        <h1>{% block title %} Questions {% endblock %}</h1>
    </span>
    <div class="questions">
        <h2>Questions Blueprint</h2>

        <div class="question">
            <div class="new-question">
                <form method="POST">
                    <p>
                        <textarea id="q-content"
                                name="content"
                                placeholder="Question"
                                cols="30" rows="3"></textarea>
                    </p>
                    <textarea id="q-answer"
                            name="answer"
                            placeholder="Answer"
                            cols="30" rows="3"></textarea>
                    <p><input type="submit"></p>
                </form>
            </div>
            <div class="questions-list">
                {% for question in questions %}
                    <div class="question">
                        <h4>{{ question.content }}</h4>
                        <p>{{ question.answer }}</p>
                        <hr>
                    </div>
                {% endfor %}
            </div>
        </div>

    </div>
{% endblock %}

ファイルを保存して閉じてください。

ここでは、質問の内容用のテキストエリアと回答用のテキストエリアの2つを持つフォームを作成します。そして、フォームの送信ボタンを追加します。

フォームの下で、質問のインデックスルートから渡されたquestions変数をループし、それぞれの質問の内容と回答を表示します。

開発サーバーが動作している状態で、ブラウザを使用して質問のインデックスページに移動します:

http://127.0.0.1:5000/questions/

ページは、青写真の見出し、提出フォーム、および2つのサンプル質問で読み込まれます:

ただし、フォームに記入して送信すると、フォームが質問のインデックスルートにPOSTリクエストを送信するため、405 Method Not AllowedのHTTPエラーが発生します。このルートはPOSTリクエストを受け付けず、処理もしません。この問題を解決し、フォームを機能させるために、質問のブループリントのインデックスルートを修正し、フォームデータを使用してデータベースに新しい質問を追加します。

質問のブループリントのroutes.pyファイルを開いてください。

  1. nano app/questions/routes.py

強調表示された行を追加してファイルを編集してください。

from flask import render_template, request, url_for, redirect
from app.questions import bp
from app.models.question import Question
from app.extensions import db

@bp.route('/', methods=('GET', 'POST'))
def index():
    questions = Question.query.all()

    if request.method == 'POST':
        new_question = Question(content=request.form['content'],
                                answer=request.form['answer'])
        db.session.add(new_question)
        db.session.commit()
        return redirect(url_for('questions.index'))

    return render_template('questions/index.html', questions=questions)

ファイルを保存して閉じてください。

GETおよびPOSTメソッドを、methodsパラメータに('GET', 'POST')タプルを渡すことで許可します。POSTリクエストはif request.method == 'POST':条件の中で処理します。そこで、request.formオブジェクトから取得したコンテンツとユーザーが送信した回答を使用して新しい質問オブジェクトを作成します。新しい質問をデータベースセッションに追加し、トランザクションをコミットし、その後、ユーザーを質問インデックスページにリダイレクトします。

このフォームは現在機能しており、新しい質問と回答をデータベースに追加できます。この機能をhttp://127.0.0.1:5000/questions/のURLでテストできます。

あなたはアプリケーションにFlask-SQLAlchemyを統合し、コードを整理するためのモデル用ディレクトリを追加しました。

あなたは最終的なファイルをDigitalOceanコミュニティリポジトリに保存されているコードと比較することができます。

結論

あなたはブループリントを使用して大規模なFlaskアプリケーションを構築し、テンプレートとモデルで整理しました。各コンポーネントがそれぞれのルート、テンプレート、およびモデルを持つように設定しました。

この例のウェブアプリケーションには、さまざまな方法で拡張できる3つの主要なコンポーネントがあります:

  • 主な青写真:ユーザーがアプリケーションの所有者に連絡できるように、約ページや問い合わせページを追加できます。

  • 投稿の青写真: 投稿の作成、編集、削除、および並べ替えのためのページを追加できます。また、Flask-SQLAlchemyを使用した多対多のデータベース関係を利用して、投稿にタグを追加することもできます。

  • 質問の青写真: 質問を管理するためのページを追加でき、Flask-SQLAlchemyを使用して、質問が複数の解決策を持てるように、別のテーブルを作成するための1対多のデータベース関係を作成できます。

認証、支払い、管理などの機能のために、さらに多くのブループリントを追加することもできます。

Flaskについてもっと知りたい場合は、『Flaskでウェブアプリケーションを構築する方法』シリーズの他のチュートリアルをチェックしてください。

関連記事: