Keeping the users of your application aware of what is going on makes a huge difference in the user experience. If there is something users hate more than slow applications, it is applications that does not communicate with them.
– The user clicks in a save button.
– Nothing happens.
– So, did it save the data or not?
– User reaction after a couple of (mili)seconds: *Click!* *Click!*
*Click!* *Click!*
Let’s make our users more confident and comfortable, shall we?
Configuration
By default, a brand new Django project already comes with the messages framework installed. If you did not change anything in relation to the messages framework, just skip to the next section. Otherwise, set it up:
- INSTALLED_APPS
django.contrib.messages
- MIDDLEWARE or MIDDLEWARE_CLASSES in older versions:
django.contrib.sessions.middleware.SessionMiddlewaredjango.contrib.messages.middleware.MessageMiddleware
- TEMPLATES
- context_processors
django.contrib.messages.context_processors.messages
- context_processors
Message Levels and Tags
| Constant | Level | Tag (for CSS) | Purpose |
|---|---|---|---|
| DEBUG | 10 | debug | Development-related messages that will be ignored (or removed) in a production deployment |
| INFO | 20 | info | Informational messages for the user |
| SUCCESS | 25 | success | An action was successful |
| WARNING | 30 | warning | A failure did not occur but may be imminent |
| ERROR | 40 | error | An action was not successful or some other failure occurred |
By default, Django will only display messages with level greater than 20 (INFO). If you want to display DEBUG messages:
settings.py
from django.contrib.messages import constants as message_constants
MESSAGE_LEVEL = message_constants.DEBUGOr if you are running into circular imports, you can add the constant value directly:
MESSAGE_LEVEL = 10 # DEBUGUsage
You have two ways to use it. If you are using the built-in message levels (which more the most cases are more than enough):
views.py
from django.contrib import messages
@login_required
def password(request):
if request.method == 'POST':
form = PasswordChangeForm(request.user, request.POST)
if form.is_valid():
form.save()
update_session_auth_hash(request, form.user)
messages.success(request, 'Your password was updated successfully!') # <-
return redirect('settings:password')
else:
messages.warning(request, 'Please correct the error below.') # <-
else:
form = PasswordChangeForm(request.user)
return render(request, 'profiles/change_password.html', {'form': form})And then in the template:
{% if messages %}
<ul class="messages">
{% for message in messages %}
<li class="{{ message.tags }}">{{ message }}</li>
{% endfor %}
</ul>
{% endif %}If the success message was added, the output would be something like that:
<ul class="messages">
<li class="success">Your password was updated successfully!</li>
</ul>You can also pass extra tags to the message:
messages.success(request, 'Your password was updated successfully!', extra_tags='alert')Output:
<ul class="messages">
<li class="success alert">Your password was updated successfully!</li>
</ul>Built-in methods:
messages.debug(request, 'Total records updated {0}'.format(count))
messages.info(request, 'Improve your profile today!')
messages.success(request, 'Your password was updated successfully!')
messages.warning(request, 'Please correct the error below.')
messages.error(request, 'An unexpected error occured.')
# Or...
messages.add_message(request, messages.DEBUG, 'Total records updated {0}'.format(count))
messages.add_message(request, messages.INFO, 'Improve your profile today!')
# Useful to define custom levels:
CRITICAL = 50
messages.add_message(request, CRITICAL, 'A very serious error ocurred.')Extra: Bootstrap Snippet
messages.html
{% for message in messages %}
<div class="alert {{ message.tags }} alert-dismissible" role="alert">
<button type="button" class="close" data-dismiss="alert" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
{{ message }}
</div>
{% endfor %}settings.py
from django.contrib.messages import constants as messages
MESSAGE_TAGS = {
messages.DEBUG: 'alert-info',
messages.INFO: 'alert-info',
messages.SUCCESS: 'alert-success',
messages.WARNING: 'alert-warning',
messages.ERROR: 'alert-danger',
}And then to use it, add messages.html to your base.html template:
base.html
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>Simple is Better Than Complex</title>
</head>
<body>
{% include 'partials/header.html' %}
<main>
<div class="container">
{% include 'partials/messages.html' %}
{% block content %}
{% endblock %}
</div>
</main>
{% include 'partials/footer.html' %}
</body>
</html>
What You Should Know About The Django User Model
Django Tips #21 Using The Redirects App
How to Use Django's Flatpages App
How to Extend Django User Model
How to Setup a SSL Certificate on Nginx for a Django Application
How to Deploy a Django Application to Digital Ocean