In today's web applications, it is often necessary to give the visitor some kind of alert. Whether “Your comment has been saved and is awaiting moderation,” or “Thank you for your interest, we will send you an invitation as soon as we open it”, these small messages appear here and there all the time, so it's nice to have a user-friendly interface to display them. to the user.
The authentication and authorization application that came with Django (django.contrib.auth) always included basic functionality for displaying pop-up messages to the user, but it had some annoying flaws. In Django 1.2, there is now a completely new framework for such messages, written primarily by Tobias McNulty.
So what was wrong with the old way?
Since the old messaging system is part of django.contrib.auth, you need to connect this application to take advantage of the small part responsible for notifications. But it happens that you do not need authentication and authorization, but you need these small messages. Or perhaps you are using your own authentication application. Or, conversely, you use django.contrib.auth, but you do not need messages. In Django 1.2, you finally have an opportunity for all this.
')
In addition, the old system stores messages in a database. And although it is normal for many projects, it still means that each view of any page is accompanied by an additional query to the database. And he is simply not needed in most cases. Django 1.2 has the ability to store messages outside the database for a small performance boost.
It is also worth noting that in previous versions of Django all messages were considered equal, i.e. it was impossible to set the message type (importance level, if you wish). This, for example, is convenient when you need to distinguish between error messages and success. In the new framework, such an opportunity has appeared.
Finally, the alert system in Django 1.1 binds each message tightly to a specific user, which means that you cannot show such messages to anonymous users. In Django 1.2, the ability to show alerts regardless of whether a user is logged in or not has appeared.
So let's get started.
The new system is already connected by default if you create a project using django-admin.py startproject. If you already have an old project, or you have created a project in some other way, it is very easy to turn on the system. Just three steps:
- Add 'django.contrib.messages.middleware.MessageMiddleware' to the list of MIDDLEWARE_CLASSES in the settings file.
- Add 'django.contrib.messages.context_processors.messages' to the TEMPLATE_CONTEXT_PROCESSORS list in the settings file.
- Add 'django.contrib.messages' to the INSTALLED_APPS list in the same settings file.
Adding Alerts
Adding alerts to users in the new framework is also elementary, especially if you only need one of the five predefined message types (DEBUG, INFO, SUCCESS, WARNING, ERROR — more on that
later ).
So, what you need to do:
from django.contrib import messages messages.success(request, "Skadoosh! You've updated your profile!" )
from django.contrib import messages messages.success(request, "Skadoosh! You've updated your profile!" )
Similarly, for other types of messages:
messages.info(request, 'Yo! There are new comments on your photo!' ) messages.error(request, 'Doh! Something went wrong.' ) messages.debug(request, 'Bam! %s objects were modified.' % modified_count) messages.warning(request, 'Uh-oh. Your account expires in %s days.' % expiration_days)
messages.info(request, 'Yo! There are new comments on your photo!' ) messages.error(request, 'Doh! Something went wrong.' ) messages.debug(request, 'Bam! %s objects were modified.' % modified_count) messages.warning(request, 'Uh-oh. Your account expires in %s days.' % expiration_days)
messages.info(request, 'Yo! There are new comments on your photo!' ) messages.error(request, 'Doh! Something went wrong.' ) messages.debug(request, 'Bam! %s objects were modified.' % modified_count) messages.warning(request, 'Uh-oh. Your account expires in %s days.' % expiration_days)
messages.info(request, 'Yo! There are new comments on your photo!' ) messages.error(request, 'Doh! Something went wrong.' ) messages.debug(request, 'Bam! %s objects were modified.' % modified_count) messages.warning(request, 'Uh-oh. Your account expires in %s days.' % expiration_days)
Since messages are attached to the request object, you will need access to it, but you already have it in all views.
If you are migrating from the old version, you will need to complete only two simple points:
- In all views.py files, where there is an alert creation, add the following line at the beginning:
from django.contrib import messages
- Replace everywhere
request.user.message_set.create(message=message)
to call one of the new API methods, for example
messages.error(request, message)
Message display
To display messages in a template, use something like the following lines:
{% if messages %} < ul class= "messages" > {% for message in messages %} < li {% if message.tags %} class= "{{ message.tags }}" {% endif %}> {{ message }} </ li > {% endfor %} </ ul > {% endif %}
{% if messages %} < ul class= "messages" > {% for message in messages %} < li {% if message.tags %} class= "{{ message.tags }}" {% endif %}> {{ message }} </ li > {% endfor %} </ ul > {% endif %}
{% if messages %} < ul class= "messages" > {% for message in messages %} < li {% if message.tags %} class= "{{ message.tags }}" {% endif %}> {{ message }} </ li > {% endfor %} </ ul > {% endif %}
{% if messages %} < ul class= "messages" > {% for message in messages %} < li {% if message.tags %} class= "{{ message.tags }}" {% endif %}> {{ message }} </ li > {% endfor %} </ ul > {% endif %}
{% if messages %} < ul class= "messages" > {% for message in messages %} < li {% if message.tags %} class= "{{ message.tags }}" {% endif %}> {{ message }} </ li > {% endfor %} </ ul > {% endif %}
{% if messages %} < ul class= "messages" > {% for message in messages %} < li {% if message.tags %} class= "{{ message.tags }}" {% endif %}> {{ message }} </ li > {% endfor %} </ ul > {% endif %}
{% if messages %} < ul class= "messages" > {% for message in messages %} < li {% if message.tags %} class= "{{ message.tags }}" {% endif %}> {{ message }} </ li > {% endfor %} </ ul > {% endif %}
{% if messages %} < ul class= "messages" > {% for message in messages %} < li {% if message.tags %} class= "{{ message.tags }}" {% endif %}> {{ message }} </ li > {% endfor %} </ ul > {% endif %}
{% if messages %} < ul class= "messages" > {% for message in messages %} < li {% if message.tags %} class= "{{ message.tags }}" {% endif %}> {{ message }} </ li > {% endfor %} </ ul > {% endif %}
As a rule, it makes sense to put these strings in your base template, so that all templates that inherit it display alerts.
The code is almost identical to what you already used in Django 1.1, but you should have noticed the new tags property. Django 1.2 gives each alert a type with a string representation for use in templates. In this case, we display this value as the name of the CSS class, which can be used to individually style various types of messages, for example:
.messages li.error { background-color : red ; } .messages li.success { background-color : green ; }
.messages li.error { background-color : red ; } .messages li.success { background-color : green ; }
If you just want to show messages to the user, you can stop reading. In fact, nothing more is needed. Everything is easy and simple.
Message Storage Mechanisms
Django provides several backends for storing messages, and you can create your own very easily. LegacyFallbackStorage is used by default and is suitable for most projects, however, there are several reasons why you want to change the backend:
- django.contrib.messages.storage.session.SessionStorage. This backend stores all messages in a session. Thus, it is required to connect the django.contrib.sessions application (most likely it is already activated in your project, since it is used by default). Since sessions are stored by default in the database, using this backend still requires a query to the database when accessing messages (for example, when calling {% if messages%} in a template).
- django.contrib.messages.storage.cookie.CookieStorage stores messages in cookies. Thus, the database query is not required, which leads to greater performance. However, there is one drawback: the maximum cookie length is 4096 bytes, so messages that are longer than 4 KB will not be delivered.
- django.contrib.messages.storage.fallback.FallbackStorage: this mechanism first uses CookieStorage, but in the case where the text does not fit in the cookie, refers to SessionStorage.
- django.contrib.messages.storage.user_messages.LegacyFallbackStorage. Provided for backward compatibility with Django 1.1 and earlier versions. It works exactly the same as FallbackStorage, but also receives messages from the old alert system - django.contrib.auth. However, like the system itself from django.contrib.auth, this mechanism has been declared obsolete and will be removed from Django 1.4. While this mechanism is used by default, but as soon as it is removed, FallbackStorage will be in its place.
Types of messages and tags
As mentioned earlier, Django provides 5 built-in message types. Each type is an integer. You can easily extend or change existing types. By default we have:
- DEBUG: 10
- INFO: 20
- SUCCESS: 25
- WARNING: 30
- ERROR: 40
To add your own type, declare a constant and call the add_message () method to create a new message type:
CRITICAL = 50 messages.add_message(request, CRITICAL, 'OH NOES! A critical error occured.' )
CRITICAL = 50 messages.add_message(request, CRITICAL, 'OH NOES! A critical error occured.' )
Of course, you will want to use this information in HTML and CSS, so you need to add the MESSAGE_TAGS setting to your settings.py file to set a string representation for your new message type:
MESSAGE_TAGS = { 50 : 'critical' }
Finally
The new messaging system included in Django 1.2 is not a very difficult part of the framework, but it provides functionality without which a modern web application cannot be imagined, and makes it very elegant and simple. In addition, it is fully compatible with previous versions, so you don’t need to worry that the old code or third-party applications will break after switching to 1.2. But do not forget that the compatibility layer will be removed in 1.4, planned somewhere in the second half of 2027.
Joke. Enjoy Django 1.2! This is a really cool update of our favorite framework.
-
Translation prepared in Vim .