2009-06-28 55 views
6

我正在使用谷歌應用程序引擎與Django的1.0.2(和Django的幫手),並想知道人們如何去做遞歸刪除。 假設你有一個模型,它是這樣的:谷歌應用程序引擎中的遞歸刪除

 
class Top(BaseModel): 
    pass 

class Bottom(BaseModel): 
    daddy = db.ReferenceProperty(Top) 

現在,當我刪除類型「頂」的目標,我希望所有的相關的「底部」的對象被刪除。

就像現在的情況一樣,當我刪除'Top'對象時,'Bottom'對象保留,然後我得到的數據不屬於任何地方。當在一個視圖訪問的數據存儲,我結束了:

Caught an exception while rendering: ReferenceProperty failed to be resolved.

當然我能找到的所有對象並將其刪除,但因爲我的真實模型至少爲5級深,我希望有辦法確保這可以自動完成。

我發現這個article關於它如何與Java協同工作,這似乎是我想要的。

任何人都知道我該如何在django中獲得該行爲?

回答

6

您需要通過查找受影響的記錄並在刪除父記錄的同時刪除它們來手動實施此操作。如果願意,可以通過重寫父類上的.delete()方法來自動刪除所有相關記錄來簡化此操作。

由於性能方面的原因,您幾乎可以肯定地希望使用僅鍵值查詢(允許您獲取要刪除的實體的鍵而不必獲取並解碼實際實體)以及批量刪除。例如:

db.delete(Bottom.all(keys_only=True).filter("daddy =", top).fetch(1000)) 
+0

出於興趣,db.delete對每個實體調用delete()嗎?這是惡魔般的優化,所以我有點懷疑你不能把這兩個技巧結合起來。儘管如此,key_only上的好點。 – 2009-07-02 23:16:40

+0

不,db.delete()直接對應於一個發送所有要並行刪除的密鑰的RPC。 Entity.delete()只是調用db.delete(self)的語法糖。 – 2009-07-03 11:09:52

2

實際上,這種行爲是特定於GAE的。 Django的ORM在.delete()上模擬「ON DELETE CASCADE」。

我知道這不是你的問題的答案,但也許它可以幫助你找到錯誤的地方。

1

如果您的層次結構是唯一的深層次的數量不多,那麼你也許能夠做一些事情,看起來像一個文件路徑字段:

daddy.ancestry = "greatgranddaddy/granddaddy/daddy/" 
me.ancestry = daddy.ancestry + me.uniquename + "/" 

之類的事情。你確實需要獨特的名字,至少在兄弟姐妹中是獨一無二的。

對象ID中的路徑已經這樣做了,但IIRC與實體組綁定在一起,建議您不要用它來表達數據域中的關係。

然後你就可以構建一個查詢返回所有使用初始子招鼻祖的後裔,像這樣:

query = Person.all() 
query.filter("ancestry >", gdaddy.ancestry + "\U0001") 
query.filter("ancestry <", gdaddy.ancestry + "\UFFFF") 

顯然,這是沒有用的,如果你不適合祖先到500字節StringProperty 。

2

重新考慮數據結構。如果關係將永遠不會在記錄生命週期的變化,您可以使用「祖先」 GAE的特點:

class Top(db.Model): pass 
class Middle(db.Model): pass 
class Bottom(db.Model): pass 

top = Top() 
middles = [Middle(parent=top) for i in range(0,10)] 
bottoms = [Bottom(parent=middle) for i in range(0,10) for middle in middles] 

然後查詢祖先=頂部會發現從所有級別的所有記錄。所以刪除它們會很容易。

descendants = list(db.Query().ancestor(top)) 
# should return [top] + middles + bottoms