2009-09-24 17 views
31

をトリガしていない私はモデルがあります:Djangoのモデル:()を削除

class MyModel(models.Model): 
... 
    def save(self): 
     print "saving" 
     ... 
    def delete(self): 
     print "deleting" 
     ... 

(保存)を - 方法)(トリガが、削除されていません。最新のsvn-Version(Djangoバージョン1.2のpre-alpha SVN-11593)を使用しています。http://www.djangoproject.com/documentation/models/save_delete_hooks/にあるドキュメンテーションに関しては、これはうまくいくはずです。 アイデア

+0

おそらくあなたは何も削除していませんか? delete()を呼び出す内容を表示できますか? – artagnon

+0

管理領域のアイテムを削除するだけで試しましたが、手動で呼び出すことはありませんでした。 – schneck

答えて

68

おそらく、管理者の一括削除機能を使用していると思われます。管理者の一括削除メソッドがdelete()(関連ticketを参照)を呼び出さないという事実に惑わされています。

これまで、モデルを削除するためのカスタム管理アクションを作成することでこれまでのことがありました。

管理者の一括削除メソッドを使用していない場合(オブジェクトの編集ページの削除ボタンをクリックしているなど)、何か他のことが起こっています。 が呼び出されることはありません、あなたのモデルのdelete()方法:

「選択したオブジェクトを削除し、」アクション が重要 注意点があり、効率 理由でQuerySet.delete()を使用しています。

は警告 hereを参照してください。

あなたは、この動作を無効にしたい場合は、 は単に があなたの 優先的に削除を実現するカスタムアクションを作成する - 例えば、 は 選択した項目ごとにModel.delete()を呼び出すことによって。

一括削除の詳細については、 object deletionのドキュメントを参照してください。

マイカスタム管理モデルは、次のようになります。

from photoblog.models import PhotoBlogEntry 
from django.contrib import admin  

class PhotoBlogEntryAdmin(admin.ModelAdmin): 
    actions=['really_delete_selected'] 

    def get_actions(self, request): 
     actions = super(PhotoBlogEntryAdmin, self).get_actions(request) 
     del actions['delete_selected'] 
     return actions 

    def really_delete_selected(self, request, queryset): 
     for obj in queryset: 
      obj.delete() 

     if queryset.count() == 1: 
      message_bit = "1 photoblog entry was" 
     else: 
      message_bit = "%s photoblog entries were" % queryset.count() 
     self.message_user(request, "%s successfully deleted." % message_bit) 
    really_delete_selected.short_description = "Delete selected entries" 

admin.site.register(PhotoBlogEntry, PhotoBlogEntryAdmin) 
+0

うん、それは、ありがとう。あなたのカスタム管理方法がどのように見えるかをすぐに説明できますか? – schneck

+0

@schneck - 確かに! –

+0

btw - それを達成するよりエレガントな方法があるかもしれませんが、それは動作します! –

29

私はこの質問は古代のですけど、私は再びこのに走ったし、常にpre_deleteにコードを移動することができますことを追加したいですか次のようなpost_deleteシグナル:

from django.db.models.signals import pre_delete 
from django.dispatch.dispatcher import receiver 

@receiver(pre_delete, sender=MyModel) 
def _mymodel_delete(sender, instance, **kwargs): 
    print "deleting" 

これは、管理者の一括削除アクション(少なくとも1.3.1以降)で動作します。

+0

非常に滑らかです。ちょうどdjango 1.4でこれが改善されたのでしょうか? –

+0

thnx a ton!再帰的削除を避けるためにpost_deleteを使用しました。 – Babu

5

管理者の一括処理は、queryset.delete()を呼び出します。

クエリーセットの.delete()メソッドを無効にすることができます。 のように、常に1行1個のオブジェクトの削除が行われます。たとえば:

managers.py

from django.db import models 
from django.db.models.query import QuerySet 

class PhotoQueryMixin(object): 
    """ Methods that appear both in the manager and queryset. """ 
    def delete(self): 
     # Use individual queries to the attachment is removed. 
     for photo in self.all(): 
      photo.delete() 

class PhotoQuerySet(PhotoQueryMixin, QuerySet): 
    pass 

class PhotoManager(PhotoQueryMixin, models.Manager): 
    def get_query_set(self): 
     return PhotoQuerySet(self.model, using=self._db) 

models.pyで:

from django.db import models 

class Photo(models.Model): 
    image = models.ImageField(upload_to='images') 

    objects = PhotoManager() 

    def delete(self, *args, **kwargs): 
     # Note this is a simple example. it only handles delete(), 
     # and not replacing images in .save() 
     super(Photo, self).delete(*args, **kwargs) 
     self.image.delete() 
3

主な問題は、Djangoの管理者の一括削除することであるSQL、ないインスタンスを使用しています。delete()は、別のところで述べたとおりです。管理者専用のソリューションの場合、Django管理者の「間違いを本当に削除しますか?」というインタースティシャルを維持します。しかし、vdboorのソリューションが最も一般的です。

from django.contrib.admin.actions import delete_selected 

class BulkDeleteMixin(object): 
    class SafeDeleteQuerysetWrapper(object): 
     def __init__(self, wrapped_queryset): 
      self.wrapped_queryset = wrapped_queryset 

     def _safe_delete(self): 
      for obj in self.wrapped_queryset: 
       obj.delete() 

     def __getattr__(self, attr): 
      if attr == 'delete': 
       return self._safe_delete 
      else: 
       return getattr(self.wrapped_queryset, attr) 

     def __iter__(self): 
      for obj in self.wrapped_queryset: 
       yield obj 

     def __getitem__(self, index): 
      return self.wrapped_queryset[index] 

     def __len__(self): 
      return len(self.wrapped_queryset) 

    def get_actions(self, request): 
     actions = super(BulkDeleteMixin, self).get_actions(request) 
     actions['delete_selected'] = (BulkDeleteMixin.action_safe_bulk_delete, 'delete_selected', ugettext_lazy("Delete selected %(verbose_name_plural)s")) 
     return actions 

    def action_safe_bulk_delete(self, request, queryset): 
     wrapped_queryset = BulkDeleteMixin.SafeDeleteQuerysetWrapper(queryset) 
     return delete_selected(self, request, wrapped_queryset) 


class SomeAdmin(BulkDeleteMixin, ModelAdmin): 
    ... 
関連する問題