LoginSignup
0
0

Flaskのmodelクラスを別モジュールに切り出す方法

Posted at

はじめに

Flaskのmodelクラスを別モジュールに切り出したので、その方法をまとめます。

ベストプラクティスとは思えませんが、今のところ動いてます。

どんな時に使うか

Flaskでアプリをガシガシ作ってきて、あるタイミングでmodelクラスを別のアプリからも使いたいと思った時。

クリーンアーキテクチャのモデルとして使いたいので、データベースの詳細には依存したくないとき。

免責

クリーンアーキテクチャと言いつつ、flaskのSQLAlchemyにおもいっきり依存しているのだが、そこはOKの前提。

方法

1. 別モジュールのためのディレクトリを作成

たとえばこんなかんじ。

shared_models/
|-- shared_models/
|   |-- __init__.py
|   |-- models.py
|-- tests/
|   |-- __init__.py
|   |-- test_models.py
|-- setup.py

2. setup.pyを作成

from setuptools import setup, find_packages

setup(
    name='shared_models',
    version='0.1',
    packages=find_packages(),
    install_requires=[
        # Any dependencies required
    ],
)

3. models.pyを作成

すでに作成済みのモデルクラスをMyModelYourModelとします。init_modelsは、モデルクラスの定義をアプリのライフサイクルでただ一度だけ行います。データベースへの依存を、引数のdbで注入しています。これにより、shared_modelsは外部に依存しないモジュールになります。

_IS_ALREADY_DEFINED = False

def init_models(db):
    global _IS_ALREADY_DEFINED
    if _IS_ALREADY_DEFINED:
        return
    _IS_ALREADY_DEFINED = True

    global MyModel, YourModel

    # すでに定義済みのモデルクラスをここにコピー
    class MyModel(db.Model):
        # My model definition
        pass

    class YourModel(db.Model):
        # Your model definition
        pass   

4. コンシューマー側のアプリでshared_modelsを使う

shared_modelsを使いたいコンシューマーアプリは、init_models(db)を呼び出してモデルクラスを定義しておきます。その後は、モデルクラスをインポートできます。

database.pyがこうなってたとします。

from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy()
# app.py
from database import db
from shared_models.core_models import init_models
init_models(db) # 依存性の注入とモデルクラスの定義
from shared_models.core_models import MyModel, YourModel # モデルクラスのインポート

@app.route('/api/my_api')
def my_api():
    my_model = MyModel.query.all()
    ...

別のファイルからも、まったく同じようにモデルクラスをインポートできます。
init_modelは何度呼び出しても、モデルクラスの定義は一度しか行われません。

# other_file.py
from database import db
from shared_models.core_models import init_models
init_models(db) # 依存性の注入とモデルクラスの定義
from shared_models.core_models import MyModel, YourModel # モデルクラスのインポート

def my_function():
    your_model = YourModel.query.all()
    ...

5. モデルクラスを継承する

shared_modelsで定義したモデルクラスを継承することもできます。

from database import db
from shared_models.core_models import init_models
init_models(db) # 依存性の注入とモデルクラスの定義
from shared_models.core_models import MyModel, YourModel # モデルクラスのインポート

class CustomMyModel(Utterance):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

    def say_hello(self):
        return f"Hello from Custom Model"


# 通常通りインポートして使える ##############
from app.models import CustomModel
custom_model = CustomMyModel.query.get(1)
print(f"TEST {custom_model}")
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0