2009-06-28 13 views
6

Używam silnika aplikacji Google z django 1.0.2 (i django-helper) i zastanawiam się, jak ludzie robią rekursywne usuwanie. Załóżmy, że masz model, który jest mniej więcej tak:Kasowanie cykliczne w silniku aplikacji Google

 
class Top(BaseModel): 
    pass 

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

Teraz, kiedy mogę usunąć obiekt typu „top”, chcę wszystkie związane „bottom” obiekty mają być usunięte.

Teraz, gdy usuwam obiekt "górny", obiekty "na dole" zostają, a następnie dostaję dane, które nigdzie nie należą. Po wejściu do magazynu danych w widoku, I skończyć z:

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

Mogłem oczywiście znaleźć wszystkie obiekty i usunąć je, ale ponieważ mój prawdziwy model jest o głębokości co najmniej 5 poziomów, mam nadzieję, że to sposób aby upewnić się, że można to zrobić automatycznie.

Znalazłem ten article o tym, jak to działa z Javą i to wydaje się być tym, czego również chcę.

Ktoś wie, jak mogę uzyskać to zachowanie również w django?

Odpowiedz

6

Należy zaimplementować to ręcznie, przeglądając zmienione rekordy i usuwając je w tym samym czasie, gdy usuwany jest rekord nadrzędny. Możesz to uprościć, jeśli chcesz, przesuwając metodę .delete() w klasie nadrzędnej, aby automatycznie usunąć wszystkie powiązane rekordy.

Ze względów wydajnościowych prawie na pewno chcesz używać zapytań typu kluczowego (pozwalających uzyskać klucze do obiektów, które mają zostać usunięte bez konieczności pobierania i dekodowania rzeczywistych elementów), a także usuwanie partii. Na przykład:

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

W interesie, czy db.delete call delete() na każdym obiekcie? Jest diabelnie zoptymalizowany, więc jestem trochę podejrzliwy, że nie możesz połączyć tych dwóch sztuczek. Jednak dobry punkt na keys_only. –

+0

Nie, db.delete() bezpośrednio odpowiada pojedynczemu wywoływaniu, które wysyła równolegle wszystkie klucze, które mają zostać usunięte. Entity.delete() to po prostu syntaktyczny cukier, który wywołuje db.delete (self). –

+1

Czy "db.delete (top.bottom_set)" nie działałby poprawnie? –

2

Właściwie to zachowanie jest specyficzne dla GAE. ORM Django symuluje "ON DELETE CASCADE" na .delete().

Wiem, że to nie jest odpowiedź na twoje pytanie, ale może może pomóc w szukaniu w niewłaściwych miejscach.

1

Jeśli hierarchia jest tylko niewielka ilość poziomów głęboko, a następnie może być w stanie coś zrobić z polem, które wygląda jak ścieżka pliku:

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

rodzaju rzeczy. Potrzebujesz unikalnych nazw, przynajmniej unikalnych wśród rodzeństwa.

Ścieżka w identyfikatorach obiektów sortuje to już, ale IIRC jest powiązany z grupami encji, które nie powinny być używane do wyrażania relacji w domenie danych.

Następnie można skonstruować zapytanie do powrotu wszystkich potomków dziadek Korzystanie początkowej podciąg trik, tak:

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

Oczywiście to nie ma sensu, jeśli nie zmieści się przodków w StringProperty 500 bajtów .

2

Ponownie rozważ strukturę danych. Jeżeli związek nigdy nie zmieni się w życiu rekordu, można użyć „przodków” cechą 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] 

Następnie zapytań do przodka = top znajdzie wszystkie rekordy ze wszystkich poziomach.Łatwo więc je usunąć.

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

Piękny. Miły sposób korzystania ze spisów. Pierwszy raz widzę, że ma się dwie pętle! Wygląda jednak na to, że będą w innej kolejności, a zewnętrzna pętla będzie pierwsza. –

Powiązane problemy