Skip to content

Commit

Permalink
[1.0.X] Fixed #10899 -- Ensured that log messages for deletions in th…
Browse files Browse the repository at this point in the history
…e admin contain useful descriptions. Thanks to Jeremy Dunck for the patch.

Merge of r10686 from trunk.

git-svn-id: http://code.djangoproject.com/svn/django/branches/releases/1.0.X@10720 bcc190cf-cafb-0310-a4f2-bffc1f526a37
  • Loading branch information
freakboy3742 committed May 8, 2009
1 parent 41ba8e7 commit 8397c1f
Show file tree
Hide file tree
Showing 2 changed files with 45 additions and 42 deletions.
82 changes: 41 additions & 41 deletions django/contrib/admin/options.py
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ def formfield_for_dbfield(self, db_field, **kwargs):
If kwargs are given, they're passed to the form Field's constructor. If kwargs are given, they're passed to the form Field's constructor.
""" """

# If the field specifies choices, we don't need to look for special # If the field specifies choices, we don't need to look for special
# admin widgets - we just need to use a select widget of some kind. # admin widgets - we just need to use a select widget of some kind.
if db_field.choices: if db_field.choices:
Expand Down Expand Up @@ -79,17 +79,17 @@ def formfield_for_dbfield(self, db_field, **kwargs):
if isinstance(db_field, models.TimeField): if isinstance(db_field, models.TimeField):
kwargs['widget'] = widgets.AdminTimeWidget kwargs['widget'] = widgets.AdminTimeWidget
return db_field.formfield(**kwargs) return db_field.formfield(**kwargs)

# For TextFields, add a custom CSS class. # For TextFields, add a custom CSS class.
if isinstance(db_field, models.TextField): if isinstance(db_field, models.TextField):
kwargs['widget'] = widgets.AdminTextareaWidget kwargs['widget'] = widgets.AdminTextareaWidget
return db_field.formfield(**kwargs) return db_field.formfield(**kwargs)

# For URLFields, add a custom CSS class. # For URLFields, add a custom CSS class.
if isinstance(db_field, models.URLField): if isinstance(db_field, models.URLField):
kwargs['widget'] = widgets.AdminURLFieldWidget kwargs['widget'] = widgets.AdminURLFieldWidget
return db_field.formfield(**kwargs) return db_field.formfield(**kwargs)

# For IntegerFields, add a custom CSS class. # For IntegerFields, add a custom CSS class.
if isinstance(db_field, models.IntegerField): if isinstance(db_field, models.IntegerField):
kwargs['widget'] = widgets.AdminIntegerFieldWidget kwargs['widget'] = widgets.AdminIntegerFieldWidget
Expand All @@ -104,7 +104,7 @@ def formfield_for_dbfield(self, db_field, **kwargs):
if isinstance(db_field, models.CharField): if isinstance(db_field, models.CharField):
kwargs['widget'] = widgets.AdminTextInputWidget kwargs['widget'] = widgets.AdminTextInputWidget
return db_field.formfield(**kwargs) return db_field.formfield(**kwargs)

# For FileFields and ImageFields add a link to the current file. # For FileFields and ImageFields add a link to the current file.
if isinstance(db_field, models.ImageField) or isinstance(db_field, models.FileField): if isinstance(db_field, models.ImageField) or isinstance(db_field, models.FileField):
kwargs['widget'] = widgets.AdminFileWidget kwargs['widget'] = widgets.AdminFileWidget
Expand Down Expand Up @@ -281,56 +281,56 @@ def get_form(self, request, obj=None, **kwargs):
def get_formsets(self, request, obj=None): def get_formsets(self, request, obj=None):
for inline in self.inline_instances: for inline in self.inline_instances:
yield inline.get_formset(request, obj) yield inline.get_formset(request, obj)

def log_addition(self, request, object): def log_addition(self, request, object):
""" """
Log that an object has been successfully added. Log that an object has been successfully added.
The default implementation creates an admin LogEntry object. The default implementation creates an admin LogEntry object.
""" """
from django.contrib.admin.models import LogEntry, ADDITION from django.contrib.admin.models import LogEntry, ADDITION
LogEntry.objects.log_action( LogEntry.objects.log_action(
user_id = request.user.pk, user_id = request.user.pk,
content_type_id = ContentType.objects.get_for_model(object).pk, content_type_id = ContentType.objects.get_for_model(object).pk,
object_id = object.pk, object_id = object.pk,
object_repr = force_unicode(object), object_repr = force_unicode(object),
action_flag = ADDITION action_flag = ADDITION
) )

def log_change(self, request, object, message): def log_change(self, request, object, message):
""" """
Log that an object has been successfully changed. Log that an object has been successfully changed.
The default implementation creates an admin LogEntry object. The default implementation creates an admin LogEntry object.
""" """
from django.contrib.admin.models import LogEntry, CHANGE from django.contrib.admin.models import LogEntry, CHANGE
LogEntry.objects.log_action( LogEntry.objects.log_action(
user_id = request.user.pk, user_id = request.user.pk,
content_type_id = ContentType.objects.get_for_model(object).pk, content_type_id = ContentType.objects.get_for_model(object).pk,
object_id = object.pk, object_id = object.pk,
object_repr = force_unicode(object), object_repr = force_unicode(object),
action_flag = CHANGE, action_flag = CHANGE,
change_message = message change_message = message
) )

def log_deletion(self, request, object, object_repr): def log_deletion(self, request, object, object_repr):
""" """
Log that an object has been successfully deleted. Note that since the Log that an object has been successfully deleted. Note that since the
object is deleted, it might no longer be safe to call *any* methods object is deleted, it might no longer be safe to call *any* methods
on the object, hence this method getting object_repr. on the object, hence this method getting object_repr.
The default implementation creates an admin LogEntry object. The default implementation creates an admin LogEntry object.
""" """
from django.contrib.admin.models import LogEntry, DELETION from django.contrib.admin.models import LogEntry, DELETION
LogEntry.objects.log_action( LogEntry.objects.log_action(
user_id = request.user.id, user_id = request.user.id,
content_type_id = ContentType.objects.get_for_model(self.model).pk, content_type_id = ContentType.objects.get_for_model(self.model).pk,
object_id = object.pk, object_id = object.pk,
object_repr = object_repr, object_repr = object_repr,
action_flag = DELETION action_flag = DELETION
) )


def construct_change_message(self, request, form, formsets): def construct_change_message(self, request, form, formsets):
""" """
Construct a change message from a changed object. Construct a change message from a changed object.
Expand All @@ -356,10 +356,10 @@ def construct_change_message(self, request, form, formsets):
'object': force_unicode(deleted_object)}) 'object': force_unicode(deleted_object)})
change_message = ' '.join(change_message) change_message = ' '.join(change_message)
return change_message or _('No fields changed.') return change_message or _('No fields changed.')

def message_user(self, request, message): def message_user(self, request, message):
""" """
Send a message to the user. The default implementation Send a message to the user. The default implementation
posts a message using the auth Message object. posts a message using the auth Message object.
""" """
request.user.message_set.create(message=message) request.user.message_set.create(message=message)
Expand All @@ -370,7 +370,7 @@ def save_form(self, request, form, change):
the object is being changed, and False if it's being added. the object is being changed, and False if it's being added.
""" """
return form.save(commit=False) return form.save(commit=False)

def save_model(self, request, obj, form, change): def save_model(self, request, obj, form, change):
""" """
Given a model instance save it to the database. Given a model instance save it to the database.
Expand Down Expand Up @@ -408,14 +408,14 @@ def render_change_form(self, request, context, add=False, change=False, form_url
"admin/%s/change_form.html" % app_label, "admin/%s/change_form.html" % app_label,
"admin/change_form.html" "admin/change_form.html"
], context, context_instance=template.RequestContext(request)) ], context, context_instance=template.RequestContext(request))

def response_add(self, request, obj, post_url_continue='../%s/'): def response_add(self, request, obj, post_url_continue='../%s/'):
""" """
Determines the HttpResponse for the add_view stage. Determines the HttpResponse for the add_view stage.
""" """
opts = obj._meta opts = obj._meta
pk_value = obj._get_pk_val() pk_value = obj._get_pk_val()

msg = _('The %(name)s "%(obj)s" was added successfully.') % {'name': force_unicode(opts.verbose_name), 'obj': force_unicode(obj)} msg = _('The %(name)s "%(obj)s" was added successfully.') % {'name': force_unicode(opts.verbose_name), 'obj': force_unicode(obj)}
# Here, we distinguish between different save types by checking for # Here, we distinguish between different save types by checking for
# the presence of keys in request.POST. # the presence of keys in request.POST.
Expand All @@ -424,7 +424,7 @@ def response_add(self, request, obj, post_url_continue='../%s/'):
if request.POST.has_key("_popup"): if request.POST.has_key("_popup"):
post_url_continue += "?_popup=1" post_url_continue += "?_popup=1"
return HttpResponseRedirect(post_url_continue % pk_value) return HttpResponseRedirect(post_url_continue % pk_value)

if request.POST.has_key("_popup"): if request.POST.has_key("_popup"):
return HttpResponse('<script type="text/javascript">opener.dismissAddAnotherPopup(window, "%s", "%s");</script>' % \ return HttpResponse('<script type="text/javascript">opener.dismissAddAnotherPopup(window, "%s", "%s");</script>' % \
# escape() calls force_unicode. # escape() calls force_unicode.
Expand All @@ -443,14 +443,14 @@ def response_add(self, request, obj, post_url_continue='../%s/'):
else: else:
post_url = '../../../' post_url = '../../../'
return HttpResponseRedirect(post_url) return HttpResponseRedirect(post_url)

def response_change(self, request, obj): def response_change(self, request, obj):
""" """
Determines the HttpResponse for the change_view stage. Determines the HttpResponse for the change_view stage.
""" """
opts = obj._meta opts = obj._meta
pk_value = obj._get_pk_val() pk_value = obj._get_pk_val()

msg = _('The %(name)s "%(obj)s" was changed successfully.') % {'name': force_unicode(opts.verbose_name), 'obj': force_unicode(obj)} msg = _('The %(name)s "%(obj)s" was changed successfully.') % {'name': force_unicode(opts.verbose_name), 'obj': force_unicode(obj)}
if request.POST.has_key("_continue"): if request.POST.has_key("_continue"):
self.message_user(request, msg + ' ' + _("You may edit it again below.")) self.message_user(request, msg + ' ' + _("You may edit it again below."))
Expand Down Expand Up @@ -503,7 +503,7 @@ def add_view(self, request, form_url='', extra_context=None):
form.save_m2m() form.save_m2m()
for formset in formsets: for formset in formsets:
self.save_formset(request, form, formset, change=False) self.save_formset(request, form, formset, change=False)

self.log_addition(request, new_object) self.log_addition(request, new_object)
return self.response_add(request, new_object) return self.response_add(request, new_object)
else: else:
Expand Down Expand Up @@ -599,11 +599,11 @@ def change_view(self, request, object_id, extra_context=None):
form.save_m2m() form.save_m2m()
for formset in formsets: for formset in formsets:
self.save_formset(request, form, formset, change=True) self.save_formset(request, form, formset, change=True)

change_message = self.construct_change_message(request, form, formsets) change_message = self.construct_change_message(request, form, formsets)
self.log_change(request, new_object, change_message) self.log_change(request, new_object, change_message)
return self.response_change(request, new_object) return self.response_change(request, new_object)

else: else:
form = ModelForm(instance=obj) form = ModelForm(instance=obj)
prefixes = {} prefixes = {}
Expand All @@ -624,7 +624,7 @@ def change_view(self, request, object_id, extra_context=None):
inline_admin_formset = helpers.InlineAdminFormSet(inline, formset, fieldsets) inline_admin_formset = helpers.InlineAdminFormSet(inline, formset, fieldsets)
inline_admin_formsets.append(inline_admin_formset) inline_admin_formsets.append(inline_admin_formset)
media = media + inline_admin_formset.media media = media + inline_admin_formset.media

context = { context = {
'title': _('Change %s') % force_unicode(opts.verbose_name), 'title': _('Change %s') % force_unicode(opts.verbose_name),
'adminform': adminForm, 'adminform': adminForm,
Expand Down Expand Up @@ -705,11 +705,11 @@ def delete_view(self, request, object_id, extra_context=None):
if perms_needed: if perms_needed:
raise PermissionDenied raise PermissionDenied
obj_display = force_unicode(obj) obj_display = force_unicode(obj)
obj.delete()

self.log_deletion(request, obj, obj_display) self.log_deletion(request, obj, obj_display)
obj.delete()

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)})

if not self.has_change_permission(request, None): if not self.has_change_permission(request, None):
return HttpResponseRedirect("../../../../") return HttpResponseRedirect("../../../../")
return HttpResponseRedirect("../../") return HttpResponseRedirect("../../")
Expand Down Expand Up @@ -784,7 +784,7 @@ def __init__(self, parent_model, admin_site):
self.verbose_name = self.model._meta.verbose_name self.verbose_name = self.model._meta.verbose_name
if self.verbose_name_plural is None: if self.verbose_name_plural is None:
self.verbose_name_plural = self.model._meta.verbose_name_plural self.verbose_name_plural = self.model._meta.verbose_name_plural

def _media(self): def _media(self):
from django.conf import settings from django.conf import settings
js = [] js = []
Expand Down
5 changes: 4 additions & 1 deletion tests/regressiontests/admin_views/tests.py
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
from django.test import TestCase from django.test import TestCase
from django.contrib.auth.models import User, Permission from django.contrib.auth.models import User, Permission
from django.contrib.contenttypes.models import ContentType from django.contrib.contenttypes.models import ContentType
from django.contrib.admin.models import LogEntry from django.contrib.admin.models import LogEntry, DELETION
from django.contrib.admin.sites import LOGIN_FORM_KEY from django.contrib.admin.sites import LOGIN_FORM_KEY
from django.contrib.admin.util import quote from django.contrib.admin.util import quote
from django.utils.html import escape from django.utils.html import escape
Expand Down Expand Up @@ -557,6 +557,9 @@ def testDeleteView(self):
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)
article_ct = ContentType.objects.get_for_model(Article)
logged = LogEntry.objects.get(content_type=article_ct, action_flag=DELETION)
self.failUnlessEqual(logged.object_id, u'1')
self.client.get('/test_admin/admin/logout/') self.client.get('/test_admin/admin/logout/')


class AdminViewStringPrimaryKeyTest(TestCase): class AdminViewStringPrimaryKeyTest(TestCase):
Expand Down

0 comments on commit 8397c1f

Please sign in to comment.