2016-01-22 28 views
0

我有一個與自身有多對多關係的模型:一個操作可以被另一個操作或其自身阻止。提交後Flask-SQLAlchemy多對多鄰接列表更改

operation_to_operation_association_table = db.Table(
    "preventing_operations", 
    db.Column("id", db.Integer, primary_key=True), 
    db.Column("preventing_operation_id", db.Integer, db.ForeignKey("operation.id")), 
    db.Column("prevents_operation_id", db.Integer, db.ForeignKey("operation.id"))) 



class Operation(BaseModel): # BaseModel defines id and creation/update times 
    name = db.Column(db.String) 

    bodypart_id = db.Column(db.Integer, db.ForeignKey(BodyPart.id)) 
    bodypart = db.relationship("BodyPart", backref="operations") 

    prevents = db.relationship("Operation", secondary=operation_to_operation_association_table, 
           foreign_keys=[operation_to_operation_association_table.c.preventing_operation_id], 
           backref="prevented_by") 


    def __eq__(self, other): 
     return other and self.name == other.name and self.bodypart == other.bodypart 
在外殼

然後,從一個新的數據庫:

In [1]: bp = BodyPart(name="liver") 

In [2]: db.session.add(bp) 

In [3]: db.session.commit() 

In [4]: o1, o2 = Operation(name="viewing", bodypart=bp), Operation(name="removing", bodypart=bp) 

In [5]: db.session.add_all([o1, o2]) 

In [6]: db.session.commit() 

In [7]: o1, o2 
Out[7]: (Viewing the liver (1), Removing the liver (2)) 

In [8]: o1.prevents, o2.prevents 
Out[8]: ([], []) 

In [9]: o2.prevents.append(o1) 

In [10]: o1.prevents, o2.prevents 
Out[10]: ([], [Viewing the liver (1)]) 

In [11]: db.session.commit() 

In [12]: o1.prevents, o2.prevents 
Out[12]: ([Viewing the liver (1)], []) 

犯下開關周圍的名單?

記錄查詢,插入查詢的SQLAlchemy發送數據庫似有不妥:

INSERT INTO preventing_operations (prevents_operation_id) VALUES (?) 
with values (1,) 

當它應該是:

INSERT INTO preventing_operations (prevents_operation_id, preventing_operation_id) VALUES (?) 
with values (2, 1) 

我在做什麼錯在這裏?我是否錯誤地定義了我的關係?那爲什麼只有我承諾時纔會改變呢?

回答

1

問題是與foreign_keys安裝程序,我實際上不知道究竟需要做什麼foreign_keys。

但我建議使用primaryjoinsecondaryjoin來代替。這樣的設置對我來說是比較明顯的(和它的作品):

prevents = relationship(
    "Operation", 
    secondary=operation_to_operation, 
    primaryjoin=id == operation_to_operation.c.preventing_operation_id, 
    secondaryjoin=id == operation_to_operation.c.prevents_operation_id, 
    backref="prevented_by") 

這裏是the working examplemodule with base model

運行的例子,因爲這: - 下載兩個文件,保存到同一個文件夾(或克隆回購) - 運行`蟒蛇many_many_save_issue.py。

我用SQLAlchemy == 1.0.6測試了它。

+0

使用該命令返回'sqlalchemy.exc.ArgumentError:找不到關於Operation.prevents關係的主要連接條件'prevent_operations.preventing_operation_id =:preventing_operation_id_1'涉及本地映射外鍵列的任何簡單相等表達式。確保引用列與ForeignKey或ForeignKeyConstraint關聯,或者在連接條件中使用foreign()註釋進行註釋。爲了允許除'=='以外的比較運算符,該關係可以被標記爲viewonly = True。' – thepandaatemyface

+0

@thepandaatemyface在定位之前,我實際測試了它,這裏是[工作示例](https://github.com/serebrov/ so-questions/blob/master/sql-alchemy/many_many_save_issue.py),你也需要[這個文件](https://github.com/serebrov/so-questions/blob/master/sql-alchemy/base .py)來運行它。只需下載並保存並運行'python many_many_save_issue.py'。我能夠重現並修復您的問題。 –

+0

我用SQLAlchemy測試了它== 1.0.6 –