概要
過去に Flask-Migrate を使ってテーブルを作成してみました
今回は外部キー制約のあるテーブルを作成する方法を紹介します
なおファイルはこちらの記事を元にリファクタリングしているものを使います
環境
- macOS 10.15.5
- MySQL 8.0.19
- Python 3.8.3
- Flask-Migrate 2.5.3
- Flask-SQLAlchemy 2.5.3
サンプルコード
とりあえずサンプルコードです
Item というテーブルを追加して User テーブルの id カラムを外部キー制約として定義します
なので User テーブルに存在しない id を Item テーブルの user_id に登録しようとするとエラーになります
vim my_app/database.py
from flask_sqlalchemy import SQLAlchemy
from flask_marshmallow import Marshmallow
db = SQLAlchemy()
ma = Marshmallow()
class User(db.Model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(128))
age = db.Column(db.Integer)
__table_args__ = (
db.UniqueConstraint('name', 'age', name='unique_name_age'),
)
# item テーブルに user という名前で参照させてあげることを宣言
item = db.relationship("Item", backref="user")
def __repr__(self):
return "%s,%s,%i" % (self.id, self.name, self.age)
class Item(db.Model):
# 必ず primary_key となる id がないとエラーになるので定義
id = db.Column(db.Integer, primary_key=True)
user_id = db.Column(db.Integer, db.ForeignKey("user.id"))
name = db.Column(db.String(20))
class UserSchema(ma.Schema):
class Meta:
fields = ("id", "name", "age")
class ItemSchema(ma.Schema):
class Meta:
fields = ("user_id", "name", "user")
user = ma.Nested(UserSchema, many=False)
参照させる側のテーブルで db.relationship
を定義します
backref=user
とすることで User テーブルを user.
で参照できるようにさせます
外部キー制約を付与したいカラムに db.ForeignKey("user.id")
という感じで定義すれば制約を付与することができます
今回は Item に対して User は一意に決まるので many=False
にすることで配列にならないようにしています
Flask-Migrate か Flask-SQLAlchemy の制約で primary_key
が必須なようなので Item テーブルに id カラムを定義しています
ItemSchema について
これもポイントです
外部キーの参照先がある場合 sqlalchemy は自動で引っ張ってきてくれます
そのためのフィールドを追加で定義してあげています
また外部のテーブルは ma.Nested
を使って階層化することで同じフィールドでも問題なくシリアライズできるようにしています
マイグレート
テーブルを作成しましょう
FLASK_APP=my_app pipenv run flask db migrate -m "Create item table"
FLASK_APP=my_app pipenv run flask upgrade
データは適当に入れておきます
mysql -u root test -e "select * from user;"
+----+------+------+
| id | name | age |
+----+------+------+
| 1 | a | 10 |
| 2 | b | 10 |
| 3 | c | 20 |
+----+------+------+
mysql -u root test -e "select * from item;"
+----+---------+-------+
| id | user_id | name |
+----+---------+-------+
| 2 | 1 | apple |
| 3 | 1 | grape |
+----+---------+-------+
データを取得してみる
実際に Flask からデータを取得してみましょう
まずは Item テーブルからデータを取得する処理を作成します
vim my_app/lib/__init__.py
from my_app.database import db, Item, ItemSchema
class ItemCRUD():
def select(self, id):
item = Item.query.get(id)
# print(item.user)
return ItemSchema(many=False).dump(item)
そしてそれを Flask アプリでそれを使います
vim my_app/__init__.py
from flask import Flask
from flask_migrate import Migrate
from my_app.database import db, ma
from my_app.lib import ItemCRUD
app = Flask(__name__)
app.debug = True
app.config['SQLALCHEMY_DATABASE_URI'] = "mysql+mysqldb://root:@localhost/test?charset=utf8"
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = True
db.init_app(app)
migrate = Migrate(app, db)
ma.init_app(app)
@app.route('/<id>')
def select(id=None):
crud = ItemCRUD()
item = crud.select(id)
return item
動作確認
FLASK_APP=my_app pipenv run flask run
curl localhost:5000/2
=> {"name":"apple","user":{"age":10,"id":1,"name":"a"},"user_id":1}
こんな感じで外部キーの参照先の User テーブルの情報も階層化されて取得されるのが確認できると思います
最後に
Flask-Migrate で外部キー制約を付与してみました
今回は One-to-Many 構成で外部キー制約を付与しましたが One-to-Many や Many-to- Many でも制約を付与することができます
作成したテーブルはマイグレートしたあとでちゃんと show create table
などで確認したほうが良いでしょう
0 件のコメント:
コメントを投稿