接收整数型文章ID参数
+ views.CommentPostView.as_view(), # jyn: 将请求分发到基于类的视图CommentPostView(需调用as_view()转换)
+ name='postcomment' # jyn: 路由名称,用于reverse反向解析URL
+ ),
+]
+>>>>>>> JYN_branch
diff --git a/src/django-master/comments/utils.py b/src/django-master/comments/utils.py
index 376c5be..7962cf7 100644
--- a/src/django-master/comments/utils.py
+++ b/src/django-master/comments/utils.py
@@ -1,3 +1,4 @@
+<<<<<<< HEAD
# 导入日志模块和Django国际化工具,以及项目自定义工具
import logging # Python内置日志模块,用于记录邮件发送过程中的错误信息
@@ -8,10 +9,22 @@ from djangoblog.utils import send_email # 项目自定义工具:封装
# 初始化日志记录器:按当前模块名称创建logger,用于记录该模块的运行日志(如邮件发送失败)
logger = logging.getLogger(__name__)
+=======
+# jyn: 评论功能邮件通知工具模块,用于评论提交后向评论者及被回复者发送邮件通知
+import logging # jyn: 日志模块,记录邮件发送过程中的异常信息
+
+from django.utils.translation import gettext_lazy as _ # jyn: 国际化翻译支持,邮件内容适配多语言
+
+from djangoblog.utils import get_current_site # jyn: 工具函数,获取当前网站域名
+from djangoblog.utils import send_email # jyn: 工具函数,封装邮件发送逻辑
+
+logger = logging.getLogger(__name__) # jyn: 创建日志实例,用于记录模块内的日志信息
+>>>>>>> JYN_branch
def send_comment_email(comment):
"""
+<<<<<<< HEAD
评论相关邮件发送函数:触发场景为用户提交评论后
1. 向评论作者发送「评论提交成功」的感谢邮件
2. 若该评论是回复(有父评论),向父评论作者发送「评论被回复」的通知邮件
@@ -44,14 +57,61 @@ def send_comment_email(comment):
# 构建回复通知的HTML邮件内容:告知父评论作者“你的评论被回复了”
html_content = _("""Your comment on %s
has
received a reply.
%s
+=======
+ jyn: 发送评论相关邮件通知的核心函数
+ :param comment: 已保存的 Comment 模型实例(新提交的评论或回复)
+ :return: 无返回值,内部处理邮件发送逻辑及异常捕获
+ """
+ # jyn: 获取当前网站域名,用于拼接文章访问链接
+ site = get_current_site().domain
+ # jyn: 邮件主题(支持国际化)
+ subject = _('Thanks for your comment')
+ # jyn: 拼接文章的完整访问链接(HTTPS协议)
+ article_url = f"https://{site}{comment.article.get_absolute_url()}"
+
+ # 1. 向当前评论者发送「评论提交成功」通知邮件
+ # jyn: 构建评论者邮件的HTML内容,包含文章链接和感谢语(支持国际化)
+ 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 # jyn: 获取当前评论者的邮箱地址
+ send_email([tomail], subject, html_content) # jyn: 调用工具函数发送邮件
+
+ # 2. 若当前评论是回复(有父评论),向父评论者发送「收到回复」通知邮件
+ try:
+ if comment.parent_comment: # jyn: 判断当前评论是否为对其他评论的回复
+ # jyn: 构建父评论者邮件的HTML内容,告知其评论被回复(支持国际化)
+ html_content = _("""Your comment on %(article_title)s
has
+ received a reply.
%(comment_body)s
+>>>>>>> JYN_branch
go check it out!
If the link above cannot be opened, please copy this link to your browser.
+<<<<<<< HEAD
%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) # 将错误信息记录到日志(便于后续排查问题,不中断程序运行)
\ No newline at end of file
+ logger.error(e) # 将错误信息记录到日志(便于后续排查问题,不中断程序运行)
+=======
+ %(article_url)s
+ """) % {
+ 'article_url': article_url,
+ 'article_title': comment.article.title,
+ 'comment_body': comment.parent_comment.body # jyn: 包含父评论的正文内容
+ }
+ tomail = comment.parent_comment.author.email # jyn: 获取父评论者的邮箱地址
+ send_email([tomail], subject, html_content) # jyn: 发送回复通知邮件
+ except Exception as e:
+ logger.error(e) # jyn: 捕获发送过程中的异常,记录错误日志(不中断程序执行)
+>>>>>>> JYN_branch
diff --git a/src/django-master/comments/views.py b/src/django-master/comments/views.py
index 895e200..5ba7383 100644
--- a/src/django-master/comments/views.py
+++ b/src/django-master/comments/views.py
@@ -1,4 +1,5 @@
<<<<<<< HEAD
+<<<<<<< HEAD
# Create your views here.
# 导入Django核心模块、异常类、视图工具及项目内模型/表单
from django.core.exceptions import ValidationError # Django内置验证异常类,用于抛出自定义验证错误
@@ -31,18 +32,43 @@ class CommentPostView(FormView):
# 1. 类视图基础配置
form_class = CommentForm # 指定关联的表单类:使用CommentForm处理提交数据
template_name = 'blog/article_detail.html' # 指定表单渲染的模板:评论在文章详情页提交,故用文章详情模板
+=======
+# jyn: 评论功能核心视图模块,处理评论提交、数据验证、权限判断及页面跳转逻辑
+from django.core.exceptions import ValidationError # jyn: Django 数据验证异常类,用于抛出评论相关错误
+from django.http import HttpResponseRedirect # jyn: 重定向响应类,评论提交后跳转至指定页面
+from django.shortcuts import get_object_or_404 # jyn: 快捷查询函数,查询不到数据时返回404
+from django.utils.decorators import method_decorator # jyn: 方法装饰器工具,用于给类视图方法添加装饰器
+from django.views.decorators.csrf import csrf_protect # jyn: CSRF防护装饰器,防止跨站请求伪造
+from django.views.generic.edit import FormView # jyn: 基于类的表单处理视图基类,简化表单验证逻辑
+
+from accounts.models import BlogUser # jyn: 导入用户模型,关联评论作者
+from blog.models import Article # jyn: 导入文章模型,关联评论所属文章
+from .forms import CommentForm # jyn: 导入评论表单类,用于前端数据验证
+from .models import Comment # jyn: 导入评论模型,用于数据存储
+
+
+class CommentPostView(FormView):
+ """jyn: 评论提交处理视图类,继承FormView实现表单验证、数据保存及页面跳转"""
+ form_class = CommentForm # jyn: 指定关联的表单类,用于前端提交数据的验证
+ template_name = 'blog/article_detail.html' # jyn: 表单验证失败时渲染的模板(文章详情页)
+>>>>>>> JYN_branch
# 2. 给dispatch方法添加CSRF保护:所有请求(GET/POST)都经过CSRF验证
@method_decorator(csrf_protect)
def dispatch(self, *args, **kwargs):
+<<<<<<< HEAD
"""
类视图的请求入口方法:所有请求都会先经过此方法
作用:调用父类的dispatch逻辑,同时应用CSRF保护
"""
+=======
+ """jyn: 重写dispatch方法,添加CSRF防护,所有请求先经过该方法分发"""
+>>>>>>> JYN_branch
return super(CommentPostView, self).dispatch(*args, **kwargs)
# 3. 处理GET请求:当用户以GET方式访问该视图时触发
def get(self, request, *args, **kwargs):
+<<<<<<< HEAD
"""
GET请求逻辑:不处理表单提交,直接重定向到对应的文章详情页的评论区
避免用户直接通过URL以GET方式访问该视图时出现异常
@@ -55,9 +81,17 @@ class CommentPostView(FormView):
url = article.get_absolute_url()
# 重定向到文章详情页的评论区
return HttpResponseRedirect(url + "#comments")
+=======
+ """jyn: 处理GET请求,直接重定向到文章详情页的评论区"""
+ article_id = self.kwargs['article_id'] # jyn: 从URL参数中获取文章ID
+ article = get_object_or_404(Article, pk=article_id) # jyn: 查询文章,不存在则返回404
+ url = article.get_absolute_url() # jyn: 获取文章的绝对URL
+ return HttpResponseRedirect(url + "#comments") # jyn: 重定向到文章评论区锚点
+>>>>>>> JYN_branch
# 4. 处理表单验证失败的逻辑:当form.is_valid()为False时触发
def form_invalid(self, form):
+<<<<<<< HEAD
"""
表单数据验证失败(如评论内容为空、格式错误)时的处理
作用:重新渲染文章详情页,带上错误的表单对象(前端显示错误提示)
@@ -67,6 +101,12 @@ class CommentPostView(FormView):
article = get_object_or_404(Article, pk=article_id)
# 渲染模板:传递错误的表单对象(form)和文章对象(article),前端可显示错误信息
+=======
+ """jyn: 表单数据验证失败时的处理逻辑,返回文章详情页并携带错误表单"""
+ article_id = self.kwargs['article_id'] # jyn: 从URL参数获取文章ID
+ article = get_object_or_404(Article, pk=article_id) # jyn: 查询目标文章
+ # jyn: 渲染文章详情页,传递错误表单和文章实例(前端显示错误信息)
+>>>>>>> JYN_branch
return self.render_to_response({
'form': form, # 带有错误信息的表单
'article': article # 当前文章对象(用于渲染文章详情)
@@ -74,6 +114,7 @@ class CommentPostView(FormView):
# 5. 处理表单验证成功的逻辑:当form.is_valid()为True时触发(核心业务逻辑)
def form_valid(self, form):
+<<<<<<< HEAD
"""提交的数据验证合法后的逻辑:保存评论数据到数据库,处理评论状态和回复关联"""
# 1. 获取当前登录用户(评论作者)
user = self.request.user # 从请求对象中获取登录用户
@@ -111,4 +152,40 @@ class CommentPostView(FormView):
comment.parent_comment = parent_comment
# (原代码缺失:最终需调用comment.save()将评论数据提交到数据库,否则评论不会保存)
- # comment.save()
\ No newline at end of file
+ # comment.save()
+=======
+ """jyn: 表单数据验证合法后的核心逻辑,保存评论数据并跳转"""
+ user = self.request.user # jyn: 获取当前登录用户
+ author = BlogUser.objects.get(pk=user.pk) # jyn: 通过用户ID查询BlogUser实例(评论作者)
+ article_id = self.kwargs['article_id'] # jyn: 从URL参数获取文章ID
+ article = get_object_or_404(Article, pk=article_id) # jyn: 查询目标文章,不存在返回404
+
+ # jyn: 校验文章评论状态和发布状态,禁止对关闭评论/草稿文章提交评论
+ if article.comment_status == 'c' or article.status == 'c':
+ raise ValidationError("该文章评论已关闭.") # jyn: 抛出验证错误,终止评论提交
+
+ # jyn: 不立即保存评论(commit=False),先补充关联字段
+ comment = form.save(False)
+ comment.article = article # jyn: 关联评论所属文章
+
+ # jyn: 根据博客设置决定评论是否需要审核(无需审核则直接启用)
+ from djangoblog.utils import get_blog_setting
+ settings = get_blog_setting() # jyn: 获取博客全局设置
+ if not settings.comment_need_review:
+ comment.is_enable = True # jyn: 无需审核时,评论直接启用
+
+ comment.author = author # jyn: 关联评论作者
+
+ # jyn: 处理回复功能,若存在父评论ID则关联父评论
+ if form.cleaned_data['parent_comment_id']:
+ parent_comment = Comment.objects.get(
+ pk=form.cleaned_data['parent_comment_id']) # jyn: 查询父评论
+ comment.parent_comment = parent_comment # jyn: 关联父评论
+
+ comment.save(True) # jyn: 最终保存评论数据到数据库
+
+ # jyn: 重定向到文章详情页的当前评论锚点(精准定位到新提交的评论)
+ return HttpResponseRedirect(
+ "%s#div-comment-%d" %
+ (article.get_absolute_url(), comment.pk))
+>>>>>>> JYN_branch