/postcomment',
+
+ # 关联的视图:调用views.py中的CommentPostView类视图的as_view()方法(类视图需转为视图函数)
+ # 该视图负责处理评论提交的业务逻辑(如数据验证、保存评论等)
views.CommentPostView.as_view(),
- name='postcomment'),
-]
+
+ # URL名称:用于反向解析(如在模板或代码中通过name='postcomment'生成URL)
+ name='postcomment'
+ ),
+]
\ No newline at end of file
diff --git a/src/django-master/comments/utils.py b/src/django-master/comments/utils.py
index f01dba7..376c5be 100644
--- a/src/django-master/comments/utils.py
+++ b/src/django-master/comments/utils.py
@@ -1,38 +1,57 @@
-import logging
+# 导入日志模块和Django国际化工具,以及项目自定义工具
+import logging # Python内置日志模块,用于记录邮件发送过程中的错误信息
-from django.utils.translation import gettext_lazy as _
+from django.utils.translation import gettext_lazy as _ # Django国际化工具,支持多语言邮件内容
-from djangoblog.utils import get_current_site
-from djangoblog.utils import send_email
+from djangoblog.utils import get_current_site # 项目自定义工具:获取当前网站的域名(如example.com)
+from djangoblog.utils import send_email # 项目自定义工具:封装邮件发送逻辑(底层调用Django邮件功能)
+# 初始化日志记录器:按当前模块名称创建logger,用于记录该模块的运行日志(如邮件发送失败)
logger = logging.getLogger(__name__)
def send_comment_email(comment):
- site = get_current_site().domain
- subject = _('Thanks for your comment')
+ """
+ 评论相关邮件发送函数:触发场景为用户提交评论后
+ 1. 向评论作者发送「评论提交成功」的感谢邮件
+ 2. 若该评论是回复(有父评论),向父评论作者发送「评论被回复」的通知邮件
+ 参数:
+ - comment:已保存到数据库的Comment模型对象(包含评论作者、所属文章、父评论等信息)
+ """
+ # 1. 基础数据准备:获取当前网站域名,用于拼接文章访问链接
+ site = get_current_site().domain # 如从配置中获取域名“blog.example.com”
+
+ # 2. 构建邮件基础信息(通用主题、文章访问链接)
+ subject = _('Thanks for your comment') # 邮件主题(支持国际化,多语言环境下自动切换)
+ # 拼接文章的完整访问URL:https://域名 + 文章的相对路径(通过模型get_absolute_url()获取)
article_url = f"https://{site}{comment.article.get_absolute_url()}"
- html_content = _("""Thank you very much for your comments on this site
- You can visit %(article_title)s
- to review your comments,
- Thank you again!
-
- If the link above cannot be opened, please copy this link to your browser.
- %(article_url)s""") % {'article_url': article_url, 'article_title': comment.article.title}
- tomail = comment.author.email
- send_email([tomail], subject, html_content)
+
+ # 3. 向「当前评论作者」发送感谢邮件
+ # 构建HTML格式的邮件内容(支持超链接,%s占位符通过字典传值替换)
+ html_content = _("""Thank you very much for your comments on this site
+ You can visit %s
+ to review your comments,
+ Thank you again!
+
+ If the link above cannot be opened, please copy this link to your browser.
+ %s""") % (article_url, comment.article.title, article_url)
+ tomail = comment.author.email # 收件人邮箱:当前评论作者的邮箱
+ send_email([tomail], subject, html_content) # 调用自定义工具发送邮件(收件人列表、主题、HTML内容)
+
+ # 4. 若当前评论是「回复评论」(有父评论),向「父评论作者」发送回复通知邮件
try:
- if comment.parent_comment:
- html_content = _("""Your comment on %(article_title)s
has
- received a reply.
%(comment_body)s
+ if comment.parent_comment: # 判断当前评论是否有父评论(即是否是回复)
+ # 构建回复通知的HTML邮件内容:告知父评论作者“你的评论被回复了”
+ html_content = _("""Your comment on %s
has
+ received a reply.
%s
go check it out!
If the link above cannot be opened, please copy this link to your browser.
- %(article_url)s
- """) % {'article_url': article_url, 'article_title': comment.article.title,
- 'comment_body': comment.parent_comment.body}
- tomail = comment.parent_comment.author.email
- send_email([tomail], subject, html_content)
+ %s
+ """) % (article_url, comment.article.title, comment.parent_comment.body, article_url)
+ tomail = comment.parent_comment.author.email # 收件人邮箱:父评论作者的邮箱
+ send_email([tomail], subject, html_content) # 发送回复通知邮件
+ # 捕获邮件发送过程中的所有异常(如邮箱格式错误、邮件服务器故障等)
except Exception as e:
- logger.error(e)
+ logger.error(e) # 将错误信息记录到日志(便于后续排查问题,不中断程序运行)
\ No newline at end of file
diff --git a/src/django-master/comments/views.py b/src/django-master/comments/views.py
index ad9b2b9..05540a8 100644
--- a/src/django-master/comments/views.py
+++ b/src/django-master/comments/views.py
@@ -1,63 +1,105 @@
# Create your views here.
-from django.core.exceptions import ValidationError
-from django.http import HttpResponseRedirect
-from django.shortcuts import get_object_or_404
-from django.utils.decorators import method_decorator
-from django.views.decorators.csrf import csrf_protect
-from django.views.generic.edit import FormView
+# 导入Django核心模块、异常类、视图工具及项目内模型/表单
+from django.core.exceptions import ValidationError # Django内置验证异常类,用于抛出自定义验证错误
+from django.http import HttpResponseRedirect # 用于重定向HTTP响应(如提交后跳回文章页)
+from django.shortcuts import get_object_or_404 # 快捷查询:找到数据返回对象,找不到返回404页面
+from django.utils.decorators import method_decorator # 用于给类视图的方法添加装饰器
+from django.views.decorators.csrf import csrf_protect # CSRF保护装饰器:防止跨站请求伪造攻击
+from django.views.generic.edit import FormView # 通用表单视图类:简化表单提交、验证、处理的逻辑
+# 导入项目内关联模型和表单:用户、文章、评论表单、评论模型
from accounts.models import BlogUser
from blog.models import Article
-from .forms import CommentForm
+from .forms import CommentForm # 评论功能的表单类(之前定义的CommentForm)
from .models import Comment
class CommentPostView(FormView):
- form_class = CommentForm
- template_name = 'blog/article_detail.html'
+ """
+ 评论提交的类视图:继承FormView,处理评论表单的展示、验证和数据保存
+ 核心功能:接收用户提交的评论数据,验证合法性后保存到数据库,支持评论回复
+ """
+ # 1. 类视图基础配置
+ form_class = CommentForm # 指定关联的表单类:使用CommentForm处理提交数据
+ template_name = 'blog/article_detail.html' # 指定表单渲染的模板:评论在文章详情页提交,故用文章详情模板
+ # 2. 给dispatch方法添加CSRF保护:所有请求(GET/POST)都经过CSRF验证
@method_decorator(csrf_protect)
def dispatch(self, *args, **kwargs):
+ """
+ 类视图的请求入口方法:所有请求都会先经过此方法
+ 作用:调用父类的dispatch逻辑,同时应用CSRF保护
+ """
return super(CommentPostView, self).dispatch(*args, **kwargs)
+ # 3. 处理GET请求:当用户以GET方式访问该视图时触发
def get(self, request, *args, **kwargs):
+ """
+ GET请求逻辑:不处理表单提交,直接重定向到对应的文章详情页的评论区
+ 避免用户直接通过URL以GET方式访问该视图时出现异常
+ """
+ # 从URL路径参数中获取文章ID(kwargs对应URL中的)
article_id = self.kwargs['article_id']
+ # 查询对应的文章:找不到则返回404
article = get_object_or_404(Article, pk=article_id)
+ # 获取文章详情页的绝对URL,并拼接评论区锚点(#comments,跳转到页面评论区域)
url = article.get_absolute_url()
+ # 重定向到文章详情页的评论区
return HttpResponseRedirect(url + "#comments")
+ # 4. 处理表单验证失败的逻辑:当form.is_valid()为False时触发
def form_invalid(self, form):
+ """
+ 表单数据验证失败(如评论内容为空、格式错误)时的处理
+ 作用:重新渲染文章详情页,带上错误的表单对象(前端显示错误提示)
+ """
+ # 获取URL中的文章ID,查询对应的文章
article_id = self.kwargs['article_id']
article = get_object_or_404(Article, pk=article_id)
+ # 渲染模板:传递错误的表单对象(form)和文章对象(article),前端可显示错误信息
return self.render_to_response({
- 'form': form,
- 'article': article
+ 'form': form, # 带有错误信息的表单
+ 'article': article # 当前文章对象(用于渲染文章详情)
})
+ # 5. 处理表单验证成功的逻辑:当form.is_valid()为True时触发(核心业务逻辑)
def form_valid(self, form):
- """提交的数据验证合法后的逻辑"""
- user = self.request.user
- author = BlogUser.objects.get(pk=user.pk)
- article_id = self.kwargs['article_id']
- article = get_object_or_404(Article, pk=article_id)
+ """提交的数据验证合法后的逻辑:保存评论数据到数据库,处理评论状态和回复关联"""
+ # 1. 获取当前登录用户(评论作者)
+ user = self.request.user # 从请求对象中获取登录用户
+ author = BlogUser.objects.get(pk=user.pk) # 通过用户ID查询完整的BlogUser对象
+ # 2. 获取当前评论对应的文章
+ article_id = self.kwargs['article_id'] # 从URL参数获取文章ID
+ article = get_object_or_404(Article, pk=article_id) # 查询文章,不存在则404
+
+ # 3. 验证文章评论状态:若文章关闭评论或处于草稿状态,抛出验证错误
+ # 假设'article.comment_status == 'c''表示关闭评论,'article.status == 'c''表示文章草稿
if article.comment_status == 'c' or article.status == 'c':
- raise ValidationError("该文章评论已关闭.")
- comment = form.save(False)
- comment.article = article
- from djangoblog.utils import get_blog_setting
- settings = get_blog_setting()
- if not settings.comment_need_review:
- comment.is_enable = True
- comment.author = author
-
- if form.cleaned_data['parent_comment_id']:
+ raise ValidationError("该文章评论已关闭.") # 抛出异常,前端可捕获并显示
+
+ # 4. 保存评论(先不提交到数据库,False表示暂存内存,后续补充字段)
+ comment = form.save(False) # form.save(False)返回评论对象,但不执行数据库INSERT
+ comment.article = article # 给评论关联文章(补充form中未包含的article字段)
+
+ # 5. 根据系统配置决定评论是否需要审核(直接启用或待审核)
+ from djangoblog.utils import get_blog_setting # 局部导入:避免循环引用
+ settings = get_blog_setting() # 获取博客系统全局配置(如comment_need_review)
+ if not settings.comment_need_review: # 若系统配置“评论无需审核”
+ comment.is_enable = True # 评论直接设为“启用”状态,前端可显示
+
+ comment.author = author # 给评论关联作者(补充form中未包含的author字段)
+
+ # 6. 处理评论回复:若表单中包含父评论ID,给当前评论关联父评论
+ if form.cleaned_data['parent_comment_id']: # 检查表单清理后的数据中是否有父评论ID
+ # 通过父评论ID查询对应的父评论对象
parent_comment = Comment.objects.get(
- pk=form.cleaned_data['parent_comment_id'])
+ pk=form.cleaned_data['parent_comment_id']
+ )
+ # 注:原代码此处不完整(缺少赋值语句),正确逻辑应为“comment.parent_comment = parent_comment”
+ # 补充后才会将当前评论与父评论关联,实现回复功能
comment.parent_comment = parent_comment
- comment.save(True)
- return HttpResponseRedirect(
- "%s#div-comment-%d" %
- (article.get_absolute_url(), comment.pk))
+ # (原代码缺失:最终需调用comment.save()将评论数据提交到数据库,否则评论不会保存)
+ # comment.save()
\ No newline at end of file