From ed8c0c941df0f321fb5751db572a9ec773d5118a Mon Sep 17 00:00:00 2001 From: Raffaele Salmaso Date: Tue, 10 Jan 2017 00:03:10 +0100 Subject: [PATCH] Fixed #27688 -- Made messages' add_message() request check use ducktyping. --- django/contrib/messages/api.py | 26 +++++++++++++++----------- tests/messages_tests/test_api.py | 21 +++++++++++++++++++++ 2 files changed, 36 insertions(+), 11 deletions(-) diff --git a/django/contrib/messages/api.py b/django/contrib/messages/api.py index ceb6057f8d..f77cf26de5 100644 --- a/django/contrib/messages/api.py +++ b/django/contrib/messages/api.py @@ -1,6 +1,5 @@ from django.contrib.messages import constants from django.contrib.messages.storage import default_storage -from django.http import HttpRequest __all__ = ( 'add_message', 'get_messages', @@ -18,16 +17,21 @@ def add_message(request, level, message, extra_tags='', fail_silently=False): """ Attempts to add a message to the request using the 'messages' app. """ - if not isinstance(request, HttpRequest): - raise TypeError("add_message() argument must be an HttpRequest object, " - "not '%s'." % request.__class__.__name__) - if hasattr(request, '_messages'): - return request._messages.add(level, message, extra_tags) - if not fail_silently: - raise MessageFailure( - 'You cannot add messages without installing ' - 'django.contrib.messages.middleware.MessageMiddleware' - ) + try: + messages = request._messages + except AttributeError: + if not hasattr(request, 'META'): + raise TypeError( + "add_message() argument must be an HttpRequest object, not " + "'%s'." % request.__class__.__name__ + ) + if not fail_silently: + raise MessageFailure( + 'You cannot add messages without installing ' + 'django.contrib.messages.middleware.MessageMiddleware' + ) + else: + return messages.add(level, message, extra_tags) def get_messages(request): diff --git a/tests/messages_tests/test_api.py b/tests/messages_tests/test_api.py index 0cb17c1656..8baff57c70 100644 --- a/tests/messages_tests/test_api.py +++ b/tests/messages_tests/test_api.py @@ -42,3 +42,24 @@ class ApiTests(SimpleTestCase): def test_middleware_missing_silently(self): messages.add_message(self.request, messages.DEBUG, 'some message', fail_silently=True) self.assertEqual(self.storage.store, []) + + +class CustomRequest(object): + def __init__(self, request): + self._request = request + + def __getattribute__(self, attr): + try: + return super(CustomRequest, self).__getattribute__(attr) + except AttributeError: + return getattr(self._request, attr) + + +class CustomRequestApiTests(ApiTests): + """ + add_message() should use ducktyping to allow request wrappers such as the + one in Django REST framework. + """ + def setUp(self): + super(CustomRequestApiTests, self).setUp() + self.request = CustomRequest(self.request)