diff --git a/src/DjangoBlog/comments/admin.py b/src/DjangoBlog/comments/admin.py index dbde14f..58a7959 100644 --- a/src/DjangoBlog/comments/admin.py +++ b/src/DjangoBlog/comments/admin.py @@ -1,49 +1,79 @@ +# 模块级注释:Django管理后台配置模块 - 评论管理 +# 本模块定义了评论模型在Django管理后台的显示配置和操作功能 from django.contrib import admin from django.urls import reverse from django.utils.html import format_html from django.utils.translation import gettext_lazy as _ +# 函数级注释:禁用评论状态操作 +# 管理员动作函数,用于批量禁用选中的评论 def disable_commentstatus(modeladmin, request, queryset): + # 核心代码:将查询集中所有评论的is_enable字段更新为False queryset.update(is_enable=False) +# 函数级注释:启用评论状态操作 +# 管理员动作函数,用于批量启用选中的评论 def enable_commentstatus(modeladmin, request, queryset): + # 核心代码:将查询集中所有评论的is_enable字段更新为True queryset.update(is_enable=True) +# 设置动作函数的显示名称(国际化) disable_commentstatus.short_description = _('Disable comments') enable_commentstatus.short_description = _('Enable comments') +# 类级注释:评论管理类 +# 继承自admin.ModelAdmin,自定义评论模型在Django管理后台的显示和行为 class CommentAdmin(admin.ModelAdmin): + # 每页显示记录数配置 list_per_page = 20 + # 列表页显示的字段配置 list_display = ( 'id', 'body', - 'link_to_userinfo', - 'link_to_article', + 'link_to_userinfo', # 自定义方法显示用户链接 + 'link_to_article', # 自定义方法显示文章链接 'is_enable', 'creation_time') + # 可点击进入编辑页的字段 list_display_links = ('id', 'body', 'is_enable') + # 右侧过滤器配置 list_filter = ('is_enable',) + # 编辑页排除的字段(不显示) exclude = ('creation_time', 'last_modify_time') + # 批量操作动作列表 actions = [disable_commentstatus, enable_commentstatus] + # 使用原始ID输入框的外键字段(提升大表性能) raw_id_fields = ('author', 'article') + # 搜索字段配置 search_fields = ('body',) + # 方法级注释:用户信息链接显示 + # 自定义方法,在列表页显示带链接的用户信息 def link_to_userinfo(self, obj): + # 核心代码:获取用户模型的app_label和model_name info = (obj.author._meta.app_label, obj.author._meta.model_name) + # 核心代码:生成用户编辑页面的URL link = reverse('admin:%s_%s_change' % info, args=(obj.author.id,)) + # 核心代码:返回带HTML链接的格式化字符串 return format_html( u'%s' % (link, obj.author.nickname if obj.author.nickname else obj.author.email)) + # 方法级注释:文章链接显示 + # 自定义方法,在列表页显示带链接的文章标题 def link_to_article(self, obj): + # 核心代码:获取文章模型的app_label和model_name info = (obj.article._meta.app_label, obj.article._meta.model_name) + # 核心代码:生成文章编辑页面的URL link = reverse('admin:%s_%s_change' % info, args=(obj.article.id,)) + # 核心代码:返回带HTML链接的格式化字符串 return format_html( u'%s' % (link, obj.article.title)) + # 设置自定义方法在列表页的显示名称(国际化) link_to_userinfo.short_description = _('User') - link_to_article.short_description = _('Article') + link_to_article.short_description = _('Article') \ No newline at end of file diff --git a/src/DjangoBlog/comments/apps.py b/src/DjangoBlog/comments/apps.py index ff01b77..48570ba 100644 --- a/src/DjangoBlog/comments/apps.py +++ b/src/DjangoBlog/comments/apps.py @@ -1,5 +1,11 @@ +# 模块级注释:Django应用配置模块 +# 本模块定义了comments应用的配置信息,用于Django应用注册和初始化设置 from django.apps import AppConfig +# 类级注释:评论应用配置类 +# 继承自AppConfig,用于配置comments应用的基本信息和启动行为 class CommentsConfig(AppConfig): - name = 'comments' + # 应用名称字段:定义应用的完整Python路径 + # 此名称用于Django内部识别和应用引用 + name = 'comments' \ No newline at end of file diff --git a/src/DjangoBlog/comments/forms.py b/src/DjangoBlog/comments/forms.py index e83737d..317dbd8 100644 --- a/src/DjangoBlog/comments/forms.py +++ b/src/DjangoBlog/comments/forms.py @@ -1,13 +1,24 @@ +# 模块级注释:Django表单定义模块 - 评论功能 +# 本模块定义了评论相关的表单类,用于前端评论数据的验证和处理 from django import forms from django.forms import ModelForm +# 导入评论模型,用于构建模型表单 from .models import Comment +# 类级注释:评论表单类 +# 继承自ModelForm,基于Comment模型自动生成表单字段和验证规则 class CommentForm(ModelForm): + # 父级评论ID字段:隐藏输入字段,用于处理评论回复功能 + # 存储被回复评论的ID,用户不可见但表单会处理 parent_comment_id = forms.IntegerField( widget=forms.HiddenInput, required=False) + # 元数据类:配置模型表单的基本行为 class Meta: + # 指定关联的模型:Comment模型 model = Comment - fields = ['body'] + # 定义表单中包含的字段:只包含评论正文字段 + # 其他字段如作者、文章等通过其他方式自动设置 + fields = ['body'] \ No newline at end of file diff --git a/src/DjangoBlog/comments/migrations/0001_initial.py b/src/DjangoBlog/comments/migrations/0001_initial.py index 61d1e53..16556d6 100644 --- a/src/DjangoBlog/comments/migrations/0001_initial.py +++ b/src/DjangoBlog/comments/migrations/0001_initial.py @@ -1,38 +1,66 @@ # Generated by Django 4.1.7 on 2023-03-02 07:14 +# 模块级注释:Django数据库迁移文件 +# 本模块定义了评论功能的数据库迁移操作,包括创建评论表和相关字段 from django.conf import settings from django.db import migrations, models import django.db.models.deletion import django.utils.timezone +# 类级注释:数据库迁移类 +# 继承自migrations.Migration,定义数据库结构变更的完整操作序列 class Migration(migrations.Migration): + # 标记为初始迁移 + # 表示这是comments应用的第一个迁移文件 initial = True + # 依赖关系定义 + # 指定本迁移执行前需要先完成的依赖迁移 dependencies = [ + # 依赖blog应用的初始迁移,确保文章表已创建 ('blog', '0001_initial'), + # 依赖用户模型迁移,确保用户表已存在 migrations.swappable_dependency(settings.AUTH_USER_MODEL), ] + # 迁移操作列表 + # 按顺序执行的数据库操作集合 operations = [ + # 创建模型操作 + # 定义Comment模型的数据库表结构 migrations.CreateModel( name='Comment', fields=[ + # 主键字段:自增BigAutoField,作为评论的唯一标识 ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + # 正文字段:存储评论内容,限制最大长度300字符 ('body', models.TextField(max_length=300, verbose_name='正文')), + # 创建时间字段:记录评论创建时间,默认使用当前时区时间 ('created_time', models.DateTimeField(default=django.utils.timezone.now, verbose_name='创建时间')), + # 修改时间字段:记录评论最后修改时间,默认使用当前时区时间 ('last_mod_time', models.DateTimeField(default=django.utils.timezone.now, verbose_name='修改时间')), + # 启用状态字段:控制评论是否显示,布尔类型默认True ('is_enable', models.BooleanField(default=True, verbose_name='是否显示')), + # 外键字段:关联到文章模型,级联删除确保数据一致性 ('article', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='blog.article', verbose_name='文章')), + # 外键字段:关联到用户模型,记录评论作者 ('author', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL, verbose_name='作者')), + # 自关联外键:支持评论回复功能,允许空值表示顶级评论 ('parent_comment', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='comments.comment', verbose_name='上级评论')), ], + # 模型元选项配置 + # 定义模型在admin中的显示名称和默认排序等行为 options={ + # 单数显示名称:在Django admin中显示的单数名称 'verbose_name': '评论', + # 复数显示名称:在Django admin中显示的复数名称 'verbose_name_plural': '评论', + # 默认排序:按ID倒序排列,最新评论显示在最前面 'ordering': ['-id'], + # 最新记录定义:指定按id字段获取最新记录 'get_latest_by': 'id', }, ), - ] + ] \ No newline at end of file diff --git a/src/DjangoBlog/comments/migrations/0002_alter_comment_is_enable.py b/src/DjangoBlog/comments/migrations/0002_alter_comment_is_enable.py index 17c44db..a0518c8 100644 --- a/src/DjangoBlog/comments/migrations/0002_alter_comment_is_enable.py +++ b/src/DjangoBlog/comments/migrations/0002_alter_comment_is_enable.py @@ -1,18 +1,34 @@ # Generated by Django 4.1.7 on 2023-04-24 13:48 +# 模块级注释:Django数据库迁移文件 - 评论功能字段修改 +# 本模块用于修改评论表中is_enable字段的默认值配置 from django.db import migrations, models +# 类级注释:数据库迁移类 +# 继承自migrations.Migration,定义对现有数据库结构的修改操作 class Migration(migrations.Migration): + # 依赖关系定义 + # 指定本迁移依赖于comments应用的初始迁移文件 dependencies = [ + # 依赖comments应用的0001_initial迁移 + # 确保评论表已创建后再执行本迁移 ('comments', '0001_initial'), ] + # 迁移操作列表 + # 包含对数据库结构的具体修改操作 operations = [ + # 修改字段操作 + # 对Comment模型的is_enable字段进行配置修改 migrations.AlterField( + # 指定要修改的模型名称 model_name='comment', + # 指定要修改的字段名称 name='is_enable', + # 新的字段配置:将默认值从True改为False + # 新创建的评论默认不显示,需要手动启用 field=models.BooleanField(default=False, verbose_name='是否显示'), ), - ] + ] \ No newline at end of file diff --git a/src/DjangoBlog/comments/migrations/0003_alter_comment_options_remove_comment_created_time_and_more.py b/src/DjangoBlog/comments/migrations/0003_alter_comment_options_remove_comment_created_time_and_more.py index a1ca970..60f2668 100644 --- a/src/DjangoBlog/comments/migrations/0003_alter_comment_options_remove_comment_created_time_and_more.py +++ b/src/DjangoBlog/comments/migrations/0003_alter_comment_options_remove_comment_created_time_and_more.py @@ -1,60 +1,89 @@ # Generated by Django 4.2.5 on 2023-09-06 13:13 +# 模块级注释:Django数据库迁移文件 - 评论模型字段重构 +# 本模块对评论模型进行重大重构,包括字段重命名、显示名称国际化等操作 from django.conf import settings from django.db import migrations, models import django.db.models.deletion import django.utils.timezone +# 类级注释:数据库迁移类 +# 继承自migrations.Migration,定义对评论模型的多个结构变更操作 class Migration(migrations.Migration): + # 依赖关系定义 + # 指定本迁移执行前需要完成的依赖迁移文件 dependencies = [ + # 依赖用户模型迁移,确保用户表结构就绪 migrations.swappable_dependency(settings.AUTH_USER_MODEL), + # 依赖博客应用的第5次迁移,确保文章表结构稳定 ('blog', '0005_alter_article_options_alter_category_options_and_more'), + # 依赖评论应用的第2次迁移,确保之前的字段修改已应用 ('comments', '0002_alter_comment_is_enable'), ] + # 迁移操作列表 + # 包含多个对评论模型的结构变更操作,按顺序执行 operations = [ + # 修改模型选项操作 + # 更新Comment模型的元数据配置,主要修改显示名称 migrations.AlterModelOptions( name='comment', options={'get_latest_by': 'id', 'ordering': ['-id'], 'verbose_name': 'comment', 'verbose_name_plural': 'comment'}, ), + # 删除字段操作 + # 移除旧的创建时间字段,为新增字段做准备 migrations.RemoveField( model_name='comment', name='created_time', ), + # 删除字段操作 + # 移除旧的最后修改时间字段,为新增字段做准备 migrations.RemoveField( model_name='comment', name='last_mod_time', ), + # 新增字段操作 + # 添加新的创建时间字段,使用更清晰的字段命名 migrations.AddField( model_name='comment', name='creation_time', field=models.DateTimeField(default=django.utils.timezone.now, verbose_name='creation time'), ), + # 新增字段操作 + # 添加新的最后修改时间字段,使用更清晰的字段命名 migrations.AddField( model_name='comment', name='last_modify_time', field=models.DateTimeField(default=django.utils.timezone.now, verbose_name='last modify time'), ), + # 修改字段操作 + # 更新文章外键字段的显示名称,改为英文 migrations.AlterField( model_name='comment', name='article', field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='blog.article', verbose_name='article'), ), + # 修改字段操作 + # 更新作者外键字段的显示名称,改为英文 migrations.AlterField( model_name='comment', name='author', field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL, verbose_name='author'), ), + # 修改字段操作 + # 更新启用状态字段的显示名称,改为英文 migrations.AlterField( model_name='comment', name='is_enable', field=models.BooleanField(default=False, verbose_name='enable'), ), + # 修改字段操作 + # 更新父级评论外键字段的显示名称,改为英文 migrations.AlterField( model_name='comment', name='parent_comment', field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='comments.comment', verbose_name='parent comment'), ), - ] + ] \ No newline at end of file diff --git a/src/DjangoBlog/comments/models.py b/src/DjangoBlog/comments/models.py index 7c3bbc8..71a0cef 100644 --- a/src/DjangoBlog/comments/models.py +++ b/src/DjangoBlog/comments/models.py @@ -1,39 +1,56 @@ +# 模块级注释:Django数据模型模块 - 评论系统 +# 本模块定义了评论系统的数据模型,包括评论的基本字段、关联关系和业务逻辑 from django.conf import settings from django.db import models from django.utils.timezone import now from django.utils.translation import gettext_lazy as _ +# 导入文章模型,用于建立评论与文章的关联 from blog.models import Article -# Create your models here. - +# 类级注释:评论模型类 +# 继承自models.Model,定义了评论数据的数据库表结构和字段约束 class Comment(models.Model): + # 正文字段:存储评论内容,最大长度300字符,使用中文标签 body = models.TextField('正文', max_length=300) + # 创建时间字段:自动记录评论创建时间,使用国际化标签 creation_time = models.DateTimeField(_('creation time'), default=now) + # 最后修改时间字段:记录评论最后修改时间,使用国际化标签 last_modify_time = models.DateTimeField(_('last modify time'), default=now) + # 作者字段:外键关联到用户模型,级联删除,使用国际化标签 author = models.ForeignKey( settings.AUTH_USER_MODEL, verbose_name=_('author'), on_delete=models.CASCADE) + # 文章字段:外键关联到文章模型,级联删除,使用国际化标签 article = models.ForeignKey( Article, verbose_name=_('article'), on_delete=models.CASCADE) + # 父级评论字段:自关联外键,支持评论回复功能,允许空值 parent_comment = models.ForeignKey( 'self', verbose_name=_('parent comment'), blank=True, null=True, on_delete=models.CASCADE) + # 启用状态字段:控制评论是否显示,默认不显示,使用国际化标签 is_enable = models.BooleanField(_('enable'), default=False, blank=False, null=False) + # 元数据类:配置模型在数据库和admin中的行为 class Meta: + # 默认排序:按ID倒序,最新评论在前 ordering = ['-id'] + # 单数显示名称:使用国际化翻译 verbose_name = _('comment') + # 复数显示名称:与单数相同 verbose_name_plural = verbose_name + # 最新记录定义:按ID字段确定最新记录 get_latest_by = 'id' + # 字符串表示方法:定义对象在Python中的显示格式 def __str__(self): - return self.body + # 返回评论正文作为对象的字符串表示 + return self.body \ No newline at end of file diff --git a/src/DjangoBlog/comments/tests.py b/src/DjangoBlog/comments/tests.py index 2a7f55f..fa4e9c8 100644 --- a/src/DjangoBlog/comments/tests.py +++ b/src/DjangoBlog/comments/tests.py @@ -1,68 +1,92 @@ +# 模块级注释:Django测试模块 - 评论系统功能测试 +# 本模块包含评论系统的完整测试用例,验证评论发布、回复、显示等核心功能 from django.test import Client, RequestFactory, TransactionTestCase from django.urls import reverse +# 导入相关模型,用于测试数据准备 from accounts.models import BlogUser from blog.models import Category, Article from comments.models import Comment +# 导入评论标签模块,测试模板标签功能 from comments.templatetags.comments_tags import * from djangoblog.utils import get_max_articleid_commentid -# Create your tests here. - +# 类级注释:评论系统测试类 +# 继承自TransactionTestCase,支持数据库事务的测试用例 class CommentsTest(TransactionTestCase): + + # 测试初始化方法:在每个测试方法执行前运行 def setUp(self): + # 创建测试客户端,用于模拟HTTP请求 self.client = Client() + # 创建请求工厂,用于构建请求对象 self.factory = RequestFactory() + + # 配置博客设置:启用评论审核功能 from blog.models import BlogSettings value = BlogSettings() - value.comment_need_review = True + value.comment_need_review = True # 设置评论需要审核 value.save() + # 创建超级用户,用于测试认证相关的评论功能 self.user = BlogUser.objects.create_superuser( email="liangliangyy1@gmail.com", username="liangliangyy1", password="liangliangyy1") + # 辅助方法:更新文章评论状态为启用 def update_article_comment_status(self, article): + # 获取文章的所有评论 comments = article.comment_set.all() + # 遍历所有评论,将其状态设置为启用 for comment in comments: comment.is_enable = True comment.save() + # 测试方法:验证评论功能 def test_validate_comment(self): + # 使用测试用户登录系统 self.client.login(username='liangliangyy1', password='liangliangyy1') + # 创建测试分类 category = Category() category.name = "categoryccc" category.save() + # 创建测试文章 article = Article() article.title = "nicetitleccc" article.body = "nicecontentccc" article.author = self.user article.category = category - article.type = 'a' - article.status = 'p' + article.type = 'a' # 文章类型 + article.status = 'p' # 发布状态 article.save() + # 生成评论提交URL comment_url = reverse( 'comments:postcomment', kwargs={ 'article_id': article.id}) + # 测试提交第一条评论 response = self.client.post(comment_url, { 'body': '123ffffffffff' }) + # 验证响应状态码为302重定向 self.assertEqual(response.status_code, 302) + # 重新获取文章对象,验证评论数量(由于审核机制,初始应为0) article = Article.objects.get(pk=article.pk) self.assertEqual(len(article.comment_list()), 0) - self.update_article_comment_status(article) + # 更新评论状态为启用后,验证评论数量变为1 + self.update_article_comment_status(article) self.assertEqual(len(article.comment_list()), 1) + # 测试提交第二条评论 response = self.client.post(comment_url, { 'body': '123ffffffffff', @@ -70,11 +94,15 @@ class CommentsTest(TransactionTestCase): self.assertEqual(response.status_code, 302) + # 验证第二条评论提交成功 article = Article.objects.get(pk=article.pk) self.update_article_comment_status(article) self.assertEqual(len(article.comment_list()), 2) + + # 获取第一条评论的ID,用于测试回复功能 parent_comment_id = article.comment_list()[0].id + # 测试提交带Markdown格式的回复评论 response = self.client.post(comment_url, { 'body': ''' @@ -93,17 +121,25 @@ class CommentsTest(TransactionTestCase): 'parent_comment_id': parent_comment_id }) + # 验证回复评论提交成功 self.assertEqual(response.status_code, 302) self.update_article_comment_status(article) article = Article.objects.get(pk=article.pk) self.assertEqual(len(article.comment_list()), 3) + + # 测试评论树解析功能 comment = Comment.objects.get(id=parent_comment_id) tree = parse_commenttree(article.comment_list(), comment) self.assertEqual(len(tree), 1) + + # 测试评论项显示功能 data = show_comment_item(comment, True) self.assertIsNotNone(data) + + # 测试获取最大文章ID和评论ID功能 s = get_max_articleid_commentid() self.assertIsNotNone(s) + # 测试评论邮件发送功能 from comments.utils import send_comment_email - send_comment_email(comment) + send_comment_email(comment) \ No newline at end of file diff --git a/src/DjangoBlog/comments/urls.py b/src/DjangoBlog/comments/urls.py index 7df3fab..07648f8 100644 --- a/src/DjangoBlog/comments/urls.py +++ b/src/DjangoBlog/comments/urls.py @@ -1,11 +1,23 @@ +# 模块级注释:Django URL配置模块 - 评论系统路由 +# 本模块定义了评论系统的URL路由配置,将URL路径映射到对应的视图函数 from django.urls import path +# 导入当前应用的视图模块,用于处理URL请求 from . import views +# 应用命名空间定义:设置评论应用的命名空间为"comments" +# 用于Django的URL反向解析,避免不同应用间的URL名称冲突 app_name = "comments" + +# URL模式列表:定义评论系统的所有URL路由规则 urlpatterns = [ + # 评论提交路由:处理文章评论的提交请求 path( + # URL路径模式:匹配/article/{文章ID}/postcomment格式的URL + # 其中为路径参数,捕获整数类型的文章ID 'article//postcomment', + # 对应的视图类:使用CommentPostView类视图处理该路径的请求 views.CommentPostView.as_view(), + # URL名称:命名为'postcomment',用于在模板和代码中进行URL反向解析 name='postcomment'), -] +] \ No newline at end of file diff --git a/src/DjangoBlog/comments/utils.py b/src/DjangoBlog/comments/utils.py index f01dba7..37cf9d2 100644 --- a/src/DjangoBlog/comments/utils.py +++ b/src/DjangoBlog/comments/utils.py @@ -1,17 +1,29 @@ +# 模块级注释:评论邮件通知模块 +# 本模块提供评论相关的邮件通知功能,包括新评论确认邮件和评论回复通知邮件 import logging +# 导入Django国际化翻译模块 from django.utils.translation import gettext_lazy as _ +# 导入工具函数:获取当前站点信息和发送邮件 from djangoblog.utils import get_current_site from djangoblog.utils import send_email +# 创建日志记录器实例,用于记录邮件发送过程中的错误信息 logger = logging.getLogger(__name__) +# 函数级注释:发送评论邮件通知 +# 主要功能:向评论作者发送评论确认邮件,如果是对回复的评论,则同时向被回复者发送通知邮件 def send_comment_email(comment): + # 获取当前站点域名,用于构建完整的文章链接 site = get_current_site().domain + # 邮件主题:使用国际化翻译 subject = _('Thanks for your comment') + # 构建完整的文章URL地址 article_url = f"https://{site}{comment.article.get_absolute_url()}" + + # 构建评论确认邮件的HTML内容 html_content = _("""

Thank you very much for your comments on this site

You can visit %(article_title)s to review your comments, @@ -19,10 +31,17 @@ def send_comment_email(comment):
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) + + # 异常处理块:处理评论回复通知邮件的发送 try: + # 检查是否存在父级评论(即当前评论是否为回复评论) if comment.parent_comment: + # 构建回复通知邮件的HTML内容 html_content = _("""Your comment on %(article_title)s
has received a reply.
%(comment_body)s
@@ -32,7 +51,11 @@ def send_comment_email(comment): %(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) + # 捕获邮件发送过程中可能出现的任何异常 except Exception as e: - logger.error(e) + # 记录异常信息到日志,但不中断程序执行 + logger.error(e) \ No newline at end of file diff --git a/src/DjangoBlog/comments/views.py b/src/DjangoBlog/comments/views.py index ad9b2b9..87f5aad 100644 --- a/src/DjangoBlog/comments/views.py +++ b/src/DjangoBlog/comments/views.py @@ -1,3 +1,5 @@ +# 模块级注释:Django视图模块 - 评论系统 +# 本模块定义了评论提交的视图处理逻辑,包括评论验证、保存和重定向等功能 # Create your views here. from django.core.exceptions import ValidationError from django.http import HttpResponseRedirect @@ -6,58 +8,94 @@ from django.utils.decorators import method_decorator from django.views.decorators.csrf import csrf_protect 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 +# 类级注释:评论提交视图类 +# 继承自FormView,处理评论表单的提交和验证 class CommentPostView(FormView): + # 指定使用的表单类 form_class = CommentForm + # 指定模板名称 template_name = 'blog/article_detail.html' + # 方法装饰器:添加CSRF保护 @method_decorator(csrf_protect) def dispatch(self, *args, **kwargs): + # 调用父类的dispatch方法,确保CSRF保护生效 return super(CommentPostView, self).dispatch(*args, **kwargs) + # GET请求处理方法 def get(self, request, *args, **kwargs): + # 从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): + # 获取文章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获取用户对象 author = BlogUser.objects.get(pk=user.pk) + # 从URL参数获取文章ID article_id = self.kwargs['article_id'] + # 获取文章对象 article = get_object_or_404(Article, pk=article_id) + # 检查文章是否允许评论 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']: + # 获取父级评论对象 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)) + (article.get_absolute_url(), comment.pk)) \ No newline at end of file