How To Solve Django ValueError: :Comment.post" must be a "Software" instance
I'm getting an error over and over again when I'm displaying comments for a program. Please what is the problem I made here? I made many attempts using get , filter but the error remains the same. Other errors may appear when changing the view of comments. Please help.
def download(request,slug):
app = get_object_or_404 (Software,slug = slug)
comments= app.comments.filter(active=True).order_by("-created")
try :
app = Software.objects.filter(slug = slug)
except :
raise Http404
new_comment = None
if request.method == "POST":
comment_form = CommentForm(data=request.POST)
if comment_form.is_valid():
new_comment = comment_form.save(commit=False)
new_comment.post= app <<<--------------------------->>> here my error
new_comment.save()
else:
comment_form = CommentForm()
context ={
'app' :app,
'comments': comments,
'new_comment': new_comment,
'comment_form': comment_form,
}
return render( request,'download.html',context)
that's my models:
class Software (models.Model):
class Meta :
verbose_name_plural = 'software'
ordering = ['created_at']
category = models.ForeignKey(Categorie,on_delete=models.CASCADE,null=True, related_name="mac")
category = models.CharField(max_length=150 , null=True,blank=True)
slug = models.SlugField(blank=True,allow_unicode=True,editable=True)
title = models.CharField(max_length=50 , null=True)
requirements = models.CharField(max_length=100 , null=True)
version = models.CharField(max_length=100 , null=True)
picture = models.ImageField(upload_to='img_pro' , null=True)
size = models.CharField(max_length=20 , null=True)
created_at = models.DateField(auto_now_add=True)
auther = models.CharField(max_length=100 , null=True)
download = models.URLField(null=True)
def __str__(self):
return self.slug
def get_absolute_url(self):
return reverse('download', args=(self.slug,))
class Comment(models.Model):
post = models.ForeignKey(Software , on_delete=models.CASCADE ,null=True, related_name='comments')
name = models.CharField(max_length=80 , null=True)
email = models.EmailField(max_length=200, blank=True , null=True)
body = models.TextField( null=True)
created = models.DateTimeField(auto_now_add=True , null=True)
active = models.BooleanField(default=False , null=True)
parent = models.ForeignKey('self', null=True, blank=True, related_name='replies',on_delete=models.CASCADE)
class Meta:
ordering = ('created',)
def __str__(self):
return 'Comment by {}'.format(self.post)
Ok, obj.objects.filter()
always returns a queryset. So in your case variable app
is a queryset and not an instance of model Software
.
To ensure that variable app
only contains one single instance of Software
you would want to use obj.objects.get()
which results in either a DoesNotExist
Error, a MultipleObjectsReturned
Error or a single hit for your wanted model instance of Software
.
Here you go with lookups with ...objects.get()
.
To replace your try-except-block entirely with the convenient function get_object_or_404()
do like this:
def download(request,slug):
app = get_object_or_404(Software, slug=slug)
if request.method == "POST":
comment_form = CommentForm(data=request.POST)
if comment_form.is_valid():
new_comment = comment_form.save(commit=False)
new_comment.comments = app <<<--------------------------->>> here my error
new_comment.save()
else:
comment_form = CommentForm()
context ={
'app' :app,
'comments': app.comments,
'new_comment': new_comment,
'comment_form': comment_form,
}
return render( request,'download.html',context)
The other issue could be, that you refer to your posts with comment.post =
but within your Comment
model you told via related_name
that you want to refer to your posts via comments
.
You need to use .get() instead of .filter() Query for getting object like this...
app = Software.objects.get(slug = slug) <--- this need to be correct
new_comment = comment_form.save(commit=False)
new_comment.comments = app
new_comment.save()