[Fixed]-You cannot add messages without installing django.contrib.messages.middleware.MessageMiddleware

28๐Ÿ‘

For me the problem was specific to unit testing. It turns out that some middleware wonโ€™t work in some kinds of unit tests, more info here:

https://code.djangoproject.com/ticket/17971

and here:

Why don't my Django unittests know that MessageMiddleware is installed?

My solution was to just mock out the messages framework for those tests, there may be better solutions (the django test client?)

๐Ÿ‘คhwjp

10๐Ÿ‘

If you are running normal django code, you should add
django.contrib.messages.middleware.MessageMiddleware to your middlewares as others have suggested

If you are running a test case and using request factory then as @hwjp answered above, itโ€™s a bug (that wonโ€™t be fixed). The request factory doesnโ€™t call the middlewares and developers donโ€™t intend to change this behaviour.

There is however a simple solution.

in your test settings file (i.e settings/test.py) add the following line

MESSAGE_STORAGE = 'django.contrib.messages.storage.cookie.CookieStorage'

in your test code you can write code like this

request = RequestFactory().get("/")
# Add support  django messaging framework
request._messages = messages.storage.default_storage(request)

and thatโ€™s it. Passing this request object to any code that uses django messages will work without a problem.

๐Ÿ‘คRamast

9๐Ÿ‘

Check if you have django.contrib.messages in INSTALLED_APPS and django.contrib.messages.middleware.MessageMiddleware in MIDDLEWARE_CLASSES.

๐Ÿ‘คalecxe

5๐Ÿ‘

Check if it is

MIDDLEWARE_CLASSES = (
    'django.middleware.common.CommonMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
)

instead of

MIDDLEWARE = (
   'django.middleware.common.CommonMiddleware',
   'django.contrib.sessions.middleware.SessionMiddleware',
   'django.contrib.auth.middleware.AuthenticationMiddleware',
   'django.contrib.messages.middleware.MessageMiddleware',
)

Tuple name should be MIDDLEWARE_CLASSES

MIDDLEWARE_CLASSES depreciated https://docs.djangoproject.com/en/2.1/releases/1.10/#id3

๐Ÿ‘คMohammed Rishad

4๐Ÿ‘

If the request is needed in tests, it can be mocked as suggested by @Ramast.
I found the solution mentioned in the bug ticket (closed, wonโ€™t fix) to be helpful.

from django.contrib.messages.storage.fallback import FallbackStorage
from django.test import RequestFactory


def dummy_request():
    """Dummy request for testing purposes with message support."""
    request = RequestFactory().get('/')
    # Add support django messaging framework
    setattr(request, 'session', 'session')
    setattr(request, '_messages', FallbackStorage(request))
    return request
๐Ÿ‘คuser42488

3๐Ÿ‘

2018 update
In django 2.0+ name in settings was changed.
Right now use MIDDLEWARE instead of MIDDLEWARE_CLASSES name of list in settings!

๐Ÿ‘คMarek Szmalc

1๐Ÿ‘

I met the same error.
You have to notice the order of middleware in MIDDLEWARE_CLASSES.
Insert the corresponding middleware in the final.Like this,

MIDDLEWARE_CLASSES = (
    'django.middleware.common.CommonMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
)

Note the order arrangement.

๐Ÿ‘คrobert

1๐Ÿ‘

Probably you put a wrong WSGI_request when usually called request as a parameter to add_message() method

1๐Ÿ‘

If your issue is simulating these middlewares during unit testing, you can spoof this by writing a couple of little helpers:

def add_session_to_request(request: HttpRequest) -> HttpRequest:
    """Adds session support to a RequestFactory generated request."""
    middleware = SessionMiddleware(get_response=lambda request: None)
    middleware.process_request(request)
    request.session.save()
    return request


def add_messages_to_request(request: HttpRequest) -> HttpRequest:
    """Adds message/alert support to a RequestFactory generated request."""
    request._messages = FallbackStorage(request)
    return request

You can then call these in your test function at the point your request needs to have the middleware bound and just pass in the request youโ€™re using, which should keep your tests happy. ๐Ÿ™‚

# To suppress the errors raised when triggering .messages through APIRequestFactory(),
            # we need to bind both a session and messages storage on the fly
            add_session_to_request(replacement_request)
            add_messages_to_request(replacement_request)
๐Ÿ‘คthms

0๐Ÿ‘

This is an implementation of Ramastโ€™s answer, which only adds the approach I used for
overriding project settings in the test using a with statment.

from django.contrib import messages

class TestClass(TestCase):
    def setUp(self):
        self.factory = RequestFactory()
        <...>

    def test_view_function(self):
        with self.settings(
            MESSAGE_STORAGE="django.contrib.messages.storage.cookie.CookieStorage"
        ):  # configure the setting required for using the messages framework in this test.
            data = {'form_field': 'form_data'}  
            request = self.factory.post('/any/path/will/do/', data)
            request._messages = messages.storage.default_storage(request)
            <...>
๐Ÿ‘คMatt

Leave a comment