'What does "IntegrityError. NOT NULL constraint failed: blog_comment.post_id " stands for?
I've added a Comment model to my application, but when the form is submitted, this error pops:
NOT NULL constraint failed: blog_comment.post_id
Here's models.py:
class Post(models.Model):
title = models.CharField(max_length=100, null=True, blank=True)
caption = models.CharField(max_length=100, null=True, blank=True)
image = models.ImageField(upload_to='post_pics/', null=True, blank=True)
date_posted = models.DateTimeField(default=timezone.now)
author = models.ForeignKey(User, on_delete=models.CASCADE)
def __str__(self):
return self.title
def get_absolute_url(self):
return reverse('post-detail', kwargs={'pk': self.pk})
class Comment(models.Model):
post = models.ForeignKey(Post, on_delete=models.CASCADE, related_name='comments')
text = models.TextField(null=True)
date_posted = models.DateTimeField(default=timezone.now)
def __str__(self):
return self.text
def get_absolute_url(self):
return reverse('post-detail', kwargs={'pk': self.pk})
This is the part for creating a comment in views.py:
class AddCommentView(LoginRequiredMixin, CreateView):
model = Comment
fields = ['text']
def form_valid(self, form):
form.instance.author = self.request.user
return super().form_valid(form)
My forms.py:
class CommentForm(forms.ModelForm):
class Meta:
model = Comment
fields = ['text']
The html form:
<div class="content-section">
<form method="POST">
{% csrf_token %}
<fieldset class="form-group">
<legend class="border-bottom mb-4">New Comment</legend>
{{ form|crispy }}
</fieldset>
<div class="form-group">
<button class="btn btn-outline-info" type="submit">Publish</button>
</div>
</form>
</div>
Solution 1:[1]
You must set the value for post
because it's a foreign key. In form_valid
you should define post = Post.objects.get(id=current_post_id)
and you can get current_post_id
from the url or receive it as a parameter. Then assign it: form.instance.post = post
Solution 2:[2]
Your problem here is you need to pass the id of the post in the url or as a form field, otherwise django can't retrieve the post.id when you create the comment.
In your url add
path('post/<pk>/add-comment', AddCommentView.as_view(), name='add_comment'),
Your view in form_valid
def form_valid(self, form):
comment=form.save(commit=False)
comment.post=self.kwargs.get(pk)
comment.save()
super().form_valid(form)
Inside the template in the form tag add action = "{% url 'add_comment' post.pk%}"
Of course this need to be passed inside a template thatdisplay a post.
Solution 3:[3]
You need to edit your forms.py
:
from django.forms import ModelForm, widgets
class CommentForm(forms.ModelForm):
class Meta:
model = Comment
fields = ['post', 'text']
widgets = {
'post': widgets.HiddenInput
}
If u will have problems with a redirect, change your def get_absolute_url in comment-model
to:
def get_absolute_url(self):
self.article_url = Article.objects.get(id=self.article_id).get_absolute_url()
return self.article_url
Solution 4:[4]
You need to set post_id for your comment. I've just solved this problem myself. I'll try to explain everything as detailed as possible.
First, go to your urls.py
and make sure you have a valid path for your AddCommentView
. It should look similar to this:
path('post/<int:pk>/addcomment/', AddCommentView.as_view(), name='comment-create'),
The pk
argument is the primary key for Post object, which you are trying to comment. Also do not forget to import AddCommentView from your views.
Second, go to your views.py
and correct form_valid
function in AddCommentView
class:
def form_valid(self, form):
form.instance.post_id = self.kwargs['pk']
form.instance.author = self.request.user
return super().form_valid(form)
Your whole class should looke like this:
class AddCommentView(LoginRequiredMixin, CreateView):
model = Comment
fields = ['text'] # filds to be displayed in your form. You may also use your custom form_class
template_name = 'blog/comment_form.html' # html template with your form
def form_valid(self, form):
form.instance.post_id = self.kwargs['pk'] # this is line sets post_id with pk from url
form.instance.author = self.request.user # in case you need to display author
return super().form_valid(form)
# returns url where you 'll be redirected after the form is correctly filled
def get_success_url(self):
pk = self.kwargs["pk"]
return reverse("post-detail", kwargs={"pk": pk})
Finally, go to your html template, where you have your "add comment" button. In your case, it should be called post_detail.html
. Make sure that you pass pk
and url name (aka comment-create
) correctly. Add this code:
<a class="text-muted" href="{% url 'comment-create' object.pk %}"> Add comment</a>
P.S. Found solution in this tutorial
P.P.S This is my very first answer on stackoverflow. Hope it helped someone.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | Juan Antonio BolaƱo |
Solution 2 | Ben Boyer |
Solution 3 | |
Solution 4 | Egor Kolobov |