#gq: import _thread import logging import django.dispatch from django.conf import settings from django.contrib.admin.models import LogEntry from django.contrib.auth.signals import user_logged_in, user_logged_out 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 from djangoblog.utils import cache, expire_view_cache, delete_sidebar_cache, delete_view_cache from djangoblog.utils import get_current_site from oauth.models import OAuthUser logger = logging.getLogger(__name__) # 自定义信号:OAuth用户登录成功后触发 oauth_user_login_signal = django.dispatch.Signal(['id']) # 自定义信号:需要发送邮件时触发 send_email_signal = django.dispatch.Signal(['emailto', 'title', 'content']) @receiver(send_email_signal) def send_email_signal_handler(sender, **kwargs): """发送HTML邮件并记录发送日志""" emailto = kwargs['emailto'] title = kwargs['title'] content = kwargs['content'] msg = EmailMultiAlternatives( title, content, from_email=settings.DEFAULT_FROM_EMAIL, to=emailto) msg.content_subtype = "html" from servermanager.models import EmailSendLog log = EmailSendLog() log.title = title log.content = content log.emailto = ','.join(emailto) try: result = msg.send() log.send_result = result > 0 except Exception as e: logger.error(f"失败邮箱号: {emailto}, {e}") log.send_result = False log.save() @receiver(oauth_user_login_signal) def oauth_user_login_signal_handler(sender, **kwargs): """OAuth用户登录后,处理头像本地化并清理侧边栏缓存""" 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() delete_sidebar_cache() @receiver(post_save) def model_post_save_callback( sender, instance, created, raw, using, update_fields, **kwargs): """ 模型保存后触发: 1. 对有get_full_url方法的模型(如文章),通知搜索引擎。 2. 对评论,清理相关缓存并异步发送邮件通知。 """ clearcache = False # 忽略Admin日志 if isinstance(instance, LogEntry): return # 处理内容模型(如文章) if 'get_full_url' in dir(instance): 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]) except Exception as ex: logger.error("notify sipder", ex) # 非仅更新浏览量,则标记需要清理缓存 if not is_update_views: clearcache = True # 处理评论 if isinstance(instance, Comment): 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') 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() @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() # 注释掉了全局缓存清理,仅清理侧边栏