|
|
# 赵瑞萍:评论提交视图模块,用于处理用户评论发布、数据验证、业务逻辑处理及响应返回
|
|
|
# 基于Django FormView实现,支持CSRF保护、表单验证、评论状态控制及回复功能处理
|
|
|
|
|
|
# 赵瑞萍:导入Django核心组件,提供异常处理、响应、数据查询及装饰器支持
|
|
|
from django.core.exceptions import ValidationError # 数据验证异常,用于抛出评论相关业务错误
|
|
|
from django.http import HttpResponseRedirect # 重定向响应类,用于评论成功后跳转
|
|
|
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 .models import Comment # 评论模型,用于数据存储
|
|
|
|
|
|
|
|
|
class CommentPostView(FormView):
|
|
|
"""
|
|
|
赵瑞萍:评论提交处理类视图,继承FormView封装表单处理流程
|
|
|
核心功能:接收评论提交请求、验证数据合法性、处理评论保存逻辑、返回对应响应
|
|
|
支持场景:普通评论发布、评论回复、评论审核状态控制、CSRF防护
|
|
|
"""
|
|
|
# 赵瑞萍:指定表单类为CommentForm,用于数据验证和字段映射
|
|
|
form_class = CommentForm
|
|
|
# 赵瑞萍:指定模板为文章详情页,用于表单错误时重新渲染页面并显示错误
|
|
|
template_name = 'blog/article_detail.html'
|
|
|
|
|
|
@method_decorator(csrf_protect)
|
|
|
def dispatch(self, *args, **kwargs):
|
|
|
"""
|
|
|
赵瑞萍:重写dispatch方法,添加CSRF保护
|
|
|
通过method_decorator将csrf_protect装饰器应用到请求分发流程,确保所有请求经过CSRF验证
|
|
|
防止跨站请求伪造攻击,保护评论提交接口安全
|
|
|
"""
|
|
|
# 赵瑞萍:调用父类dispatch方法,维持原有请求分发逻辑
|
|
|
return super(CommentPostView, self).dispatch(*args, **kwargs)
|
|
|
|
|
|
def get(self, request, *args, **kwargs):
|
|
|
"""
|
|
|
赵瑞萍:处理GET请求,避免直接通过URL访问评论提交接口
|
|
|
当用户以GET方式访问时,重定向到对应文章详情页的评论区
|
|
|
"""
|
|
|
# 赵瑞萍:从URL参数中获取文章ID,确定评论所属文章
|
|
|
article_id = self.kwargs['article_id']
|
|
|
# 赵瑞萍:查询文章对象,不存在则返回404
|
|
|
article = get_object_or_404(Article, pk=article_id)
|
|
|
# 赵瑞萍:获取文章绝对URL,拼接评论区锚点,重定向到评论区
|
|
|
url = article.get_absolute_url()
|
|
|
return HttpResponseRedirect(url + "#comments")
|
|
|
|
|
|
def form_invalid(self, form):
|
|
|
"""
|
|
|
赵瑞萍:表单数据验证失败时的处理方法
|
|
|
当用户输入不符合规则(如评论为空、长度超限),重新渲染文章详情页并携带错误信息
|
|
|
"""
|
|
|
# 赵瑞萍:从URL参数获取文章ID,关联当前评论的文章
|
|
|
article_id = self.kwargs['article_id']
|
|
|
# 赵瑞萍:查询文章对象,确保页面渲染时有文章数据
|
|
|
article = get_object_or_404(Article, pk=article_id)
|
|
|
|
|
|
# 赵瑞萍:返回渲染后的页面,携带包含错误信息的表单和文章对象
|
|
|
return self.render_to_response({
|
|
|
'form': form, # 含错误提示的表单对象,前端可渲染错误信息
|
|
|
'article': article # 文章对象,用于页面展示文章内容
|
|
|
})
|
|
|
|
|
|
def form_valid(self, form):
|
|
|
"""
|
|
|
赵瑞萍:表单数据验证通过后的核心业务逻辑处理
|
|
|
完成评论对象的构建、关联数据设置、业务规则校验及保存,最后重定向到评论位置
|
|
|
"""
|
|
|
# 赵瑞萍:获取当前登录用户对象(需登录才能评论)
|
|
|
user = self.request.user
|
|
|
# 赵瑞萍:根据用户ID查询BlogUser实例,作为评论作者
|
|
|
author = BlogUser.objects.get(pk=user.pk)
|
|
|
# 赵瑞萍:从URL参数获取文章ID,确定评论所属文章
|
|
|
article_id = self.kwargs['article_id']
|
|
|
# 赵瑞萍:查询文章对象,不存在则返回404
|
|
|
article = get_object_or_404(Article, pk=article_id)
|
|
|
|
|
|
# 赵瑞萍:业务规则校验——检查文章是否允许评论
|
|
|
# 若文章评论状态为'c'(关闭)或文章状态为'c'(关闭),抛出验证异常
|
|
|
if article.comment_status == 'c' or article.status == 'c':
|
|
|
raise ValidationError("该文章评论已关闭.")
|
|
|
|
|
|
# 赵瑞萍:保存表单数据但不提交到数据库(commit=False),预留字段补充空间
|
|
|
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 # 关联评论到作者
|
|
|
|
|
|
# 赵瑞萍:处理评论回复功能——判断是否存在父评论ID
|
|
|
if form.cleaned_data['parent_comment_id']:
|
|
|
# 赵瑞萍:根据父评论ID查询父评论对象,建立回复关联
|
|
|
parent_comment = Comment.objects.get(
|
|
|
pk=form.cleaned_data['parent_comment_id'])
|
|
|
comment.parent_comment = parent_comment # 关联当前评论到父评论
|
|
|
|
|
|
# 赵瑞萍:最终将评论数据提交到数据库保存
|
|
|
comment.save(True)
|
|
|
|
|
|
# 赵瑞萍:重定向到文章详情页中当前评论的锚点位置,方便用户查看自己的评论
|
|
|
return HttpResponseRedirect(
|
|
|
"%s#div-comment-%d" %
|
|
|
(article.get_absolute_url(), comment.pk) # 拼接文章URL和评论锚点(如#div-comment-1)
|
|
|
) |