Flask-SQLAlchemyを使用してFlaskアプリケーションのデータベースと対話する方法

提供:Dev Guides
移動先:案内検索

著者は、 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をインストールします。

pip install Flask Flask-SQLAlchemy

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

OutputSuccessfully 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クラスです。 データベースを開始し、宣言するモデルに基づいて学生用のテーブルを作成し、数人の学生を学生テーブルに追加します。

データベース接続の設定

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

nano app.py

このファイルは、database.dbというSQLiteデータベースに接続し、Flaskルートに加えて、学生情報を格納するためのデータベース学生テーブルを表すStudentというクラスを持ちます。 app.pyの先頭に次のimportステートメントを追加します。

フラスコ_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を作成するurl_for()関数、ユーザーをリダイレクトするredirect()関数。 ルートとテンプレートの詳細については、Flaskアプリケーションでテンプレートを使用する方法を参照してください。

次に、Flask-SQLAlchemy拡張機能から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という変数に保存します。

次に、appというFlaskアプリケーションインスタンスを作成します。これを使用して、2つのFlask-SQLAlchemy構成キーを構成します。

  • SQLALCHEMY_DATABASE_URI:接続を確立するデータベースを指定するデータベースURI。 この場合、URIはsqlite:///path/to/database.dbの形式に従います。 os.path.join()関数を使用して、作成してbasedir変数に格納したベースディレクトリと、database.dbファイル名をインテリジェントに結合します。 これにより、flask_appディレクトリのdatabase.dbデータベースファイルに接続されます。 データベースを開始すると、ファイルが作成されます。
  • 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}>'

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

Studentモデルに対して次の列を定義します。

  • id:学生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 now()日時関数を呼び出すfunc.now()関数を渡します。 SQLiteでは、学生テーブルを作成するときにCURRENT_TIMESTAMPとしてレンダリングされます。
  • bio:学生の略歴。 db.Text()は、列が長いテキストを保持していることを示します。

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

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

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モデルに基づいてデータベースと学生テーブルを作成します。

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

export FLASK_APP=app
flask shell

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

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

from app import db, Student
db.create_all()

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

ノート:

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

db.drop_all()
db.create_all()

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


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

テーブルへの入力

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

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

flask shell

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

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

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

student_john

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

Output<Student john>

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

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

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

print(student_john.id)
OutputNone

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

db.session.add(student_john)

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

db.session.commit()

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

print(student_john.id)
Output1

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

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

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

sammy = Student(firstname='Sammy',
               lastname='Shark',
               email='[email protected]',
               age=20,
               bio='Marine biology student')

carl = Student(firstname='Carl',
               lastname='White',
               email='[email protected]',
               age=22,
               bio='Marine geology student')

db.session.add(sammy)
db.session.add(carl)
db.session.commit()

これで、query属性とall()メソッドを使用して、studentテーブルのすべてのレコードをクエリできます。

Student.query.all()

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

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

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

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

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

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

app.pyファイルを開いて、インデックスページのルートを追加します。

nano app.py

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

フラスコ_app/app.py

# ...

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

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

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

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

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

mkdir templates
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ボイラープレートが含まれています。 titleブロックは各ページのタイトルを設定するために置き換えられ、contentブロックは各ページのコンテンツに置き換えられます。 ナビゲーションバーには3つのリンクがあります。1つはurl_for()ヘルパー機能を使用してindex()ビュー機能にリンクするインデックスページ用、もう1つはCreateページ用です。アプリケーションに追加することを選択した場合は、Aboutページの場合。 Create リンクを機能させるために新しい学生を作成するためのページを追加した後、このファイルを後で編集します。

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

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>の見出しを使用します。 {% for student in students %}行のJinjafor loop を使用して、index()ビュー関数からこれに渡したstudents変数の各学生を調べます。レンプレート。 学生ID、名前と名前、電子メール、年齢、データベースに追加された日付、および経歴を表示します。

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

export FLASK_APP=app
export FLASK_ENV=development

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

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シェルを開きます。

flask shell

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

たとえば、filter_by()メソッドをfirstnameなどのパラメーターとともに使用して、特定の学生を取得するための引数を持つテーブルの列に一致させることができます。

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

ここでは、Sammyを名としてすべての学生を取得します。 all()メソッドを使用して、すべての結果のリストを取得します。 ここで唯一の結果である最初の結果を取得するには、first()メソッドを使用できます。

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

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

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

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

Student.query.get(3)

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

Output<Student Carl>

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

exit()

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

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のデフォルトの文字列を整数に変換するコンバーターです。 また、student_idは、ページに表示する生徒を決定するURL変数です。

IDは、student_idパラメーターを介してURLからstudent()ビュー関数に渡されます。 関数内で、学生コレクションをクエリし、get_or_404()メソッドを使用してIDで学生を取得します。 これにより、学生データが存在する場合はstudent変数に保存され、指定されたIDの学生がデータベースに存在しない場合は404 Not FoundHTTPエラーで応答します。

student.htmlというテンプレートをレンダリングし、取得した生徒に渡します。

この新しいstudent.htmlテンプレートファイルを開きます。

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を編集して、各生徒の名前を自分のページにリンクさせます。

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 %}

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

url_for()関数を使用して学生ページにリンクする<a>タグを学生のフルネームに追加し、student.idに保存されている学生IDを[に渡します。 X177X]表示機能。

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

http://127.0.0.1:5000/

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

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

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

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

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

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

まず、app.pyファイルを開きます。

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リクエストのみが許可されます。 ユーザーが最初にGETリクエストを使用して/createルートをリクエストすると、create.htmlというテンプレートファイルがレンダリングされます。 後でこのルートを編集して、ユーザーが新しい学生を追加するためのWebフォームに入力して送信するときのPOSTリクエストを処理します。

新しいcreate.htmlテンプレートを開きます。

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 %}

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

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

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

emailという名前の電子メールフィールド、学生の年齢の番号フィールド、および学生の略歴のテキスト領域があります。

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

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

http://127.0.0.1:5000/create

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

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

app.pyを開いて、ユーザーが送信するPOST要求を処理します。

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')

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

if request.method == 'POST'条件内でPOST要求を処理します。 request.formオブジェクトから、ユーザーが送信した名、姓、電子メール、年齢、および略歴を抽出します。 int() Python関数を使用して、文字列として渡される年齢を整数に変換します。 Studentモデルを使用して、studentオブジェクトを作成します。 学生オブジェクトをデータベースセッションに追加してから、トランザクションをコミットします。

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

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

http://127.0.0.1:5000/create

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

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

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

nano templates/base.html

Createリンクのhref属性の値を変更して、<body>タグを編集します。

フラスコ_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を開きます:

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)

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

ここでは、POSTメソッドとGETメソッドの両方を受け入れるルート/<int:student_id>/edit/があり、IDをedit()ビュー関数に渡すURL変数としてstudent_idがあります。

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

指定された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オブジェクトから対応する変数に抽出します。 手順2で行ったように、studentオブジェクトの各属性を新しく送信されたデータに設定して、列の値を変更します。 Webフォームのフィールドで変更が実行されなかった場合、その列の値はデータベース内で同じままになります。

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

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

nano templates/edit.html

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

フラスコ_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 %}

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

タイトルには、学生の名前と名前があります。 各入力フィールドのvalue属性とバイオテキスト領域の値は、edit()ビュー関数から[に渡したstudentオブジェクトの対応する値に設定されます。 X189X]テンプレート。

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

http://127.0.0.1:5000/1/edit

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

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

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

nano templates/index.html

この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>
        <a href="{{ url_for('edit', student_id=student.id) }}">Edit</a>
    </div>
{% endfor %}

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

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

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

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

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

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

app.pyを開いて編集します。

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

次に、index.htmlテンプレートを編集して、学生の削除ボタンを追加します。

nano templates/index.html

Editリンクのすぐ下に新しい<form>タグを追加して、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>
        <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リクエストをdelete()ビュー関数に送信するWebフォームがあります。 student.idstudent_idパラメーターの引数として渡して、削除する学生のエントリを指定します。 Webブラウザで利用可能なconfirm()メソッド関数を使用して、リクエストを送信する前に確認メッセージを表示します。

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

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

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

結論

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

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

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