From 2d5359b2c794d5a2b683952fba69ebd4c9bc16c6 Mon Sep 17 00:00:00 2001 From: plhw57tbe <2723863608@qq.com> Date: Sun, 19 Oct 2025 23:11:12 +0800 Subject: [PATCH] Update blog_signals.py --- .../djangoblog/blog_signals.py | 76 +++++++++++++++---- 1 file changed, 62 insertions(+), 14 deletions(-) diff --git a/src/DjangoBlog-master/djangoblog/blog_signals.py b/src/DjangoBlog-master/djangoblog/blog_signals.py index 393f441..ffc3b89 100644 --- a/src/DjangoBlog-master/djangoblog/blog_signals.py +++ b/src/DjangoBlog-master/djangoblog/blog_signals.py @@ -1,7 +1,11 @@ +# 导入线程模块:用于异步执行耗时操作(如发送邮件,避免阻塞主流程) import _thread +# 导入日志模块:记录操作日志和错误信息 import logging +# 导入 Django 信号核心类:用于定义和处理自定义信号 import django.dispatch +# 导入 Django 配置、模型、工具类:支撑信号处理中的业务逻辑 from django.conf import settings from django.contrib.admin.models import LogEntry from django.contrib.auth.signals import user_logged_in, user_logged_out @@ -9,6 +13,7 @@ from django.core.mail import EmailMultiAlternatives from django.db.models.signals import post_save from django.dispatch import receiver +# 导入项目自定义模型和工具函数:适配博客业务场景 from comments.models import Comment from comments.utils import send_comment_email from djangoblog.spider_notify import SpiderNotify @@ -16,54 +21,73 @@ 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参数 oauth_user_login_signal = django.dispatch.Signal(['id']) +# 定义自定义信号:发送邮件的信号,携带收件人、标题、内容参数 send_email_signal = django.dispatch.Signal( ['emailto', 'title', 'content']) +# 信号接收器:监听 send_email_signal 信号,触发邮件发送逻辑 @receiver(send_email_signal) def send_email_signal_handler(sender, **kwargs): - emailto = kwargs['emailto'] - title = kwargs['title'] - content = kwargs['content'] + # 从信号参数中提取邮件相关信息 + emailto = kwargs['emailto'] # 收件人列表 + title = kwargs['title'] # 邮件标题 + content = kwargs['content'] # 邮件内容(HTML格式) + # 构建 HTML 格式邮件:支持富文本内容 msg = EmailMultiAlternatives( title, content, - from_email=settings.DEFAULT_FROM_EMAIL, + from_email=settings.DEFAULT_FROM_EMAIL, # 发件人(从项目配置中获取) to=emailto) - msg.content_subtype = "html" + 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 = 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 # 标记发送失败 + finally: + # 保存日志记录到数据库 + log.save() +# 信号接收器:监听 oauth_user_login_signal 信号,处理 OAuth 登录后的逻辑 @receiver(oauth_user_login_signal) def oauth_user_login_signal_handler(sender, **kwargs): + # 从信号参数中提取 OAuth 用户ID id = kwargs['id'] + # 获取对应的 OAuth 用户对象 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() +# 信号接收器:监听所有模型的 post_save 信号(模型保存后触发) @receiver(post_save) def model_post_save_callback( sender, @@ -73,50 +97,74 @@ def model_post_save_callback( using, update_fields, **kwargs): + # 标记是否需要清理缓存 clearcache = False + + # 跳过 Admin 操作日志(LogEntry)的处理:避免日志保存时触发不必要的逻辑 if isinstance(instance, LogEntry): return + + # 处理有 "get_full_url" 方法的模型(如 Article 文章模型) 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) + # 非阅读量更新:标记需要清理缓存(如文章内容、标题修改) if not is_update_views: clearcache = True + # 处理 Comment 评论模型的保存逻辑 if isinstance(instance, Comment): + # 仅处理已启用的评论(is_enable=True) if instance.is_enable: + # 获取评论所属文章的访问路径 path = instance.article.get_absolute_url() + # 获取当前站点域名(处理端口号,仅保留域名部分) site = get_current_site().domain if site.find(':') > 0: site = site[0:site.find(':')] + # 清理文章详情页的视图缓存:避免显示旧评论 expire_view_cache( path, servername=site, serverport=80, key_prefix='blogdetail') + # 清理 SEO 处理器缓存:评论变化可能影响页面 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() +# 信号接收器:同时监听用户登录(user_logged_in)和登出(user_logged_out)信号 @receiver(user_logged_in) @receiver(user_logged_out) def user_auth_callback(sender, request, user, **kwargs): + # 若用户存在且用户名有效(排除异常情况) if user and user.username: + # 记录用户登录/登出日志 logger.info(user) + # 清理侧边栏缓存:登录状态变化可能影响侧边栏(如显示/隐藏用户菜单) delete_sidebar_cache() - # cache.clear() + # cache.clear() # 注释:若需全局清缓存可启用,当前仅清理侧边栏缓存 \ No newline at end of file