Django Message 组件使用方法源码分析
目录
[Django Message超全总结教程]
1.使用方法
1.1 基础配置
INSTALLED_APPS = [
...
'django.contrib.messages',
...
]
# 在django setting.py 取消注释的message app
MIDDLEWARE = [
...
'django.contrib.messages.middleware.MessageMiddleware',
...
]
# 在django setting.py 取消注释的message 的中间件
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
...
'django.contrib.messages.context_processors.messages',
],
}
}
]
# 在django setting.py 添加message template设置
MESSAGE_STORAGE = "django.contrib.messages.storage.session.SessionStorage"
# 在django setting.py 添加 MESSAGE_STORAGE 配置
# 可用配置为 SessionStorage, CookieStorage, FallbackStorage
# SessionStorage: 设置的Message 存储于Session中
# CookieStorage: 设置的Message 存储于Cookie中
# FallbackStorage: 设置的Message 存储于Cookie和Session中
1.2 代码使用
#添加message
from django.contrib import messages
def concel_order(request):
messages.add_message(request, messages.SUCCESS, "删除成功1")
messages.add_message(request, messages.SUCCESS, "删除成功2")
return redirect("/order/control/")
# 在视图函数中添加messages模块
# 再通过messages.add_message导入提示信息
# 在视图函数中import get_messages模块获取添加的提示信息
def control_order(request):
if request.method == "GET":
from django.contrib.messages.api import get_messages
m1 = get_messages(request)
print(m1)
# 在html模板中添加for循环拿到message
<div>
{% for obj in messages %}
<ul>{{ obj.message }}</ul>
{% endfor %}
</div>
2.源码流程
2.1 中间件process_request
# 在html模板中添加for循环拿到message
MIDDLEWARE = [
....
'django.contrib.messages.middleware.MessageMiddleware',
....
]
# 在中间件process_request中定义了request._messages = default_storage(request)
# 接着看default_storage是什么
from django.contrib.messages.storage import default_storage
class MessageMiddleware(MiddlewareMixin):
"""
Middleware that handles temporary messages.
"""
def process_request(self, request):
request._messages = default_storage(request)
# default_storage 写入了函数import_string方法 就等于
# setting配置文件中
# MESSAGE_STORAGE = "django.contrib.messages.storage.session.SessionStorage"
# 等于 SessionStorage(request)
from django.conf import settings
from django.utils.module_loading import import_string
def default_storage(request):
return import_string(settings.MESSAGE_STORAGE)(request)
现在 request._messages = SessionStorage(request)
2.2 视图函数views.py, 添加message
from django.contrib import messages
def concel_order(request):
messages.add_message(request, messages.SUCCESS, "删除成功1")
messages.add_message(request, messages.SUCCESS, "删除成功2")
return redirect("/order/control/")
def add_message(request, level, message, extra_tags="", fail_silently=False):
"""
Attempt to add a message to the request using the 'messages' app.
"""
try:
# 尝试拿到request._messages
messages = request._messages
except AttributeError:
# 如果失败看request 有没有META参数如果没有说明request对象不是HttpRequest对象报错
if not hasattr(request, "META"):
raise TypeError(
"add_message() argument must be an HttpRequest object, not "
"'%s'." % request.__class__.__name__
)
# 如果 fail_silently = False说明MessageMiddleware中间件未安装,报错
if not fail_silently:
raise MessageFailure(
"You cannot add messages without installing "
"django.contrib.messages.middleware.MessageMiddleware"
)
else:
# 如果没有报错调用 request._messages.add(level, message, extra_tags)
# 等于 SessionStorage(request).add(level, message, extra_tags)
return messages.add(level, message, extra_tags)
# SessionStorage的init方法先调用super().__init__(request, *args, **kwargs) 传入参数 super等于BaseStorage类
# SessionStorage 中没有add方法,所以看父类(BaseStorage)中寻找add方法
class SessionStorage(BaseStorage):
"""
Store messages in the session (that is, django.contrib.sessions).
"""
session_key = "_messages"
def __init__(self, request, *args, **kwargs):
if not hasattr(request, "session"):
raise ImproperlyConfigured(
"The session-based temporary message storage requires session "
"middleware to be installed, and come before the message "
"middleware in the MIDDLEWARE list."
)
super().__init__(request, *args, **kwargs)
class BaseStorage:
def __init__(self, request, *args, **kwargs):
self.request = request
self._queued_messages = []
self.used = False
self.added_new = False
super().__init__(*args, **kwargs)
def add(self, level, message, extra_tags=""):
# messages.add_message(request, messages.SUCCESS, "删除成功1") = return messages.add(level=messages.SUCCESS, message="删除成功1", extra_tags)
# 如果这里的 message是空,跳过添加message
if not message:
return
# Check that the message level is not less than the recording level.
# message.SUCCESS = 25
level = int(level)
# self.level 还未定义跳过
if level < self.level:
return
# Add the message.
# 添加message, 设置 self.added_new = True, 调用Message类传入参数
self.added_new = True
# 在下一段代码中为Message源码类 中的__init__方法中添加信息
message = Message(level, message, extra_tags=extra_tags)
# 类中append, self._queued_messages = [Message(message.SUCCESS, "删除成功1"), Message(message.SUCCESS, "删除成功2")]
self._queued_messages.append(message)
class Message:
"""
Represent an actual message that can be stored in any of the supported
storage classes (typically session- or cookie-based) and rendered in a view
or template.
"""
def __init__(self, level, message, extra_tags=None):
self.level = int(level)
self.message = message
self.extra_tags = extra_tags
2.3 视图函数views.py, 提取message
def control_order(request):
if request.method == "GET":
from django.contrib.messages.api import get_messages
m1 = get_messages(request)
print(m1)
# get_messages(request) 等于 request._messages 等于 SesssionStorage对象
def get_messages(request):
"""
Return the message storage on the request if it exists, otherwise return
an empty list.
"""
return getattr(request, "_messages", [])
# 在html中for循环, 对象被循环需要执行对象中的iter方法
<div>
{% for obj in messages %}
<ul>{{ obj.message }}</ul>
{% endfor %}
</div>
# iter魔法方法中, 如果self._queued_messages有值,
# self._queued_messages = [Message(message.SUCCESS, "删除成功1"), Message(message.SUCCESS, "删除成功2")]
# self._loaded_messages.extend 所以 self._loaded_messages = [Message(message.SUCCESS, "删除成功1"), Message(message.SUCCESS, "删除成功2")]
# return iter(self._loaded_messages) 就等于循环[Message(message.SUCCESS, "删除成功1"), Message(message.SUCCESS, "删除成功2")]列表
def __iter__(self):
self.used = True
if self._queued_messages:
self._loaded_messages.extend(self._queued_messages)
self._queued_messages = []
return iter(self._loaded_messages)
@property
def _loaded_messages(self):
"""
Return a list of loaded messages, retrieving them first if they have
not been loaded yet.
"""
# self._loaded_data 为空的 if成立
if not hasattr(self, "_loaded_data"):
# messages, all_retrieved = self._get()的返回值需要看一下_get方法
messages, all_retrieved = self._get()
self._loaded_data = messages or []
return self._loaded_data
def _get(self, *args, **kwargs):
# self.session_key = "_messages"
# self.deserialize_messages(self.request.session.get(_messages)),
# 从session中拿到 key = _messages的value, 再解序列化
return (
self.deserialize_messages(self.request.session.get(self.session_key)),
True,
)
2.4 中间件process_response
def process_response(self, request, response):
if hasattr(request, "_messages"):
# 删除session中存储的message信息
unstored_messages = request._messages.update(response)
if unstored_messages and settings.DEBUG:
raise ValueError("Not all temporary messages could be stored.")
return response