|
|
|
|
@ -1,63 +1,91 @@
|
|
|
|
|
# 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
|
|
|
|
|
# gst: 导入Django核心模块,用于异常处理、HTTP响应、数据查询等
|
|
|
|
|
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
|
|
|
|
|
# gst: 导入关联模型和表单,用于视图数据处理
|
|
|
|
|
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'
|
|
|
|
|
"""
|
|
|
|
|
gst: 评论提交视图类,继承FormView(专门处理表单提交的通用视图)
|
|
|
|
|
负责评论表单的展示、数据验证、提交保存及跳转逻辑
|
|
|
|
|
"""
|
|
|
|
|
form_class = CommentForm # gst: 关联的表单类(CommentForm),用于验证提交数据
|
|
|
|
|
template_name = 'blog/article_detail.html' # gst: 表单验证失败时渲染的模板(文章详情页)
|
|
|
|
|
|
|
|
|
|
@method_decorator(csrf_protect)
|
|
|
|
|
def dispatch(self, *args, **kwargs):
|
|
|
|
|
return super(CommentPostView, self).dispatch(*args, **kwargs)
|
|
|
|
|
"""
|
|
|
|
|
gst: 重写dispatch方法,添加CSRF保护装饰器
|
|
|
|
|
确保所有通过该视图的请求都经过CSRF验证,防止跨站请求伪造攻击
|
|
|
|
|
"""
|
|
|
|
|
return super(CommentPostView, self).dispatch(*args, **kwargs) # gst: 调用父类dispatch方法,保持原有逻辑
|
|
|
|
|
|
|
|
|
|
def get(self, request, *args, **kwargs):
|
|
|
|
|
article_id = self.kwargs['article_id']
|
|
|
|
|
article = get_object_or_404(Article, pk=article_id)
|
|
|
|
|
url = article.get_absolute_url()
|
|
|
|
|
return HttpResponseRedirect(url + "#comments")
|
|
|
|
|
"""
|
|
|
|
|
gst: 处理GET请求(直接访问评论提交URL时)
|
|
|
|
|
重定向到对应文章详情页的评论区,避免直接访问表单提交接口
|
|
|
|
|
"""
|
|
|
|
|
article_id = self.kwargs['article_id'] # gst: 从URL路径参数中获取文章ID
|
|
|
|
|
article = get_object_or_404(Article, pk=article_id) # gst: 查找文章,不存在则返回404
|
|
|
|
|
url = article.get_absolute_url() # gst: 获取文章的绝对路径(详情页URL)
|
|
|
|
|
return HttpResponseRedirect(url + "#comments") # gst: 重定向到文章详情页的评论区锚点
|
|
|
|
|
|
|
|
|
|
def form_invalid(self, form):
|
|
|
|
|
article_id = self.kwargs['article_id']
|
|
|
|
|
article = get_object_or_404(Article, pk=article_id)
|
|
|
|
|
"""
|
|
|
|
|
gst: 表单数据验证失败时的处理逻辑
|
|
|
|
|
渲染文章详情页,携带错误表单数据,展示验证失败信息
|
|
|
|
|
"""
|
|
|
|
|
article_id = self.kwargs['article_id'] # gst: 从URL参数获取文章ID
|
|
|
|
|
article = get_object_or_404(Article, pk=article_id) # gst: 获取对应的文章对象
|
|
|
|
|
|
|
|
|
|
# gst: 返回文章详情页模板,传递错误表单和文章对象(用于页面渲染错误信息)
|
|
|
|
|
return self.render_to_response({
|
|
|
|
|
'form': form,
|
|
|
|
|
'article': article
|
|
|
|
|
'form': form, # 验证失败的表单(含错误信息)
|
|
|
|
|
'article': article # 关联的文章对象
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
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)
|
|
|
|
|
"""
|
|
|
|
|
gst: 表单数据验证合法后的核心逻辑
|
|
|
|
|
处理评论保存、状态设置、回复关联等业务,最后重定向到评论位置
|
|
|
|
|
"""
|
|
|
|
|
user = self.request.user # gst: 获取当前登录用户(评论提交者)
|
|
|
|
|
author = BlogUser.objects.get(pk=user.pk) # gst: 通过用户ID获取对应的BlogUser对象(评论作者)
|
|
|
|
|
article_id = self.kwargs['article_id'] # gst: 从URL参数获取文章ID
|
|
|
|
|
article = get_object_or_404(Article, pk=article_id) # gst: 获取评论关联的文章,不存在则404
|
|
|
|
|
|
|
|
|
|
# gst: 检查文章状态:评论关闭(comment_status='c')或文章草稿(status='c')时,禁止评论
|
|
|
|
|
if article.comment_status == 'c' or article.status == 'c':
|
|
|
|
|
raise ValidationError("该文章评论已关闭.")
|
|
|
|
|
comment = form.save(False)
|
|
|
|
|
comment.article = article
|
|
|
|
|
raise ValidationError("该文章评论已关闭.") # gst: 抛出验证错误,终止评论提交
|
|
|
|
|
|
|
|
|
|
comment = form.save(False) # gst: 表单数据暂存(不立即保存到数据库)
|
|
|
|
|
comment.article = article # gst: 关联评论到当前文章
|
|
|
|
|
|
|
|
|
|
# gst: 获取博客全局设置,判断评论是否需要审核
|
|
|
|
|
from djangoblog.utils import get_blog_setting
|
|
|
|
|
settings = get_blog_setting()
|
|
|
|
|
if not settings.comment_need_review:
|
|
|
|
|
if not settings.comment_need_review: # gst: 若不需要审核,直接启用评论
|
|
|
|
|
comment.is_enable = True
|
|
|
|
|
comment.author = author
|
|
|
|
|
comment.author = author # gst: 关联评论作者
|
|
|
|
|
|
|
|
|
|
# gst: 处理回复功能:若表单提交了父评论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
|
|
|
|
|
pk=form.cleaned_data['parent_comment_id']) # gst: 根据ID获取父评论对象
|
|
|
|
|
comment.parent_comment = parent_comment # gst: 关联当前评论到父评论
|
|
|
|
|
|
|
|
|
|
comment.save(True) # gst: 最终保存评论数据到数据库(True表示执行完整保存逻辑)
|
|
|
|
|
|
|
|
|
|
comment.save(True)
|
|
|
|
|
# gst: 重定向到文章详情页的当前评论位置(锚点定位到具体评论)
|
|
|
|
|
return HttpResponseRedirect(
|
|
|
|
|
"%s#div-comment-%d" %
|
|
|
|
|
(article.get_absolute_url(), comment.pk))
|
|
|
|
|
(article.get_absolute_url(), comment.pk)) # 拼接URL:文章绝对路径 + 评论ID锚点
|