2012-04-13 80 views
2

如何在刪除類別時自動將產品category_id設置爲默認值?例如1指向第一個類別。如何將外鍵設置爲刪除時的默認值?

class Product(db.Model): 
    id = db.Column(db.Integer, primary_key=True) 
    name = db.Column(db.String(80)) 
    content = db.Column(db.Text(), unique=True) 
    category_id = db.Column(db.Integer, db.ForeignKey('category.id')) 
    atime = db.Column(db.DateTime()) 

    def __init__(self, name, content, category_id): 
     self.name = name 
     self.content = content 
     self.category_id = category_id 
     self.atime = datetime.now() 

    def __repr__(self): 
     return '<Product %r>' % self.id 

class Category(db.Model): 
    id = db.Column(db.Integer, primary_key=True) 
    name = db.Column(db.String(80)) 
    products = db.relationship('Product', backref='category', cascade="all, delete, delete-orphan") 

    def __init__(self, *args, **kwargs): 
     if len(kwargs) > 0: 
      self.name = kwargs['name'] 

    def __repr__(self): 
     return '<Category %r>' % self.name 

我不想用級聯刪除它們!

回答

6

有需要在編排這裏要執行兩件事情:

  1. 定義適當的參照作用
  2. 配置SA關係

我覺得級聯選項外鍵最簡潔的方法是將category_id的值設置爲NULL,當刪除其類別時:​​是ON DELETE子句可能的Referential Actions之一,w HICH您可以添加到您的ForeignKey定義:

category_id = db.Column(db.Integer, db.ForeignKey('category.id', ondelete='SET NULL')) 

在你可以使用一個選項SET DEFAULT以同樣的方式,但在這種情況下,你還需要爲列category_id配置默認值:category_id = Column(..., server_default=1)。請注意,這些實現在不同的RDBMS之間有所不同。

至於cascade選項:你應該從products關係定義中刪除cascade="all, delete, delete-orphan"。事實上,你想確保delete, delete-orphan不存在。

說了這麼多,你真的需要對代碼進行測試,以覆蓋不同的場景,爲Category對象的兩個不同的缺失可能會產生不同的結果,這取決於您的RDBMS和SA配置:

# scenario-1: delete in session: SA might set category_id of all chilren Products to None 
c1 = session.query(Category).get(1) 
session.delete(c1) 
session.commit() 

# scenario-2: delete without loading an object into the session: SA will perform no additional logic 
session.query(Category).filter(Category.id == 2).delete() 
session.commit() 

希望這一切指出你在正確的方向。像往常一樣,使用echo=True或只需配置logging模塊即可在測試代碼中啓用SQL日誌記錄,您將看到SA對您的數據庫執行的操作。在SQL中沒有看到的其他更改由RDBMS本身在給定參考操作的情況下完成。