著者は、 Write for DOnations プログラムの一環として、 Free and Open SourceFundを選択して寄付を受け取りました。

序章

Webアプリケーションでは、通常、データの組織化されたコレクションであるデータベースが必要です。 データベースを使用して、効率的に取得および操作できる永続データを保存および維持します。 たとえば、ソーシャルメディアアプリケーションでは、ユーザーデータ(個人情報、投稿、コメント、フォロワー)が効率的に操作できる方法で保存されているデータベースがあります。 さまざまな要件や条件に応じて、データベースにデータを追加、取得、変更、または削除できます。 Webアプリケーションでは、これらの要件は、ユーザーが新しい投稿を追加したり、投稿を削除したり、アカウントを削除したりする場合があります。これにより、投稿が削除される場合と削除されない場合があります。 データを操作するために実行するアクションは、アプリケーションの特定の機能によって異なります。 たとえば、タイトルのない投稿をユーザーに追加させたくない場合があります。

Flaskは、Python言語でWebアプリケーションを作成するための便利なツールと機能を提供する軽量のPythonWebフレームワークです。 SQLAlchemy は、リレーショナルデータベースに効率的で高性能なデータベースアクセスを提供するSQLツールキットです。 SQLite、MySQL、PostgreSQLなどのいくつかのデータベースエンジンと対話する方法を提供します。 これにより、データベースのSQL機能にアクセスできます。 また、オブジェクトリレーショナルマッパー(ORM)も提供します。これにより、単純なPythonオブジェクトとメソッドを使用してクエリを実行し、データを処理できます。 Flask-SQLAlchemy は、FlaskでSQLAlchemyを簡単に使用できるようにする、Flask拡張機能であり、SQLAlchemyを介してFlaskアプリケーションのデータベースと対話するためのツールとメソッドを提供します。

このチュートリアルでは、Flask-SQLAlchemy拡張機能の使用方法を示す小さな学生管理システムを構築します。 これをFlaskで使用して、データベースサーバーへの接続、テーブルの作成、テーブルへのデータの追加、取得、データベースからのアイテムの更新と削除などの基本的なタスクを実行します。 SQLAlchemyはSQLiteで使用しますが、PostgreSQLやMySQLなどの他のデータベースエンジンでも使用できます。 SQLiteはPythonでうまく機能します。これは、Python標準ライブラリが sqlite3モジュールを提供するためです。これは、SQLAlchemyがバックグラウンドで使用して、何もインストールせずにSQLiteデータベースと対話するために使用されます。 SQliteはデフォルトでLinuxシステムにインストールされ、WindowsのPythonパッケージの一部としてインストールされます。

前提条件

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

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

仮想環境をアクティブにして、 pip FlaskとFlaskをインストールするには-SQLAlchemy:

  1. pip install Flask Flask-SQLAlchemy

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

Output
Successfully installed Flask-2.0.3 Flask-SQLAlchemy-2.5.1 Jinja2-3.0.3 MarkupSafe-2.1.0 SQLAlchemy-1.4.31 Werkzeug-2.0.3 click-8.0.4 greenlet-1.1.2 itsdangerous-2.1.0

必要なPythonパッケージがインストールされたら、次にデータベースをセットアップします。

ステップ2—データベースとモデルの設定

このステップでは、データベース接続をセットアップし、SQLAlchemy データベースモデルを作成します。これは、データを格納するテーブルを表すPythonクラスです。 データベースを開始し、宣言するモデルに基づいて学生用のテーブルを作成し、数人の学生を学生テーブルに追加します。

データベース接続の設定

というファイルを開きます app.py あなたの中で flask_app ディレクトリ。 このファイルには、データベースとFlaskルートを設定するためのコードが含まれています。

  1. nano app.py

このファイルは、と呼ばれるSQLiteデータベースに接続します database.db、と呼ばれるクラスがあります Student これは、Flaskルートに加えて、学生情報を格納するためのデータベース学生テーブルを表します。 以下を追加します import 上部のステートメント app.py:

フラスコ_app/app.py
import os
from flask import Flask, render_template, request, url_for, redirect
from flask_sqlalchemy import SQLAlchemy

from sqlalchemy.sql import func

ここでは、 osモジュールをインポートします。これにより、さまざまなオペレーティングシステムインターフェイスにアクセスできます。 これを使用して、ファイルパスを作成します database.db データベースファイル。

から flask パッケージの場合、アプリケーションに必要なヘルパーをインポートします。 Flask Flaskアプリケーションインスタンスを作成するクラス、 render_template() テンプレートをレンダリングする機能、 request リクエストを処理するオブジェクト、 url_for() ルートのURLを作成する関数、および redirect() ユーザーをリダイレクトするための関数。 ルートとテンプレートの詳細については、Flaskアプリケーションでテンプレートを使用する方法を参照してください。

次に、 SQLAlchemy Flask-SQLAlchemy拡張機能のクラス。ヘルパーに加えて、SQLAlchemyのすべての関数とクラス、およびFlaskをSQLAlchemyと統合する機能にアクセスできます。 これを使用して、Flaskアプリケーションに接続するデータベースオブジェクトを作成します。これにより、SQL言語を使用せずに、Pythonクラス、オブジェクト、および関数を使用してテーブルを作成および操作できます。

また、 func からのヘルパー sqlalchemy.sql SQL関数にアクセスするためのモジュール。 学生レコードが作成されるときのデフォルトの作成日時を設定するには、学生管理システムでこれが必要になります。

インポートの下で、データベースファイルパスを設定し、Flaskアプリケーションをインスタンス化し、アプリケーションを構成してSQLAlchemyに接続します。 次のコードを追加します。

フラスコ_app/app.py

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

app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] =\
        'sqlite:///' + os.path.join(basedir, 'database.db')
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False

db = SQLAlchemy(app)

ここでは、SQLiteデータベースファイルのパスを作成します。 まず、ベースディレクトリを現在のディレクトリとして定義します。 os.path.abspath()関数を使用して、現在のファイルのディレクトリの絶対パスを取得します。 特別な __file__ 変数は現在のパス名を保持します app.py ファイル。 ベースディレクトリの絶対パスをという変数に保存します basedir.

次に、Flaskアプリケーションインスタンスを作成します。 app、2つのFlask-SQLAlchemy構成キーを構成するために使用します。

  • SQLALCHEMY_DATABASE_URI:接続を確立するデータベースを指定するデータベースURI。 この場合、URIは次の形式に従います sqlite:///path/to/database.db. os.path.join()関数を使用して、作成して保存したベースディレクトリにインテリジェントに参加します。 basedir 変数、および database.db ファイル名。 これはに接続します database.db あなたのデータベースファイル flask_app ディレクトリ。 データベースを開始すると、ファイルが作成されます。

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

ノート:

PostgreSQLやMySQLなどの別のデータベースエンジンを使用する場合は、適切なURIを使用する必要があります。

PostgreSQLの場合、次の形式を使用します。

postgresql://username:password@host:port/database_name

MySQLの場合:

mysql://username:password@host:port/database_name

詳細については、SQLAlchemyのドキュメントでエンジン構成を参照してください。

データベースURIを設定し、追跡を無効にしてSQLAlchemyを構成した後、を使用してデータベースオブジェクトを作成します。 SQLAlchemy クラス、アプリケーションインスタンスを渡してFlaskアプリケーションをSQLAlchemyに接続します。 データベースオブジェクトをという変数に格納します db. これを使用します db データベースと対話するオブジェクト。

テーブルの宣言

データベース接続が確立され、データベースオブジェクトが作成されたら、データベースオブジェクトを使用して、学生用のデータベーステーブルを作成します。このテーブルは、 model —基本クラスFlask-から継承するPythonクラスで表されます。 SQLAlchemyは db 以前に作成したデータベースインスタンス。 学生テーブルをモデルとして定義するには、次のクラスを app.py ファイル:

フラスコ_app/app.py
# ...

class Student(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    firstname = db.Column(db.String(100), nullable=False)
    lastname = db.Column(db.String(100), nullable=False)
    email = db.Column(db.String(80), unique=True, nullable=False)
    age = db.Column(db.Integer)
    created_at = db.Column(db.DateTime(timezone=True),
                           server_default=func.now())
    bio = db.Column(db.Text)

    def __repr__(self):
        return f'<Student {self.firstname}>'

ここでは、 Student から継承するモデル db.Model クラス。 これは学生テーブルを表します。 db.Column クラスを使用して、テーブルの列を定義します。 最初の引数は列タイプを表し、追加の引数は列構成を表します。

次の列を定義します Student モデル:

  • id:学生証。 あなたはそれを整数として定義します db.Integer. primary_key=True この列を主キーとして定義します。これにより、各エントリ(つまり学生)のデータベースによって一意の値が割り当てられます。
  • firstname:学生の名。 最大長が 100 文字。 nullable=False この列が空であってはならないことを意味します。
  • lastname:学生の名前。 最大長が 100 文字。 nullable=False この列が空であってはならないことを意味します。
  • email:学生のメール。 最大長が 80 文字。 unique=True 各メールは生徒ごとに一意である必要があることを意味します。 nullable=False この列が空であってはならないことを意味します。
  • age:学生の年齢。
  • created_at:データベースに学生レコードが作成された時刻。 db.DateTime を使用して、Python datetimeオブジェクトとして定義します。 timezone=True タイムゾーンのサポートを有効にします。 server_default は、テーブルの作成時にデータベースのデフォルト値を設定するため、デフォルト値はモデルではなくデータベースによって処理されます。 SQLを呼び出すfunc.now()関数を渡します now() 日時関数。 SQLiteでは、次のようにレンダリングされます CURRENT_TIMESTAMP 学生テーブルを作成するとき。
  • bio:学生の略歴。 db.Text() 列が長いテキストを保持していることを示します。

前のコードブロックで使用したタイプ以外の列タイプについては、SQLAlchemyのドキュメントを参照してください。

特別な__repr __ 関数を使用すると、デバッグ目的で各オブジェクトを認識するための文字列表現を各オブジェクトに与えることができます。 この場合、学生の名を使用します。

The app.py ファイルは次のようになります。

フラスコ_app/app.py
import os
from flask import Flask, render_template, request, url_for, redirect
from flask_sqlalchemy import SQLAlchemy

from sqlalchemy.sql import func


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

app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] =\
        'sqlite:///' + os.path.join(basedir, 'database.db')
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False

db = SQLAlchemy(app)


class Student(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    firstname = db.Column(db.String(100), nullable=False)
    lastname = db.Column(db.String(100), nullable=False)
    email = db.Column(db.String(80), unique=True, nullable=False)
    age = db.Column(db.Integer)
    created_at = db.Column(db.DateTime(timezone=True),
                           server_default=func.now())
    bio = db.Column(db.Text)

    def __repr__(self):
        return f'<Student {self.firstname}>'

保存して閉じます app.py.

データベースの作成

データベース接続と学生モデルを設定したので、Flaskシェルを使用して、データベースと学生テーブルを作成します。 Student モデル。

仮想環境をアクティブにして、 app.py を使用してFlaskアプリケーションとしてファイル FLASK_APP 環境変数。 次に、次のコマンドを使用してFlaskシェルを開きます。 flask_app ディレクトリ:

  1. export FLASK_APP=app
  2. flask shell

Pythonインタラクティブシェルが開きます。 この特別なシェルは、Flaskアプリケーションのコンテキストでコマンドを実行するため、呼び出すFlask-SQLAlchemy関数がアプリケーションに接続されます。

データベースオブジェクトと学生モデルをインポートしてから、 db.create_all() モデルに関連付けられているテーブルを作成する関数。 この場合、モデルは1つだけです。つまり、関数呼び出しはデータベースに1つのテーブルのみを作成します。

  1. from app import db, Student
  2. db.create_all()

シェルを実行したままにして、別のターミナルウィンドウを開き、次の場所に移動します。 flask_app ディレクトリ。 これで、という新しいファイルが表示されます。 database.dbflask_app.

ノート:

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

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

これにより、モデルに加えた変更が適用されますが、データベース内の既存のデータもすべて削除されます。 データベースを更新して既存のデータを保持するには、スキーマ移行を使用する必要があります。これにより、テーブルを変更してデータを保持できます。 Flask-Migrate 拡張機能を使用して、Flaskコマンドラインインターフェイスを介してSQLAlchemyスキーマの移行を実行できます。

エラーが発生した場合は、データベースURIとモデル宣言が正しいことを確認してください。

テーブルへの入力

データベースと学生テーブルを作成したら、フラスコシェルを使用して、データベースに学生を追加します。 Student モデル。

以前に開いたものと同じフラスコシェルを使用するか、仮想環境をアクティブにして新しいフラスコシェルを開きます。 flask_app ディレクトリ:

  1. flask shell

データベースに学生を追加するには、データベースオブジェクトと Student モデル化し、のインスタンスを作成します Student モデル、次のようにキーワード引数を介して学生データを渡します。

  1. from app import db, Student
  2. student_john = Student(firstname='john', lastname='doe',
  3. email='[email protected]', age=23,
  4. bio='Biology student')

The student_john オブジェクトはデータベースに追加される学生を表しますが、このオブジェクトはまだデータベースに書き込まれていません。 フラスコシェル内のオブジェクトをチェックして、で作成した表現文字列を確認します。 __repr__() 方法:

  1. student_john

次の出力が表示されます。

Output
<Student john>

列の値は、で定義したクラス属性を使用して取得できます。 Student モデル:

  1. student_john.firstname
  2. student_john.bio
Output
'john' 'Biology student'

この学生はまだデータベースに追加されていないため、そのIDは次のようになります。 None:

  1. print(student_john.id)
Output
None

この学生をデータベースに追加するには、まず、データベーストランザクションを管理するデータベースセッションに学生を追加する必要があります。 Flask-SQLAlchemyは db.session データベースの変更を管理できるオブジェクト。 追加します student_john を使用してセッションに反対する db.session.add() データベースに書き込む準備をする方法:

  1. db.session.add(student_john)

これにより、 INSERT ステートメントですが、データベーストランザクションがまだコミットされていないため、IDは返されません。 トランザクションをコミットしてデータベースに変更を適用するには、 db.session.commit() 方法:

  1. db.session.commit()

学生のジョンがデータベースに追加されたので、そのIDを取得できます。

  1. print(student_john.id)
Output
1

また、使用することができます db.session.add() データベース内のアイテムを編集するメソッド。 たとえば、次のように学生の電子メールを変更できます。

  1. student_john.email = '[email protected]'
  2. db.session.add(student_john)
  3. db.session.commit()

Flaskシェルを使用して、データベースにさらに数人の学生を追加します。

  1. sammy = Student(firstname='Sammy',
  2. lastname='Shark',
  3. email='[email protected]',
  4. age=20,
  5. bio='Marine biology student')
  6. carl = Student(firstname='Carl',
  7. lastname='White',
  8. email='[email protected]',
  9. age=22,
  10. bio='Marine geology student')
  11. db.session.add(sammy)
  12. db.session.add(carl)
  13. db.session.commit()

これで、studentテーブルのすべてのレコードを次のコマンドを使用してクエリできます。 query を持つ属性 all() 方法:

  1. Student.query.all()

次の出力が表示されます。

Output
[<Student john>, <Student Sammy>, <Student Carl>]

この時点で、データベースには3人の学生がいます。 次に、インデックスページのFlaskルートを作成し、データベース内のすべての学生をそのページに表示します。

ステップ3—すべてのレコードを表示する

このステップでは、データベース内のすべての学生をインデックスページに表示するためのルートとテンプレートを作成します。

Flaskシェルを実行したままにして、新しいターミナルウィンドウを開きます。

あなたの app.py インデックスページのルートを追加するファイル:

  1. nano app.py

ファイルの最後に次のルートを追加します。

フラスコ_app/app.py

# ...

@app.route('/')
def index():
    students = Student.query.all()
    return render_template('index.html', students=students)

ファイルを保存して閉じます。

ここでは、 index() を使用した表示機能 app.route() デコレータ。 この関数では、データベースにクエリを実行し、を使用してすべての学生を取得します Student とのモデル query 属性。さまざまな方法を使用して、データベースから1つ以上のアイテムを取得できます。 あなたは all() データベース内のすべての学生エントリを取得するメソッド。 クエリ結果をという変数に格納します students それをというテンプレートに渡します index.html を使用してレンダリングする render_template() ヘルパー関数。

作成する前に index.html データベース内の既存の学生を表示するテンプレートファイルでは、最初にベーステンプレートを作成します。このテンプレートには、コードの繰り返しを避けるために他のテンプレートでも使用されるすべての基本的なHTMLコードが含まれます。 次に、を作成します index.html レンダリングしたテンプレートファイル index() 関数。 テンプレートの詳細については、Flaskアプリケーションでテンプレートを使用する方法を参照してください。

作成する templates ディレクトリ、次にという名前の新しいテンプレートを開きます base.html:

  1. mkdir templates
  2. nano templates/base.html

内に次のコードを追加します base.html ファイル:

フラスコ_app/templates / base.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>{% block title %} {% endblock %} - FlaskApp</title>
    <style>
        .title {
            margin: 5px;
        }

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

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

        .bio {
            padding: 10px;
            margin: 5px;
            background-color: #ffffff;
            color: #004835;
        }

        .name 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('index') }}">FlaskApp</a>
        <a href="#">Create</a>
        <a href="#">About</a>
    </nav>
    <hr>
    <div class="content">
        {% block content %} {% endblock %}
    </div>
</body>
</html>

ファイルを保存して閉じます。

この基本テンプレートには、他のテンプレートで再利用する必要があるすべてのHTMLボイラープレートが含まれています。 The title 各ページのタイトルを設定するためにブロックが置き換えられ、 content ブロックは各ページのコンテンツに置き換えられます。 ナビゲーションバーには3つのリンクがあります。1つはインデックスページ用で、 index() を使用した表示機能 url_for() ヘルパー関数。1つはCreateページ用で、もう1つはアプリケーションに追加する場合はAboutページ用です。 Create リンクを機能させるために新しい学生を作成するためのページを追加した後、このファイルを後で編集します。

次に、新しい index.html テンプレートファイル。 これは、で参照したテンプレートです。 app.py ファイル:

  1. nano templates/index.html

次のコードを追加します。

フラスコ_app/templates / index.html
{% extends 'base.html' %}

{% block content %}
    <h1 class="title">{% block title %} Students {% endblock %}</h1>
    <div class="content">
        {% for student in students %}
            <div class="student">
                <p><b>#{{ student.id }}</b></p>
                <b>
                    <p class="name">{{ student.firstname }} {{ student.lastname }}</p>
                </b>
                <p>{{ student.email }}</p>
                <p>{{ student.age }} years old.</p>
                <p>Joined: {{ student.created_at }}</p>
                <div class="bio">
                    <h4>Bio</h4>
                    <p>{{ student.bio }}</p>
                </div>
            </div>
        {% endfor %}
    </div>
{% endblock %}

ファイルを保存して閉じます。

ここでは、ベーステンプレートを拡張し、コンテンツブロックのコンテンツを置き換えます。 あなたは <h1> タイトルを兼ねる見出し。 行でJinjaforloopを使用します {% for student in students %} の各学生を通過する students から渡した変数 index() このテンプレートに関数を表示します。 学生ID、名前と名前、電子メール、年齢、データベースに追加された日付、および経歴を表示します。

あなたの中に flask_app 仮想環境がアクティブ化されているディレクトリ、アプリケーションについてFlaskに通知します(app.py この場合)を使用して FLASK_APP 環境変数。 次に、 FLASK_ENV 環境変数から development アプリケーションを開発モードで実行し、デバッガーにアクセスします。 Flaskデバッガーの詳細については、Flaskアプリケーションでエラーを処理する方法を参照してください。 これを行うには、次のコマンドを使用します。

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

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

  1. flask run

開発サーバーが実行されている状態で、ブラウザーを使用して次のURLにアクセスします。

http://127.0.0.1:5000/

次のようなページに、データベースに追加した学生が表示されます。

データベースにある生徒をインデックスページに表示しました。 次に、個々の学生の詳細を表示できる学生ページのルートを作成します。

ステップ4—単一のレコードを表示する

このステップでは、Flaskシェルを使用して、IDで生徒にクエリを実行し、専用ページに各生徒の詳細を表示するルートとテンプレートを作成します。

このステップの終わりまでに、URL http://127.0.0.1:5000/1 最初の学生を表示するページになります(IDを持っているため) 1). URL http://127.0.0.1:5000/ID 関連付けられた投稿が表示されます ID 番号(存在する場合)。

開発サーバーを実行したままにして、新しいターミナルウィンドウを開きます。

生徒にクエリを実行する方法のデモンストレーションについては、Flaskシェルを開きます。

  1. flask shell

レコードをクエリしてデータベースからデータを取得するために、Flask-SQLAlchemyは query モデルクラスの属性。 そのメソッドを使用して、特定のフィルターでレコードを取得できます。

たとえば、 filter_by() 次のようなパラメータを持つメソッド firstname これは、特定の学生を取得するための引数を持つテーブルの列と一致します。

  1. from app import db, Student
  2. Student.query.filter_by(firstname='Sammy').all()
Output
[<Student Sammy>]

ここでは、すべての学生を取得します Sammy 彼らの名として。 あなたは all() すべての結果のリストを取得するメソッド。 ここで唯一の結果である最初の結果を取得するには、 first() 方法:

  1. Student.query.filter_by(firstname='Sammy').first()
Output
<Student Sammy>

IDで学生を取得するには、次を使用できます filter_by(id=ID):

  1. Student.query.filter_by(id=3).first()

または、短い方を使用できます get() メソッド。主キーを使用して特定のアイテムを取得できます。

  1. Student.query.get(3)

どちらも同じ出力になります。

Output
<Student Carl>

これで、シェルを終了できます。

  1. exit()

IDで生徒を取得するには、個々の生徒ごとにページをレンダリングする新しいルートを作成します。 を使用します get_or_404() Flask-SQLAlchemyが提供するメソッド。これは get() 方法。 違いは get() 値を返します None 指定されたIDに一致する結果がない場合、および get_or_404() を返します 404 Not Found HTTP応答。 開ける app.py 変更の場合:

  1. nano app.py

ファイルの最後に次のルートを追加します。

フラスコ_app/app.py
# ...

@app.route('/<int:student_id>/')
def student(student_id):
    student = Student.query.get_or_404(student_id)
    return render_template('student.html', student=student)

ファイルを保存して閉じます。

ここでは、ルートを使用します '/<int:student_id>/'、 と int: URLのデフォルトの文字列を整数に変換するconverterです。 と student_id ページに表示する学生を決定するURL変数です。

IDはURLからに渡されます student() を介して機能を表示 student_id パラメータ。 関数内で、学生コレクションをクエリし、IDを使用して学生を取得します。 get_or_404() 方法。 これにより、生徒のデータが student 存在する場合は変数であり、 404 Not Found 指定されたIDの学生がデータベースに存在しない場合のHTTPエラー。

と呼ばれるテンプレートをレンダリングします student.html 取得した生徒に渡します。

この新しいを開く student.html テンプレートファイル:

  1. nano templates/student.html

この新しいコードに次のコードを入力します student.html ファイル。 これは、 index.html テンプレート。ただし、1人の学生のみが表示されます。

フラスコ_app/templates / student.html
{% extends 'base.html' %}

{% block content %}
    <span class="title">
        <h1>{% block title %} {{ student.firstname }} {{ student.lastname }}{% endblock %}</h1>
    </span>
    <div class="content">
            <div class="student">
                <p><b>#{{ student.id }}</b></p>
                <b>
                    <p class="name">{{ student.firstname }} {{ student.lastname }}</p>
                </b>
                <p>{{ student.email }}</p>
                <p>{{ student.age }} years old.</p>
                <p>Joined: {{ student.created_at }}</p>
                <div class="bio">
                    <h4>Bio</h4>
                    <p>{{ student.bio }}</p>
                </div>
            </div>
    </div>
{% endblock %}

ファイルを保存して閉じます。

このファイルでは、基本テンプレートを拡張して、ページのタイトルとして学生のフルネームを設定します。 学生ID、学生の姓名、電子メール、年齢、レコード作成日、およびその経歴を表示します。

ブラウザを使用して、2番目の学生のURLに移動します。

http://127.0.0.1:5000/2

次のようなページが表示されます。

今、編集 index.html 各生徒の名前を自分のページにリンクさせるには:

  1. nano templates/index.html

編集します for 次のようにループします。

フラスコ_app/templates / index.html
{% for student in students %}
    <div class="student">
        <p><b>#{{ student.id }}</b></p>
        <b>
            <p class="name">
                <a href="{{ url_for('student', student_id=student.id)}}">
                    {{ student.firstname }} {{ student.lastname }}
                </a>
            </p>
        </b>
        <p>{{ student.email }}</p>
        <p>{{ student.age }} years old.</p>
        <p>Joined: {{ student.created_at }}</p>
        <div class="bio">
            <h4>Bio</h4>
            <p>{{ student.bio }}</p>
        </div>
    </div>
{% endfor %}

ファイルを保存して閉じます。

追加しました <a> を使用して学生ページにリンクする学生のフルネームにタグを付ける url_for() 関数、に保存されている学生IDを渡します student.idstudent() ビュー機能。

インデックスページに移動するか、更新します。

http://127.0.0.1:5000/

これで、各生徒の名前が適切な生徒のページにリンクしていることがわかります。

個々の学生用のページを作成したら、次に、データベースに新しい学生を追加するためのページを追加します。

ステップ5—新しいレコードを作成する

このステップでは、Webフォームを使用してデータベースに新しい学生を追加するための新しいルートをアプリケーションに追加します。

ユーザーが学生のデータを入力するWebフォームを使用してページをレンダリングします。 次に、フォームの送信を処理し、を使用して新しい学生用のオブジェクトを作成します Student モデルを作成し、それをセッションに追加してから、トランザクションをコミットします。これは、手順2で学生のエントリを追加した場合と同じです。

開発サーバーを実行したままにして、新しいターミナルウィンドウを開きます。

まず、 app.py ファイル:

  1. nano app.py

の最後に次のルートを追加します app.py ファイル:

フラスコ_app/app.py
# ...


@app.route('/create/', methods=('GET', 'POST'))
def create():
    return render_template('create.html')

ファイルを保存して閉じます。

このルートでは、タプルを渡します ('GET', 'POST')methods GET要求とPOST要求の両方を許可するパラメーター。 GETリクエストは、サーバーからデータを取得するために使用されます。 POSTリクエストは、特定のルートにデータを投稿するために使用されます。 デフォルトでは、GETリクエストのみが許可されます。 ユーザーが最初にリクエストしたとき /create GETリクエストを使用してルーティングします。 create.html レンダリングされます。 後でこのルートを編集して、ユーザーが新しい学生を追加するためのWebフォームに入力して送信するときのPOSTリクエストを処理します。

新しいを開く create.html テンプレート:

  1. nano templates/create.html

次のコードを追加します。

{% extends 'base.html' %}

{% block content %}
    <h1 style="width: 100%">{% block title %} Add a New Student {% endblock %}</h1>
    <form method="post">
        <p>
            <label for="firstname">First Name</label>
            <input type="text" name="firstname"
                   placeholder="First name">
            </input>
        </p>

        <p>
            <label for="lastname">Last Name</label>
            <input type="text" name="lastname"
                   placeholder="Last name">
            </input>
        </p>

        <p>
            <label for="email">Email</label>
            <input type="email" name="email"
                   placeholder="Student email">
            </input>
        </p>

        <p>
            <label for="age">Age</label>
            <input type="number" name="age"
                   placeholder="Age">
            </input>
        </p>

        <p>
        <label for="bio">Bio</label>
        <br>
        <textarea name="bio"
                  placeholder="Bio"
                  rows="15"
                  cols="60"
                  ></textarea>
        </p>
        <p>
            <button type="submit">Submit</button>
        </p>
    </form>
{% endblock %}

ファイルを保存して閉じます。

基本テンプレートを拡張し、見出しをタイトルとして設定し、 <form> 属性を持つタグ method に設定 post フォームがPOSTリクエストを送信することを示します。

名前の付いた2つのテキストフィールドがあります firstnamelastname. これらの名前を使用して、後でユーザーがビュー機能で送信するフォームデータにアクセスします。

名前の付いたメールフィールドがあります email、学生の年齢の数値フィールド、および学生の略歴のテキスト領域。

最後に、フォームの最後に送信ボタンがあります。

これで、開発サーバーが実行されている状態で、ブラウザーを使用してに移動します。 /create ルート:

http://127.0.0.1:5000/create

新しい学生を追加ページが表示されます。このページには、次のようなWebフォームと送信ボタンがあります。

フォームに入力して送信し、サーバーにPOSTリクエストを送信すると、POSTリクエストを処理しなかったため、何も起こりません。 /create ルート。

開ける app.py ユーザーが送信するPOSTリクエストを処理するには:

  1. nano app.py

編集します /create 次のように見えるルート:

フラスコ_app/app.py

@app.route('/create/', methods=('GET', 'POST'))
def create():
    if request.method == 'POST':
        firstname = request.form['firstname']
        lastname = request.form['lastname']
        email = request.form['email']
        age = int(request.form['age'])
        bio = request.form['bio']
        student = Student(firstname=firstname,
                          lastname=lastname,
                          email=email,
                          age=age,
                          bio=bio)
        db.session.add(student)
        db.session.commit()

        return redirect(url_for('index'))

    return render_template('create.html')

ファイルを保存して閉じます。

POSTリクエストは内部で処理します if request.method == 'POST' 調子。 ユーザーが送信した名、姓、メールアドレス、年齢、略歴を request.form 物体。 int() Python関数を使用して、文字列として渡される年齢を整数に変換します。 あなたは student を使用するオブジェクト Student モデル。 学生オブジェクトをデータベースセッションに追加してから、トランザクションをコミットします。

最後に、ユーザーをインデックスページにリダイレクトします。このページでは、既存の学生の下に新しく追加された学生が表示されます。

開発サーバーが実行されている状態で、ブラウザを使用してに移動します /create ルート:

http://127.0.0.1:5000/create

フォームにデータを入力して送信します。

新しく追加された生徒が表示されるインデックスページにリダイレクトされます。

新しい生徒を追加する機能ができたので、ナビゲーションバーのCreateページへのリンクを追加する必要があります。 開ける base.html:

  1. nano templates/base.html

編集します <body> の値を変更してタグを付ける href の属性 Create リンク:

フラスコ_app/templates / base.html
<body>
    <nav>
        <a href="{{ url_for('index') }}">FlaskApp</a>
        <a href="{{ url_for('create') }}">Create</a>
        <a href="#">About</a>
    </nav>
    <hr>
    <div class="content">
        {% block content %} {% endblock %}
    </div>
</body>

ファイルを保存して閉じます。

インデックスページを更新すると、ナビゲーションバーのCreateリンクが機能するようになります。

これで、新しい学生を追加するためのWebフォームを含むページができました。 Webフォームの詳細については、FlaskアプリケーションでWebフォームを使用する方法を参照してください。 Webフォームを管理するためのより高度で安全な方法については、Flask-WTFを使用してWebフォームを使用および検証する方法を参照してください。 次に、既存の学生のデータを編集するためのページを追加します。

ステップ6—レコードの編集

このステップでは、既存の学生データを編集するための新しいページをアプリケーションに追加します。 新しいを追加します /ID/edit/ IDに基づいて学生のデータを編集するためのルート。

開ける app.py:

  1. nano app.py

次のルートをファイルの最後に追加します。 これにより、IDを使用して編集する学生エントリが取得されます。 後で作成するWebフォームを介して送信された新しい学生データを抽出します。 次に、学生データを編集し、ユーザーをインデックスページにリダイレクトします。

フラスコ_app/app.py
# ...


@app.route('/<int:student_id>/edit/', methods=('GET', 'POST'))
def edit(student_id):
    student = Student.query.get_or_404(student_id)

    if request.method == 'POST':
        firstname = request.form['firstname']
        lastname = request.form['lastname']
        email = request.form['email']
        age = int(request.form['age'])
        bio = request.form['bio']

        student.firstname = firstname
        student.lastname = lastname
        student.email = email
        student.age = age
        student.bio = bio

        db.session.add(student)
        db.session.commit()

        return redirect(url_for('index'))

    return render_template('edit.html', student=student)

ファイルを保存して閉じます。

ここに、あなたはルートを持っています /<int:student_id>/edit/ POSTメソッドとGETメソッドの両方を受け入れます。 student_id IDをに渡すURL変数として edit() ビュー機能。

あなたは get_or_404() のクエリメソッド Student 指定された学生IDに関連付けられた学生を取得するためのモデル。 これはで応答します 404 Not Found 指定されたIDの学生がデータベースに存在しない場合のエラー。

指定されたIDに学生が関連付けられている場合、コードの実行は if request.method == 'POST' 調子。 リクエストがGETリクエストであった場合、つまりユーザーがフォームを送信しなかった場合、この条件はfalseであり、その中のコードはその行にスキップされます。 return render_template('edit.html', student=student). これにより、 edit.html テンプレート。データベースから取得した学生オブジェクトを渡し、学生のWebフォームに現在の学生データを入力できるようにします。 これを作成します edit.html 後でテンプレート。

ユーザーが学生データを編集してフォームを送信すると、 if request.method == 'POST' 実行されます。 提出された学生データを request.form 対応する変数へのオブジェクト。 の各属性を設定します student 手順2で行ったように、新しく送信されたデータに反対して列の値を変更します。 Webフォームのフィールドで変更が実行されなかった場合、その列の値はデータベース内で同じままになります。

学生データを新しく送信されたデータに設定した後、 student データベースセッションに反対し、変更をコミットします。 最後に、ユーザーをインデックスページにリダイレクトします。

次に、ユーザーが編集できるページを作成する必要があります。 新しいを開く edit.html テンプレート:

  1. nano templates/edit.html

この新しいファイルには、次のようなWebフォームがあります。 create.html フィールドのデフォルト値として現在の学生データを含むファイル。 その中に次のコードを追加します。

フラスコ_app/templates / edit.html

{% extends 'base.html' %}

{% block content %}
    <h1 style="width: 100%">
        {% block title %} Edit {{ student.firstname }}
                               {{ student.lastname }}'s Details
        {% endblock %}
    </h1>
    <form method="post">
        <p>
            <label for="firstname">First Name</label>
            <input type="text" name="firstname"
                   value={{ student.firstname }}
                   placeholder="First name">
            </input>
        </p>

        <p>
            <label for="lastname">Last Name</label>
            <input type="text" name="lastname"
                   value={{ student.lastname }}
                   placeholder="Last name">
            </input>
        </p>

        <p>
            <label for="email">Email</label>
            <input type="email" name="email"
                   value={{ student.email }}
                   placeholder="Student email">
            </input>
        </p>

        <p>
            <label for="age">Age</label>
            <input type="number" name="age"
                   value={{ student.age }}
                   placeholder="Age">
            </input>
        </p>

        <p>
        <label for="bio">Bio</label>
        <br>
        <textarea name="bio"
                  placeholder="Bio"
                  rows="15"
                  cols="60"
                  >{{ student.bio }}</textarea>
        </p>
        <p>
            <button type="submit">Submit</button>
        </p>
    </form>
{% endblock %}

ファイルを保存して閉じます。

タイトルには、学生の名前と名前があります。 The value 各入力フィールドの属性とバイオテキスト領域の値は、 student から渡したオブジェクト edit() 関数を表示します edit.html テンプレート。

次に、次のURLに移動して、最初の学生の詳細を編集します。

http://127.0.0.1:5000/1/edit

次のようなページが表示されます。

学生のデータを編集し、フォームを送信します。 インデックスページにリダイレクトされ、学生の情報が更新されます。

次に、インデックスページの各生徒の下に編集ボタンを追加して、編集ページにリンクします。 を開きます index.html テンプレートファイル:

  1. nano templates/index.html

編集します for これでループ index.html 次のように正確に表示されるファイル:

フラスコ_app/templates / index.html

{% for student in students %}
    <div class="student">
        <p><b>#{{ student.id }}</b></p>
        <b>
            <p class="name">
                <a href="{{ url_for('student', student_id=student.id)}}">
                    {{ student.firstname }} {{ student.lastname }}
                </a>
            </p>
        </b>
        <p>{{ student.email }}</p>
        <p>{{ student.age }} years old.</p>
        <p>Joined: {{ student.created_at }}</p>
        <div class="bio">
            <h4>Bio</h4>
            <p>{{ student.bio }}</p>
        </div>
        <a href="{{ url_for('edit', student_id=student.id) }}">Edit</a>
    </div>
{% endfor %}

ファイルを保存して閉じます。

ここに追加します <a> リンクするタグ edit() ビュー関数、渡して student.id Editリンクを使用して各学生の編集ページにリンクする値。

これで、既存の学生を編集するためのページができました。 次に、削除ボタンを追加して、データベースから生徒を削除します。

ステップ7—レコードを削除する

このステップでは、新しいルートを追加し、既存の生徒を削除するための削除ボタンを追加します。

まず、新しいものを追加します /id/delete POSTリクエストを受け入れるルート。 あなたの新しい delete() ビュー機能は、削除したい学生のIDを受け取り、そのIDを get_or_404() のクエリメソッド Student 存在する場合はそれを取得するためのモデル、または 404 Not Found 指定されたIDの学生がデータベースで見つからなかった場合はページ。

開ける app.py 編集用:

  1. nano app.py

次のルートをファイルの最後に追加します。

フラスコ_app/app.py

# ...

@app.post('/<int:student_id>/delete/')
def delete(student_id):
    student = Student.query.get_or_404(student_id)
    db.session.delete(student)
    db.session.commit()
    return redirect(url_for('index'))

ファイルを保存して閉じます。

ここでは、通常の代わりに app.route デコレータでは、Flaskバージョン2.0.0で導入されたapp.post デコレータを使用します。これにより、一般的なHTTPメソッドのショートカットが追加されました。 例えば、 @app.post("/login") のショートカットです @app.route("/login", methods=["POST"]). これは、このビュー関数がPOSTリクエストのみを受け入れ、 /ID/delete ブラウザのルートは 405 Method Not Allowed エラー。WebブラウザはデフォルトでGETリクエストを使用しているためです。 学生を削除するには、ユーザーはこのルートにPOSTリクエストを送信するボタンをクリックします。

これ delete() ビュー機能は、削除する学生のIDを student_id URL変数。 あなたは get_or_404() 学生を取得して保存する方法 student 変数、またはで応答する 404 Not Found 学生が存在しない場合に備えて。 あなたは delete() 行のデータベースセッションのメソッド db.session.delete(student)、学生オブジェクトを渡します。 これにより、トランザクションがコミットされるたびに学生を削除するようにセッションが設定されます。 他の変更を行う必要がないため、を使用してトランザクションを直接コミットします。 db.session.commit(). 最後に、ユーザーをインデックスページにリダイレクトします。

次に、 index.html 学生の削除ボタンを追加するためのテンプレート:

  1. nano templates/index.html

編集します for 新しいを追加してループする <form> 編集リンクのすぐ下にタグを付けます。

フラスコ_app/templates / index.html

{% for student in students %}
    <div class="student">
        <p><b>#{{ student.id }}</b></p>
        <b>
            <p class="name">
                <a href="{{ url_for('student', student_id=student.id)}}">
                    {{ student.firstname }} {{ student.lastname }}
                </a>
            </p>
        </b>
        <p>{{ student.email }}</p>
        <p>{{ student.age }} years old.</p>
        <p>Joined: {{ student.created_at }}</p>
        <div class="bio">
            <h4>Bio</h4>
            <p>{{ student.bio }}</p>
        </div>
        <a href="{{ url_for('edit', student_id=student.id) }}">Edit</a>

        <hr>
        <form method="POST"
                action="{{ url_for('delete', student_id=student.id) }}">
            <input type="submit" value="Delete Student"
                onclick="return confirm('Are you sure you want to delete this entry?')">
        </form>

    </div>
{% endfor %}

ファイルを保存して閉じます。

ここに、POSTリクエストを送信するWebフォームがあります。 delete() ビュー機能。 あなたは合格します student.id の引数として student_id 削除する学生のエントリを指定するパラメータ。 Webブラウザで利用可能なconfirm()メソッド関数を使用して、リクエストを送信する前に確認メッセージを表示します。

次に、インデックスページを更新します。

各学生のエントリの下に学生の削除ボタンが表示されます。 それをクリックして、削除を確認します。 インデックスページにリダイレクトされ、生徒はそこにいなくなります。

これで、学生管理アプリケーションのデータベースから学生を削除する方法があります。

結論

SQLiteデータベースでFlaskとFlask-SQLAlchemyを使用して学生を管理するための小さなFlaskWebアプリケーションを構築しました。 データベースに接続する方法、テーブルを表すデータベースモデルを設定する方法、データベースにアイテムを追加する方法、テーブルにクエリを実行する方法、データベースデータを変更する方法を学びました。

アプリケーションでSQLAlchemyを使用すると、Pythonクラスとオブジェクトを使用してSQLデータベースを管理できます。 SQLiteの代わりに、別のデータベースエンジンを使用できます。 SQLALCHEMY_DATABASE_URI 接続を担当する構成では、コアアプリケーションコードで何も変更する必要はありません。 これにより、最小限のコード変更で、あるSQLデータベースエンジンから別のSQLデータベースエンジンに移動できます。 詳細については、Flask-SQLAlchemyのドキュメントを参照してください。

Flaskの詳細については、Flaskを使用してWebアプリケーションを構築する方法シリーズの他のチュートリアルをご覧ください。