Fixed #11108 -- added ModelAdmin.delete_model, a hook with which to perform custom pre-post delete behavior. Thanks to Florian Apolloner for the patch.

git-svn-id: http://code.djangoproject.com/svn/django/trunk@14673 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
Alex Gaynor 2010-11-21 19:00:40 +00:00
parent 0cf1c96d06
commit 274aba3b9b
5 changed files with 49 additions and 4 deletions

View File

@ -601,6 +601,12 @@ class ModelAdmin(BaseModelAdmin):
""" """
obj.save() obj.save()
def delete_model(self, requet, obj):
"""
Given a model instance delete it from the database.
"""
obj.delete()
def save_formset(self, request, form, formset, change): def save_formset(self, request, form, formset, change):
""" """
Given an inline formset save it to the database. Given an inline formset save it to the database.
@ -1122,7 +1128,7 @@ class ModelAdmin(BaseModelAdmin):
raise PermissionDenied raise PermissionDenied
obj_display = force_unicode(obj) obj_display = force_unicode(obj)
self.log_deletion(request, obj, obj_display) self.log_deletion(request, obj, obj_display)
obj.delete() self.delete_model(request, obj)
self.message_user(request, _('The %(name)s "%(obj)s" was deleted successfully.') % {'name': force_unicode(opts.verbose_name), 'obj': force_unicode(obj_display)}) self.message_user(request, _('The %(name)s "%(obj)s" was deleted successfully.') % {'name': force_unicode(opts.verbose_name), 'obj': force_unicode(obj_display)})

View File

@ -757,6 +757,12 @@ templates used by the :class:`ModelAdmin` views:
``ModelAdmin`` methods ``ModelAdmin`` methods
---------------------- ----------------------
.. warning::
:meth:`ModelAdmin.save_model` and :meth:`ModelAdmin.delete_model` must
save/delete the object, they are not for veto purposes, rather they allow
you to perform extra operations.
.. method:: ModelAdmin.save_model(self, request, obj, form, change) .. method:: ModelAdmin.save_model(self, request, obj, form, change)
The ``save_model`` method is given the ``HttpRequest``, a model instance, The ``save_model`` method is given the ``HttpRequest``, a model instance,
@ -770,6 +776,13 @@ For example to attach ``request.user`` to the object prior to saving::
obj.user = request.user obj.user = request.user
obj.save() obj.save()
.. method:: ModelAdmin.delete_model(self, request, obj)
.. versionadded:: 1.3
The ``delete_model`` method is given the ``HttpRequest`` and a model instance.
Use this method to do pre- or post-delete operations.
.. method:: ModelAdmin.save_formset(self, request, form, formset, change) .. method:: ModelAdmin.save_formset(self, request, form, formset, change)
The ``save_formset`` method is given the ``HttpRequest``, the parent The ``save_formset`` method is given the ``HttpRequest``, the parent

View File

@ -458,7 +458,7 @@ database other than that that specified by your router chain, you'll
need to write custom :class:`~django.contrib.admin.ModelAdmin` classes need to write custom :class:`~django.contrib.admin.ModelAdmin` classes
that will direct the admin to use a specific database for content. that will direct the admin to use a specific database for content.
``ModelAdmin`` objects have four methods that require customization for ``ModelAdmin`` objects have five methods that require customization for
multiple-database support:: multiple-database support::
class MultiDBModelAdmin(admin.ModelAdmin): class MultiDBModelAdmin(admin.ModelAdmin):
@ -469,6 +469,10 @@ multiple-database support::
# Tell Django to save objects to the 'other' database. # Tell Django to save objects to the 'other' database.
obj.save(using=self.using) obj.save(using=self.using)
def delete_model(self, requqest, obj):
# Tell Django to delete objects from the 'other' database
obj.delete(using=self.using)
def queryset(self, request): def queryset(self, request):
# Tell Django to look for objects on the 'other' database. # Tell Django to look for objects on the 'other' database.
return super(MultiDBModelAdmin, self).queryset(request).using(self.using) return super(MultiDBModelAdmin, self).queryset(request).using(self.using)

View File

@ -107,6 +107,25 @@ class ArticleAdmin(admin.ModelAdmin):
modeladmin_year.admin_order_field = 'date' modeladmin_year.admin_order_field = 'date'
modeladmin_year.short_description = None modeladmin_year.short_description = None
def delete_model(self, request, obj):
EmailMessage(
'Greetings from a deleted object',
'I hereby inform you that some user deleted me',
'from@example.com',
['to@example.com']
).send()
return super(ArticleAdmin, self).delete_model(request, obj)
def save_model(self, request, obj, form, change=True):
EmailMessage(
'Greetings from a created object',
'I hereby inform you that some user created me',
'from@example.com',
['to@example.com']
).send()
return super(ArticleAdmin, self).save_model(request, obj, form, change)
class CustomArticle(models.Model): class CustomArticle(models.Model):
content = models.TextField() content = models.TextField()
date = models.DateTimeField() date = models.DateTimeField()

View File

@ -3,6 +3,7 @@
import re import re
import datetime import datetime
from django.conf import settings from django.conf import settings
from django.core import mail
from django.core.files import temp as tempfile from django.core.files import temp as tempfile
from django.contrib.auth import admin # Register auth models with the admin. from django.contrib.auth import admin # Register auth models with the admin.
from django.contrib.auth.models import User, Permission, UNUSABLE_PASSWORD from django.contrib.auth.models import User, Permission, UNUSABLE_PASSWORD
@ -540,6 +541,8 @@ class AdminViewPermissionsTest(TestCase):
post = self.client.post('/test_admin/admin/admin_views/article/add/', add_dict) post = self.client.post('/test_admin/admin/admin_views/article/add/', add_dict)
self.assertRedirects(post, '/test_admin/admin/') self.assertRedirects(post, '/test_admin/admin/')
self.failUnlessEqual(Article.objects.all().count(), 4) self.failUnlessEqual(Article.objects.all().count(), 4)
self.assertEquals(len(mail.outbox), 1)
self.assertEquals(mail.outbox[0].subject, 'Greetings from a created object')
self.client.get('/test_admin/admin/logout/') self.client.get('/test_admin/admin/logout/')
# Super can add too, but is redirected to the change list view # Super can add too, but is redirected to the change list view
@ -695,6 +698,8 @@ class AdminViewPermissionsTest(TestCase):
post = self.client.post('/test_admin/admin/admin_views/article/1/delete/', delete_dict) post = self.client.post('/test_admin/admin/admin_views/article/1/delete/', delete_dict)
self.assertRedirects(post, '/test_admin/admin/') self.assertRedirects(post, '/test_admin/admin/')
self.failUnlessEqual(Article.objects.all().count(), 2) self.failUnlessEqual(Article.objects.all().count(), 2)
self.assertEquals(len(mail.outbox), 1)
self.assertEquals(mail.outbox[0].subject, 'Greetings from a deleted object')
article_ct = ContentType.objects.get_for_model(Article) article_ct = ContentType.objects.get_for_model(Article)
logged = LogEntry.objects.get(content_type=article_ct, action_flag=DELETION) logged = LogEntry.objects.get(content_type=article_ct, action_flag=DELETION)
self.failUnlessEqual(logged.object_id, u'1') self.failUnlessEqual(logged.object_id, u'1')
@ -1440,8 +1445,6 @@ class AdminInheritedInlinesTest(TestCase):
self.failUnlessEqual(BarAccount.objects.all()[0].username, "%s-1" % bar_user) self.failUnlessEqual(BarAccount.objects.all()[0].username, "%s-1" % bar_user)
self.failUnlessEqual(Persona.objects.all()[0].accounts.count(), 2) self.failUnlessEqual(Persona.objects.all()[0].accounts.count(), 2)
from django.core import mail
class AdminActionsTest(TestCase): class AdminActionsTest(TestCase):
fixtures = ['admin-views-users.xml', 'admin-views-actions.xml'] fixtures = ['admin-views-users.xml', 'admin-views-actions.xml']