Back to Blog

Flaskでデータベースのリレーションを設定する方法【Flask-SQLAlchemy】

flask

2024年7月17日

こんにちは!

Flaskは、PythonのWebフレームワークであり、そのシンプルさと柔軟性から多くの開発者に支持されています。

Flaskでデータベースを使用する際、リレーション(関連付け)を設定することが多いでしょう。

リレーショナルデータベースでは、複数のテーブル間の関連付けを適切に設定することで、データの整合性や効率的なデータアクセスを実現できます。

そこで、今回の記事では、Flaskを用いてデータベースのリレーションを設定する方法について詳細に解説します。

リレーションとは?

そもそもリレーションとは何なのでしょうか?

データベースのリレーションとは、テーブル間の関係を定義する仕組みです。

例えば、1人のユーザーが複数のブログポストを持つ「一対多」関係をUserテーブルとBlogPostテーブルで設定できます。

リレーションを定義することで、異なるテーブルのデータを効率的に関連付けたり結合したりすることが可能になります。

データベースの設定

まずは、Flaskでデータベースを使用する設定方法について解説します。

以下のパッケージをインストールしましょう。

pip install Flask SQLAlchemy Flask-SQLAlchemy Flask-Migrate

続いて、app.pyに設定を行います。

from flask import Flask, render_template, redirect, url_for
from flask_sqlalchemy import SQLAlchemy
from flask_migrate import Migrate

app = Flask(__name__)

# Configuration settings
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///app.db'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False

# Initialize extensions
db = SQLAlchemy(app)
migrate = Migrate(app, db)

ここまでは、データベースの初期設定です。SQLAlcemyとFlask-Migrateの設定をしています。

データベースの設定方法については、以下の記事で詳しく解説しています。

【関連】Flask-SQLAlchemyとは?FlaskでDBを使おう

次にモデルの設定を行います。

モデルでリレーションを設定する

リレーションの設定は、モデルで定義します。

今回は、ユーザー(User)とブログ記事(BlogPost)のデータがあるとします。

class User(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    username = db.Column(db.String(80), unique=True, nullable=False)
    posts = db.relationship('BlogPost', backref='author')

class BlogPost(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    title = db.Column(db.String(120), nullable=False)
    content = db.Column(db.Text, nullable=False)
    user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)

上記のコードでは、UserとBlogPostの間に一対多(one-to-many)のリレーションを設定しています。具体的には、Userモデルは複数のBlogPostを持つことができ、BlogPostは1つのUserに関連付けられます。

db.relationship

ここでは、リレーションの設定を詳しく解説します。

まず、Userモデルでは、以下の設定をしています。

posts = db.relationship('BlogPost', backref='author')

これは、UserモデルとBlogPostモデルの関係を定義します。このリレーションにより、Userオブジェクトから関連するBlogPostオブジェクトにアクセスできるようになります。

db.relationshipの書式は以下のようになります。

db.relationship([リレーションを持つ対象のクラス名], [オプション1], [オプション2]...)

db.relationshipの一つ目の引数には、リレーションを持つ対象のクラス名を文字列で指定します。例えば、BlogPostクラスとのリレーションを定義する場合、'BlogPost'と記述します。

また、オプションには以下のようなものがあります。

オプション説明
backref逆方向のリレーションを設定。関連オブジェクトから元のオブジェクトにアクセス可能。
lazyリレーションのロード方法を指定。値としてselect、immediate、joined、subquery、dynamicなどが使用可能。
uselistリレーションがリストとして扱われるか、単一のオブジェクトとして扱われるかを指定。
cascade親オブジェクトに対する操作が関連オブジェクトに伝播する方法を指定。
secondary多対多のリレーションを設定するための中間テーブルを指定。
primaryjoinカスタムのJOIN条件を指定。複雑な条件が必要な場合に使用。
order_byリレーションの結果をソートするための条件を指定。

今回の場合、backref=’author’というオプションを設定しています。

これにより、BlogPostオブジェクトから関連するUserオブジェクトにアクセスできるようになります。BlogPostオブジェクトからは、post.authorでそのブログポストの著者(User)にアクセスできます。

db.ForeignKey

また、BlogPostクラスでは、以下のように定義しています。

user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)

db.ForeignKey(‘user.id’)は、BlogPostがUserに関連付けられるための外部キーを定義します。

外部キーとは、あるテーブルのカラムが別のテーブルのプライマリキーを参照することを意味します。これにより、テーブル間のリレーション(関連付け)を確立することができます。

今回は、userのidを外部キーとして設定しています。

このようにdb.relationshipとdb.ForeignKeyを使うことでデータベースにリレーションシップを設定することができます。

リレーションのデータをテンプレートに表示する

ここまで、モデルの定義方法について解説しました。

次は、テンプレートにデータを表示させてみましょう。以下のようにルーティングの設定を追加します。

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

if __name__ == '__main__':
    app.run(debug=True)

上記では、BlogPostのデータをテンプレートに渡しています。

次にテンプレートを作成します。

templates/index.htmlには、以下のように設定します。

<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Blog Posts</title>
</head>
<body>
    <h1>Blog Posts</h1>
    <ul>
        {% for post in posts %}
            <li>
                <h2>{{ post.title }}</h2>
                <p>{{ post.content }}</p>
                <p>作成者: {{ post.author.username }}</p>
            </li>
        {% endfor %}
    </ul>
</body>
</html>

これでテンプレートとアプリの設定は完了です。

ここまでのapp.pyの全文はこちらです。

from flask import Flask, render_template, redirect, url_for
from flask_sqlalchemy import SQLAlchemy
from flask_migrate import Migrate

app = Flask(__name__)

# Configuration settings
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///app.db'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False

# Initialize extensions
db = SQLAlchemy(app)
migrate = Migrate(app, db)

# Model
class User(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    username = db.Column(db.String(80), unique=True, nullable=False)
    posts = db.relationship('BlogPost', backref='author')

class BlogPost(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    title = db.Column(db.String(120), nullable=False)
    content = db.Column(db.Text, nullable=False)
    user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)

#view
@app.route('/')
def index():
    posts = BlogPost.query.all()
    return render_template('index.html', posts=posts)

if __name__ == '__main__':
    app.run(debug=True)

データベースの作成とデータの追加

アプリケーションの準備ができたら、データベースの作成とデータの追加を行います。

flask db init
flask db migrate
flask db upgrade

上記のコマンドで、データベースとテーブルが作成されます。

その後、コマンドラインからデータを追加します。まずは、flask shellを起動します。

flask shell

flask shellを起動すると、コンソールが>>>となります。その状態で以下のコマンドを実行していきます。

user = User(username='john')
db.session.add(user)
db.session.commit()

post1 = BlogPost(title='First Post', content='Content of the first post', author=user)
post2 = BlogPost(title='Second Post', content='Content of the second post', author=user)

db.session.add(post1)
db.session.add(post2)
db.session.commit()

動作確認

最後にFlaskを起動して動作確認してみましょう。

python app.py

ブラウザから、http://127.0.0.1:5000にアクセスすると、以下のようにブログのデータとユーザーのデータが表示されています。

このようにデータベースのリレーションのデータを使用します。

まとめ

今回の記事では、Flaskでデータベースのリレーションを設定する方法について解説しました。

モデルの定義の方法から、テンプレートでのデータの使用方法まで、Webアプリケーションの開発でよく使う部分を中心に説明しました。

FlaskでWebアプリケーションの開発をしている方の参考になれば嬉しいです。

ここまでお読みいただきありがとうございました。

Webの知識を作りながら学ぶ
Flask WebAcademy

SNSアプリやチャットアプリ、さまざまなアプリを作りながら学べる実践的なカリキュラム

詳細を見る