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>
Related
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 have a little confusion in my app.
I have an HTML page in which I have added one form (form data submitting) and one table (to display the submitted data).
For which I have a view that submit and retrieve the data at the same time but unfortunately, data is successfully storing in the table but in retrieving time, it gives me the error which is mentioned below.
Error
NoReverseMatch at /staff/add_staff_type
Reverse for 'student_profile' with keyword arguments '{'id': ''}' not
found. 1 pattern(s) tried: ['student/profile/(?P[0-9]+)$']
Views.py
def add_staff_type(request):
if request.method == 'POST':
designation = request.POST.get('designation')
salary = request.POST.get('salary')
datetime = request.POST.get('datetime')
add_staff_type = staff_type.objects.create(designation=designation, salary=salary, datetime=datetime)
add_staff_type.save()
messages.info(request, "Staff type has been Added.")
return redirect('add_staff_type')
else:
#fetching records from the database table
display_staff_type = staff_type.objects.all()
return render(request, 'staff/staff_type.html',{'display_staff_type':display_staff_type})
urls.py
urlpatterns = [
path("", views.index, name="index"),
path("student/Add_Student", views.Add_Student, name="Add_Student"),
path("student/display_students", views.Display_Student, name="display_students"),
path("student/edit/<int:id>", views.student_edit, name="student_edit"),
path("student/update/<int:id>", views.student_update, name="student_update"),
path("student/profile/<int:id>", views.student_profile, name="student_profile"),
path("student/delete/<int:id>", views.student_delete, name="student_delete"),
#below url is for staff_type on which i am currently workin
path("staff/add_staff_type", views.add_staff_type, name="add_staff_type"),
]
staff_type.html
<div class="card">
<div class="card-header">
<h3 class="card-title">Add Staff Type</h3>
</div>
<!-- /.card-header -->
<!-- form start -->
<form
class="needs-validation"
action="add_staff_type"
method="POST"
enctype="multipart/form-data"
novalidate
>
{% csrf_token %}
<div class="card-body">
<div class="form-row">
<div class="col-md-4 mb-3">
<label for="validationCustom01">Designation</label>
<input
type="text"
class="form-control"
id="validationCustom01"
placeholder="Acountant, Librarian, Teacher"
name="designation"
required
/>
<div class="valid-feedback">Looks good!</div>
</div>
<div class="col-md-4 mb-3">
<label for="validationCustom04">Salary</label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text">Rs.</span>
</div>
<input type="number" class="form-control" id="validationCustom04" name="salary" min="0">
<div class="valid-feedback">Looks good!</div>
</div>
</div>
<div class="col-md-4 mb-3">
<label for="validationCustom03">Date and Time</label>
<input
type="datetime-local"
class="form-control"
id="validationCustom03"
placeholder="MM/DD/YYY"
name="datetime"
required
/>
<div class="valid-feedback">Looks good!</div>
</div>
</div>
<!--
<div class="form-row">
<div class="col-md-4 mb-3">
<label for="validationCustomUsername">Username</label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text" id="inputGroupPrepend">#</span>
</div>
<input type="text" class="form-control" id="validationCustomUsername" placeholder="Username" aria-describedby="inputGroupPrepend" required>
<div class="invalid-feedback">
Please choose a username.
</div>
</div>
</div>
-->
<button class="btn btn-primary" type="submit">Add Staff Type</button>
</div>
</form>
</div>
<div class="card">
<div class="card-header">
<h3 class="card-title">Available Staff Types</h3>
</div>
<!-- /.card-header -->
<div class="card-body">
<table id="example1" class="table table-bordered table-striped">
<thead>
<tr>
<th>Designation</th>
<th>Salary</th>
<th>Entry Date</th>
<th>Action</th>
</tr>
</thead>
<tbody>
{% for staff_type in display_staff_type %}
<tr>
<td>{{staff_type.designation}}</td>
<td>{{staff_type.salary}}</td>
<td>{{staff_type.datetime}}</td>
<td>
<a href="{% url 'student_profile' id=student.id %}">
<i class="far fa-eye"></i>
</a>
<a href="{% url 'student_edit' id=student.id %}">
<i class="far fa-edit"></i>
</a>
<a href="{% url 'student_delete' id=student.id %}">
<i class="far fa-trash-alt"></i>
</a>
</td>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
<!-- /.card-body -->
</div>
You can revise your view function to this:
def add_staff_type(request):
if request.method == 'POST':
designation = request.POST.get('designation')
salary = request.POST.get('salary')
datetime = request.POST.get('datetime')
add_staff_type = staff_type.objects.create(designation=designation, salary=salary, datetime=datetime)
add_staff_type.save()
messages.info(request, "Staff type has been Added.")
# this can also be return redirect('staff:add_staff_type')
return redirect('add_staff_type')
#fetching records from the database table
display_staff_type = staff_type.objects.all()
return render(request, 'staff/staff_type.html',{'display_staff_type':display_staff_type})
Since you are calling the same view and serving data to the same form and view you can remove the action value of the form which goes like this:
<form
class="needs-validation"
action=""
method="POST"
enctype="multipart/form-data"
novalidate
>
Info: i have sales_item QuerySet in view. i want to approve, decline and add some comments on specific sales_items. i also include html code were add sales list and form is inside of a dropdown menu. Where the menu pops up and we fill out the form.
Problem: The code below of views file is getting error Sale matching query does not exist.
models.py
class Authorize(models.Model):
APPROVED = 'AP'
DECLINED = 'DL'
STATUS_CHOICES = [
(APPROVED, 'Approved'),
(DECLINED, 'Declined'),
]
user = models.ForeignKey(User, on_delete=models.CASCADE, null=True)
sales_item = models.ForeignKey(Sale, on_delete=models.CASCADE, null=True, blank=True)
comments = models.TextField(max_length=1000, blank=True)
created_at = models.DateTimeField(auto_now_add=True)
status = models.CharField(choices=STATUS_CHOICES, default=APPROVED, max_length=2)
forms.py
class AuthorizeForm(forms.ModelForm):
class Meta:
model = Authorize
fields = [
'comments',
'status'
]
views.py
def SalesListView(request):
queryset = Sale.objects.all()
auth_form = AuthorizeForm(data=request.POST)
if request.method == 'POST':
pk = request.POST.get('pk')
sales = Sale.objects.get(id=pk)
if auth_form.is_valid():
approved = auth_form.save(commit=False)
approved.sales_item = sales
approved.save()
context = {
'sales': queryset,
'form': auth_form
}
return render(request, 'pending_sale.html', context)
index.html
{% for object in sales %}
<div class="col-lg-6">
<div class="hpanel hblue">
<div class="panel-body">
<div class="row">
<div class="col-sm-8">
<h4> {{ object.customers }}</h4>
<p>
{{ object.content }}
</p>
<div class="row">
<div class="col-sm-3">
<div class="project-label">Saler</div>
<small>{{ object.saler }}</small>
</div>
<div class="col-sm-4">
<div class="project-label">Timestamp</div>
<small>{{ object.created_on|naturalday }}</small>
</div>
<div class="col-sm-4">
<div class="project-label">Product</div>
<small>{{ object.created_on|naturalday }}</small>
</div>
</div>
</div>
<div class="col-sm-4 project-info">
<div class="project-action">
<div class="dropdown">
<div class="btn-group">
<button class="btn btn-xs btn-default"> View</button>
<button class="btn btn-xs btn-default dropdown-toggle" data-toggle="dropdown">
Edit
</button>
<div class="dropdown-menu auth-form-dropdown dropdown-menu-sw " style="width:352px;">
<a class="Link">
<i class="pe-7s-help1" style="font-style: 150px;"></i>
</a>
<div style="font-weight: bold;">
Approvels
</div>
<div style="margin-top: 10px;">
<form action="." method="POST"> {% csrf_token %}
<div class="form-group">
<textarea name="comments" id="id_comments" cols="30" rows="2" required
class="form-control" placeholder="comments..."></textarea>
</div>
<div class=" float-right">
<div id="id_status">
<input type="radio" name="status" value="AP" required
id="id_status_0">
<label for="id_status_0" class="waves-effect waves-themed"
required>Approved</label>
<input type="radio" name="status" value="DL" required
id="id_status_1">
<label for="id_status_1" class="waves-effect waves-themed"
required>Declined</label>
</div>
</div>
<button type="submit" class="btn btn-sm btn-default"
style="font-size: 13px; padding: 3px; font-weight: 400;">submit</button>
</form>
</div>
</div>
</div>
</div>
</div>
<div class="project-value">
<h2 class="text-info">
${{ object.products.price }}
</h2>
<p id="stores"></p>
</div>
</div>
</div>
</div>
</div>
</div>
{% endfor %}
The primary key('pk') you are passing is not valid.Try fetching some id i.e primary key using a simple print statement
q=Sale.objects.all().values('id')
print(q)
Try these two commands to know what are the available id options you have and then try working on the queryset.
Anyways there is another ways to do this task instead of using a form you can pass the id directly into the url section .Here is a nice tutorial explaining how to pass id through url.
You get his exception while trying to get object by:
sales = Sale.objects.get(id=pk)
You can catch this error by this example
try:
sales = Sale.objects.get(id=pk)
except Sale.DoesNotExist:
return ValidationError(f'No sale by id {pk}')
Try to check, what primary key you passed into query, does it exists in database, and return error if not.
Maybe you nees to create Sale if it doesn't exist
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)
I am new to programming. I found nice bootstrap modal for registration, so i put it to my html code and it looks nice but nothing can be pressed or post.
Before i was using django and UserCreationForm without modals. So help me to concatenate these two things:
so this is my bootstrap modal that i found
<!-- Modal -->
<div class="modal fade" id="elegantModalForm" tabindex="-1" role="dialog" aria-labelledby="myModalLabel"
aria-hidden="true">
<div class="modal-dialog" role="document">
<!--Content-->
<div class="modal-content form-elegant">
<!--Header-->
<div class="modal-header text-center">
<h3 class="modal-title w-100 dark-grey-text font-weight-bold my-3" id="myModalLabel"><strong>Войти</strong></h3>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
<!--Body-->
<form type="post" action="{% url 'common:login' %}">
<div class="modal-body mx-4">
<!--Body-->
<div class="md-form mb-5">
<input type="email" name="useremail" id="Form-email1" class="form-control validate">
<label data-error="wrong" data-success="right" for="Form-email1">Ваша почта</label>
</div>
<div class="md-form pb-3">
<input type="password" id="Form-pass1" class="form-control validate">
<label data-error="wrong" data-success="right" for="Form-pass1">Пароль</label>
<p class="font-small blue-text d-flex justify-content-end">Забыли <a href="#" class="blue-text ml-1">
пароль?</a></p>
</div>
<div class="text-center mb-3">
<button type="button" class="btn blue-gradient btn-block btn-rounded">ок</button>
</div>
<p class="font-small dark-grey-text text-right d-flex justify-content-center mb-3 pt-2"> или войти
с помощью:</p>
<div class="row my-3 d-flex justify-content-center">
<!--Facebook-->
<button type="button" class="btn btn-white btn-rounded mr-md-3 z-depth-1a"><i class="fab fa-facebook-f text-center"></i></button>
<!--Twitter-->
<button type="button" class="btn btn-white btn-rounded mr-md-3 z-depth-1a"><i class="fab fa-twitter"></i></button>
<!--Google +-->
<button type="button" class="btn btn-white btn-rounded z-depth-1a"><i class="fab fa-google-plus-g"></i></button>
</div>
</div>
</form>
<!--Footer-->
<div class="modal-footer mx-5 pt-3 mb-1">
<p class="font-small grey-text d-flex justify-content-end">Первый раз? <a href="{% url 'common:signup' %}" class="blue-text ml-1">
Зарегистрируйся</a></p>
</div>
</div>
<!--/.Content-->
</div>
</div>
<!-- Modal -->
and this is my views.py before using modal:
def signup(request):
if request.method == 'POST':
form = UserCreationForm(request.POST)
if form.is_valid():
form.save()
return redirect('index')
else:
form = UserCreationForm()
return render(request, 'registration/signup.html', {'form': form})
So help me to show how it should work. Actually i used to use {{form.as_p}} but how should i do in this case?
I think what you are looking for is Django Forms
official doc- https://docs.djangoproject.com/en/2.2/topics/forms/
other- ( https://www.tutorialspoint.com/django/django_form_processing)
First, you need to create a form model and define the fields which you are taking as input.
Here is a sample-
from django import forms
class LoginForm(forms.Form):
user = forms.CharField(max_length = 100)
password = forms.CharField(max_length =100)
Then, you need to modify the view according to form. Here is a sample-
def login(request):
username = "not logged in"
if request.method == "POST":
#Get the posted form
MyLoginForm = LoginForm(request.POST)
if MyLoginForm.is_valid():
username = MyLoginForm.cleaned_data['username']
else:
MyLoginForm = Loginform()
return render(request, 'loggedin.html', {"username" : username})
and if you are sending data through POST, don't forget to add csrf token just in Html file.
form type="post" action="{% url 'common:login' %}">
{% csrf_token %}