Search code examples
pythonpython-3.xdjangobootstrap-5django-messages

Django django.contrib.messages add new constant messages.NOTICE


How can I create a new constant to Django messages?

I want to add a new constant messages.NOTICE in addition to the existing six constants. That I can use to display notices using Bootstrap CSS.

# settings.py
from django.contrib.messages import constants as messages

MESSAGE_TAGS = {
        messages.DEBUG: 'alert-secondary',
        messages.INFO: 'alert-info',
        messages.SUCCESS: 'alert-success',
        messages.WARNING: 'alert-warning',
        messages.ERROR: 'alert-danger',
        #messages.NOTICE: 'alert-primary', #To add
}

Error if I try to add the above.

    G:\runtime\devui\devui\settings.py changed, reloading.
Traceback (most recent call last):
  File "G:\runtime\devui\manage.py", line 22, in <module>
    main()
  File "G:\runtime\devui\manage.py", line 18, in main
    execute_from_command_line(sys.argv)
  File "C:\Users\devuser\AppData\Local\Programs\Python\Python311\Lib\site-packages\django\core\management\__init__.py", line 442, in execute_from_command_line
    utility.execute()
  File "C:\Users\devuser\AppData\Local\Programs\Python\Python311\Lib\site-packages\django\core\management\__init__.py", line 382, in execute
    settings.INSTALLED_APPS
  File "C:\Users\devuser\AppData\Local\Programs\Python\Python311\Lib\site-packages\django\conf\__init__.py", line 89, in __getattr__
    self._setup(name)
  File "C:\Users\devuser\AppData\Local\Programs\Python\Python311\Lib\site-packages\django\conf\__init__.py", line 76, in _setup
    self._wrapped = Settings(settings_module)
                    ^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\devuser\AppData\Local\Programs\Python\Python311\Lib\site-packages\django\conf\__init__.py", line 190, in __init__
    mod = importlib.import_module(self.SETTINGS_MODULE)
          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\devuser\AppData\Local\Programs\Python\Python311\Lib\importlib\__init__.py", line 126, in import_module
    return _bootstrap._gcd_import(name[level:], package, level)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "<frozen importlib._bootstrap>", line 1204, in _gcd_import
  File "<frozen importlib._bootstrap>", line 1176, in _find_and_load
  File "<frozen importlib._bootstrap>", line 1147, in _find_and_load_unlocked
  File "<frozen importlib._bootstrap>", line 690, in _load_unlocked
  File "<frozen importlib._bootstrap_external>", line 940, in exec_module
  File "<frozen importlib._bootstrap>", line 241, in _call_with_frames_removed
  File "G:\runtime\devui\devui\settings.py", line 44, in <module>
    messages.NOTICE: 'alert-primary',
    ^^^^^^^^^^^^^^^
AttributeError: module 'django.contrib.messages.constants' has no attribute 'NOTICE'
PS G:\runtime\devui>

Solution

  • You cannot add new levels to the messages collection. You don't in fact have to add it anywhere if all you need is for that level to exist, you just have to pass it to the add_message method - but for the CSS-part of messages to work you have to add it to MESSAGES_TAGS in settings.py.

    Message levels are just integers. That means you can add integers directly, or you can make a constant for it if you want, I'll show both below.

    # settings.py
    from django.contrib.messages import constants as messages
    
    NOTICE = 60 # Or some other integer
    
    MESSAGE_TAGS = {
            messages.DEBUG: 'alert-secondary',
            messages.INFO: 'alert-info',
            messages.SUCCESS: 'alert-success',
            messages.WARNING: 'alert-warning',
            messages.ERROR: 'alert-danger',
            NOTICE: 'alert-primary',
            80: 'alert-tertiary',
    }
    
    # elsewhere.py
    from django.contrib import messages
    messages.add_message(request, 60, "Hello world.") # Would trigger the `NOTICE` CSS class from `MESSAGE_TAGS`
    

    If you want unified convenience for passing in constants to your message invocations, make a custom collection (enum or Django *Choice-class) based on the original constants:

    # constants.py
    from django.contrib.messages import constants as message_constants
    from django.db import models
    
    class MessageLevels(models.IntegerChoices):
        DEBUG    = message_constants.DEBUG,
        INFO     = message_constants.INFO,
        [...] # repeat for the standard levels
    
        NOTICE   = 60
        CRITICAL = 90
    
    # elsewhere.py
    from .constants import MessageLevels as msg
    
    messages.add_message(request, msg.NOTICE, "Hello world.")
    messages.add_message(request, msg.DEBUG, "Hello debugger.")
    

    As noted initially - remember to make sure to also add the custom integers in your message level collection to MESSAGE_TAGS, otherwise there won't be any CSS passthrough. You can (and probably should) use the collection for that as well:

    # settings.py
    from ./constants import MessageLevels as msg
    
    MESSAGE_TAGS = {
            messages.DEBUG: 'alert-secondary',
            messages.INFO: 'alert-info',
            messages.SUCCESS: 'alert-success',
            messages.WARNING: 'alert-warning',
            messages.ERROR: 'alert-danger',
            msg.NOTICE, 'alert-primary',
            msg.CRITICAL, 'alert-tertiary',
    }