show Reply button should be specific for different comments . When I press show reply button it opens different replies which dosen't belong to that comment.
views.py
from django.shortcuts import render, HttpResponse, redirect,reverse
from fitness.models import Post, BlogComment
from django.contrib.auth.models import User
from fitness.templatetags import extras
# Create your views here.
def fitness(request):
everypost=Post.objects.all()
context={"everypost":everypost}
return render(request, "fitness/fit.html", context)
def blogfit(request, slug):
post=Post.objects.filter(slug=slug).first()
comments= BlogComment.objects.filter(post=post, parent=None)
replies= BlogComment.objects.filter(post=post).exclude(parent=None)
replyDict={}
for reply in replies:
if reply.parent.sno not in replyDict.keys():
replyDict[reply.parent.sno]=[reply]
else:
replyDict[reply.parent.sno].append(reply)
context={"post":post, 'comments': comments, 'user': request.user, 'replyDict': replyDict}
return render(request, "fitness/blogfit.html", context)
def postComment(request):
if request.method == "POST":
comment=request.POST.get('comment')
user=request.user
postSno =request.POST.get('postSno')
post= Post.objects.get(sno=postSno)
parentSno= request.POST.get('parentSno')
if parentSno=="":
comment=BlogComment(comment= comment, user=user, post=post)
comment.save()
else:
parent= BlogComment.objects.get(sno=parentSno)
comment=BlogComment(comment= comment, user=user, post=post , parent=parent)
comment.save()
return HttpResponse(reverse('fitness:fitness'))
Models.py
from django.db import models
from ckeditor.fields import RichTextField
from django.contrib.auth.models import User
from django.utils.timezone import now
# Create your models here.
class Post(models.Model):
sno=models.AutoField(primary_key=True)
title=models.CharField(max_length=255)
author=models.CharField(max_length=14)
slug=models.CharField(max_length=130)
timeStamp=models.DateTimeField(blank=True)
content=RichTextField(blank=True, null=True)
def __str__(self):
return self.title + " by " + self.author
class BlogComment(models.Model):
sno= models.AutoField(primary_key=True)
comment=models.TextField()
user=models.ForeignKey(User, on_delete=models.CASCADE)
post=models.ForeignKey(Post, on_delete=models.CASCADE)
parent=models.ForeignKey('self',on_delete=models.CASCADE, null=True )
timestamp= models.DateTimeField(default=now)
def __str__(self):
return self.comment[0:13] + "..." + "by" + " " + self.user.username
Html page
<h2 class="blog-post-title">{{post.title}}</h2>
<p class="blog-post-meta">{{post.timeStamp}} by {{post.author}}</p>
<p>{{post.content|safe}}</p>
<hr>
</div>
</div>
</div>
{% if user.is_authenticated %}
<form action="{% url 'fitness:postComment' %}" method="post">
{% csrf_token %}
<div class="form-group">
<label for="exampleInputEmail1">Post Comment </label>
<input type="text" class="form-control" name="comment" placeholder="Enter comment here">
</div>
<input type="hidden" name="postSno" value="{{post.sno}}">
<input type="hidden" name="parentSno" value="">
<button type="submit" class="btn btn-primary">Submit</button>
</form>
{% else %}
Please login to post a comment
{% endif %}
</div>
{% for comment in comments %}
<div class="row my-3">
<div class="col-md-1 ">
<img class="rounded mx-auto d-block w-100 border border-dark p-2" src="http://i9.photobucket.com/albums/a88/creaticode/avatar_1_zps8e1c80cd.jpg" alt="user">
</div>
<div class="col-md-11 ">
<h6 class="comment-name by-author"> {{comment.user.username}} </h6> <span class="badge badge-secondary "></span>
<b> {{comment.comment}} </b> <span class="badge badge-secondary "></span><br>
<button class="btn btn-sm btn-primary" type="button" data-toggle="collapse" data-target="#replyBox{{comment.sno}}" aria-expanded="false" aria-controls="replyBox{{comment.sno}}">
Reply
</button>
<button class="btn btn-sm btn-primary" type="button" onClick="myFunction()" id= "show-hide" >
Show Replies
</button>
<div class="reply mx-0" >
<div class="collapse" id="replyBox{{comment.sno}}">
<div class="card card-body my-2" >
<form action="{% url 'fitness:postComment' %}" method="post">
{% csrf_token %}
<div class="form-group" >
<label for="comment">Post a reply </label>
<input type="text" class="form-control" name="comment" placeholder="Enter comment here">
<input type="hidden" name="parentSno" value="{{comment.sno}}">
</div>
<input type="hidden" name="postSno" value="{{post.sno}}">
<button type="submit" class="btn btn-primary">Submit</button>
</form>
</div>
</div>
<div class="replies bg-danger my-2" id = "replies" >
{% for reply in replyDict|get_val:comment.sno %}
<div class="replies">{{reply}}</div>
<br>
{% endfor %}
</div>
</div>
</div>
</div>
{% endfor %}
<!-- Contenedor Principal -->
<script>
function myFunction(){
var x = document.getElementById("replies");
if(x.style.display === "none"){
x.style.display = "block";
}
else{
x.style.display = "none";
}
}
</script>
I think it is a logical error. Can someone help me to find out this error? While everything is working fine but my reply button not working fine.
Change in models.py. update parent in BlogComment (add related_name)
parent=models.ForeignKey('self', on_delete=models.CASCADE, null=True, related_name='replies' )
Change in views.py where you are getting comments
comments= BlogComment.objects.filter(post=post, parent=None).prefetch_related('replies')
You don't need separate query for replies.
In html (Only for replies. Please change as per your requirement)
{% for comment in comments %}
{% for reply in comment.replies.all %}
{{ reply.comment }}
{% endfor %}
{% endfor %}
This will work. Remember related_name=replies
(Sorry for unclear answer. It's closing time in office and I am leaving. Good luck)
Related
Created a website with products. I need to make a window for editing them on the site in order to change the manufacturer and other characteristics. This must be done in a pop-up window. I have data displayed, I change it, but nothing changes when I save it. How can this problem be solved.
My vievs:
def parts(request):
added = ''
error = ''
PartAllView = Part.objects.order_by('-id')
if request.method == 'POST' and 'parts_add' in request.POST:
form = PartForm(request.POST, request.FILES)
if form.is_valid():
form.save()
added = 'Добавлено'
else:
error = 'Данная запчасть уже добавлена'
if request.method == 'POST' and 'parts_edit' in request.POST:
PartPost = int(request.POST['parts_edit'])
PartID = Part.objects.get(id=PartPost)
if PartID:
PartID.save()
added = 'Запчасть успешно отредактирована'
else:
error = 'Ошибка редактирования'
form = PartForm()
data = {
'added': added,
'error': error,
'form': form,
'PartAllView': PartAllView,
}
return render(request, 'kross/parts.html', data)
My HTML:
{% if PartAllView %}
{% for el in PartAllView %}
<form method="post" enctype="multipart/form-data">
{% csrf_token %}
<div class="modal fade" id="partEdit{{ el.id }}">
<div class="modal-dialog modal-dialog-centered text-center" role="document">
<div class="modal-content modal-content-demo">
<div class="modal-header">
<h6 class="modal-title">Добавление запчасти</h6><button aria-label="Close" class="btn-close"
data-bs-dismiss="modal"><span aria-hidden="true">×</span></button>
</div>
<div class="modal-body">
<div class="row row-sm">
<div class="col-lg-6">
<div class="form-group">
<input type="text" class="form-control" name="brand" value="{{ el.brand }}">
</div>
</div>
<div class="col-lg-6">
<div class="form-group">
<input type="text" class="form-control" value="{{ el.number }}">
</div>
</div>
<div class="col-lg-12">
<div class="form-group">
<input type="text" class="form-control" value="{{ el.name }}"><br>
<input type="textarea" class="form-control" rows="2" value="{{ el.description }}">
</div>
</div>
</div>
{{ el.analog }}
...
You can use updateView to edit an existing data in your website by simply:
from django.views.generic.edit import UpdateView
From MyApp models import #Model
class editview(UpdateView):
model = #Your Model You want to edit
fields = [#Add the fields you want to edit]
template_name = 'edit.html'
success_url = ('Home')
In your edit Template add:
<form method="post">
{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="Update">
I hope it help.
I have a comment section and I want to allow users to delete their comments, however when I click the delete button the comment doesn't get delete, and over that a new comment with nothing get add.
Here is my python code. When I tried to print "delete" I got none in my terminal window
#app.route("/deletecomment", methods=["GET", "POST"])
#login_required
def deletecomment():
delete = request.args.get("delete")
print(delete)
#if the method is get
if request.method == "GET":
#testing purpose
print("vvv")
print(delete)
#delete the comment
comments = db.execute("DELETE FROM comment WHERE comment=?",delete)
return redirect (url_for("addcomment"))
Here is my html. Is it bad to have a form inside another form?
<form action="/comment" method="get">
<div class="row bootstrap snippets bootdeys">
<div class="col-md-8 col-sm-12">
<div class="comment-wrapper">
<div class="panel panel-info">
<div class="panel-heading">
Comment panel
</div>
<div class="panel-body">
<textarea name="comment" class="form-control" placeholder="write a comment..." rows="3"></textarea>
<br>
<button type="submit" class="btn btn-info pull-right">Post</button>
<div class="clearfix"></div>
<hr>
{% for comments in comments %}
<ul class="media-list">
<!--<button type="submit" class="btn btn-danger">Delete</button>-->
<li class="media">
<a href="#" class="pull-left">
<img src="https://bootdey.com/img/Content/user_1.jpg" alt="" class="img-circle">
</a>
<div class="media-body">
<!--<button type="submit" class="btn btn-danger">Delete</button>-->
<span class="text-muted pull-right">
</span>
<!--<button type="submit" class="btn btn-danger">Delete</button>-->
<strong class="text-success">{{comments.user}}</strong>
<form action="/deletecomment" method="get">
<p name="delete">
{{comments.comment}}
</p>
<button id="but" type="submit" class="btn btn-danger">Delete</button>
</form>
</div>
</li>
</div>
</ul>
{% endfor %}
</div>
</div>
</div>
</div>
</div>
</form>
Put the comment ID as a URL parameter in the action URL
<form action="/deletecomment?delete={{comment.id}}" method="get">
and change the controller to use the parameter as the ID in the query.
#app.route("/deletecomment", methods=["GET", "POST"])
#login_required
def deletecomment():
#if the method is get
if request.method == "GET":
delete = request.args.get("delete")
print(delete)
#testing purpose
print("vvv")
print(delete)
#delete the comment
comments = db.execute("DELETE FROM comment WHERE id=?",delete)
return redirect (url_for("addcomment"))
I'm trying to build a comment section in my flask web app. My code works fine, but when I try to delete the last comment that was just added it doesn't delete and I also got an empty comment. this just happens when I try to delete the last comment.
Here is my python code
#app.route("/addcomment", methods=["GET", "POST"])
#login_required
def addcomment():
global book
if request.method == "GET":
book = request.args.get("book")
comments = db.execute("SELECT * FROM comment WHERE book_id=? ORDER BY Timestamp DESC",book)
# print(comments)
return render_template ("comment.html", comments=comments)
else:
comment = request.form.get("comment")
id = session["user_id"]
user = db.execute("SELECT username FROM users WHERE id=?", id)
db.execute("INSERT INTO comment (comment, user,book_id) VALUES(?, ?,?)",comment, user[0]["username"],book)
return redirect (request.referrer)
#app.route("/deletecomment/<comment_id>", methods=["GET", "POST"])
#login_required
def deletecomment(comment_id):
#get the comment that will delete
#if the method is get
delete = request.args.get("delete")
#delete the comment
db.execute("DELETE FROM comment WHERE id=?",comment_id)
print("Djyhhh")
return redirect (request.referrer)
And if it's important here is my comment.html
<form action="{{url_for('addcomment')}}" method="post">
<div class="row bootstrap snippets bootdeys">
<div class="col-md-8 col-sm-12">
<div class="comment-wrapper">
<div class="panel panel-info">
<div class="panel-heading">
Comment panel
</div>
<div class="panel-body">
<textarea name="comment" class="form-control" placeholder="write a comment..." rows="3"></textarea>
<br>
<button type="submit" class="btn btn-info pull-right">Post</button>
<div class="clearfix"></div>
<hr>
{% for comments in comments %}
<ul class="media-list">
<!--<button type="submit" class="btn btn-danger">Delete</button>-->
<li class="media">
<a href="#" class="pull-left">
<img src="https://bootdey.com/img/Content/user_1.jpg" alt="" class="img-circle">
</a>
<div class="media-body">
<!--<button type="submit" class="btn btn-danger">Delete</button>-->
<span class="text-muted pull-right">
</span>
<!--<button type="submit" class="btn btn-danger">Delete</button>-->
<strong class="text-success">{{comments.user}}</strong>
<form action="/deletecomment/{{comments.id}}" method="get">
<p>
{{comments.comment}}
</p>
<button id="but" type="submit" class="btn btn-danger">Delete</button>
</form>
</div>
</li>
</div>
</ul>
{% endfor %}
</div>
</div>
</div>
</div>
</div>
</form>
I'm novice adapting a simple address book database program using Django from a course I've done on Codemy.
I have a page where I enter the names, surnames etc together with a DELETE and EDIT button next to each address. There's no problem when I click the EDIT button (the form populates automatically and takes me to website/edit1,2,3,4 etc/), but when I click the 'edit' button after editing the addressee info, I get the error as below. The btn1 is the name="btn1" of the button as indicated.
GET /edit/3?csrfmiddlewaretoken=b4IkMxxxxxxxxxxxDHrDIgRnjvEWr53rL&**btn1**=140 HTTP/1.1" 200 5751
Here is my views file
from django.shortcuts import render, redirect
from .models import List
from .forms import ListForm
from django.contrib import messages
from django.http import HttpResponseRedirect
def home(request):
all_items = List.objects.all
return render(request, 'home.html', {'all_items': all_items})
def about(request):
return render(request, 'about.html', {})
def edit(request, item_id):
if request.method =='POST':
item = List.objects.get(pk=item_id)
form = ListForm(request.POST or None, instance=item)
if form.is_valid():
form.save()
messages.success(request, ('Item Had Been Edited'))
return redirect('home')
else:
item = List.objects.get(pk=item_id)
return render(request, 'edit.html', {'item': item})
def delete(request, item_id):
item = List.objects.get(pk=item_id)
item.delete()
return redirect('home')
...And here is the edit.html file
{% extends 'base.html' %}
{% block title %}To-Do-List | Edit {% endblock %}
{% block content %}
{% if item %}
{{ item.item }}
<form class="needs-validation" novalidate>
{% csrf_token %}
<div class="form-row">
<div class="col-md-6 mb-3">
<label for="validationCustom01">First name</label>
<input type="text" class="form-control" id="validationCustom01" value="{{ item.First_name }}" required>
<div class="valid-feedback">
Looks good!
</div>
</div>
<div class="col-md-6 mb-3">
<label for="validationCustom02">Last name</label>
<input type="text" class="form-control" id="validationCustom02" value="{{ item.Surname }}" required>
<div class="valid-feedback">
Looks good!
</div>
</div>
</div>
<div class="form-row">
<div class="col-md-6 mb-3">
<label for="validationCustom03">Street</label>
<input type="text" class="form-control" value="{{ item.Street }}" id="validationCustom03" required>
<div class="invalid-feedback">
Please provide a valid city.
</div>
</div>
<div class="col-md-3 mb-3">
<label for="validationCustom03">Town</label>
<input type="text" class="form-control" value="{{ item.Town }}" id="validationCustom03" required>
<div class="invalid-feedback">
Please provide a valid city.
</div>
</div>
<div class="col-md-3 mb-3">
<label for="validationCustom05">Province</label>
<input type="text" class="form-control" value="{{ item.Province }}" id="validationCustom05" required>
<div class="invalid-feedback">
Please provide a valid zip.
</div>
</div>
</div>
<div class="form-group">
<div class="col-md-3 mb-3">
<label for="validationCustom05">Postal code</label>
<input type="text" class="form-control" value="{{ item.Postal_code }}" id="validationCustom05" required>
<div class="invalid-feedback">
Please provide a valid zip.
</div>
</div>
</div>
<button class="btn btn-primary" type="submit" type="hidden" value="" name='btn1'>Edit</button>
</form>
<script>
// Example starter JavaScript for disabling form submissions if there are invalid fields
(function() {
'use strict';
window.addEventListener('load', function() {
// Fetch all the forms we want to apply custom Bootstrap validation styles to
var forms = document.getElementsByClassName('needs-validation');
// Loop over them and prevent submission
var validation = Array.prototype.filter.call(forms, function(form) {
form.addEventListener('submit', function(event) {
if (form.checkValidity() === false) {
event.preventDefault();
event.stopPropagation();
}
form.classList.add('was-validated');
}, false);
});
}, false);
})();
</script>
{% endif %}
{% endblock %}
I cannot locate an issue with the CSRF token. it is included just like the tutorial on the edit.html page. Not even sure if the issue is with the token?
I've gone through the tutorial time and again and cannot see an issue.
I'm a noob, so any info would be great!
Normally, when you save information after editing it in a form, you should "post" your data to the server.
It appears your form method is not set which default to get. It should be set to post.
<form method="post">...</form>
This being said, your view should also be configured accordingly. Without more details, it is hard to provide deeper answer.
I am adding a functionality in my website, where users can like posts.
I have successfully done this, however I am having trouble adding one functionality.
This is text within a button depending on whether a post is liked or not.
Right now the button stays the same no matter if the post is liked or not.
models.py
class Post(models.Model):
file = models.ImageField(upload_to='images/')
summary = models.TextField(max_length=600)
pub_date = models.DateTimeField(auto_now=True)
user = models.ForeignKey(User, on_delete=models.CASCADE)
likes = models.ManyToManyField(User, through='Like', related_name='likes')
def __str__(self):
return self.user.username
def pub_date_pretty(self):
return self.pub_date.strftime('%b %e %Y')
def summary_pretty(self):
return self.summary[:50]
#property
def total_likes(self):
return self.likes.count()
class Like(models.Model):
status = models.BooleanField()
post = models.ForeignKey(Post, on_delete=models.CASCADE)
user = models.ForeignKey(User, on_delete=models.CASCADE)
views.py
def likepost(request, post_id):
if request.method == 'POST':
post = get_object_or_404(Post, pk=post_id)
user = request.user
if post.likes.filter(id=user.id).exists():
post.likes.remove(user)
return redirect('home')
else:
like = Like()
like.post = post
like.user = user
like.status = True
like.save()
post.likes.add(user)
return redirect('home')
my template:
{% if post.likes.status == True %}
<button class="btn btn-primary btn-lg btn-block"><span class="oi oi-caret-top"></span> Unlike {{ post.total_likes }} </button>
{% else %}
<button class="btn btn-primary btn-lg btn-block"><span class="oi oi-caret-top"></span> Like {{ post.total_likes }} </button>
{% endif %}
EDIT - HOME VIEW:
#login_required(login_url="/login")
def home(request):
posts = Post.objects.all()
return render(request, 'posts/home.html', {'posts': posts})
EDIT 2:
{% extends 'accounts/base.html' %}
{% block content %}
{% load static %}
{% for post in posts.all %}
<div class="container pl-5">
<div class="row pt-3">
<img src="{% static 'grey.jpg' %}" width="600px" height="60px">
<div class="pt-3 pl-5" style="position: absolute;"> <b> {{ post.user.username }} </b> </div>
</div>
<br>
<div class="card" style="width: 600px; bottom: 24px; right: 15px;">
<img src="{{ post.file.url }}" width="599px">
</div>
<br>
<div class="card" style="width: 600px; bottom: 50px; right: 15px;"> <img src="{% static 'grey.jpg' %}" width="600px" height="150px"> </div>
<div class="col-6" style="bottom:145px; left: 5px;">
<div style="position: absolute;"> <b> {{ post.user.username }} </b> {{ post.summary_pretty }}</div>
</div>
{% for like in post.likes.all %}
{{like.username}}
{% endfor %}
{% if like.status %}
<button class="btn btn-primary btn-lg btn-block"><span class="oi oi-caret-top"></span> Unlike {{ post.total_likes }} </button>
{% else %}
<button class="btn btn-primary btn-lg btn-block"><span class="oi oi-caret-top"></span> Like {{ post.total_likes }} </button>
{% endif %}
<form id="likepost{{ post.id }}" method="POST" action="{% url 'likepost' post.id %}">
{% csrf_token%}
<input type="hidden">
</form>
</div>
<br>
<br>
<br>
{% endfor %}
{% endblock %}
In your model you have defined likes as a ManyToManyField field:
class Post(models.Model):
likes = models.ManyToManyField(User, through='Like', related_name='likes')
But in your template you are trying to get a single boolean value from many likes:
{% if post.likes.status == True %}
post.likes will return multiple objects. You need to instead get the like based on the user.
EDIT:
One way you could get the like status is by doing the following in your view:
context['like'] = Like.objects.get(post=post, user=request.user)
Then in your template:
{% if like.status == True %}