1

I持って私のフラスコ/ SQLAlchemyのアプリケーションで、以下の4つのモデルクラス(MyClassA参照をここに示されされないが、第五級):Flask-Migrateコマンドdb initdb migratedb upgrade作品だけを使用して、このスキーマの作成Flask/SQLAlchemyモデルでこの循環参照を防止する方法は?

class MyClassF(db.Model): 
    valid_fs = ['F1', 'F2'] 
    f_id = db.Column(db.Integer, nullable=False, primary_key=True) 
    name = db.Column(db.Enum(*valid_fs, name='f_enum'), default='F1', nullable=False) 

class MyClassD(db.Model): 
    d_id = db.Column(db.Integer, nullable=False, primary_key=True) 
    name = db.Column(db.String(128)) 
    v_collection = db.relationship('MyClassV', lazy='dynamic', backref=db.backref('d'), cascade='all, delete-orphan') 

class MyClassV(db.Model): 
    v_id = db.Column(db.Integer, nullable=False, primary_key=True) 
    d_id = db.Column(db.Integer, db.ForeignKey(MyClassD.d_id), nullable=False) 
    c_collection = db.relationship('MyClassC', lazy='dynamic', backref=db.backref('v'), cascade='all, delete-orphan') 
    a_collection = db.relationship('MyClassA', lazy='dynamic', backref=db.backref('v'), cascade='all, delete-orphan') 

class MyClassC(db.Model): 
    c_id = db.Column(db.Integer, nullable=False, primary_key=True) 
    v_id = db.Column(db.Integer, db.ForeignKey(MyClassV.v_id), nullable=False) 
    f_id = db.Column(
     db.Integer, 
     db.ForeignKey(MyClassF.f_id), 
     nullable=False, 
     #default=MyClassF.query.filter(MyClassF.name == "F1").one().f_id 
    ) 

良い。しかし

、I非コメント行MyClassC.f_idの定義と(migrationsディレクトリを削除した後)、再びそれを試して、私は、次の循環依存関係のエラーが出る:

sqlalchemy.exc.InvalidRequestError: When initializing mapper Mapper|MyClassV|my_classV, expression 'MyClassC' failed to locate a name ("name 'MyClassC' is not defined"). If this is a class name, consider adding this relationship() to the class after both dependent classes have been defined.

私がしようとしているすべてのMyClassFテーブルを照会することによって、デフォルト値MyClassC.f_idが設定されていることを確認してください。このチェックは、データベースが作成されているときではなく、挿入時に実行されます。だから私は今なぜこのエラーが発生しているのか分からない。

db.relationship()(または他の手法)を使用して、この循環依存関係のエラーを回避し、実装しようとしているデータベース整合性ルールを強制するにはどうすればよいですか?

答えて

3

デフォルトのパラメータはSQL DEFAULT constraintに変換されていると思います。 AFAICTこの制約は挿入時には評価されませんが、表を作成するときに値がデフォルトとして使用されます(つまり、表の作成時にデフォルト値が設定され、その列を欠くすべての行に使用されます)他の表の内容に従って動的に変更することはできません)。

しかしthe documentation of SQLAlchemyあなたはデフォルト値としてPython 機能に渡すことができるという事実に言及し、あなたが行うことができますので、使用するデフォルト値を得るために、各挿入のために呼び出されます。

class MyClassC(db.Model): 
    c_id = db.Column(db.Integer, nullable=False, primary_key=True) 
    v_id = db.Column(db.Integer, db.ForeignKey(MyClassV.v_id), nullable=False) 
    f_id = db.Column(
     db.Integer, 
     db.ForeignKey(MyClassF.f_id), 
     nullable=False, 
     default=lambda: MyClassF.query.filter(MyClassF.name == "F1").one().f_id 
    ) 

ただし、これはではありません。はデフォルト値を提供するためにデータベース機能を使用しますが、SQLAlchemyはまずデフォルト値を取得してから手動でクエリに挿入します。

+0

完璧な答え。ありがとうございました! –