diff --git a/django/contrib/admin/actions.py b/django/contrib/admin/actions.py
index 5b56402..0621406 100644
a
|
b
|
Built-in, globally-available admin actions.
|
3 | 3 | """ |
4 | 4 | |
5 | 5 | from django.core.exceptions import PermissionDenied |
| 6 | from django.contrib import messages |
6 | 7 | from django.contrib.admin import helpers |
7 | 8 | from django.contrib.admin.util import get_deleted_objects, model_ngettext |
8 | 9 | from django.db import router |
… |
… |
def delete_selected(modeladmin, request, queryset):
|
47 | 48 | queryset.delete() |
48 | 49 | modeladmin.message_user(request, _("Successfully deleted %(count)d %(items)s.") % { |
49 | 50 | "count": n, "items": model_ngettext(modeladmin.opts, n) |
50 | | }) |
| 51 | }, messages.SUCCESS) |
51 | 52 | # Return None to display the change list page again. |
52 | 53 | return None |
53 | 54 | |
diff --git a/django/contrib/admin/options.py b/django/contrib/admin/options.py
index 2071792..b738b78 100644
a
|
b
|
class ModelAdmin(BaseModelAdmin):
|
688 | 688 | change_message = ' '.join(change_message) |
689 | 689 | return change_message or _('No fields changed.') |
690 | 690 | |
691 | | def message_user(self, request, message): |
| 691 | def message_user(self, request, message, level=messages.INFO): |
692 | 692 | """ |
693 | 693 | Send a message to the user. The default implementation |
694 | 694 | posts a message using the django.contrib.messages backend. |
695 | 695 | """ |
696 | | messages.info(request, message) |
| 696 | messages.add_message(request, level, message) |
697 | 697 | |
698 | 698 | def save_form(self, request, form, change): |
699 | 699 | """ |
… |
… |
class ModelAdmin(BaseModelAdmin):
|
773 | 773 | # Here, we distinguish between different save types by checking for |
774 | 774 | # the presence of keys in request.POST. |
775 | 775 | if "_continue" in request.POST: |
776 | | self.message_user(request, msg + ' ' + _("You may edit it again below.")) |
| 776 | self.message_user(request, msg + ' ' + _("You may edit it again below."), messages.SUCCESS) |
777 | 777 | if "_popup" in request.POST: |
778 | 778 | post_url_continue += "?_popup=1" |
779 | 779 | return HttpResponseRedirect(post_url_continue % pk_value) |
… |
… |
class ModelAdmin(BaseModelAdmin):
|
785 | 785 | # escape() calls force_unicode. |
786 | 786 | (escape(pk_value), escapejs(obj))) |
787 | 787 | elif "_addanother" in request.POST: |
788 | | self.message_user(request, msg + ' ' + (_("You may add another %s below.") % force_unicode(opts.verbose_name))) |
| 788 | self.message_user(request, msg + ' ' + (_("You may add another %s below.") % force_unicode(opts.verbose_name)), messages.SUCCESS) |
789 | 789 | return HttpResponseRedirect(request.path) |
790 | 790 | else: |
791 | | self.message_user(request, msg) |
| 791 | self.message_user(request, msg, messages.SUCCESS) |
792 | 792 | |
793 | 793 | # Figure out where to redirect. If the user has change permission, |
794 | 794 | # redirect to the change-list page for this object. Otherwise, |
… |
… |
class ModelAdmin(BaseModelAdmin):
|
821 | 821 | |
822 | 822 | msg = _('The %(name)s "%(obj)s" was changed successfully.') % {'name': force_unicode(verbose_name), 'obj': force_unicode(obj)} |
823 | 823 | if "_continue" in request.POST: |
824 | | self.message_user(request, msg + ' ' + _("You may edit it again below.")) |
| 824 | self.message_user(request, msg + ' ' + _("You may edit it again below."), messages.SUCCESS) |
825 | 825 | if "_popup" in request.REQUEST: |
826 | 826 | return HttpResponseRedirect(request.path + "?_popup=1") |
827 | 827 | else: |
828 | 828 | return HttpResponseRedirect(request.path) |
829 | 829 | elif "_saveasnew" in request.POST: |
830 | 830 | msg = _('The %(name)s "%(obj)s" was added successfully. You may edit it again below.') % {'name': force_unicode(verbose_name), 'obj': obj} |
831 | | self.message_user(request, msg) |
| 831 | self.message_user(request, msg, messages.SUCCESS) |
832 | 832 | return HttpResponseRedirect(reverse('admin:%s_%s_change' % |
833 | 833 | (opts.app_label, module_name), |
834 | 834 | args=(pk_value,), |
835 | 835 | current_app=self.admin_site.name)) |
836 | 836 | elif "_addanother" in request.POST: |
837 | | self.message_user(request, msg + ' ' + (_("You may add another %s below.") % force_unicode(verbose_name))) |
| 837 | self.message_user(request, msg + ' ' + (_("You may add another %s below.") % force_unicode(verbose_name)), messages.SUCCESS) |
838 | 838 | return HttpResponseRedirect(reverse('admin:%s_%s_add' % |
839 | 839 | (opts.app_label, module_name), |
840 | 840 | current_app=self.admin_site.name)) |
841 | 841 | else: |
842 | | self.message_user(request, msg) |
| 842 | self.message_user(request, msg, messages.SUCCESS) |
843 | 843 | # Figure out where to redirect. If the user has change permission, |
844 | 844 | # redirect to the change-list page for this object. Otherwise, |
845 | 845 | # redirect to the admin index. |
… |
… |
class ModelAdmin(BaseModelAdmin):
|
898 | 898 | # Reminder that something needs to be selected or nothing will happen |
899 | 899 | msg = _("Items must be selected in order to perform " |
900 | 900 | "actions on them. No items have been changed.") |
901 | | self.message_user(request, msg) |
| 901 | self.message_user(request, msg, messages.ERROR) |
902 | 902 | return None |
903 | 903 | |
904 | 904 | if not select_across: |
… |
… |
class ModelAdmin(BaseModelAdmin):
|
916 | 916 | return HttpResponseRedirect(request.get_full_path()) |
917 | 917 | else: |
918 | 918 | msg = _("No action selected.") |
919 | | self.message_user(request, msg) |
| 919 | self.message_user(request, msg, messages.ERROR) |
920 | 920 | return None |
921 | 921 | |
922 | 922 | @csrf_protect_m |
… |
… |
class ModelAdmin(BaseModelAdmin):
|
1158 | 1158 | else: |
1159 | 1159 | msg = _("Items must be selected in order to perform " |
1160 | 1160 | "actions on them. No items have been changed.") |
1161 | | self.message_user(request, msg) |
| 1161 | self.message_user(request, msg, messages.ERROR) |
1162 | 1162 | action_failed = True |
1163 | 1163 | |
1164 | 1164 | # Actions with confirmation |
… |
… |
class ModelAdmin(BaseModelAdmin):
|
1203 | 1203 | changecount) % {'count': changecount, |
1204 | 1204 | 'name': name, |
1205 | 1205 | 'obj': force_unicode(obj)} |
1206 | | self.message_user(request, msg) |
| 1206 | self.message_user(request, msg, messages.SUCCESS) |
1207 | 1207 | |
1208 | 1208 | return HttpResponseRedirect(request.get_full_path()) |
1209 | 1209 | |
… |
… |
class ModelAdmin(BaseModelAdmin):
|
1280 | 1280 | self.log_deletion(request, obj, obj_display) |
1281 | 1281 | self.delete_model(request, obj) |
1282 | 1282 | |
1283 | | self.message_user(request, _('The %(name)s "%(obj)s" was deleted successfully.') % {'name': force_unicode(opts.verbose_name), 'obj': force_unicode(obj_display)}) |
| 1283 | self.message_user(request, _('The %(name)s "%(obj)s" was deleted successfully.') % { |
| 1284 | 'name': force_unicode(opts.verbose_name), |
| 1285 | 'obj': force_unicode(obj_display) |
| 1286 | }, messages.SUCCESS) |
1284 | 1287 | |
1285 | 1288 | if not self.has_change_permission(request, None): |
1286 | 1289 | return HttpResponseRedirect(reverse('admin:index', |
diff --git a/django/contrib/admin/static/admin/img/icon_alert.gif b/django/contrib/admin/static/admin/img/icon_alert.gif
index a1dde26..0765aa8 100644
Binary files a/django/contrib/admin/static/admin/img/icon_alert.gif and b/django/contrib/admin/static/admin/img/icon_alert.gif differ
diff --git a/django/contrib/comments/admin.py b/django/contrib/comments/admin.py
index 4cb9066..e74c99c 100644
a
|
b
|
|
1 | | from django.contrib import admin |
| 1 | from django.contrib import admin, messages |
2 | 2 | from django.contrib.comments.models import Comment |
3 | 3 | from django.utils.translation import ugettext_lazy as _, ungettext |
4 | 4 | from django.contrib.comments import get_model |
… |
… |
class CommentsAdmin(admin.ModelAdmin):
|
65 | 65 | msg = ungettext(u'1 comment was successfully %(action)s.', |
66 | 66 | u'%(count)s comments were successfully %(action)s.', |
67 | 67 | n_comments) |
68 | | self.message_user(request, msg % {'count': n_comments, 'action': done_message(n_comments)}) |
| 68 | self.message_user(request, msg % {'count': n_comments, 'action': done_message(n_comments)}, messages.SUCCESS) |
69 | 69 | |
70 | 70 | # Only register the default admin if the model is the built-in comment model |
71 | 71 | # (this won't be true if there's a custom comment app). |
diff --git a/tests/regressiontests/admin_views/tests.py b/tests/regressiontests/admin_views/tests.py
index 0be8b36..47858f7 100644
a
|
b
|
class AdminInheritedInlinesTest(TestCase):
|
2103 | 2103 | bar_id = BarAccount.objects.all()[0].id |
2104 | 2104 | |
2105 | 2105 | # test the edit case |
2106 | | |
2107 | 2106 | response = self.client.get('/test_admin/admin/admin_views/persona/%d/' % persona_id) |
2108 | 2107 | names = name_re.findall(response.content) |
2109 | 2108 | # make sure we have no duplicate HTML names |
… |
… |
class AdminActionsTest(TestCase):
|
2322 | 2321 | } |
2323 | 2322 | response = self.client.post('/test_admin/admin/admin_views/subscriber/', action_data) |
2324 | 2323 | msg = """Items must be selected in order to perform actions on them. No items have been changed.""" |
2325 | | self.assertContains(response, msg) |
| 2324 | self.assertContains(response, '<li class="error">' + msg + '</li>', html=True) |
2326 | 2325 | self.assertEqual(Subscriber.objects.count(), 2) |
2327 | 2326 | |
2328 | 2327 | def test_user_message_on_no_action(self): |
… |
… |
class AdminActionsTest(TestCase):
|
2336 | 2335 | } |
2337 | 2336 | response = self.client.post('/test_admin/admin/admin_views/subscriber/', action_data) |
2338 | 2337 | msg = """No action selected.""" |
2339 | | self.assertContains(response, msg) |
| 2338 | self.assertContains(response, '<li class="error">' + msg + '</li>', html=True) |
2340 | 2339 | self.assertEqual(Subscriber.objects.count(), 2) |
2341 | 2340 | |
2342 | 2341 | def test_selection_counter(self): |
… |
… |
class TestCustomChangeList(TestCase):
|
2377 | 2376 | self.assertEqual(response.status_code, 302) # redirect somewhere |
2378 | 2377 | # Hit the page once to get messages out of the queue message list |
2379 | 2378 | response = self.client.get('/test_admin/%s/admin_views/gadget/' % self.urlbit) |
| 2379 | self.assertContains(response, '<li class="success">The gadget "First Gadget" was added successfully.</li>', html=True) |
2380 | 2380 | # Ensure that that data is still not visible on the page |
2381 | 2381 | response = self.client.get('/test_admin/%s/admin_views/gadget/' % self.urlbit) |
2382 | 2382 | self.assertEqual(response.status_code, 200) |
… |
… |
class AdminCustomQuerysetTest(TestCase):
|
2439 | 2439 | post_data, follow=True) |
2440 | 2440 | self.assertEqual(response.status_code, 200) |
2441 | 2441 | # Message should contain non-ugly model name. Instance representation is set by unicode() (ugly) |
2442 | | self.assertContains(response, '<li class="info">The paper "Paper_Deferred_author object" was changed successfully.</li>', html=True) |
| 2442 | self.assertContains(response, '<li class="success">The paper "Paper_Deferred_author object" was changed successfully.</li>', html=True) |
2443 | 2443 | |
2444 | 2444 | # defer() is used in ModelAdmin.queryset() |
2445 | 2445 | cl = CoverLetter.objects.create(author=u"John Doe") |
… |
… |
class AdminCustomQuerysetTest(TestCase):
|
2454 | 2454 | post_data, follow=True) |
2455 | 2455 | self.assertEqual(response.status_code, 200) |
2456 | 2456 | # Message should contain non-ugly model name. Instance representation is set by model's __unicode__() |
2457 | | self.assertContains(response, '<li class="info">The cover letter "John Doe II" was changed successfully.</li>', html=True) |
| 2457 | self.assertContains(response, '<li class="success">The cover letter "John Doe II" was changed successfully.</li>', html=True) |
2458 | 2458 | |
2459 | 2459 | class AdminInlineFileUploadTest(TestCase): |
2460 | 2460 | urls = "regressiontests.admin_views.urls" |