@hoge_piyo

Are you sure you want to delete the question?

Leaving a resolved question undeleted may help others!

IntegrityError: NOT NULL constraint failed: comment_comment.target_idの解消

解決したいこと

djangoで記事に対するコメント機能を実装しようとした際に
IntegrityError: NOT NULL constraint failed: comment_comment.target_id
が発生してしまったので解消したいです。

発生している問題・エラー

Internal Server Error: /comment/2/
Traceback (most recent call last):
  File "C:\Users\user\Documents\Django-original\web_app\Lib\site-packages\django\db\backends\utils.py", line 85, in _execute
    return self.cursor.execute(sql, params)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\user\Documents\Django-original\web_app\Lib\site-packages\django\db\backends\sqlite3\base.py", line 416, in execute
    return Database.Cursor.execute(self, query, params)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
sqlite3.IntegrityError: NOT NULL constraint failed: comment_comment.target_id

The above exception was the direct cause of the following exception:       

Traceback (most recent call last):
  File "C:\Users\user\Documents\Django-original\web_app\Lib\site-packages\django\core\handlers\exception.py", line 47, in inner
    response = get_response(request)
               ^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\user\Documents\Django-original\web_app\Lib\site-packages\django\core\handlers\base.py", line 181, in _get_response
    response = wrapped_callback(request, *callback_args, **callback_kwargs)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\user\Documents\Django-original\web_app\Lib\site-packages\django\views\generic\base.py", line 69, in view
    return self.dispatch(request, *args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\user\Documents\Django-original\web_app\Lib\site-packages\django\views\generic\base.py", line 101, in dispatch
    return handler(request, *args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\user\Documents\Django-original\web_app\Lib\site-packages\django\views\generic\edit.py", line 174, in post
    return super().post(request, *args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\user\Documents\Django-original\web_app\Lib\site-packages\django\views\generic\edit.py", line 144, in post
    return self.form_valid(form)
           ^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\user\Documents\Django-original\photoproject\comment\views.py", line 20, in form_valid
    commentdata.save()
  File "C:\Users\user\Documents\Django-original\web_app\Lib\site-packages\django\db\models\base.py", line 743, in save
    self.save_base(using=using, force_insert=force_insert,
  File "C:\Users\user\Documents\Django-original\web_app\Lib\site-packages\django\db\models\base.py", line 780, in save_base
    updated = self._save_table(
              ^^^^^^^^^^^^^^^^^
  File "C:\Users\user\Documents\Django-original\web_app\Lib\site-packages\django\db\models\base.py", line 885, in _save_table
    results = self._do_insert(cls._base_manager, using, fields, returning_fields, raw)
              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\user\Documents\Django-original\web_app\Lib\site-packages\django\db\models\base.py", line 923, in _do_insert
    return manager._insert(
           ^^^^^^^^^^^^^^^^
  File "C:\Users\user\Documents\Django-original\web_app\Lib\site-packages\django\db\models\manager.py", line 85, in manager_method
    return getattr(self.get_queryset(), name)(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\user\Documents\Django-original\web_app\Lib\site-packages\django\db\models\query.py", line 1301, in _insert
    return query.get_compiler(using=using).execute_sql(returning_fields)   
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^   
  File "C:\Users\user\Documents\Django-original\web_app\Lib\site-packages\django\db\models\sql\compiler.py", line 1441, in execute_sql
    cursor.execute(sql, params)
  File "C:\Users\user\Documents\Django-original\web_app\Lib\site-packages\django\db\backends\utils.py", line 99, in execute
    return super().execute(sql, params)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\user\Documents\Django-original\web_app\Lib\site-packages\django\db\backends\utils.py", line 67, in execute
    return self._execute_with_wrappers(sql, params, many=False, executor=self._execute)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\user\Documents\Django-original\web_app\Lib\site-packages\django\db\backends\utils.py", line 76, in _execute_with_wrappers       
    return executor(sql, params, many, context)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\user\Documents\Django-original\web_app\Lib\site-packages\django\db\backends\utils.py", line 80, in _execute
    with self.db.wrap_database_errors:
  File "C:\Users\user\Documents\Django-original\web_app\Lib\site-packages\django\db\utils.py", line 90, in __exit__
    raise dj_exc_value.with_traceback(traceback) from exc_value
  File "C:\Users\user\Documents\Django-original\web_app\Lib\site-packages\django\db\backends\utils.py", line 85, in _execute
    return self.cursor.execute(sql, params)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\user\Documents\Django-original\web_app\Lib\site-packages\django\db\backends\sqlite3\base.py", line 416, in execute
    return Database.Cursor.execute(self, query, params)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
django.db.utils.IntegrityError: NOT NULL constraint failed: comment_comment.target_id

該当するソースコード

comment/models.py
from django.db import models
from accounts.models import CustomUser
from django.urls import reverse
import datetime
from photo.models import Post

class Comment(models.Model):
    name=models.ForeignKey(
        CustomUser,
        on_delete=models.CASCADE,
    )
    
    target=models.ForeignKey(
        Post,
        on_delete=models.CASCADE,
    )

    content=models.TextField('コメント')

    created_at=models.DateTimeField(auto_now_add=True)

    def __str__(self):
        return self.content[:10]
    
    class Meta:
        verbose_name_plural='コメント'
comment/forms.py
from django import forms
from .models import Comment

class CommentForm(forms.ModelForm):
    class Meta:
        model = Comment
        fields = ['name', 'content']
comment/views.py
from typing import Any
from django.views.generic import CreateView

from .forms import CommentForm
from .models import Post

class CommentCreateView(CreateView):
    form_class = CommentForm
    template_name = 'comment_form.html'

    def form_valid(self, form):
        commentdata = form.save(commit=False)
        commentdata.user = self.request.user
        commentdata.save()
        return super().form_valid(form)
comment/urls.py
from django.urls import path
from . import views

app_name = 'comment'

urlpatterns = [
    path('comment/<int:pk>/', views.CommentCreateView.as_view(), name='comment'),
]
photo/models.py
from django.db import models

from accounts.models import CustomUser
from django.urls import reverse
import datetime

class Category(models.Model):
    title = models.CharField(
        verbose_name='カテゴリ',
        max_length=20)
    
    def __str__(self):
        return self.title
    
    class Meta:
        verbose_name_plural = 'カテゴリ'
    
class Post(models.Model):
    user = models.ForeignKey(
        CustomUser,
        verbose_name='ユーザ',
        on_delete=models.CASCADE,   
    )

    category = models.ForeignKey(
        Category,
        verbose_name='カテゴリ',
        on_delete=models.PROTECT,
    )
    
    title = models.CharField(
        verbose_name='タイトル',
        max_length=50
    )

    content = models.TextField(
        verbose_name='コメント',
        max_length=1000
    )

    image1 = models.ImageField(
        verbose_name='イメージ1',
        # upload_to:保存先のフォルダ名
        upload_to='photos',
    )

    image2 = models.ImageField(
        verbose_name='イメージ2',
        upload_to='photos',
        blank=True,
        null=True,
    )

    posted_at = models.DateField(
        verbose_name='投稿日時',
        auto_now_add=True,
    )

    def __str__(self):
        return self.title[:10]
    
    def get_absolute_url(self):
        return reverse('photo:post_detail', kwargs={'pk': self.pk})
    
    class Meta:
        verbose_name_plural='投稿'
photo/forms.py
from django import forms
from .models import Post

# ModelForm:モデルに対する入力フォーム
class PhotoPostForm(forms.ModelForm):
    class Meta:
        model = Post
        fields = ['category', 'title', 'content', 'image1', 'image2']

自分で試したこと

target=models.ForeignKey(
    pk=Post.pk,
    on_delete=models.CASCADE,
)

のようにpostのpkを指定しようとしてみたが、別のエラーが出てしまいました。
forms.pyに複数のフォームクラスを定義したのですが、うまくいかなかったのでコメント作成のアプリを作ってコメント用の入力フォームを定義しました。
色々調べてみましたが、そもそも自分のコードのどこが正しく、どこが間違っているかがわからなかったため、自己解決することができませんでした。

0 likes

2Answer

エラーメッセージだけ見ての想像ですのでハズレかもしれませんが・・・

IntegrityError: NOT NULL constraint failed

データベースのあるフィールドに NULL を insert しようとしたが、そのフィールドが NULL 不可なのでエラーになったと言ってます。心当たりはないですか?

「コメント」というのはユーザーがブラウザから送信してくるものだと思いますが、送信されてこないとか、プログラムのミスなど何らかの理由で失われたとか。

デフォルトを設定したはずだが、実際のデータベースでは、それが落ちてしまっているとか。

0Like

Comments

  1. @hoge_piyo

    Questioner

    回答ありがとうございます。
    null=Trulを記述してないのでエラーが起きているものと思われます。
    しかし、記事に対するコメントなので記事のpkが取得できないと、どの記事に対するコメントなのか判別できないのでnull=Trueにできません。
    target_id=Nullの原因はわかりません。

  2. 記事に対するコメントなので記事のpkが取得できないと、どの記事に対するコメントなのか判別できないのでnull=Trueにできません。

    上記の文を読んでの想像ですが、

    (1) SQLite には、記事本文を格納するテーブル(以下「本文テーブル」と書きます)と、コメントを格納する comment_comment テーブルがある

    (2) 記事本文を読んだユーザーが随時コメントを付けられる。その際、ユーザーから送信されてきたコメントは comment_comment テーブルに保存する

    (3) comment_comment テーブルには「どの記事に対するコメントなのか判別」するための target_id というフィールドが含まれている (1 対多の FK 制約も張られている?)。target_id フィールドは NULL 不可に設定されている

    (4) comment_comment テーブルの target_id フィールドには、「本文テーブル」の当該記事のレコードの id 値を設定する

    (5) コメントを comment_comment テーブルに保存 (insert) する際、「本文テーブル」の当該記事のレコードの id 値が取得できず(もしくは取得はできるが値を target_id に渡すことができず)、insert 操作を行う際に target_id は NULL となってしまう。

    (6) 結果、IntegrityError: NOT NULL constraint failed: comment_comment.target_id というエラーで失敗する。

    ・・・ということではなかろうかと思いますが、違いますか?

    target_id というのは質問に書かれたコードのどこにも見当たりませんし、どうやって取得してどのように insert 文に渡すのか質問のコードからは自分は読めません。

    ブラウザの開発者ツールは使えるのですよね? IDE のデバッガは使えるのですよね? それらを使って調べれば原因はわかると思いますので、ぜひ自分でチャレンジしてみてください。

  3. @hoge_piyo

    Questioner

    ありがとうございます。(1)~(6)であっていると思います。
    dbのテーブルを見たところ、targetがForeignKeyであるため自動でtarget_idが設定されているようです。
    色々調べて頑張ってみます。

sqlite3.IntegrityError: NOT NULL constraint failed: comment_comment.target_id

sqlite3のエラーはtarget_idのnull制約違反となっていますが、comment/models.pyには、target_idが定義されていません。(targetが それでしょうか)

DBスキーマとモデルの定義で名称不一致により、target_idが未設定になっているのでは?
もしくは、外部キーのような定義に見えるので、そちらがnullとか。

0Like

Comments

  1. @hoge_piyo

    Questioner

    回答ありがとうございます。
    comment/models.pyのtargetをtarget_idに変更する必要があるということでしょうか。
    また、どのファイルを見ればエラーの原因が特定できるのでしょうか。

  2. comment/models.pyのtargetをtarget_idに変更する必要があるということでしょうか。

    そんな単純では無いようです。
    下記のサイトに、ForeignKeyを指定した項目がIntegrityError: NOT NULL constraint failedになる場合の対応方法が解説されています。

    今回だと、comment/forms.pycomment/views.pyに追加の処理が必要みたいです。

  3. @hoge_piyo

    Questioner

    情報ありがとうございます。
    いただいたサイトを参考にさせていただきます。

Your answer might help someone💌