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

Django评论表单报错:NOT NULL约束失败:courses_comment.lesson_id

评论表单提交时出现IntegrityError问题解决

问题背景

创建评论表单时提交报错,提示NOT NULL constraint failed: courses_comment.lesson_id,不确定views.py的post方法中lesson的使用是否正确。


相关代码

models.py

class Comment(models.Model):
    text = models.TextField('Comment text')
    user = models.ForeignKey(User, on_delete=models.CASCADE)
    lesson = models.ForeignKey(Lesson, on_delete=models.CASCADE)

views.py

class LessonDetailPage(DetailView):
    ....
    def post(self, request, *args, **kwargs):

        lesson = Lesson.objects.filter(slug=self.kwargs['lesson_slug']).first()
    
        post = request.POST.copy()
        post['user'] = request.user
        post['lesson'] = lesson
        request.POST = post
    
        form = CommentForms(request.POST)
        if form.is_valid():
           form.save()

urls.py 片段

path('course/<slug>/<lesson_slug>', views.LessonDetailPage.as_view(), name='lesson-detail'),

forms.py

class CommentForms(forms.ModelForm):

    text = forms.CharField(
        label='Text',
        required=True,
        widget=forms.Textarea(attrs={'class': 'form-control'})
    )
    user = forms.CharField(
        widget=forms.HiddenInput()
    )
    lesson = forms.CharField(
        widget=forms.HiddenInput()
    )

    class Meta:
        model = Comment
        fields = ['text']

comment.html

<div class="form-section">
    <form method="post">
    {% csrf_token %}
    {{ form }}
    <button type="submit">ОК</button>
</div>

报错信息

IntegrityError at /course/linux/set-on-linux
NOT NULL constraint failed: courses_comment.lesson_id
Request Method: POST
Request URL:    http://127.0.0.1:8000/course/linux/set-on-linux
Django Version: 4.0.6
Exception Type: IntegrityError
Exception Value:    
NOT NULL constraint failed: courses_comment.lesson_id

问题原因及解决方法

核心问题

  1. 表单中定义了user和lesson的CharField,但Meta类仅包含text字段,这两个字段不会被表单处理;直接将模型对象赋值给POST数据,表单无法识别。
  2. 即使POST中传入对象,CharField只会将其转为字符串(如<Lesson object>),无法正确关联外键。

修正步骤

1. 简化表单,移除不必要字段

无需在表单中定义user和lesson,这两个值无需用户输入,直接在视图中处理:

class CommentForms(forms.ModelForm):
    text = forms.CharField(
        label='Text',
        required=True,
        widget=forms.Textarea(attrs={'class': 'form-control'})
    )

    class Meta:
        model = Comment
        fields = ['text']

2. 修改视图逻辑,直接为表单实例赋值外键

不要手动修改request.POST,表单验证通过后,先暂不保存,赋值外键后再提交:

class LessonDetailPage(DetailView):
    ....
    def post(self, request, *args, **kwargs):
        # 利用DetailView特性直接获取当前lesson,无需重复查询
        lesson = self.get_object()
        form = CommentForms(request.POST)
        if form.is_valid():
            comment = form.save(commit=False)  # 暂不保存到数据库
            comment.user = request.user
            comment.lesson = lesson
            comment.save()  # 保存完整数据
            # 可添加跳转或提示,比如return redirect到当前页面
        # 表单无效时返回原页面
        return self.get(request, *args, **kwargs)

3. 优化说明

DetailView会自动根据URL参数获取对应对象,直接使用self.get_object()即可拿到当前Lesson实例,比手动查询更简洁可靠。

额外提示

  • 不要手动修改request.POST,不符合Django最佳实践,易引发问题。
  • 外键字段无需在前端展示,直接在视图中关联当前用户和课程,可避免前端篡改数据。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.25 18:58:35