Update blog_signals.py

pull/10/head
plhw57tbe 4 months ago
parent dd1d9aed71
commit 2d5359b2c7

@ -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() # 注释:若需全局清缓存可启用,当前仅清理侧边栏缓存
Loading…
Cancel
Save