2016-11-08 74 views
0

通用的解決方案要刪除的不作爲外鍵通用的解決方案要刪除的不作爲外鍵

這裏有預設,有多種型號記錄記載:「ParentA」,「ParentB」,」 ChildAA','ChildBA'等。
ParentX和ChildXY之間的關係是ChildXY有ParentX, 的例如一個外鍵:

#this is ParentA 
class ParentA(Base): 
    __tablename__ = 'parenta' 
    id = Column(Integer, primary_key=True) 
    name = Column(String(12)) 
    need_delete = Column(Integer) 
    children = relationship("ChildAA", 
          back_populates="parent") 
#this is ChildAA 
class ChildAA(Base): 
    __tablename__ = 'childaa' 
    name = Column(String(12)) 
    id = Column(Integer, primary_key=True) 
    need_delete = Column(Integer) 
    parenta_id = Column(Integer, ForeignKey('parenta.id')) 
    parenta = relationship("ParentA") 

#this is ParentB 
........ 

而且我想刪除所有記錄(所有childx,parentx包括在內),其屬性「need_delete」是1並且記錄自己沒有被用作子表的外鍵。我發現了一個直接的,但複雜的方式:

我可以先通過所有的childx表和安全removd記錄,然後到parentx表和一個刪除與 代碼塊一個記錄:

#deletion is for ParentA 
for parent in session.query(ParentA).join(ParentA.children).group_by(ParentA).having(func.count(ChildAA.id) == 0):  
    if parent.need_delete == 1 
     session.delete(parent) 

#deletion is for ParentB 
...... 
#deletion is for ParentC 
..... 
session.commit() 

這是硬編碼,是否有任何通用的方式來刪除當前用作外鍵的記錄?

+0

@ IljaEverilä,謝謝,我更新了這個問題〜 – TommyLike

+0

另一個問題是,所有的「父母」模型都將關係定義爲「children」屬性嗎? –

+0

@IljaEverilä,是的,他們都有一個表明這一點,但他們的屬性名稱不同於childrenx,childreny .... – TommyLike

回答

2

你可以使用NOT EXISTS,一個antijoin,查詢那些沒有孩子,需要刪除的父母:

通過一個使用
from sqlalchemy import inspect 

# After you've cleaned up the child tables: 
# (Replace the triple dot with the rest of your parent types) 
for parent_type in [ParentA, ParentB, ...]: 
    # Query for `parent_type` rows that need delete 
    q = session.query(parent_type).filter(parent_type.need_delete == 1) 
    # Go through all the relationships 
    for rel in inspect(parent_type).relationships: 
     # Add a NOT EXISTS(...) to the query predicates (the antijoin) 
     q = q.filter(~getattr(parent_type, rel.key).any()) 

    # Issue a bulk delete. Replace `False` with 'fetch', 
    # if you do need to synchronize the deletions with the ongoing 
    # SQLA session. In your example you commit after the deletions, 
    # which expires instances in session, so no synchronization is 
    # required. 
    q.delete(synchronize_session=False) 

... 

session.commit() 

而不是首先查詢所有實例的會話,並標記爲刪除一個bulk delete

請注意,您必須明確您的關係,並且必須定義父方。如果你有外鍵引用的父表沒有被定義爲父對象上的SQLAlchemy關係,你可能會得到不需要的子對象刪除(取決於外鍵約束是如何配置的)。

另一種方法可能是配置外鍵約束來限制刪除並處理子事務(保存點)中引發的錯誤,但是我想你已經設置了你的模式,並且需要改變現有的外鍵限制。

+0

如果我使用raise和except代碼塊,我是否需要檢索每條記錄並分別刪除它? – TommyLike

+0

你是指使用['ondelete ='restrict'']的後一種方法(http://docs.sqlalchemy.org/en/latest/core/constraints.html#sqlalchemy.schema.ForeignKey.params.ondelete) ?在這種情況下,我認爲你必須恢復到需要刪除的父母(至少是ID),然後嘗試刪除保存點,忽略由於限制引發的錯誤。當然,沒有任何東西阻止你使用反連接方法*和*配置外鍵約束來限制刪除,以防出現錯誤。 –

相關問題