ブループリントとビュー—フラスコのドキュメント

提供:Dev Guides
< FlaskFlask/docs/1.0.x/tutorial/views
移動先:案内検索

ブループリントとビュー

ビュー関数は、アプリケーションへの要求に応答するために作成するコードです。 Flaskはパターンを使用して、受信リクエストURLをそれを処理するビューに一致させます。 ビューは、Flaskが発信応答に変換するデータを返します。 Flaskは逆方向に進み、名前と引数に基づいてビューへのURLを生成することもできます。

ブループリントを作成する

Blueprintは、関連するビューやその他のコードのグループを整理する方法です。 ビューやその他のコードをアプリケーションに直接登録するのではなく、ブループリントで登録します。 次に、ブループリントは、ファクトリ関数で使用可能になったときにアプリケーションに登録されます。

Flaskrには2つの青写真があります。1つは認証機能用で、もう1つはブログ投稿機能用です。 各ブループリントのコードは、個別のモジュールに含まれます。 ブログは認証について知る必要があるので、最初に認証を記述します。

flaskr/auth.py

import functools

from flask import (
    Blueprint, flash, g, redirect, render_template, request, session, url_for
)
from werkzeug.security import check_password_hash, generate_password_hash

from flaskr.db import get_db

bp = Blueprint('auth', __name__, url_prefix='/auth')

これにより、'auth'という名前のBlueprintが作成されます。 アプリケーションオブジェクトと同様に、ブループリントはそれがどこで定義されているかを知る必要があるため、__name__が2番目の引数として渡されます。 url_prefixは、ブループリントに関連付けられているすべてのURLの先頭に追加されます。

app.register_blueprint()を使用して、工場からブループリントをインポートして登録します。 アプリを返す前に、ファクトリ関数の最後に新しいコードを配置します。

flaskr/__init__.py

def create_app():
    app = ...
    # existing code omitted

    from . import auth
    app.register_blueprint(auth.bp)

    return app

認証ブループリントには、新しいユーザーを登録し、ログインおよびログアウトするためのビューがあります。


最初のビュー:登録

ユーザーが/auth/register URLにアクセスすると、registerビューは HTML とフォームを返します。 フォームを送信すると、入力が検証され、エラーメッセージが表示されてフォームが再度表示されるか、新しいユーザーを作成してログインページに移動します。

今のところ、ビューコードを書くだけです。 次のページでは、HTMLフォームを生成するためのテンプレートを作成します。

flaskr/auth.py

@bp.route('/register', methods=('GET', 'POST'))
def register():
    if request.method == 'POST':
        username = request.form['username']
        password = request.form['password']
        db = get_db()
        error = None

        if not username:
            error = 'Username is required.'
        elif not password:
            error = 'Password is required.'
        elif db.execute(
            'SELECT id FROM user WHERE username = ?', (username,)
        ).fetchone() is not None:
            error = 'User {} is already registered.'.format(username)

        if error is None:
            db.execute(
                'INSERT INTO user (username, password) VALUES (?, ?)',
                (username, generate_password_hash(password))
            )
            db.commit()
            return redirect(url_for('auth.login'))

        flash(error)

    return render_template('auth/register.html')

registerビュー関数の機能は次のとおりです。

  1. @bp.routeは、URL /registerregisterビュー機能に関連付けます。 Flaskは、/auth/registerへのリクエストを受信すると、registerビューを呼び出し、戻り値を応答として使用します。

  2. ユーザーがフォームを送信した場合、request.method'POST'になります。 この場合、入力の検証を開始します。

  3. request.formは、送信されたフォームのキーと値をマッピングする特別なタイプのdictです。 ユーザーはusernamepasswordを入力します。

  4. usernamepasswordが空でないことを確認します。

  5. データベースにクエリを実行し、結果が返されるかどうかを確認して、usernameがまだ登録されていないことを確認します。 db.executeは、任意のユーザー入力に対して?プレースホルダーを使用し、プレースホルダーを置き換える値のタプルを使用してSQLクエリを取得します。 データベースライブラリが値のエスケープを処理するため、 SQLインジェクション攻撃に対して脆弱ではありません。

    fetchone()は、クエリから1行を返します。 クエリが結果を返さなかった場合は、Noneを返します。 その後、fetchall()が使用され、すべての結果のリストが返されます。

  6. 検証が成功した場合は、新しいユーザーデータをデータベースに挿入します。 セキュリティ上の理由から、パスワードをデータベースに直接保存しないでください。 代わりに、generate_password_hash()を使用してパスワードを安全にハッシュし、そのハッシュを保存します。 このクエリはデータを変更するため、変更を保存するには、後でdb.commit()を呼び出す必要があります。

  7. ユーザーを保存した後、ユーザーはログインページにリダイレクトされます。 url_for()は、名前に基づいてログインビューのURLを生成します。 これは、URLに直接リンクするすべてのコードを変更せずに、後でURLを変更できるため、URLを直接書き込むよりも望ましい方法です。 redirect()は、生成されたURLへのリダイレクト応答を生成します。

  8. 検証が失敗した場合、エラーがユーザーに表示されます。 flash()は、テンプレートのレンダリング時に取得できるメッセージを格納します。

  9. ユーザーが最初にauth/registerに移動したとき、または検証エラーが発生したときは、登録フォームを含むHTMLページが表示されます。 render_template()は、チュートリアルの次のステップで作成するHTMLを含むテンプレートをレンダリングします。


ログイン

このビューは、上記のregisterビューと同じパターンに従います。

flaskr/auth.py

@bp.route('/login', methods=('GET', 'POST'))
def login():
    if request.method == 'POST':
        username = request.form['username']
        password = request.form['password']
        db = get_db()
        error = None
        user = db.execute(
            'SELECT * FROM user WHERE username = ?', (username,)
        ).fetchone()

        if user is None:
            error = 'Incorrect username.'
        elif not check_password_hash(user['password'], password):
            error = 'Incorrect password.'

        if error is None:
            session.clear()
            session['user_id'] = user['id']
            return redirect(url_for('index'))

        flash(error)

    return render_template('auth/login.html')

registerビューとはいくつかの違いがあります。

  1. ユーザーは最初に照会され、後で使用するために変数に格納されます。
  2. check_password_hash()は、保存されたハッシュと同じ方法で送信されたパスワードをハッシュし、それらを安全に比較します。 それらが一致する場合、パスワードは有効です。
  3. session は、リクエスト間でデータを保存するdictです。 検証が成功すると、ユーザーのidが新しいセッションに保存されます。 データはブラウザに送信される cookie に保存され、ブラウザはその後のリクエストでデータを送り返します。 データが改ざんされないように、データを安全に署名します。

ユーザーのidセッションに保存されたので、以降のリクエストで利用できるようになります。 各リクエストの開始時に、ユーザーがログインしている場合は、情報を読み込んで他のビューで利用できるようにする必要があります。

flaskr/auth.py

@bp.before_app_request
def load_logged_in_user():
    user_id = session.get('user_id')

    if user_id is None:
        g.user = None
    else:
        g.user = get_db().execute(
            'SELECT * FROM user WHERE id = ?', (user_id,)
        ).fetchone()

bp.before_app_request()は、要求されたURLに関係なく、ビュー関数の前に実行される関数を登録します。 load_logged_in_userは、ユーザーIDがセッションに保存されているかどうかを確認し、そのユーザーのデータをデータベースから取得して、 g.user に保存します。リクエスト。 ユーザーIDがない場合、またはIDが存在しない場合、g.userNoneになります。


ログアウト

ログアウトするには、セッションからユーザーIDを削除する必要があります。 その場合、load_logged_in_userは後続のリクエストでユーザーをロードしません。

flaskr/auth.py

@bp.route('/logout')
def logout():
    session.clear()
    return redirect(url_for('index'))

他のビューで認証が必要

ブログ投稿を作成、編集、削除するには、ユーザーがログインする必要があります。 デコレータを使用して、適用されているビューごとにこれを確認できます。

flaskr/auth.py

def login_required(view):
    @functools.wraps(view)
    def wrapped_view(**kwargs):
        if g.user is None:
            return redirect(url_for('auth.login'))

        return view(**kwargs)

    return wrapped_view

このデコレータは、適用された元のビューをラップする新しいビュー関数を返します。 新しい関数は、ユーザーがロードされているかどうかを確認し、ロードされていない場合はログインページにリダイレクトします。 ユーザーがロードされると、元のビューが呼び出され、通常どおり続行されます。 ブログビューを作成するときに、このデコレータを使用します。


エンドポイントとURL

url_for()関数は、名前と引数に基づいてビューへのURLを生成します。 ビューに関連付けられた名前はエンドポイントとも呼ばれ、デフォルトではビュー関数の名前と同じです。

たとえば、チュートリアルの前半でアプリファクトリに追加されたhello()ビューは、'hello'という名前で、url_for('hello')とリンクできます。 後で説明する引数を取ると、url_for('hello', who='World')を使用するようにリンクされます。

ブループリントを使用する場合、ブループリントの名前が関数の名前の前に付加されるため、上記で記述したlogin関数のエンドポイントは、'auth'青写真。

テンプレートに進みます。