I'm not able to display content of comment in Django template.
do i have to pass something to the view or do i just call the object simply the wrong way.
views.py
def comment_delete(request, pk):
comment = get_object_or_404(Comment, pk=pk)
try:
if request.method == 'POST':
comment.delete()
messages.success(request, 'You have successfully deleted the Comment')
return redirect('post_detail', pk=comment.post.pk)
else:
template = 'myproject/comment_delete.html'
form = CommentForm(instance=comment)
context = {
'form': form,
}
return render(request, template, context)
except Exception as e:
messages.warning(request, 'The comment could not be deleted. Error {}'.format(e))
models.py
class Comment(models.Model):
author = models.ForeignKey(User, on_delete=models.CASCADE)
post = models.ForeignKey(Post, on_delete=models.CASCADE)
content = models.TextField()
published_date = models.DateField(auto_now_add=True, null=True)
def publish(self):
self.published_date = timezone.now()
self.save()
def __str__(self):
return self.content
template.html
<div class="class-one-box">
<p>{{ comment.post.content }}</p>
<p>Are you sure that you want to delete this Comment? If so, please confirm.</p>
<form method="POST">
{% csrf_token %}
<button class="btn btn-danger" type="submit">Delete Comment</button>
</form>
</div>
Yes, you need to pass the comment object through context. So try like this:
if request.method == 'POST':
comment.delete()
messages.success(request, 'You have successfully deleted the Comment')
return redirect('post_detail', pk=comment.post.pk)
else:
template = 'myproject/comment_delete.html'
form = CommentForm(instance=comment)
context = {
'comment': comment, # <-- Here
'form': form,
}
return render(request, template, context)
Related
I'm working on a Django blog and I'm stuck here... I want to post comment and when I do that it just refresh the page and nothing happens.
I have no idea where I'm making a mistake, please see my code below:
this is views.py
def post_detail(request, slug):
post = get_object_or_404(Post, slug=slug)
related_posts = post.tags.similar_objects()[:3]
comments = post.comments.filter(active=True)
new_comment = None
if request.method == 'POST':
if request.user.is_authenticated:
comment_form = CommentForm(data=request.POST)
if comment_form.is_valid():
new_comment = comment_form.save(commit=False)
new_comment.post = post
new_comment.author = request.user
new_comment.save()
else:
messages.warning(request, 'You need to be logged in to add a comment.')
else:
if request.user.is_authenticated:
comment_form = CommentForm(initial={'author': request.user})
else:
comment_form = CommentForm()
context = {'post': post, 'related_posts': related_posts, 'comments': comments, 'new_comment': new_comment, 'comment_form': comment_form}
return render(request, 'post_detail.html', context)
this is comment part post_detail.html
{% if user.is_authenticated %}
<!--comment form-->
<div class="comment-form">
<h3 class="mb-30">Leave a Reply</h3>
<form class="form-contact comment_form" action="{% url 'post_detail' post.slug %}" method="post">
{% csrf_token %}
<div class="row">
<div class="col-12">
<div class="form-group">
{{ comment_form | crispy }}
</div>
</div>
</div>
<div class="form-group">
<button type="submit" class="button button-contactForm">Post Comment</button>
</div>
</form>
</div>
{% else %}
<div class="alert alert-danger" role="alert">
Please log in to post a comment.
</div>
{% endif %}
this is models.py
class Post(models.Model):
created_at = models.DateTimeField(auto_now_add=True, verbose_name="Created at")
updated_at = models.DateTimeField(auto_now=True, verbose_name="Updated at")
published_at = models.DateTimeField(null=True, blank=True, editable=False, verbose_name="Published at")
post_title = models.CharField(max_length=200, verbose_name="Title")
slug = models.SlugField(max_length=200, unique=True)
author = models.ForeignKey('auth.User', verbose_name="Author", on_delete=models.CASCADE)
category = models.ForeignKey(Category, verbose_name="Category", on_delete=models.CASCADE)
tags = TaggableManager()
body = QuillField()
image = StdImageField(upload_to='featured_image/%Y/%m/%d/', variations={'standard':(1170,820),'banner':(1170,530),'single_post':(1170,556),'thumbnail':(500,500)})
image_credit = models.CharField(max_length=200, verbose_name="Image credit:")
status = models.IntegerField(choices=STATUS, default=0)
def get_absolute_url(self):
return reverse('post_detail', args=[self.slug])
def get_readtime(self):
result = readtime.of_text(self.body)
return result.text
class Meta:
verbose_name = "Post"
verbose_name_plural = "Posts"
ordering = ['-created_at']
def publish(self):
self.is_published = True
self.published_at = timezone.now()
self.save()
def __str__(self):
return self.post_title
class Comment(models.Model):
post = models.ForeignKey(Post, on_delete=models.CASCADE, related_name='comments')
body = models.TextField()
author = models.ForeignKey(User, on_delete=models.CASCADE)
created_on = models.DateTimeField(auto_now_add=True)
active = models.BooleanField(default=False)
class Meta:
ordering = ['created_on']
def __str__(self):
return 'Comment "{}" by {}'.format(self.body, self.author.username)
this is forms.py
class CommentForm(forms.ModelForm):
author = forms.CharField(widget=forms.HiddenInput)
class Meta:
model = Comment
fields = ('body', 'user')
Please not that I can post comment over admin page (http://127.0.0.1:8000/admin), but on the front-end doesn't work for some reason.
Any ideas?
You need to redirect() after dealing with POST data, the tip is not specific to Django, its a good web practice in general so:
from django.shortcuts import render, redirect, get_object_or_404
from django.contrib import messages
def post_detail(request, slug):
post = get_object_or_404(Post, slug=slug)
related_posts = post.tags.similar_objects()[:3]
comments = post.comments.filter(active=True)
new_comment = None
if request.method == 'POST':
if request.user.is_authenticated:
comment_form = CommentForm(data=request.POST)
if comment_form.is_valid():
new_comment = comment_form.save(commit=False)
new_comment.post = post
new_comment.author = request.user
new_comment.save()
return redirect(post.get_absolute_url()) # redirect here
else:
messages.warning(request, 'You need to be logged in to add a comment.')
else:
if request.user.is_authenticated:
comment_form = CommentForm(initial={'author': request.user})
else:
comment_form = CommentForm()
context = {'post': post, 'related_posts': related_posts, 'comments': comments, 'new_comment': new_comment, 'comment_form': comment_form}
return render(request, 'post_detail.html', context)
I am following the guide to create comment given by Django central, https://djangocentral.com/creating-comments-system-with-django/ and it is working. However I am using the {{ form.as_p }} Which will give 3 fields, as the form say, with name, email and the body. But i wanted to have predefined name, which would be your username you are logged inn with and the email attached to that account. How would i go ahead to create that?
forms.py
class CommentForm(forms.ModelForm):
class Meta:
model = Comment
fields = ['name', 'email', 'body']
models.py
class Comment(models.Model):
post = models.ForeignKey(Post, related_name='comments', on_delete=models.CASCADE)
name = models.CharField(max_length=255)
email = models.EmailField()
body = models.TextField()
date_added = models.DateTimeField(auto_now_add=True)
class Meta:
ordering = ['-date_added']
def __str__(self):
return self.name
views.py
def post_detail(request, category_slug, slug, status=Post.ACTIVE):
post = get_object_or_404(Post, slug=slug)
if request.method == 'POST':
form = CommentForm(request.POST)
if form.is_valid():
comment = form.save(commit=False)
comment.post = post
comment.save()
return redirect('post_detail', category_slug=category_slug, slug=slug)
else:
form = CommentForm()
return render(request, 'blog/post_detail.html', {'post': post, 'form': form})
in the html template
{% if user.is_authenticated %}
<h2 class="subtitle is-4">Comments</h2>
<form method="post" class="mb-6">
{% csrf_token %}
{{ form.as_p }}
<div class="field">
<div class="control">
<button class="button is-success">Submit comment</button>
</div>
</div>
</form>
{% endif %}
If you want to pre-set the username and email fields, you can use the initial form parameters like this:
views.py
def post_detail(request, category_slug, slug, status=Post.ACTIVE):
post = get_object_or_404(Post, slug=slug)
if request.method == 'POST':
form = CommentForm(request.POST)
if form.is_valid():
comment = form.save(commit=False)
comment.post = post
comment.save()
return redirect('post_detail', category_slug=category_slug, slug=slug)
else:
user = request.user
form = CommentForm(initial={"name": user.username, "email": user.email})
return render(request, 'blog/post_detail.html', {'post': post, 'form': form})
forms.py
class CommentForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields['name'].disabled = True
self.fields['email'].disabled = True
# OR set readonly widget attribute.
# self.fields['name'].widget.attrs['readonly'] = True
# self.fields['email'].widget.attrs['readonly'] = True
class Meta:
model = Comment
fields = ['name', 'email', 'body']
I am working on a movie website with Django and I'm trying to add user comments. Only the registered users should be allowed to comment. I have the following so far:
models.py:
class Comment(models.Model):
movie = models.ForeignKey(Movie, related_name = "comments", on_delete=models.CASCADE)
user = models.ForeignKey(User, on_delete = models.CASCADE)
content = models.TextField()
date_added = models.DateTimeField(auto_now_add=True)
def __str__(self):
return '%s - %s' % (self.movie.title, self.name)
forms.py
class CommentForm(forms.ModelForm):
content = forms.CharField(label ="", widget = forms.Textarea(
attrs ={
'class':'form-control',
'placeholder':'Comment here!',
'rows':5,
'cols':50
}))
class Meta:
model = Comment
fields =['content']
views.py
class MovieDetailsView(generic.DetailView):
model = Movie
template_name = "details.html"
def comment(request, id):
movie= Movie.objects.get(id)
if request.method == 'POST':
cf = CommentForm(request.POST or None)
if cf.is_valid():
content = request.POST.get('content')
comment = Comment.objects.create(movie = movie, user = request.user, content = content)
comment.save()
return redirect(movie.get_absolute_url())
else:
cf = CommentForm()
context ={
'comment_form':cf,
}
return render(request, 'details.html', context)
details.html
<form method="POST" action="#" class="form">
{% csrf_token %}
{{comment_form.as_p}}
<button type="submit" class="btn btn-primary btn-lg">Submit</button>
<textarea id="text" name="text" class="form__textarea" placeholder="Add comment"></textarea>
<button type="button" class="form__btn">Send</button>
</form>
The MovieDetailsView displays the details page of the movie and has a comment section. However, when I submit the comment, it simply displays a white page and this link: http://127.0.0.1:8000/details/1# . The comment is not saved on the database and I can't seem to find what the issue is. I am also following the example from this link.
Thanks in advance!
You can combine FormMixin with DetailView - Using FormMixin with DetailView.
from django.urls import reverse
from django.views.generic.detail import DetailView
from django.views.generic.edit import FormMixin
from django.http import HttpResponseForbidden
class MovieDetailsView(FormMixin, DetailView):
model = Movie
template_name = "details.html"
form_class = CommentForm
def get_success_url(self):
return reverse('movie_detail', kwargs={'pk': self.object.pk})
# or
# return self.object.get_absolute_url()
def post(self, request, *args, **kwargs):
if not request.user.is_authenticated:
return HttpResponseForbidden()
self.object = self.get_object()
form = self.get_form()
if form.is_valid():
return self.form_valid(form)
else:
return self.form_invalid(form)
def form_valid(self, form):
form.instance.user = self.request.user
form.instance.movie = self.object
form.save()
return super().form_valid(form)
In the post() method, we first check if the user is logged in:
if not request.user.is_authenticated:
return HttpResponseForbidden()
In template:
<form method="POST" class="form">
{% csrf_token %}
{{ form.as_p }}
<button type="submit" class="btn btn-primary btn-lg">Submit</button>
</form>
You can remove the action attribute, the form will be submitted to the same page.
I am new to django, I created a form to save Data into my database but it not working corectly, I got no error but data is not sent in database. Thanks for helping!
views.py
#login_required()
def data(request):
if request.POST == "POST":
form = CreatePost(request.POST)
if form.is_valid():
form.instance.author = request.user
form.save()
return redirect(data)
else:
form = CreatePost()
context = {
"form": form
}
return render(request, "sms/data.html", context)
forms.py
class CreatePost(forms.ModelForm):
class Meta:
model = Post
fields = ["title", "content"]
models.py
class Post(models.Model):
title = models.CharField(max_length=100)
content = models.TextField()
author = models.ForeignKey(User, on_delete=models.CASCADE)
def __str__(self):
return self.title
data.html
<form method="POST">
{% csrf_token %}
{{ form|crispy }}
<pre></pre>
<button class="btn btn-outline-info" type="submit" value="Submit">Data</button>
</form>
try like this
#login_required()
def data(self, request):
if request.method == "POST": #this line
form = CreatePost(request.POST)
if form.is_valid():
post = form.save(commit=False) #new line
post.author = self.request.user #this line
post.save() #this line
return redirect(data)
else:
form = CreatePost()
context = {
"form": form
}
return render(request, "sms/data.html", context)
if request.POST == "POST":
Should instead be:
if request.method == 'POST':
I have a problem when I was creating the comment form with django. After I wrote my view.py, models.py and html, I got an ValueError that said:
Cannot assign "<class 'blog.models.post'>": "Comment.post" must be a "post" instance".
Below are my codes.
HTML
{% block content %}
<h1>Add New Comment:</h1>
<form method='POST' action=''>
{% csrf_token %}
{{ form.as_p }}
<button type='submit'>Submit</button>
</form>
{% endblock %}
views.py
def add_comment(request, slug):
po = get_object_or_404(post, slug=slug)
if request.method == 'POST':
form = CommentForm(request.POST or None)
if form.is_valid():
comment = form.save(commit=False)
comment.post = post
comment.save()
return redirect('blog:post', slug=post.slug)
else:
form = CommentForm()
return render(request, 'blog/post/add_comment.html', {'form': form})
models.py
class Comment(models.Model):
post = models.ForeignKey(post, related_name='comments', on_delete=models.CASCADE)
user = models.CharField(max_length=250)
email = models.EmailField()
body = models.TextField()
created = models.DateTimeField(auto_now_add=True)
approved = models.BooleanField(default=False)
def approved(self):
self.approved = True
self.save()
def __str__(self):
return self.user
The post you fetched from the database is po:
po = get_object_or_404(post, slug=slug)
Therefore you should set form.post = po:
def add_comment(request, slug):
po = get_object_or_404(post, slug=slug)
if request.method == 'POST':
form = CommentForm(request.POST or None)
if form.is_valid():
comment = form.save(commit=False)
comment.post = po
comment.save()
Note that normally in Django you would use Post for your model and post for the instance you fetch from the database.
Try it:
class Comment(models.Model):
post = models.ForeignKey(Post, related_name='comments', on_delete=models.CASCADE)