如何在Django CBV的文章详情页中添加评论提交表单?
解决Django文章详情页同时展示详情与评论提交表单的问题
核心思路
将评论表单的创建与提交逻辑整合到ArtDetailView中,让同一个视图同时处理GET请求(展示文章详情+空表单)和POST请求(处理评论提交),避免分开视图导致的上下文数据缺失问题。
步骤1:创建评论表单类
在forms.py(无则新建)中定义评论表单:
from django import forms from .models import Comment class CommentForm(forms.ModelForm): class Meta: model = Comment fields = ['text']
步骤2:修改ArtDetailView视图
更新视图代码,整合表单处理逻辑:
from django.shortcuts import redirect from django.views.generic import DetailView from django.contrib.auth.decorators import login_required from django.utils.decorators import method_decorator from .models import Art, Comment from .forms import CommentForm @method_decorator(login_required(login_url='login'), name='dispatch') class ArtDetailView(DetailView): model = Art template_name = 'art_detail.html' def get_context_data(self, **kwargs): # 获取默认上下文(包含当前文章对象) context = super().get_context_data(**kwargs) # 添加上下文数据:评论表单、当前文章的所有评论(按时间倒序) context['comment_form'] = CommentForm() context['comments'] = self.object.comment_set.all().order_by('-date') return context def post(self, request, *args, **kwargs): self.object = self.get_object() # 获取当前文章对象 form = CommentForm(request.POST) if form.is_valid(): # 保存评论但不提交到数据库,先补充关联字段 comment = form.save(commit=False) comment.art = self.object comment.writer = request.user comment.save() # 提交成功后重定向回当前文章详情页 return redirect('art_detail', pk=self.object.pk) # 表单验证失败时,重新渲染页面并携带错误表单 context = self.get_context_data(**kwargs) context['comment_form'] = form return self.render_to_response(context)
- 用
method_decorator给类视图添加登录验证,确保只有登录用户能提交评论 get_context_data方法负责传递文章详情、空表单、评论列表到模板post方法处理评论提交逻辑,验证通过则保存评论,失败则返回带错误的表单
步骤3:配置URL
只保留ArtDetailView的URL配置,删除原CommentView相关URL:
from django.urls import path from .views import ArtDetailView urlpatterns = [ # 其他URL... path('art/<int:pk>/', ArtDetailView.as_view(), name='art_detail'), ]
步骤4:更新模板art_detail.html
在模板中添加评论表单和评论列表的渲染代码:
<!-- 展示文章详情 --> <h1>{{ object.title }}</h1> <div>{{ object.content }}</div> <!-- 评论提交表单(仅登录用户可见) --> {% if user.is_authenticated %} <h3>发表评论</h3> <form method="post"> {% csrf_token %} {{ comment_form.as_p }} <button type="submit">提交评论</button> </form> {% else %} <p>请<a href="{% url 'login' %}">登录</a>后发表评论</p> {% endif %} <!-- 展示评论列表 --> <h3>评论区</h3> {% for comment in comments %} <div class="comment-item"> <p><strong>{{ comment.writer.username }}</strong> · {{ comment.date|date:"Y-m-d H:i" }}</p> <p>{{ comment.text }}</p> </div> {% empty %} <p>暂无评论,快来写下第一条评论吧!</p> {% endfor %}
关键说明
- 避免了两个视图重复渲染同一模板的问题,确保上下文同时包含文章数据、表单和评论列表
- 用
self.get_object()获取当前文章,比直接通过ID查询更安全,能自动处理对象不存在的情况 - 表单提交后重定向回原页面,符合PRG(Post/Redirect/Get)模式,避免重复提交
内容的提问来源于stack exchange,提问作者Nicolas_Darksoul
相关产品推荐
相关产品推荐

