I want to create a comment system with using Ajax. My main purpose is getting new comments in my page without page refreshing. I add some js code to my HTML file but it didn't work. Where are my mistakes and what should I do?
views.py
...
def post_detail(request, pk, ):
post = get_object_or_404(Post, pk=pk)
form = CommentForm(request.POST or None)
if form.is_valid():
comment = form.save(commit=False)
comment.post = post
comment.save()
return redirect('post_detail', pk=post.pk)
context = {
'post': post,
'form': form,
}
return render(request, 'blog/post_detail.html', context)
comments.html
{% load crispy_forms_tags %}
{% load static %}
<hr>
<form method="POST" style="width: 50%; margin-left: 20px" id="comment_form">
{% csrf_token %}
{{ form|crispy }}
<input type="submit" class="btn btn-info" value="Yorum Ekle" style="margin-left: 20px">
</form>
<script type="text/javascript" src="{% static 'js/jquery-1.11.1.min.js' %}"></script>
<script type="text/javascript">
$(document).on('submit', '#comment_form', function (e) {
e.preventDefault();
$.ajax({
type: 'POST',
url: 'http://127.0.0.1:8000/post/12/',
data: {
name: $('#name').val(),
content: $('#content').val(),
created_date: $('#created_date').val(),
post: $('#post').val(),
csrfToken: $('input[name=csrfmiddlewaretoken]').val()
},
success: function () {
alert("YEAH! It works!");
}
}
)
})
</script>
post_detail.html
...
{% include 'blog/comment.html' %}
<hr>
{% for comment in post.comments.all %}
<h4>{{ comment.name }} | <small>{{ comment.created_date|timesince }} önce</small></h4>
<p>{{ comment.content|linebreaks }}</p>
{% endfor %}
urls.py
...
url(r'^post/(?P<pk>\d+)/$', views.post_detail, name='post_detail'),
When I click comment button there is no action. But when I look inspect elements, when I click button it shows Status code:403
Note: I get "YEAH! It works!" alert
You need to return a JsonResponse or a partial template in post_detail method so that you can use these data in ajax success function. I have created a django app for commenting system using ajax response for preventing page refresh. If you are interested Here the package repo
The success function takes an argument, which is the data sent back by the server.
Update your code like this:
success: function (result) {
alert("YEAH! It works!");
}
Related
I'm trying to clone the Instagram web page using Django(version-3.1).
My Django project has an app called 'post'.
One of its template I have a form which is posting a comment to a post. The form post request should call the path('add_comment/',views.add_comment,name='add_comment'), but It's calling path('<slug:slug>/',views.post_details,name='post_details'), instead. And raising DoesNotExist at /post/add_comment error. I added print() statement at the beginning of both add_comment() and post_details() methods to find out which is running when the request is made. I have no idea what I have done wrong.
The project GitHub link - https://github.com/mirasel/Instagram_Clone
the post_details.html template is -
{% extends 'base.html' %}
{% load static %}
{% block title %} post {% endblock %}
{% block profilephoto %} {{ propic.url }} {% endblock %}
{% block body %}
<div>
<div>
<img src="{{post.image.url}}" alt="post" height="250px" width="250px">
</div>
<div>
<a href="{% url 'instagram:profile' post.uploader %}">
<img src="{{uploader.profile_pic.url}}" alt="{{uploader}}" style="border-radius: 50%;" height="24px" width="24px">
{{ post.uploader }}
</a><br>
<p>{{ post.date_published.date }}</p>
</div>
<div>
<p>{{ post.caption }}</p>
</div>
<div>
<form action="{% url 'post:add_comment' %}" id="comment_form" method="POST">
{% csrf_token %}
<textarea name="comment" id="comment" cols="30" rows="1" placeholder="Write a comment..."></textarea>
<input type="hidden" name="slug" id="slug" value="{{post.slug}}">
<!-- <input type="submit" style="display: none;" name="submit"> -->
</form>
<script>
$(function(){
$("#comment").keypress(function (e) {
if(e.which == 13 && !e.shiftKey) {
$(this).closest("form").submit();
e.preventDefault();
}
});
});
</script>
{% endblock %}
the views.py -
from django.shortcuts import render,redirect
from instagram.views import get_nav_propic,get_profile_details
from .models import UserPost,PostComment,PostLike
from django.http import JsonResponse
def get_post_likes(post):
likes = PostLike.objects.filter(post=post)
total_likes = len(likes)
likers = []
for l in likes:
likers.append(get_profile_details(l.liker))
return {'likers':likers,'total_likes':total_likes}
def get_post_comments(post):
comments = PostComment.objects.filter(post=post)
total_comments = len(comments)
commenter = []
comment = []
for c in comments:
commenter.append(get_profile_details(c.commenter))
comment.append(c.comment)
postcomment = zip(commenter,comment)
return {'post_comment':postcomment,'total_comments':total_comments}
def upload_post(request):
if request.method == 'POST':
image = request.FILES['post_img']
caption = request.POST['caption']
uploader = request.user
UserPost.objects.create(uploader=uploader,image=image,caption=caption)
return redirect('instagram:feed')
else:
context = {
'propic' : get_nav_propic(request.user)
}
return render(request,'post/upload_post.html',context)
def post_details(request,slug):
print('I am here in post details')
post = UserPost.objects.get(slug=slug)
context = {
'propic' : get_nav_propic(request.user),
'post' : post,
'uploader' : get_profile_details(post.uploader),
'LIKES' : get_post_likes(post),
'COMMENTS' : get_post_comments(post),
}
return render(request,'post/post_details.html',context)
def add_comment(request):
print('I am here in add comment')
if request.method == 'POST':
post_slug = request.POST.get('slug')
post = UserPost.objects.get(slug=post_slug)
user = request.user
comment = request.POST.get('comment')
PostComment.objects.create(post=post,commenter=user,comment=comment)
return redirect('post:post_details',slug=post_slug)
the urls.py -
from django.urls import path
from . import views
app_name='post'
urlpatterns = [
path('upload_post/',views.upload_post,name='upload_post'),
path('<slug:slug>/',views.post_details,name='post_details'),
path('add_comment/',views.add_comment,name='add_comment'),
]
The error - Error page
Solved
I had to make the URL path of add_comment as following-
#previous one
path('add_comment/',views.add_comment,name='add_comment'),
#modified one
path('comment/add_comment/',views.add_comment,name='add_comment'),
This is because the pattern for the slug URL and add comment URL were similar.
Because Django will process the urlpatterns sequentially, from docs:
Django runs through each URL pattern, in order, and stops at the first
one that matches the requested URL, matching against path_info.
And '/add_comment' is a valid slug <slug:slug>, so post_details will be called.
So you should keep the definition of the most generic url patterns at last:
urlpatterns = [
path('upload_post/',views.upload_post,name='upload_post'),
path('add_comment/',views.add_comment,name='add_comment'),
path('<slug:slug>/',views.post_details,name='post_details'),
]
Hopefully this will work for you.
I have created a wishlist page which lists the items wishlisted by a user. The user can remove any item from the wishlist by clicking on the Remove button. On clicking the remove button, the HTML <form> submits it to the back-end application. The back-end application then removes the item from the wishlist database and redirects back to the same page using return redirect(url_for('wishlist')).
The problem I am facing is that if the user goes back after removing the item from the wishlist he has to go back twice to reach the page from where the user came from. This is caused due to the redirect that I am performing after removing the item which is necessary to show the updated wishlist.
I have also tried render_template() instead of redirect() but it is also causing the same problem.
Code for back-end:
#app.route('/wishlist/',methods=['GET','POST'])
#login_required
def wishlist():
userid=current_user.get_id()
if request.method=='POST':
toRemove=request.form['remove']
deleteWish=session.query(Wishlist).filter_by(userId=userid,productId=toRemove).one()
session.delete(deleteWish)
session.commit()
return redirect(url_for('wishlist'))
subquery=session.query(Wishlist.productId).filter(Wishlist.userId==userid).subquery()
wishes=session.query(Products).filter(Products.id.in_(subquery))
return render_template("wishlist.html",wishes=wishes)
HTML:
<html>
<body>
{% for wish in wishes %}
<img src={{wish.image_path}} width="150" height="200">
</br>
{{wish.material}}
{{wish.productType}}
</br>
{{wish.price}}
</br>
<form action="{{url_for('wishlist')}}" method="POST" target="_self">
<button name="remove" type="submit" value="{{wish.id}}">Remove</button>
</form>
</br>
{% endfor %}
</body>
</html>
Please suggest me a way to prevent this.
You may want to create a different end point for deleting wishes. This endpoint then redirects to your wish list once deletion is done.
FLASK
#app.route('/wishlist/',methods=['GET','POST'])
#login_required
userid=current_user.get_id()
def wishlist():
subquery=session.query(Wishlist.productId).filter(Wishlist.userId==userid).subquery()
wishes=session.query(Products).filter(Products.id.in_(subquery))
return render_template("wishlist.html")
#app.route('/deletewish', methods = ['GET', 'POST']
def deletewish():
if request.method=='POST':
toRemove=request.form['wish_delete_id']
deleteWish=...
session.delete(deleteWish)
session.commit()
return redirect(url_for('wishlist'))
HTML
<html>
<body>
{% for wish in wishes %}
<img src={{wish.image_path}} width="150" height="200">
</br>
{{wish.material}}
{{wish.productType}}
</br>
{{wish.price}}
</br>
<form method="POST" target="_self">
<button class="remove_wish" type="submit" value={{wish.id}}>Remove</button>
</form>
</br>
{% endfor %}`
<script src='path_to_jquery.js'></script>
<script src='path_to_deletewish.js'></script>
</body>
</html>
JS //deletewish.js content
<script>
$(document).ready(function() {
$('.remove_wish').click(function (event) {
event.preventDefault();
$.ajax({
data : {
wish_delete_id : $(this).val();
},
type : 'POST',
url : '/deletewish',
success: function (data) {
location.reload();
},
error: function (e) {
alert('something went wrong')
}
});
});
})
</script>
I would like to show an upload progress bar for S3 uploads from a Django site. Currently without the progress bar being manipulated by JQuery, the uploads are working direct to S3. Once I try to implement the progress bar using JQuery, the upload form still functions as far accepting input and the file, but will not communicate the file to S3.
Here is the upload view:
from .forms import UploadForm
def upload(request):
if request.method == 'POST':
form = UploadForm(request.POST, request.FILES)
if form.is_valid():
form.save()
return redirect('upload')
else:
form = UploadForm()
context = {
'form': form
}
return render(request, 'content/upload.html', context)
Here is the HTML:
{% extends "about/base.html" %}
{% load crispy_forms_tags %}
{% block content %}
{% block navbar %}{% endblock %}
<div class="site-section mb-5">
<div class="container">
<div class="form-register">
<form method="POST" enctype="multipart/form-data">
{% csrf_token %}
<legend>Upload Content</legend>
<div class="form-group">
{{ form | crispy }}
</div>
<button class="btn btn-outline-info" type="submit">Upload</button>
</form>
<div class="progress">
<div id="progressBar" class="progress-bar" role="progressbar" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100" style="width: 0%;">
0%
</div>
</div>
</div>
</div>
{% endblock %}
Here is the JQuery:
$(document).ready(function() {
$('form').on('submit', function(event) {
event.preventDefault();
var formData = new FormData($('form')[0]);
$.ajax({
xhr : function() {
var xhr = new window.XMLHttpRequest();
xhr.upload.addEventListener('progress', function(e) {
if (e.lengthComputable) {
console.log('Bytes Loaded: ' + e.loaded);
console.log('Total Size: ' + e.total);
console.log('Percentage Uploaded: ' + (e.loaded / e.total))
var percent = Math.round((e.loaded / e.total) * 100);
$('#progressBar').attr('aria-valuenow', percent).css('width', percent + '%').text(percent + '%');
}
});
return xhr;
},
type : 'POST',
url : '/upload',
data : formData,
processData : false,
contentType : false,
success : function() {
alert('File uploaded!');
}
});
});
});
I assume there is something I need to change in the JQuery since I am overriding the default submit button action, but I am not sure what exactly to change in order to make sure the file goes to S3 via django-storages and boto3, the packages being used to communicate with S3.
I have a problem with "like" functionality. I want to make it possible to like the post, without overloading the whole page. So I used CBV django connected to ajax.
My problem is that it receives: Not Found: /like/ by pressing the "Like" button.
My view:
class PostLikeView(generic.View):
def post(self, request):
post = get_object_or_404(Post, id=request.POST.get('id'))
is_liked = False
if post.likes.filter(id=request.user.id).exists():
post.likes.remove(request.user)
is_liked = False
else:
post.likes.add(request.user)
is_liked = True
context = {
'post': post,
'is_liked': is_liked,
'total_likes': post.total_likes(),
}
if request.is_ajax():
html = render_to_string('post/like_section.html', context, request=request)
return JsonResponse({'form': html})
Below is jquery code:
<script type="text/javascript">
$(document).ready(function(event){
$(document).on('click', '#like', function(event){
event.preventDefault;
var pk = $(this).attr('value');
$.ajax({
type: 'POST',
url: "{% url 'post:post_like' %}",
data: {'id': pk, 'csrfmiddlewaretoken': '{{ csrf_token }}'},
dataType: 'json',
success: function(response){
$('#like-section').html(response['form'])
console.log($('#like-section').html(response['form']))
},
error: function(rs, e){
console.log(rs.responseText);
},
});
});
});
</script>
url to view:
url(r'^like/$', login_required(PostLikeView.as_view()), name='post_like'),
code in html:
<form action="{% url 'post:post_like' %}" method="post">
{% csrf_token %}
{% if is_liked %}
<button type="submit" id="like" name="post_id" value="{{ post.id }}" class="btn btn-danger">Dislike</button>
{% else %}
<button type="submit" id="like" name="post_id" value="{{ post.id }}" class="btn btn-primary">Like</button>
{% endif %}
</form>
I would like the button to work on the principle of not reloading the whole page.
The issue I think is that you've not actually called event.preventDefault in your click event handler (you're missing the brackets). That means that the submit button submits the form, but the form doesn't contain a parameter named id and so get_object_or_404(Post, id=request.POST.get('id')) raises a 404.
Add the missing brackets to event.preventDefault, and also note that the value of id= attributes on HTML elements should be unique within the page. Change the values of the id= attributes on the <button> elements so that they are unique.
I am implementing Like functionality in Web application. Idea is Simple to List number of Post(Blogs) on Home page and Add a Like Button to each post(Blog). It works fine when I build it with normal
<form action='{% url target %}' method='POST'>
But when I implemented this with AJAX call It only allows me to like or dislike a particular post(blog) a single time.i.e One I liked a Post for first time it works, also when I dislike the same Post It works fine, But when I again Like that Post it throws an django.db.utils.OperationalError: database is locked
Also, when I like same post multiple(4 to 5) times it respond in a weird way. I goes in Loop of liking and dislikig post.
like_section.html
<form id="like-form{{ post.id }}">
{% csrf_token %}
<button type="submit" id="{{ post.id }}btn" name="like" value="{{ post.id }}" class="btn upvote">Like</button>
<script type="text/javascript">
{% for like in post.likes.all %}
{% if like != user %}
dislikingPost("{{ post.id }}btn");
{% else %}
likingPost("{{ post.id }}btn");
{% endif %}
{% endfor %}
$(document).ready(function(event){
$(document).on('click', '#{{ post.id }}btn', function(event){
event.preventDefault();
pk = $(this).attr('value');
$.ajax({
type: 'POST',
url: '{% url "like_post" %}',
data: {
'id': pk,
'csrfmiddlewaretoken': '{{ csrf_token }}'
},
success:function(response){
$('#like-form{{ post.id }}').html(response['form'])
// $('#{{ post.id }}btn').style.color = 'green';
}, error: function(er, e){
console.log(er.responseText);
}
});
});
});
</script>
</form>
views.py:
def like_post(request):
all_posts = Posts.objects.all()
print("Insisde Like Post")
print('ID coming from form is', request.POST.get('id'))
post = get_object_or_404(Posts, id=request.POST.get('id')) # for AJAX call
context = {
'all_posts': all_posts,
'post': post
}
if post.likes.filter(id=request.user.id).exists():
post.likes.remove(request.user) # Liking The Post
print("DisLiking the post")
else:
post.likes.add(request.user)
print("Liking the post")
if request.is_ajax():
print('Hey its an AJAX calls') # TEsting AJAX request
html = render_to_string('like_section.html', context, request=request)
return JsonResponse({'form': html})
Note:
1. I am beginner in AJAX.
2. I know SQLite can not handle redundant calls, But why it was working before without AJAX calls.
3. I am not providing models.py and complete template of home page and I don't think they are required.
The Problem was not with the Django code. It was ajax call which was triggering Database more then one time on a single Button Click.
Adding event.stopImmediatePropagation(); below event.preventDefault(); in ajax call works perfect