|
|
# Create your views here.
|
|
|
# 导入Django相关异常、响应和工具类
|
|
|
from django.core.exceptions import ValidationError # 用于抛出数据验证异常
|
|
|
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 .models import Comment # 评论模型
|
|
|
|
|
|
|
|
|
class CommentPostView(FormView):
|
|
|
"""评论提交处理的类视图"""
|
|
|
form_class = CommentForm # 指定使用的表单类
|
|
|
template_name = 'blog/article_detail.html' # 表单渲染和错误显示的模板
|
|
|
|
|
|
@method_decorator(csrf_protect)
|
|
|
def dispatch(self, *args, **kwargs):
|
|
|
"""
|
|
|
重写dispatch方法,添加CSRF保护
|
|
|
|
|
|
使用method_decorator将csrf_protect装饰器应用到dispatch方法,
|
|
|
确保表单提交经过CSRF验证,防止跨站请求伪造攻击
|
|
|
"""
|
|
|
return super(CommentPostView, self).dispatch(*args, **kwargs)
|
|
|
|
|
|
def get(self, request, *args, **kwargs):
|
|
|
"""
|
|
|
处理GET请求
|
|
|
|
|
|
当通过GET访问评论提交URL时,重定向到对应的文章详情页的评论区
|
|
|
"""
|
|
|
article_id = self.kwargs['article_id'] # 从URL参数中获取文章ID
|
|
|
article = get_object_or_404(Article, pk=article_id) # 获取对应的文章对象
|
|
|
url = article.get_absolute_url() # 获取文章的绝对URL
|
|
|
return HttpResponseRedirect(url + "#comments") # 重定向到文章详情页的评论锚点
|
|
|
|
|
|
def form_invalid(self, form):
|
|
|
"""
|
|
|
表单数据验证失败时的处理
|
|
|
|
|
|
当表单提交的数据验证不通过(如必填项为空、格式错误等),
|
|
|
重新渲染文章详情页,并携带错误表单对象和文章对象,方便前端显示错误信息
|
|
|
"""
|
|
|
article_id = self.kwargs['article_id'] # 获取文章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 # 获取当前登录用户
|
|
|
author = BlogUser.objects.get(pk=user.pk) # 根据用户ID获取对应的用户对象
|
|
|
article_id = self.kwargs['article_id'] # 获取文章ID
|
|
|
article = get_object_or_404(Article, pk=article_id) # 获取文章对象
|
|
|
|
|
|
# 检查文章评论状态:若文章评论关闭或文章状态为关闭,则抛出验证异常
|
|
|
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']:
|
|
|
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)) |