Con mucha frecuencia en las aplicaciones web, es necesario mostrar un mensaje de notificación por única vez (también conocido como “mensaje flash”) al usuario después de procesar un formulario o algunos otros tipos de entrada del usuario.

Para esto, Django proporciona soporte completo para mensajes basados ​​en cookies y sesiones, tanto para usuarios anónimos como autenticados. El marco de mensajes le permite almacenar mensajes temporalmente en una solicitud y recuperarlos para mostrarlos en una solicitud posterior (generalmente la siguiente). Cada mensaje está etiquetado con un level que determina su prioridad (p. ej., info, warning, o error).

Habilitación de mensajes

Los mensajes se implementan a través de un middleware clase y correspondiente procesador de contexto.

El valor por defecto settings.py creado por django-admin startproject ya contiene todas las configuraciones necesarias para habilitar la funcionalidad de mensajes:

  • 'django.contrib.messages' es en INSTALLED_APPS.
  • MIDDLEWARE contiene 'django.contrib.sessions.middleware.SessionMiddleware' y 'django.contrib.messages.middleware.MessageMiddleware'.

    El valor por defecto backend de almacenamiento se basa en sesiones. Es por eso SessionMiddleware debe estar habilitado y aparecer antes MessageMiddleware en MIDDLEWARE.

  • los 'context_processors' opción de la DjangoTemplates backend definido en tu TEMPLATES el ajuste contiene 'django.contrib.messages.context_processors.messages'.

Si no desea utilizar mensajes, puede eliminar 'django.contrib.messages' de tu INSTALLED_APPS, los MessageMiddleware línea de MIDDLEWARE, y el messages procesador de contexto de TEMPLATES.

Configurar el motor de mensajes

Backends de almacenamiento

El marco de mensajes puede usar diferentes backends para almacenar mensajes temporales.

Django proporciona tres clases de almacenamiento integradas en django.contrib.messages:

class storage.session.SessionStorage

Esta clase almacena todos los mensajes dentro de la sesión de la solicitud. Por lo tanto, requiere de Django contrib.sessions solicitud.

class storage.cookie.CookieStorage

Esta clase almacena los datos del mensaje en una cookie (firmada con un hash secreto para evitar la manipulación) para conservar las notificaciones entre las solicitudes. Los mensajes antiguos se descartan si el tamaño de los datos de la cookie excede los 2048 bytes.

Cambiado en Django 3.2:

El formato de los mensajes se cambió al RFC 6265 formato compatible.

class storage.fallback.FallbackStorage

Esta clase utiliza por primera vez CookieStoragey vuelve a usar SessionStorage para los mensajes que no caben en una sola cookie. También requiere de Django contrib.sessions solicitud.

Este comportamiento evita escribir en la sesión siempre que sea posible. Debería proporcionar el mejor rendimiento en el caso general.

FallbackStorage es la clase de almacenamiento predeterminada. Si no es adecuado para sus necesidades, puede seleccionar otra clase de almacenamiento configurando MESSAGE_STORAGE a su ruta de importación completa, por ejemplo:

MESSAGE_STORAGE = 'django.contrib.messages.storage.cookie.CookieStorage'
class storage.base.BaseStorage

Para escribir su propia clase de almacenamiento, subclase el BaseStorage clase en django.contrib.messages.storage.base e implementar el _get y _store métodos.

Niveles de mensaje

El marco de mensajes se basa en una arquitectura de nivel configurable similar a la del módulo de registro de Python. Los niveles de mensaje le permiten agrupar mensajes por tipo para que se puedan filtrar o mostrar de manera diferente en vistas y plantillas.

Los niveles integrados, que se pueden importar desde django.contrib.messages directamente, son:

Constante Objetivo
DEBUG Mensajes relacionados con el desarrollo que se ignorarán (o eliminarán) en una implementación de producción
INFO Mensajes informativos para el usuario
SUCCESS Una acción se realizó correctamente, por ejemplo, “Su perfil se actualizó correctamente”.
WARNING No se produjo una falla, pero puede ser inminente
ERROR Una acción fue no exitoso o se produjo algún otro error

los MESSAGE_LEVEL La configuración se puede utilizar para cambiar el nivel mínimo registrado (o se puede cambiar por solicitud). Se ignorarán los intentos de agregar mensajes de un nivel inferior a este.

Etiquetas de mensaje

Las etiquetas de mensaje son una representación de cadena del nivel del mensaje más cualquier etiqueta adicional que se haya agregado directamente en la vista (consulte Agregar etiquetas de mensaje adicionales a continuación para obtener más detalles). Las etiquetas se almacenan en una cadena y están separadas por espacios. Normalmente, las etiquetas de mensaje se utilizan como clases CSS para personalizar el estilo del mensaje según el tipo de mensaje. De forma predeterminada, cada nivel tiene una sola etiqueta que es una versión en minúsculas de su propia constante:

Constante de nivel Etiqueta
DEBUG debug
INFO info
SUCCESS success
WARNING warning
ERROR error

Para cambiar las etiquetas predeterminadas para un nivel de mensaje (ya sea integrado o personalizado), configure el MESSAGE_TAGS ajuste a un diccionario que contiene los niveles que desea cambiar. Como esto amplía las etiquetas predeterminadas, solo necesita proporcionar etiquetas para los niveles que desea anular:

from django.contrib.messages import constants as messages
MESSAGE_TAGS = {
    messages.INFO: '',
    50: 'critical',
}

Usar mensajes en vistas y plantillas

add_message(request, level, message, extra_tags="", fail_silently=False)

Agregar un mensaje

Para agregar un mensaje, llame al:

from django.contrib import messages
messages.add_message(request, messages.INFO, 'Hello world.')

Algunos métodos de acceso directo proporcionan una forma estándar de agregar mensajes con etiquetas de uso común (que generalmente se representan como clases HTML para el mensaje):

messages.debug(request, '%s SQL statements were executed.' % count)
messages.info(request, 'Three credits remain in your account.')
messages.success(request, 'Profile details updated.')
messages.warning(request, 'Your account expires in three days.')
messages.error(request, 'Document deleted.')

Visualización de mensajes

get_messages(request)

En tu plantilla, usa algo como:

{% if messages %}
<ul class="messages">
    {% for message in messages %}
    <li{% if message.tags %} class="{{ message.tags }}"{% endif %}>{{ message }}</li>
    {% endfor %}
</ul>
{% endif %}

Si está utilizando el procesador de contexto, su plantilla debe renderizarse con un RequestContext. De lo contrario, asegúrese messages está disponible para el contexto de la plantilla.

Incluso si sabe que solo hay un mensaje, debe repetir el messages secuencia, porque de lo contrario el almacenamiento de mensajes no se borrará para la siguiente solicitud.

El procesador de contexto también proporciona un DEFAULT_MESSAGE_LEVELS variable que es una asignación de los nombres de nivel de mensaje a su valor numérico:

{% if messages %}
<ul class="messages">
    {% for message in messages %}
    <li{% if message.tags %} class="{{ message.tags }}"{% endif %}>
        {% if message.level == DEFAULT_MESSAGE_LEVELS.ERROR %}Important: {% endif %}
        {{ message }}
    </li>
    {% endfor %}
</ul>
{% endif %}

Fuera de las plantillas, puedes usar get_messages():

from django.contrib.messages import get_messages

storage = get_messages(request)
for message in storage:
    do_something_with_the_message(message)

Por ejemplo, puede recuperar todos los mensajes para devolverlos en un JSONResponseMixin en lugar de un TemplateResponseMixin.

get_messages() devolverá una instancia del backend de almacenamiento configurado.

los Message clase

class storage.base.Message

Cuando recorre la lista de mensajes en una plantilla, lo que obtiene son instancias del Message clase. Tienen solo algunos atributos:

  • message: El texto real del mensaje.
  • level: Un número entero que describe el tipo de mensaje (consulte la sección de niveles de mensaje más arriba).
  • tags: Una cadena que combina todas las etiquetas del mensaje (extra_tags y level_tag) separados por espacios.
  • extra_tags: Una cadena que contiene etiquetas personalizadas para este mensaje, separadas por espacios. Está vacío por defecto.
  • level_tag: La representación de cadena del nivel. De forma predeterminada, es la versión en minúsculas del nombre de la constante asociada, pero esto se puede cambiar si lo necesita utilizando el MESSAGE_TAGS configuración.

Crear niveles de mensajes personalizados

Los niveles de los mensajes no son más que números enteros, por lo que puede definir sus propias constantes de nivel y usarlas para crear comentarios de usuario más personalizados, por ejemplo:

CRITICAL = 50

def my_view(request):
    messages.add_message(request, CRITICAL, 'A serious error occurred.')

Al crear niveles de mensajes personalizados, debe tener cuidado de no sobrecargar los niveles existentes. Los valores de los niveles integrados son:

Constante de nivel Valor
DEBUG 10
INFO 20
SUCCESS 25
WARNING 30
ERROR 40

Si necesita identificar los niveles personalizados en su HTML o CSS, debe proporcionar un mapeo a través del MESSAGE_TAGS configuración.

Nota

Si está creando una aplicación reutilizable, se recomienda utilizar solo los niveles de mensajes integrados y no depender de ningún nivel personalizado.

Cambiar el nivel mínimo registrado por solicitud

El nivel mínimo registrado se puede configurar por solicitud a través del set_level método:

from django.contrib import messages

# Change the messages level to ensure the debug message is added.
messages.set_level(request, messages.DEBUG)
messages.debug(request, 'Test message...')

# In another request, record only messages with a level of WARNING and higher
messages.set_level(request, messages.WARNING)
messages.success(request, 'Your profile was updated.') # ignored
messages.warning(request, 'Your account is about to expire.') # recorded

# Set the messages level back to default.
messages.set_level(request, None)

Del mismo modo, el nivel efectivo actual se puede recuperar con get_level:

from django.contrib import messages
current_level = messages.get_level(request)

Para obtener más información sobre cómo funciona el nivel mínimo registrado, consulte Niveles de mensaje más arriba.

Agregar etiquetas de mensaje adicionales

Para un control más directo sobre las etiquetas de los mensajes, opcionalmente puede proporcionar una cadena que contenga etiquetas adicionales a cualquiera de los métodos de adición:

messages.add_message(request, messages.INFO, 'Over 9000!', extra_tags='dragonball')
messages.error(request, 'Email box full', extra_tags='email')

Las etiquetas adicionales se agregan antes de la etiqueta predeterminada para ese nivel y están separadas por espacios.

Fallar silenciosamente cuando el marco de mensajes está deshabilitado

Si está escribiendo una aplicación reutilizable (u otro fragmento de código) y desea incluir la funcionalidad de mensajería, pero no desea que sus usuarios la habiliten si no lo desean, puede pasar un argumento de palabra clave adicional fail_silently=True a cualquiera de los add_message familia de métodos. Por ejemplo:

messages.add_message(
    request, messages.SUCCESS, 'Profile details updated.',
    fail_silently=True,
)
messages.info(request, 'Hello world.', fail_silently=True)

Nota

Configuración fail_silently=True solo esconde el MessageFailure que de otro modo ocurriría cuando el marco de mensajes se deshabilita y uno intenta usar uno de los add_message familia de métodos. No oculta fallas que puedan ocurrir por otras razones.

Agregar mensajes en vistas basadas en clases

class views.SuccessMessageMixin

Agrega un atributo de mensaje de éxito a FormView clases basadas

get_success_message(cleaned_data)

cleaned_data son los datos limpios del formulario que se utiliza para formatear cadenas

Ejemplo views.py:

from django.contrib.messages.views import SuccessMessageMixin
from django.views.generic.edit import CreateView
from myapp.models import Author

class AuthorCreateView(SuccessMessageMixin, CreateView):
    model = Author
    success_url = '/success/'
    success_message = "%(name)s was created successfully"

Los datos limpios del form está disponible para la interpolación de cadenas utilizando el %(field_name)s sintaxis. Para ModelForms, si necesita acceder a los campos del archivo guardado object anular el get_success_message() método.

Vistas de ejemplo.py para ModelForms:

from django.contrib.messages.views import SuccessMessageMixin
from django.views.generic.edit import CreateView
from myapp.models import ComplicatedModel

class ComplicatedCreateView(SuccessMessageMixin, CreateView):
    model = ComplicatedModel
    success_url = '/success/'
    success_message = "%(calculated_field)s was created successfully"

    def get_success_message(self, cleaned_data):
        return self.success_message % dict(
            cleaned_data,
            calculated_field=self.object.calculated_field,
        )

Caducidad de mensajes

Los mensajes se marcan para que se borren cuando se itera la instancia de almacenamiento (y se borran cuando se procesa la respuesta).

Para evitar que los mensajes se borren, puede configurar el almacenamiento de mensajes en False después de iterar:

storage = messages.get_messages(request)
for message in storage:
    do_something_with(message)
storage.used = False

Comportamiento de solicitudes paralelas

Debido a la forma en que funcionan las cookies (y, por lo tanto, las sesiones), el comportamiento de cualquier backend que hace uso de cookies o sesiones no está definido cuando el mismo cliente realiza múltiples solicitudes que configuran u obtienen mensajes en paralelo. Por ejemplo, si un cliente inicia una solicitud que crea un mensaje en una ventana (o pestaña) y luego otra que recupera cualquier mensaje no alfabetizado en otra ventana, antes de que la primera ventana se redireccione, el mensaje puede aparecer en la segunda ventana en lugar de la primera. ventana donde se puede esperar.

En resumen, cuando se involucran múltiples solicitudes simultáneas del mismo cliente, no se garantiza que los mensajes se entreguen en la misma ventana que los creó ni, en algunos casos, en absoluto. Tenga en cuenta que esto no suele ser un problema en la mayoría de las aplicaciones y no será un problema en HTML5, donde cada ventana / pestaña tendrá su propio contexto de navegación.

Ajustes

Unos pocos ajustes le da control sobre el comportamiento del mensaje:

  • MESSAGE_LEVEL
  • MESSAGE_STORAGE
  • MESSAGE_TAGS

Para los backends que usan cookies, la configuración de la cookie se toma de la configuración de la cookie de sesión:

  • SESSION_COOKIE_DOMAIN
  • SESSION_COOKIE_SECURE
  • SESSION_COOKIE_HTTPONLY