The Messages Framework

Reviewed & published by Brayan K

Django's messages framework is a built-in system for showing one-time "flash" notifications — short status messages like "Profile saved!" or "Login failed" that appear once after an action and then disappear, surviving the redirect that usually follows a form submission.

Learn The Messages Framework in our free Django course — a beginner-friendly interactive lesson with worked examples, a practice exercise and a quick reference.

Part of the free Django course at LearnCodingFast — hands-on lessons with examples you run in your browser, plus practice exercises and a quick quiz.

In this lesson you'll learn how to add messages with messages.success() , messages.error() , messages.info() , and messages.warning() , how to display them in a template, and how message tags let you style each level differently.

What You'll Learn in This Lesson

1 Adding Messages in a View

The messages framework lets a view attach a short notification to the current request. You import django.contrib.messages as messages and call one of its level methods, passing the request and the text to show.

The most common pattern is "do something, add a message, then redirect." Because the message is stored between the redirect and the next page, the user reliably sees it even though they land on a brand-new request.

2 Displaying Messages in a Template

Once a view has added messages, your template displays them by looping over the messages variable that Django's context processor makes available. Each message has a tags attribute (like success or error ) you can drop straight into a CSS class.

Here alert- {{ message.tags }} renders to something like alert-success or alert-error , letting you give each severity its own colour. Messages are consumed once read, so they appear exactly once and then vanish.

3 Message Levels and Tags

Django provides five severity levels, each with its own convenience method and default tag. Choosing the right one tells the user how important a notification is and lets your CSS colour it appropriately.

If your CSS framework expects different class names (for example Bootstrap uses danger instead of error ), you can remap the tags in settings.py with MESSAGE_TAGS .

🎯 Your Turn: Pick the Right Level

Fill in the blank with the correct messages method so a successful save shows a green success notification.

Why Your Messages Don't Show Up

By far the most common problem with this framework is adding a message and seeing nothing. Almost always it is one of three settings, because the framework needs all three working together — and each failure looks different.

Missing middleware is the loud one. Django raises a MessageFailure the moment you call messages.success() :

A missing context processor is the quiet one — no error at all, the view runs fine, and {% for message in messages %} simply loops over nothing, because the template never received the variable.

startproject gives you all three, which is why this usually bites on a hand-rolled settings file. If you genuinely need to add messages somewhere they may not be configured — a management command, say — pass fail_silently=True and the call becomes a no-op instead of raising.

Levels, extra_tags and Where Messages Are Stored

Each level is a number, and the ordering is worth knowing because MESSAGE_LEVEL filters on it — anything below the threshold is silently dropped. Note that success is 25 , between info and warning, not above them:

That is why MESSAGE_LEVEL = 30 hides your success messages along with debug and info — a surprise if you assumed success outranked a warning.

For styling one specific message differently, extra_tags appends to the tag string without changing the level:

Storage defaults to django.contrib.messages.storage.fallback.FallbackStorage , which puts messages in a cookie and spills over into the session when they will not fit — cookies cap at about 4KB. Set MESSAGE_STORAGE to the session backend if you would rather never put message text in a cookie. Either way messages are read-once: iterating them in a template marks them consumed, so they do not reappear on the next page.

Common Errors (And How to Fix Them)

❌ Messages added but nothing shows on the page

Your template never loops over the messages variable.

✅ Fix: add a {% for message in messages %} loop to your base template.

❌ MessageFailure: You cannot add messages without...

The message middleware or context processor is missing.

✅ Fix: ensure django.contrib.messages is in INSTALLED_APPS and its middleware is enabled.

You rendered the messages list more than once on the page.

✅ Fix: loop over messages in exactly one place, usually the base template.

📋 Quick Reference

Call

What It Does

messages.success(request, text)

Add a success-level message

messages.error(request, text)

Add an error-level message

messages.info(request, text)

Add a neutral informational message

message.tags

CSS-friendly tag for the message level

🏆 Mini Challenge: Checkout Notifier

Write a function that adds the right message for each checkout outcome: success when paid, warning when low stock, and error when the card is declined.

❓ Frequently Asked Questions

Lesson complete — you can flash messages to your users!

You now know how to add messages with the level methods, display them in a template by looping over messages , and style each level using its tag or a custom MESSAGE_TAGS mapping.

🚀 Up next: User Authentication — log users in and out, and protect views with login_required.

Practice quiz

What is the messages framework mainly used for?

  • Storing user passwords
  • One-time flash notifications shown on the next page
  • Sending email
  • Caching query results

Answer: One-time flash notifications shown on the next page. It attaches one-time notifications that survive a redirect.

How many built-in message levels does Django provide?

  • Three
  • Four
  • Five
  • Six

Answer: Five. debug, info, success, warning, and error are the five levels.

Which call adds a success-level message?

  • messages.ok(request, text)
  • messages.success(request, text)
  • messages.add('success', text)
  • messages.green(request, text)

Answer: messages.success(request, text). messages.success(request, text) adds a success message.

What attribute on a message gives a CSS-friendly tag like 'success'?

  • message.level
  • message.css
  • message.tags
  • message.style

Answer: message.tags. message.tags yields a tag string derived from the level.

How are messages shown in a template?

  • By calling messages.render()
  • By looping over the messages variable
  • Automatically in every response
  • With a context processor only

Answer: By looping over the messages variable. You loop over the messages variable, e.g. {% for message in messages %}.

What happens to a message once it has been read/rendered?

  • It is consumed and disappears
  • It persists forever
  • It is emailed to the user
  • It is saved to the database permanently

Answer: It is consumed and disappears. Messages are consumed once read, so they appear exactly once.

Which setting remaps message levels to custom CSS classes?

  • MESSAGE_LEVELS
  • MESSAGE_CLASSES
  • TAGS
  • MESSAGE_TAGS

Answer: MESSAGE_TAGS. MESSAGE_TAGS in settings.py remaps levels to your own class names.

Why is the common pattern 'add a message, then redirect'?

  • Redirects are faster
  • The message survives the redirect via Post/Redirect/Get
  • Messages require a redirect to be created
  • It clears the database

Answer: The message survives the redirect via Post/Redirect/Get. The message is stored across the redirect so the user reliably sees it.

Which level signals that an action failed?

  • messages.info()
  • messages.warning()
  • messages.error()
  • messages.success()

Answer: messages.error(). messages.error() indicates an action failed.

If messages are added but nothing shows, what is the most common cause?

  • The template never loops over the messages variable
  • The database is offline
  • The user is logged out
  • Django is too old

Answer: The template never loops over the messages variable. Usually the template is missing the loop over messages.

Continue this course