web-dev-qa-db-ja.com

Flaskのdb.Modelとdb.Table-SQLAlchemy

Flask-SQLAlchemy docs は、多対多のルックアップテーブルはdb.Modelをサブクラス化するのではなく、db.Tablesとして記述する必要があると述べています。ドキュメントから:

多対多の関係を使用する場合は、関係に使用されるヘルパーテーブルを定義する必要があります。このヘルパーテーブルでは、モデルではなく実際のテーブルを使用することを強くお勧めします

どうして?すべてをモデルにすることの欠点は何ですか?データベースでテーブルを宣言する統一された方法がある方がきれいに見えると思います。また、後で開発者が、モデルを必要とする関係を介してではなく、これらのマッピングレコードに直接アクセスしたいと思う可能性もあります。

9
Matt Davis

_db.Table_はもっと単純です。

_db.Table_を介して多対多の関係を定義すると、SQLAlchemyが引き継ぎ、ほとんどの作業を代行します。

したがって、次のTableおよびModelの定義を持つ投稿およびタグとの関係があると仮定します。

テーブル:

_tagging = db.Table('tagging',
    db.Column('post_id', db.Integer, db.ForeignKey('post.id')),
    db.Column('tag_id', db.Integer, db.ForeignKey('tag.id'))
)
_

モデル:

_class Tagging(db.Model):
    tag_id = db.Column(db.Integer, db.ForeignKey('tag.id'),
                              primary_key=True)
    post_id = db.Column(db.Integer, db.ForeignKey('post.id'),
                               primary_key=True)
_

挿入と削除

docs の説明として:

Relationship()の2次引数に固有の動作は、ここで指定されたテーブルは、オブジェクトがコレクションに追加またはコレクションから削除されるときに、自動的にINSERTおよびDELETEステートメントの対象となることです。このテーブルから手動で削除する必要はありません。コレクションからレコードを削除するという行為は、フラッシュ時に行が削除される効果があります。

_db.Table_を使用すると、次のようなことができます。

_>>> post.tags.append(tag_foo)
>>> db.session.commit()
_

セッションに追加する必要はありません。その後、remove()との関係を削除できます。

_>>> post.tags.remove(tag_foo)
>>> db.session.commit()
_

ただし、_db.Model_を使用する場合は、次のようにする必要があります(TaggingはModelクラスです)。

_>>> tagging = Tagging(post=post_foo, tag=tag_bar)
>>> db.session.add(tagging)
>>> db.session.commit()
_

次に、次のように削除します。

_>>> tagging = post.tags.filter_by(post_id=post.id).first()
>>> db.session.delete(tagging)
>>> db.session.commit()
_

クエリ

_db.Table_の場合:

_>>> post.tags.all()
>>> [<Tag 'foo'>, ...]
_

次に_db.Model_:

_>>> post.tags.all()  # You only get Tagging item.
>>> [<Tagging 'post_foo -- tag_bar'>, ...]
>>> for tagging in post.tags:
>>>     print tagging.tag  # <Tag 'foo'>
_

つまり、関係に関する追加のデータを保存する必要がない場合は、_db.Table_を使用するだけで、時間を節約できます。

7
Grey Li