Using Django’s messages framework to show success, error, warning, and informational feedback to users after actions like create, update, delete, login, or form submission.
When users interact with a website, they need feedback. If they create a post, they should know it was saved successfully. If a form fails, they should see an error. If an action needs attention, a warning message can help. Django provides a built-in system for this called the messages framework.
In this tutorial, you will learn what the Django messages framework is, why it is useful, how to configure it, how to send messages from views, and how to display them in templates with reusable layouts.
The Django messages framework is a built-in feature that allows you to temporarily store and display messages to users.
These messages are usually shown after an action, such as:
Messages are typically displayed once and then disappear after the next page load.
Without messages, users may not know what happened after they submit a form or click a button.
For example:
Messages improve user experience because they provide immediate and clear feedback.
Django supports several standard message levels:
successerrorwarninginfodebugThe most commonly used ones are:
In a standard Django project, yes. It is usually already configured.
Check settings.py.
settings.pyINSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
]Also make sure the middleware includes:
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
]And in the template context processors:
'OPTIONS': {
'context_processors': [
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
},If these are present, the framework is ready to use.
To use messages in a view, import Django’s messages module.
from django.contrib import messagesNow you can send feedback messages inside your views.
Suppose a user creates a post successfully.
from django.shortcuts import render, redirect
from django.contrib import messages
from .forms import PostForm
def post_create(request):
if request.method == 'POST':
form = PostForm(request.POST)
if form.is_valid():
form.save()
messages.success(request, "Post created successfully.")
return redirect('blog:post_list')
else:
form = PostForm()
return render(request, 'blog/post_form.html', {'form': form})messages.success(request, "...") stores a success messageYou can also send an error message if something goes wrong.
from django.contrib import messages
def post_create(request):
if request.method == 'POST':
form = PostForm(request.POST)
if form.is_valid():
form.save()
messages.success(request, "Post created successfully.")
return redirect('blog:post_list')
else:
messages.error(request, "Please correct the errors below.")
else:
form = PostForm()
return render(request, 'blog/post_form.html', {'form': form})This helps users understand that the form failed validation.
messages.info(request, "You are viewing draft posts.")messages.warning(request, "This action cannot be undone.")messages.debug(request, "Debug message example.")In real beginner projects, success, error, warning, and info are the most useful.
Messages sent from views do not appear automatically. You need to render them in your templates.
A common place to display them is inside base.html so they appear on all pages.
base.html<!DOCTYPE html>
<html>
<head>
<title>{% block title %}My Site{% endblock %}</title>
</head>
<body>
<h1>My Django Site</h1>
{% if messages %}
<ul>
{% for message in messages %}
<li>{{ message }}</li>
{% endfor %}
</ul>
{% endif %}
{% block content %}
{% endblock %}
</body>
</html>Now any message sent from a view will be displayed.
Each Django message has a tag that shows its type.
For example:
successerrorwarninginfoYou can use this tag in the template to style messages differently.
{% if messages %}
<ul>
{% for message in messages %}
<li class="{{ message.tags }}">{{ message }}</li>
{% endfor %}
</ul>
{% endif %}This lets you add CSS classes based on message type.
Here is a better and more realistic version using classes.
base.html{% if messages %}
<div class="messages">
{% for message in messages %}
<div class="alert {{ message.tags }}">
{{ message }}
</div>
{% endfor %}
</div>
{% endif %}.messages {
margin: 20px 0;
}
.alert {
padding: 12px;
margin-bottom: 10px;
border-radius: 6px;
font-weight: bold;
}
.success {
background-color: #d4edda;
color: #155724;
}
.error {
background-color: #f8d7da;
color: #721c24;
}
.warning {
background-color: #fff3cd;
color: #856404;
}
.info {
background-color: #d1ecf1;
color: #0c5460;
}Now messages will look much better.
Messages are especially useful in CRUD applications.
def post_create(request):
if request.method == 'POST':
form = PostForm(request.POST)
if form.is_valid():
form.save()
messages.success(request, "Post created successfully.")
return redirect('blog:post_list')
else:
messages.error(request, "Please fix the form errors.")
else:
form = PostForm()
return render(request, 'blog/post_form.html', {'form': form})def post_update(request, post_id):
post = get_object_or_404(Post, id=post_id)
if request.method == 'POST':
form = PostForm(request.POST, instance=post)
if form.is_valid():
form.save()
messages.success(request, "Post updated successfully.")
return redirect('blog:post_detail', post_id=post.id)
else:
messages.error(request, "Please fix the form errors.")
else:
form = PostForm(instance=post)
return render(request, 'blog/post_form.html', {'form': form})def post_delete(request, post_id):
post = get_object_or_404(Post, id=post_id)
if request.method == 'POST':
post.delete()
messages.warning(request, "Post deleted successfully.")
return redirect('blog:post_list')
return render(request, 'blog/post_confirm_delete.html', {'post': post})Now users receive clear feedback after every action.
Messages are often used together with redirect().
Why?
Because the common pattern is:
This pattern avoids duplicate submissions and improves user flow.
Messages are also useful in authentication.
messages.success(request, "You have logged in successfully.")messages.info(request, "You have been logged out.")messages.error(request, "Invalid username or password.")This makes authentication flows much clearer for users.
<hr>It is common to use both:
For example:
if form.is_valid():
form.save()
messages.success(request, "Your feedback was submitted.")
else:
messages.error(request, "Please correct the errors below.")And in the template:
<form method="POST">
{% csrf_token %}
{{ form.as_p }}
<button type="submit">Submit</button>
</form>
This gives users both:
If you are already using reusable layouts, a nice practice is to move message display into a partial template.
blog/templates/blog/partials/messages.html
{% if messages %}
<div class="messages">
{% for message in messages %}
<div class="alert {{ message.tags }}">
{{ message }}
</div>
{% endfor %}
</div>
{% endif %}Then include it in base.html.
base.html<!DOCTYPE html>
<html>
<head>
<title>{% block title %}My Site{% endblock %}</title>
</head>
<body>
<h1>My Django Site</h1>
{% include 'blog/partials/messages.html' %}
{% block content %}
{% endblock %}
</body>
</html>This keeps your layout cleaner.
Good messages should be:
Specific messages improve usability.
Wrong:
messages.success(request, "Saved!")without importing:
from django.contrib import messagesIf you do not render messages, users will never see them.
It is usually better to place message display in base.html or a partial.
Choose the correct message level for each situation.
Messages should be short and easy to scan.
views.pyfrom django.shortcuts import render, get_object_or_404, redirect
from django.contrib import messages
from .models import Post
from .forms import PostForm
def post_list(request):
posts = Post.objects.all().order_by('-created_at')
return render(request, 'blog/post_list.html', {'posts': posts})
def post_create(request):
if request.method == 'POST':
form = PostForm(request.POST)
if form.is_valid():
form.save()
messages.success(request, "Post created successfully.")
return redirect('blog:post_list')
else:
messages.error(request, "Please correct the errors below.")
else:
form = PostForm()
return render(request, 'blog/post_form.html', {'form': form})
def post_update(request, post_id):
post = get_object_or_404(Post, id=post_id)
if request.method == 'POST':
form = PostForm(request.POST, instance=post)
if form.is_valid():
form.save()
messages.success(request, "Post updated successfully.")
return redirect('blog:post_detail', post_id=post.id)
else:
messages.error(request, "Please correct the errors below.")
else:
form = PostForm(instance=post)
return render(request, 'blog/post_form.html', {'form': form})
def post_delete(request, post_id):
post = get_object_or_404(Post, id=post_id)
if request.method == 'POST':
post.delete()
messages.warning(request, "Post deleted successfully.")
return redirect('blog:post_list')
return render(request, 'blog/post_confirm_delete.html', {'post': post})
This is a practical real-world pattern.
Think of the messages framework like notifications from a receptionist.
Without these notifications, users would feel lost.
In this tutorial, you learned how Django’s messages framework helps you provide feedback to users after important actions. You saw how to send success, error, warning, and info messages from views, display them in templates, style them with CSS, and reuse message display through a partial template.
This is an important skill because professional applications always need clear user feedback.
success, error, warning, and infomessages.success(), messages.error(), and similar functionsmessage.tags helps style them with CSSbase.html a good place to display messages?message.tags provide?The Django messages framework is a simple but powerful feature that greatly improves user experience. Once you start using it, your application becomes clearer, more interactive, and more professional.