2009-03-25 14 views
7

Modellerim arasında gevşek bir kaplin modellemek için modelimde boş olabilecek bir ForeignKey var. Biraz benziyor: gönderenler adı sender_name özniteliği yazılır kaydetmek OnNullable ForeignKeys ve başvurulan model örneğini silme

class Message(models.Model): 
    sender = models.ForeignKey(User, null=True, blank=True) 
    sender_name = models.CharField(max_length=255) 

. Şimdi, gönderen tarafından başvurulan Kullanıcı örneğini silmek ve mesajı yerinde bırakmak istiyorum.

Bu kod her zaman Kullanıcı örneğini sildikten sonra silinen iletilerle sonuçlanır. Bu yüzden bir sinyal işleyicisinin iyi bir fikir olacağını düşündüm.

def my_signal_handler(sender, instance, **kwargs): 
    instance.message_set.clear() 
pre_delete.connect(my_signal_handler, sender=User) 

Ne yazık ki, hiçbir şekilde bir çözüm değildir. Bir şekilde Django ilk önce silmek istediğini toplar ve daha sonra pre_delete işleyicisini kovur.

Herhangi bir fikrin var mı? Beynimdeki düğüm nerede?

cevap

13

Django gerçekten de SQL'in ON DELETE CASCADE davranışını taklit eder ve bunu değiştirmek için kutuda belgelenmiş bir yol yoktur. Bunlardan bahsettikleri dokümanlar bu bölümün sonuna yakındır: Deleting objects.

Django'nun ilgili tüm model örneklerini topladığı, daha sonra her biri için ön silme işleyicisini çağırdığı doğru. Sinyalin göndericisi, silinmesi gereken model sınıfı olacak, bu durumda, User yerine, kullanıcı tarafından tetiklenen basamaklı silme ile normal silme arasındaki farkı tespit etmeyi zorlaştırıyor. Kullanıcı sınıfının silinmesi için sonuncu gelir, çünkü son silme bu yana :-)

Ancak, Django'nun User.delete() işlevini çağırmadan önce silmeyi önerdiği nesnelerin listesini alabilirsiniz. Her model örneği, yabancı anahtarların işaret ettiği örneklerin listesini derleyen _collect_sub_objects() adlı yarı özel bir yönteme sahiptir (bu listeyi örnekleri silmeden derler). Bu yöntemin, django.db.base'da delete()'a bakarak nasıl göründüğünü görebilirsiniz.

Bu, kendi nesnelerinizden biri olsaydı, örneğinizde _collect_sub_objects() işlevini çalıştırmak için delete() yöntemini geçersiz kılmayı ve ardından süper sınıf silme işlemini çağırmadan önce ForeignKeyleri kırmanızı öneririm. Alt sınıf için çok zor bulabileceğiniz yerleşik bir Django nesnesi kullandığınızdan (django'lar için kendi Kullanıcı nesnesini değiştirmek mümkün olsa da), _collect_sub_objects'u çalıştırmak ve önce FK'leri kesmek için mantığa güvenmeniz gerekebilir. silme.

İşte kirli hızlı ve-örnek:

from django.db.models.query import CollectedObjects 
u = User.objects.get(id=1) 


instances_to_be_deleted = CollectedObjects() 
u._collect_sub_objects(instances_to_be_deleted) 

for k in instances_to_be_deleted.ordered_keys(): 
    inst_dict = instances_to_be_deleted.data[k] 
    for i in inst_dict.values(): 
     i.sender = None # You will need a more generic way for this 
     i.save() 

u.delete() 
+0

Açmak için açıklama ve işaretçiler için teşekkürler. –

+0

Tam cevap. –

0

sadece CASCADE Davranışı kendim SİL keşfeden Django 1.3 onlar yabancı anahtar davranışı configurable yapmış olduğunu görüyoruz.

İlgili konular