You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Django中UpdateView无法保存Topic的first_comment字段值求助

问题:Topic的first_comment无法通过UpdateView修改

我开发了一个「论坛-子论坛-主题-评论」结构的Django论坛应用,主题隶属于对应子论坛,评论隶属于对应主题且仅在主题内展示,视图主要基于类视图实现。创建新Topic时,除subject字段外,还需定义初始评论first_comment(该字段属于Topic模型,功能与Comment模型的content字段类似)。

目前遇到的问题:Comment对应的UpdateView(UpdateComment)可正常编辑保存评论,但Topic的first_comment对应的UpdateView(UpdateFirstComment)无报错,页面正常渲染、返回200状态码,但字段内容始终未修改。


相关代码

models.py(仅展示Topic和Comment模型)

class Topic(models.Model):
    subject = models.CharField(verbose_name='Заголовок', max_length=255, unique=True)
    first_comment = models.TextField(verbose_name='Сообщение', max_length=2000, default='')
    slug = models.SlugField(default='', unique=True, max_length=25, editable=False)
    subforum = models.ForeignKey('Subforum', verbose_name='Раздел',
                                 on_delete=models.CASCADE, related_name='subforum')
    creator = models.ForeignKey(User, verbose_name='Создатель темы',
                                on_delete=models.SET('deleted'), related_name='creator')
    created = models.DateTimeField(auto_now_add=True)
    closed = models.BooleanField(default=False)
    objects = models.Manager()

    class Meta:
        ordering = ['id']
        verbose_name = 'Обсуждения'
        verbose_name_plural = 'Обсуждения'

    def __str__(self):
        return self.subject

    def save(self, *args, **kwargs):
        self.slug = f'topic-{slugify(self.subject)}'
        return super(Topic, self).save(*args, **kwargs)

    def get_absolute_url(self):
        return reverse('forum:topic', kwargs={'topic_slug': self.slug, 'subforum_slug': self.subforum.slug})


class Comment(models.Model):
    topic = models.ForeignKey('Topic', verbose_name='Тема', on_delete=models.CASCADE, 
                              related_name='comments')
    author = models.ForeignKey(User, verbose_name='Комментатор',
                               on_delete=models.SET('deleted'), related_name='author')
    content = models.TextField(verbose_name='Текст', max_length=2000)
    created = models.DateTimeField(verbose_name='Дата публикации', auto_now_add=True)
    updated = models.DateTimeField(verbose_name='Дата изменения', auto_now=True)
    objects = models.Manager()

    class Meta:
        ordering = ['created']
        verbose_name = 'Комментарии'
        verbose_name_plural = 'Комментарии'

    def __str__(self):
        return f'Post of {self.topic.subject} is posted by {self.author.username}.'

views.py(展示关键视图)

class ShowTopic(DetailView):
    model = Topic
    template_name = "forum/topic.html"
    slug_url_kwarg = 'topic_slug'
    context_object_name = 'topic'
    paginate_by = 5

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        topic = self.get_object()

        comments_list = Comment.objects.filter(topic=topic).order_by('created')
        paginator = Paginator(comments_list, self.paginate_by)
        page_number = self.request.GET.get('page', 1)
        page_obj = paginator.get_page(page_number)

        context.update({
            'menu': menu,
            'comments': page_obj,
            'page_obj': page_obj,
            'is_paginated': page_obj.has_other_pages(),
            'paginator': paginator,
            'comm_num': comments_list.count(),
        })

        return context


class AddTopic(LoginRequiredMixin, DataMixin, CreateView):
    form_class = AddTopicForm
    template_name = 'forum/addtopic.html'
    page_title = 'Create a new topic'

    def get_success_url(self):
        return reverse('forum:topic', kwargs={
            'subforum_slug': self.kwargs['subforum_slug'], 'topic_slug': self.object.slug})

    def form_valid(self, form):
        subforum = Subforum.objects.get(slug=self.kwargs['subforum_slug'])
        form.instance.creator = self.request.user
        form.instance.subforum = subforum
        return super(AddTopic, self).form_valid(form)


class UpdateFirstComment(LoginRequiredMixin, DataMixin, UpdateView):
    model = Topic
    form_class = AddTopicForm
    template_name = 'forum/editcomment.html'
    page_title = 'Edit comment'

    def get_success_url(self):
        return reverse('forum:topic', kwargs={
            'subforum_slug': self.kwargs['subforum_slug'],
            'topic_slug': self.kwargs['topic_slug']
        })

    def get_object(self, queryset=None):
        return Topic.objects.get(slug=self.kwargs['topic_slug'], subforum__slug=self.kwargs['subforum_slug'])

    def form_valid(self, form):
        topic = self.get_object()
        first_comment = topic.first_comment
        form.instance.creator = self.request.user
        form.instance.topic = topic
        form.instance.first_comment = first_comment
        return super(UpdateFirstComment, self).form_valid(form)


class UpdateComment(LoginRequiredMixin, DataMixin, UpdateView):
    model = Comment
    form_class = AddCommentForm
    context_object_name = 'comment'
    template_name = 'forum/editcomment.html'
    page_title = 'Edit comment'

    def get_success_url(self):
        return reverse('forum:topic', kwargs={
            'subforum_slug': self.kwargs['subforum_slug'],
            'topic_slug': self.kwargs['topic_slug']
        })

urls.py

app_name = 'forum'

urlpatterns = [
    path('', SubForumListView.as_view(), name='forum'),
    path('<slug:subforum_slug>/', TopicListView.as_view(), name='subforum'),
    path('<slug:subforum_slug>/add_topic/', AddTopic.as_view(), name="add_topic"),
    path('<slug:subforum_slug>/topics/<slug:topic_slug>/', ShowTopic.as_view(), name='topic'),
    path('<slug:subforum_slug>/topics/<slug:topic_slug>/edit_topic/', UpdateFirstComment.as_view(), name='edit_topic'),
    path('<slug:subforum_slug>/topics/<slug:topic_slug>/add_comment/', AddComment.as_view(), name="add_comment"),
    path('<slug:subforum_slug>/topics/<slug:topic_slug>/<int:pk>/edit_comment/', UpdateComment.as_view(), name="edit_comment"),
    path('<slug:subforum_slug>/topics/<slug:topic_slug>/<int:pk>/delete_comment/', DeleteComment.as_view(), name="delete_comment"),
]

问题原因

UpdateFirstComment的form_valid方法存在核心错误:

  1. 手动将form.instance.first_comment赋值为原topic的first_comment,直接覆盖了表单提交的新内容,导致修改无法保存到数据库。
  2. form.instance.topic = topic是多余操作,Topic模型中不存在topic字段,属于无效赋值。
  3. 不必要地设置form.instance.creator = self.request.user,会错误覆盖主题原创建者,不符合编辑初始评论的逻辑。

解决方案

1. 修复UpdateFirstComment的form_valid方法

移除错误的字段赋值逻辑,直接调用父类方法即可:

class UpdateFirstComment(LoginRequiredMixin, DataMixin, UpdateView):
    model = Topic
    form_class = AddTopicForm
    template_name = 'forum/editcomment.html'
    page_title = 'Edit comment'

    def get_success_url(self):
        return reverse('forum:topic', kwargs={
            'subforum_slug': self.kwargs['subforum_slug'],
            'topic_slug': self.kwargs['topic_slug']
        })

    def get_object(self, queryset=None):
        return Topic.objects.get(slug=self.kwargs['topic_slug'], subforum__slug=self.kwargs['subforum_slug'])

    # 可选:添加权限验证,仅允许主题创建者编辑初始评论
    def dispatch(self, request, *args, **kwargs):
        self.object = self.get_object()
        if self.object.creator != request.user:
            raise PermissionDenied
        return super().dispatch(request, *args, **kwargs)

2. 确认表单包含first_comment字段

确保AddTopicForm包含first_comment字段,否则表单无法提交修改内容:

from django import forms
from .models import Topic

class AddTopicForm(forms.ModelForm):
    class Meta:
        model = Topic
        fields = ['subject', 'first_comment']  # 必须包含first_comment字段

内容的提问来源于stack exchange,提问作者TiimeIrre

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.16 12:47:02