I'm trying to use ajax in Django to post comment in a news website.However it doesn't work.When I click the submit button,it still refreshes the page and make no difference like no ajax.
I'm really new in Django and Ajax.Any friend can help me solve it?
Here is my view.py:
def newsDetailView(request, news_pk):
news = News.objects.get(id=news_pk)
title = news.title
author = news.author_name
add_time = news.add_time
content = news.content
category = news.category
tags = news.tag.annotate(news_count=Count('news'))
all_comments = NewsComments.objects.filter(news=news)
comment_form = CommentForm(request.POST or None)
if request.method == 'POST' and comment_form.is_valid():
if not request.user.is_authenticated:
return render(request, 'login.html', {})
comments = comment_form.cleaned_data.get("comment")
news_comment = NewsComments(user=request.user, comments=comments, news=news)
news_comment.save()
return render(request, "news_detail.html", {
'title': title,
'author': author,
'add_time': add_time,
'content': content,
'tags': tags,
'category': category,
'all_comments': all_comments,
'comment_form': comment_form
})
Here is my news_detail template where I get form data:
{% if user.is_authenticated %}
<form id="js-pl-submit" method="POST" action="">{% csrf_token %}
{% for field in comment_form %}
{% for error in field.errors %}
<div class="alert alert-warning text-center mb-3" role="alert">{{ error }}</div>
{% endfor %}
{% endfor %}
Here in my news_detail template I render all the comments to the template:
{% for user_comments in all_comments %}
<img class="mr-3 comment-avatar rounded-circle"src="{{ MEDIA_URL }}{{ user_comments.user.image }}"alt="Generic placeholder image">
<div class="media-body">
<h6 class="mt-0 mb-1">{{ user_comments.user.username }}</h6>
{{ user_comments.comments }}
</div>
<span>{{ user_comments.add_time }}</span>
{% endfor %}
Here is my Ajax in news_detail template:
$('#js-pl-submit').on('click', function(){
var comments = $("#js-pl-textarea").val()
if(comments == ""){
alert("评论不能为空")
return false
}
$.ajax({
cache: false,
type: "POST",
url:"",
data:{'news_pk':{{ news.id }}, 'comments':comments},
async: true,
beforeSend:function(xhr, settings){
xhr.setRequestHeader("X-CSRFToken", "{{ csrf_token }}");
},
success: function(data) {
if(data.status == 'fail'){
if(data.msg == '用户未登录'){
window.location.href="login";
}else{
alert(data.msg)
}
}else if(data.status == 'success'){
window.location.reload();//刷新当前页面.
}
},
});
return false;
});
Finally here is my form.py of the comment.
def words_validator(comment):
if len(comment) < 4:
raise ValidationError("亲,最少写两个字")
class CommentForm(forms.Form):
comment = forms.CharField(widget=forms.Textarea(), validators=[words_validator])
Add click event on button
not on form
and You have to change that to button
implicitly. By default the type of a button
is submit.
<form method="POST" action="">
<button type="button" id="js-pl-submit">
Remove id
of form. Submit button submits form-data and reload the page.
Your binding is incorrect, you have the click handler on the form it should be a submit handler. If you were binding it to a button then you'd use click a handler.
$('#js-pl-submit').on('submit', function(){//<-- here
var comments = $("#js-pl-textarea").val()
if(comments == ""){
alert("评论不能为空")
return false
}
$.ajax({
cache: false,
type: "POST",
url:"",
data:{'news_pk':{{ news.id }}, 'comments':comments},
async: true,
beforeSend:function(xhr, settings){
xhr.setRequestHeader("X-CSRFToken", "{{ csrf_token }}");
},
success: function(data) {
if(data.status == 'fail'){
if(data.msg == '用户未登录'){
window.location.href="login";
}else{
alert(data.msg)
}
}else if(data.status == 'success'){
window.location.reload();//刷新当前页面.
}
},
});
return false;
});
This could work, it contains some suggestions from your codes.
++ newsDetailView
++ in news_details.html
++ in you scripts
views.py
def newsDetailView(request, news_pk):
#news = News.objects.get(id=news_pk) No need to get the object like this anymore
news = get_object_or_404(News,id=news_pk) #
title = news.title
author = news.author_name
add_time = news.add_time
content = news.content
category = news.category
tags = news.tag.annotate(news_count=Count('news'))
comment_form = CommentForm(request.POST or None)
if request.method == 'POST' and comment_form.is_valid():
# if request.method == 'POST' and request.is_ajax() and comment_form.is_valid(): To make sure it's ajax
if not request.user.is_authenticated:
return JsonResponse({"msg":"You need to login",
"url":'login_url','status':'login_required'})
comments = comment_form.cleaned_data.get("comment")
news_comment = NewsComments(user=request.user, comments=comments, news=news)
news_comment.save()
# This needs to be after request.POST process
all_comments = NewsComments.objects.filter(news=news)
context = {
'title': title,
'author': author,
'add_time': add_time,
'content': content,
'tags': tags,
'category': category,
'all_comments': all_comments,
'comment_form': comment_form,
}
return render(request, "news_detail.html", context)
news_detail.html | Form
{% if user.is_authenticated %}
<form id="js-pl-submit" method="POST" action="">{% csrf_token %}
{% for field in comment_form %}
{% for error in field.errors %}
<div class="alert alert-warning text-center mb-3" role="alert">{{ error }}</div>
{% endfor %}
{% endfor %}
</form>
{% endif %}
news_detail.html | Comments
<div id="comments_section">
{% for user_comments in all_comments %}
<img class="mr-3 comment-avatar rounded-circle" src="{{ MEDIA_URL }}{{ user_comments.user.image }}" alt="Generic placeholder image">
<div class="media-body">
<h6 class="mt-0 mb-1">{{ user_comments.user.username }}</h6>
{{ user_comments.comments }}
</div>
<span>{{ user_comments.add_time }}</span>
{% endfor %}
</div>
JS script
$(document).on('submit','#js-pl-submit',function(){ // Correction : Not click, but submit
var comments = $("#js-pl-textarea").val()
if(!comments){
alert("评论不能为空")
return false
}
$.ajax({
cache: false,
type: "POST",
url:"",
data:{
// 'news_pk':{{ news.id }}, No need to send the news.id
/// you are actually on the instance of `news` Object
'comments':comments,
'csrfmiddlewaretoken':$("input[name=csrfmiddlewaretoken]").val(), // retrieve `csrf_token` from `form`
},
async: true,
success: function(data) {
// Not sure it's the more powerful, but this should work like a charm
if(data.status == 'login_url'){
alert(data.msg);
window.location.href = data.url;
}
// Those 2 next lines are useful if you want to refresh without reload the page.
$("#js-pl-submit").replaceWith($('#js-pl-submit',data));//刷新当前页面.
$("#comments_section").replaceWith($('#comments_section',data));
// This next line will reload the page
windows.location.reload();
},
error:function(){
// Codes here in case of error
},
statusCode:{
404:function(){
alert("Object not found");
},
500:function(){
alert("An error has occured on the server");
},
}
});
return false;
});
Feel free to comment, so that I can edit my answer, to help you succeed.
Finally I made it!Thanks Lord!Very excited!Please check my detailed answer here:Django Ajax Form submit wrongly redirect to another page really appreciate everyone's reply!With your reply I figured out these issue step by step!