mirror of
				https://github.com/django/django.git
				synced 2025-10-31 09:41:08 +00:00 
			
		
		
		
	[1.5.x] Fixed #18658 -- Improved ModelAdmin.message_user API
Thanks to Lowe Thiderman for the patch and tests
This commit is contained in:
		
							
								
								
									
										1
									
								
								AUTHORS
									
									
									
									
									
								
							
							
						
						
									
										1
									
								
								AUTHORS
									
									
									
									
									
								
							| @@ -530,6 +530,7 @@ answer newbie questions, and generally made Django that much better: | ||||
|     Terry Huang <terryh.tp@gmail.com> | ||||
|     Travis Terry <tdterry7@gmail.com> | ||||
|     thebjorn <bp@datakortet.no> | ||||
|     Lowe Thiderman <lowe.thiderman@gmail.com> | ||||
|     Zach Thompson <zthompson47@gmail.com> | ||||
|     Michael Thornhill <michael.thornhill@gmail.com> | ||||
|     Deepak Thukral <deep.thukral@gmail.com> | ||||
|   | ||||
| @@ -691,12 +691,30 @@ class ModelAdmin(BaseModelAdmin): | ||||
|         change_message = ' '.join(change_message) | ||||
|         return change_message or _('No fields changed.') | ||||
|  | ||||
|     def message_user(self, request, message): | ||||
|     def message_user(self, request, message, level=messages.INFO, extra_tags='', | ||||
|                      fail_silently=False): | ||||
|         """ | ||||
|         Send a message to the user. The default implementation | ||||
|         posts a message using the django.contrib.messages backend. | ||||
|  | ||||
|         Exposes almost the same API as messages.add_message(), but accepts the | ||||
|         positional arguments in a different order to maintain backwards | ||||
|         compatibility. For convenience, it accepts the `level` argument as | ||||
|         a string rather than the ususal level number. | ||||
|         """ | ||||
|         messages.info(request, message) | ||||
|  | ||||
|         if not isinstance(level, int): | ||||
|             # attempt to get the level if passed a string | ||||
|             try: | ||||
|                 level = getattr(messages.constants, level.upper()) | ||||
|             except AttributeError: | ||||
|                 levels = messages.constants.DEFAULT_TAGS.values() | ||||
|                 levels_repr = ', '.join('`%s`' % l for l in levels) | ||||
|                 raise ValueError('Bad message level string: `%s`. ' | ||||
|                         'Possible values are: %s' % (level, levels_repr)) | ||||
|  | ||||
|         messages.add_message(request, level, message, extra_tags=extra_tags, | ||||
|                 fail_silently=fail_silently) | ||||
|  | ||||
|     def save_form(self, request, form, change): | ||||
|         """ | ||||
|   | ||||
| @@ -140,6 +140,15 @@ That's really all there is to it! If you're itching to write your own actions, | ||||
| you now know enough to get started. The rest of this document just covers more | ||||
| advanced techniques. | ||||
|  | ||||
| Handling errors in actions | ||||
| -------------------------- | ||||
|  | ||||
| If there are foreseeable error conditions that may occur while running your | ||||
| action, you should gracefully inform the user of the problem. This means | ||||
| handling exceptions and and using | ||||
| :meth:`django.contrib.admin.ModelAdmin.message_user` to display a user friendly | ||||
| description of the problem in the response. | ||||
|  | ||||
| Advanced action techniques | ||||
| ========================== | ||||
|  | ||||
|   | ||||
| @@ -1303,11 +1303,19 @@ templates used by the :class:`ModelAdmin` views: | ||||
|                     return qs | ||||
|                 return qs.filter(author=request.user) | ||||
|  | ||||
| .. method:: ModelAdmin.message_user(request, message) | ||||
| .. method:: ModelAdmin.message_user(request, message, level=messages.INFO, extra_tags='', fail_silently=False) | ||||
|  | ||||
|     Sends a message to the user. The default implementation creates a message | ||||
|     using the :mod:`django.contrib.messages` backend. See the | ||||
|     :ref:`custom ModelAdmin example <custom-admin-action>`. | ||||
|     Sends a message to the user using the :mod:`django.contrib.messages` | ||||
|     backend.  See the :ref:`custom ModelAdmin example <custom-admin-action>`. | ||||
|  | ||||
|     .. versionadded:: 1.5 | ||||
|  | ||||
|     Keyword arguments allow you to change the message level, add extra CSS | ||||
|     tags, or fail silently if the ``contrib.messages`` framework is not | ||||
|     installed. These keyword arguments match those for | ||||
|     :func:`django.contrib.messages.add_message`, see that function's | ||||
|     documentation for more details. One difference is that the level may be | ||||
|     passed as a string label in addition to integer/constant. | ||||
|  | ||||
| .. method:: ModelAdmin.get_paginator(queryset, per_page, orphans=0, allow_empty_first_page=True) | ||||
|  | ||||
|   | ||||
| @@ -313,6 +313,11 @@ Django 1.5 also includes several smaller improvements worth noting: | ||||
|   DeprecationWarnings should be printed to the console in development | ||||
|   environments the way they have been in Python versions < 2.7. | ||||
|  | ||||
| * The API for :meth:`django.contrib.admin.ModelAdmin.message_user` method has | ||||
|   been modified to accept additional arguments adding capabilities similar to | ||||
|   :func:`django.contrib.messages.add_message`. This is useful for generating | ||||
|   error messages from admin actions. | ||||
|  | ||||
| Backwards incompatible changes in 1.5 | ||||
| ===================================== | ||||
|  | ||||
|   | ||||
| @@ -27,7 +27,7 @@ from .models import (Article, Chapter, Account, Media, Child, Parent, Picture, | ||||
|     Album, Question, Answer, ComplexSortedPerson, PrePopulatedPostLargeSlug, | ||||
|     AdminOrderedField, AdminOrderedModelMethod, AdminOrderedAdminMethod, | ||||
|     AdminOrderedCallable, Report, Color2, UnorderedObject, MainPrepopulated, | ||||
|     RelatedPrepopulated, UndeletableObject, Simple) | ||||
|     RelatedPrepopulated, UndeletableObject, UserMessenger, Simple) | ||||
|  | ||||
|  | ||||
| def callable_year(dt_value): | ||||
| @@ -592,6 +592,28 @@ def callable_on_unknown(obj): | ||||
| class AttributeErrorRaisingAdmin(admin.ModelAdmin): | ||||
|     list_display = [callable_on_unknown, ] | ||||
|  | ||||
| class MessageTestingAdmin(admin.ModelAdmin): | ||||
|     actions = ["message_debug", "message_info", "message_success", | ||||
|                "message_warning", "message_error", "message_extra_tags"] | ||||
|  | ||||
|     def message_debug(self, request, selected): | ||||
|         self.message_user(request, "Test debug", level="debug") | ||||
|  | ||||
|     def message_info(self, request, selected): | ||||
|         self.message_user(request, "Test info", level="info") | ||||
|  | ||||
|     def message_success(self, request, selected): | ||||
|         self.message_user(request, "Test success", level="success") | ||||
|  | ||||
|     def message_warning(self, request, selected): | ||||
|         self.message_user(request, "Test warning", level="warning") | ||||
|  | ||||
|     def message_error(self, request, selected): | ||||
|         self.message_user(request, "Test error", level="error") | ||||
|  | ||||
|     def message_extra_tags(self, request, selected): | ||||
|         self.message_user(request, "Test tags", extra_tags="extra_tag") | ||||
|  | ||||
|  | ||||
| site = admin.AdminSite(name="admin") | ||||
| site.register(Article, ArticleAdmin) | ||||
| @@ -667,6 +689,7 @@ site.register(AdminOrderedAdminMethod, AdminOrderedAdminMethodAdmin) | ||||
| site.register(AdminOrderedCallable, AdminOrderedCallableAdmin) | ||||
| site.register(Color2, CustomTemplateFilterColorAdmin) | ||||
| site.register(Simple, AttributeErrorRaisingAdmin) | ||||
| site.register(UserMessenger, MessageTestingAdmin) | ||||
|  | ||||
| # Register core models we need in our tests | ||||
| from django.contrib.auth.models import User, Group | ||||
|   | ||||
| @@ -651,6 +651,10 @@ class UndeletableObject(models.Model): | ||||
|     """ | ||||
|     name = models.CharField(max_length=255) | ||||
|  | ||||
| class UserMessenger(models.Model): | ||||
|     """ | ||||
|     Dummy class for testing message_user functions on ModelAdmin | ||||
|     """ | ||||
|  | ||||
| class Simple(models.Model): | ||||
|     """ | ||||
|   | ||||
| @@ -3697,3 +3697,61 @@ class AdminViewLogoutTest(TestCase): | ||||
|         self.assertEqual(response.template_name, 'admin/login.html') | ||||
|         self.assertEqual(response.request['PATH_INFO'], '/test_admin/admin/') | ||||
|         self.assertContains(response, '<input type="hidden" name="next" value="/test_admin/admin/" />') | ||||
|  | ||||
|  | ||||
| @override_settings(PASSWORD_HASHERS=('django.contrib.auth.hashers.SHA1PasswordHasher',)) | ||||
| class AdminUserMessageTest(TestCase): | ||||
|     urls = "regressiontests.admin_views.urls" | ||||
|     fixtures = ['admin-views-users.xml'] | ||||
|  | ||||
|     def setUp(self): | ||||
|         self.client.login(username='super', password='secret') | ||||
|  | ||||
|     def tearDown(self): | ||||
|         self.client.logout() | ||||
|  | ||||
|     def send_message(self, level): | ||||
|         """ | ||||
|         Helper that sends a post to the dummy test methods and asserts that a | ||||
|         message with the level has appeared in the response. | ||||
|         """ | ||||
|         action_data = { | ||||
|             ACTION_CHECKBOX_NAME: [1], | ||||
|             'action': 'message_%s' % level, | ||||
|             'index': 0, | ||||
|         } | ||||
|  | ||||
|         response = self.client.post('/test_admin/admin/admin_views/usermessenger/', | ||||
|                                     action_data, follow=True) | ||||
|         self.assertContains(response, | ||||
|                             '<li class="%s">Test %s</li>' % (level, level), | ||||
|                             html=True) | ||||
|  | ||||
|     @override_settings(MESSAGE_LEVEL=10)  # Set to DEBUG for this request | ||||
|     def test_message_debug(self): | ||||
|         self.send_message('debug') | ||||
|  | ||||
|     def test_message_info(self): | ||||
|         self.send_message('info') | ||||
|  | ||||
|     def test_message_success(self): | ||||
|         self.send_message('success') | ||||
|  | ||||
|     def test_message_warning(self): | ||||
|         self.send_message('warning') | ||||
|  | ||||
|     def test_message_error(self): | ||||
|         self.send_message('error') | ||||
|  | ||||
|     def test_message_extra_tags(self): | ||||
|         action_data = { | ||||
|             ACTION_CHECKBOX_NAME: [1], | ||||
|             'action': 'message_extra_tags', | ||||
|             'index': 0, | ||||
|         } | ||||
|  | ||||
|         response = self.client.post('/test_admin/admin/admin_views/usermessenger/', | ||||
|                                     action_data, follow=True) | ||||
|         self.assertContains(response, | ||||
|                             '<li class="extra_tag info">Test tags</li>', | ||||
|                             html=True) | ||||
|   | ||||
		Reference in New Issue
	
	Block a user