Fixed #18658 -- Improved ModelAdmin.message_user API
Thanks to Lowe Thiderman for the patch and tests
This commit is contained in:
parent
8b659e439b
commit
edf7ad36fa
1
AUTHORS
1
AUTHORS
|
@ -531,6 +531,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)
|
||||
|
|
Loading…
Reference in New Issue