添加 blog_signals.py 注释

jyf_branch
姜雨菲 4 months ago
parent 51e5b99eaa
commit c9a2a3baf2

@ -1,3 +1,8 @@
# Django博客系统信号处理模块
# 该模块用于注册和处理Django内置信号及自定义信号实现事件驱动的业务逻辑
# 核心功能包括邮件发送、OAuth用户登录处理、模型保存后缓存清理/搜索引擎通知、用户登录登出缓存处理等
# 通过信号机制解耦业务逻辑,当特定事件触发时自动执行对应处理函数
import _thread
import logging
@ -9,6 +14,7 @@ from django.core.mail import EmailMultiAlternatives
from django.db.models.signals import post_save
from django.dispatch import receiver
# 导入项目内部模块评论相关、插件通知、缓存工具、站点工具、OAuth模型
from comments.models import Comment
from comments.utils import send_comment_email
from djangoblog.spider_notify import SpiderNotify
@ -16,51 +22,72 @@ from djangoblog.utils import cache, expire_view_cache, delete_sidebar_cache, del
from djangoblog.utils import get_current_site
from oauth.models import OAuthUser
# 初始化日志记录器,记录信号处理过程中的信息和错误
logger = logging.getLogger(__name__)
# 自定义信号OAuth用户登录信号携带参数'id'OAuthUser的主键
oauth_user_login_signal = django.dispatch.Signal(['id'])
# 自定义信号:邮件发送信号,携带参数'emailto'(收件人列表)、'title'(邮件标题)、'content'(邮件内容)
send_email_signal = django.dispatch.Signal(
['emailto', 'title', 'content'])
@receiver(send_email_signal)
def send_email_signal_handler(sender, **kwargs):
"""
邮件发送信号的处理函数
当send_email_signal信号触发时自动发送HTML格式邮件并记录发送日志
"""
# 从信号参数中提取邮件相关信息
emailto = kwargs['emailto']
title = kwargs['title']
content = kwargs['content']
# 构建HTML格式邮件content_subtype设为html支持富文本
msg = EmailMultiAlternatives(
title,
content,
from_email=settings.DEFAULT_FROM_EMAIL,
to=emailto)
msg.content_subtype = "html"
from_email=settings.DEFAULT_FROM_EMAIL, # 发件人从Django配置中读取
to=emailto) # 收件人列表
msg.content_subtype = "html" # 指定邮件内容为HTML格式
# 初始化邮件发送日志模型,记录发送详情
from servermanager.models import EmailSendLog
log = EmailSendLog()
log.title = title
log.content = content
log.emailto = ','.join(emailto)
log.emailto = ','.join(emailto) # 多个收件人用逗号拼接存储
try:
# 发送邮件result为成功发送的邮件数量
result = msg.send()
log.send_result = result > 0
log.send_result = result > 0 # 发送数量>0表示发送成功
except Exception as e:
# 捕获发送异常,记录错误日志
logger.error(f"失败邮箱号: {emailto}, {e}")
log.send_result = False
log.save()
log.send_result = False # 标记发送失败
log.save() # 保存日志到数据库
@receiver(oauth_user_login_signal)
def oauth_user_login_signal_handler(sender, **kwargs):
"""
OAuth用户登录信号的处理函数
当OAuth用户登录成功后处理用户头像如跨域头像本地化存储并清理侧边栏缓存
"""
# 从信号参数中提取OAuthUser的id查询对应的用户实例
id = kwargs['id']
oauthuser = OAuthUser.objects.get(id=id)
# 获取当前站点域名(用于判断头像是否为本地地址)
site = get_current_site().domain
# 若用户有头像且头像地址不包含当前站点域名(跨域头像),则本地化存储
if oauthuser.picture and not oauthuser.picture.find(site) >= 0:
from djangoblog.utils import save_user_avatar
oauthuser.picture = save_user_avatar(oauthuser.picture)
oauthuser.save()
oauthuser.picture = save_user_avatar(oauthuser.picture) # 保存头像到本地并更新地址
oauthuser.save() # 保存更新后的用户信息
# 清理侧边栏缓存(确保登录后侧边栏展示最新数据)
delete_sidebar_cache()
@ -73,42 +100,64 @@ def model_post_save_callback(
using,
update_fields,
**kwargs):
clearcache = False
"""
Django模型保存后信号的处理函数post_save
触发时机任何模型执行save()方法后新增/更新
主要处理搜索引擎通知缓存清理评论审核通过后的联动操作
"""
clearcache = False # 标记是否需要清理全局缓存
# 跳过Admin操作日志模型LogEntry的处理无需触发后续逻辑
if isinstance(instance, LogEntry):
return
# 若模型实例有get_full_url方法通常是博客文章等需要对外展示的模型
if 'get_full_url' in dir(instance):
# 判断是否仅更新浏览量字段views
is_update_views = update_fields == {'views'}
# 非测试环境且不是仅更新浏览量时,通知搜索引擎(如百度)收录新链接
if not settings.TESTING and not is_update_views:
try:
notify_url = instance.get_full_url()
SpiderNotify.baidu_notify([notify_url])
notify_url = instance.get_full_url() # 获取模型实例的完整访问链接
SpiderNotify.baidu_notify([notify_url]) # 通知百度搜索引擎
except Exception as ex:
logger.error("notify sipder", ex)
logger.error("notify sipder", ex) # 记录搜索引擎通知失败的错误
# 非浏览量更新时,标记需要清理缓存
if not is_update_views:
clearcache = True
# 若保存的是评论模型实例
if isinstance(instance, Comment):
# 仅处理审核通过的评论is_enable为True
if instance.is_enable:
# 获取评论对应的文章绝对路径
path = instance.article.get_absolute_url()
site = get_current_site().domain
# 处理带端口的域名如localhost:8000仅保留主域名部分
if site.find(':') > 0:
site = site[0:site.find(':')]
# 清理文章详情页的视图缓存(确保评论实时展示)
expire_view_cache(
path,
servername=site,
serverport=80,
key_prefix='blogdetail')
# 清理SEO相关缓存
if cache.get('seo_processor'):
cache.delete('seo_processor')
# 清理该文章的评论列表缓存
comment_cache_key = 'article_comments_{id}'.format(
id=instance.article.id)
cache.delete(comment_cache_key)
# 清理侧边栏缓存和评论相关视图缓存
delete_sidebar_cache()
delete_view_cache('article_comments', [str(instance.article.pk)])
# 启动新线程发送评论通知邮件(避免阻塞主线程)
_thread.start_new_thread(send_comment_email, (instance,))
# 若标记需要清理缓存,则执行全局缓存清理
if clearcache:
cache.clear()
@ -116,7 +165,13 @@ def model_post_save_callback(
@receiver(user_logged_in)
@receiver(user_logged_out)
def user_auth_callback(sender, request, user, **kwargs):
"""
用户登录/登出信号的处理函数
触发时机用户登录user_logged_in或登出user_logged_out
主要处理记录日志并清理侧边栏缓存确保登录状态变化后展示最新数据
"""
# 若用户存在且用户名有效
if user and user.username:
logger.info(user)
delete_sidebar_cache()
# cache.clear()
logger.info(user) # 记录用户登录/登出日志
delete_sidebar_cache() # 清理侧边栏缓存
# cache.clear() # 全局缓存清理(按需启用)
Loading…
Cancel
Save