1

When I use ajax to submit a comment form in Django,the page will redirect to a blank page shows me the success data:

{"status":"success", "msg":"添加成功"}

,but not stay in current page.I want the page stay in current page and show me the new comment.

Here is my update_comment view:

def update_comment(request, news_pk):
    news = get_object_or_404(News, id=news_pk)
    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 redirect(reverse('news:news_detail', kwargs={'news_pk': news.id}))
        return HttpResponse('{"status":"success", "msg":"添加成功"}', content_type='application/json')
    else:
        return HttpResponse('{"status":"fail", "msg":"添加失败"}', content_type='application/json')

Here is my ajax:

$(document).on('submit', 'comment_form', function(e){
        e.preventDefault();

        $.ajax({
            cache: false,
            type: "POST",
            url:"{% url 'operation:update_comment' news.id %}",
            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();//refresh current page.
                }

                },
        });
    });

Here is my form:

<form id="comment_form" action="{%  url 'operation:update_comment' news.id %}" method="POST" >
{% csrf_token %}

<textarea id="comment_textarea"name="comment"></textarea>

<input type="submit" value="Submit"> </input>

</form>
William
  • 3,724
  • 9
  • 43
  • 76
  • The only thing I can think of is that you're actually submitting the form directly, not just via the ajax call, otherwise there's no way you would see the blank page with the status message. Check in your debugger/console if your `update_comment` view is called 2 times. Try adding `e.stopPropagation();` as well after the call to `preventDefault()` – dirkgroten Apr 28 '18 at 09:43
  • Actually, you might want to add `return false;` at the end, after the call to `$.ajax()`. – dirkgroten Apr 28 '18 at 09:49
  • Also instead of reloading the page in your ajax call, I would create the comment div (the one that was just posted) in place in case of success, better user experience. – dirkgroten Apr 28 '18 at 09:51
  • Very good advice,I will check them,thank you very much!Have a nice weekend!:) – William Apr 28 '18 at 12:26
  • Finally I made it!Please check my answer!Thank you so much! – William Apr 28 '18 at 14:46

2 Answers2

2

Finally I made it!Thanks Lord!Very excited!

I have Three major issues in my previous code.

First:Since the ajax will post the news_pk to the view update_comment,so I don't need add news_pk in this view's url and template(in the url of <form> tag and the url in the ajax),so I removed them,or the data will still pass through Form but not ajax.

Second:My binding is incorrect,I have the click handler on the form it should be a submit handler. If I was binding it to a button then I'd use click a handler.Ajax not work in Django post But for this part I'm still a some confused,between the button summit way and form submit way.

The third issue is I mistaked 'comments' and 'comment'.'comment' is the name attribute of <textarea> ,through which forms.py gets the data.

comments is defined by ajax through var comments = $("#js-pl-textarea").val(), so in the view I need use comments = request.POST.get("comments", "") but not comment,that's the reason why 'post failed'.

Following is my code.

Here is the ajax:

 $("#comment_form").submit(function(){
        var comments = $("#js-pl-textarea").val()

        $.ajax({
            cache: false,
            type: "POST",
            url:"{% url 'operation:update_comment' %}",
            data:{'news_pk':{{ news.pk }}, '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();//refresh current page.
                }

                },
        });
        return false;

    });

Here is my udate_comment view:

@login_required
def update_comment(request):
        news_pk = request.POST.get("news_pk", 0)
        comments = request.POST.get("comments", "")
        if int(news_pk) > 0 and comments:
            news_comments = NewsComments()
            news = News.objects.get(id=int(news_pk))
            news_comments.news = news
            news_comments.comments = comments
            news_comments.user = request.user
            news_comments.save()
            return HttpResponse('{"status":"success", "msg":"添加成功"}', content_type='application/json')
        else:
            return HttpResponse('{"status":"fail", "msg":"添加失败"}', content_type='application/json')

Here is my form in template:

<form id="comment_form" action="{%  url 'operation:update_comment'%}" method="POST" >
{% csrf_token %}

<textarea id="js-pl-textarea"name="comment"></textarea>

<input type="submit" value="Submit"> </input>

</form>

I really appreciate everyone's reply!With your reply I figured out these issue step by step!

William
  • 3,724
  • 9
  • 43
  • 76
1

I have something similar in my project. Its a script to like a song. I'm just gonna put the relevant codes here.

  1. The ajax script. I put this script in a separate file named like_script.html. I call it in a template using django template include

<script>
    $('#like').click(function(){
          $.ajax({
                   type: "POST",
                   url: "{% url 'song:like_song' %}",
                   data: {'pk': $(this).attr('pk'), 'csrfmiddlewaretoken': '{{ csrf_token }}'},
                   dataType: "json",
                   success: function(response) {
                          alert(response.message);
                    },
                    error: function(rs, e) {
                           alert(rs.responseText);
                    }
              }); 
        })
    </script>

The django view

import json
from django.http import HttpResponse
from django.contrib.auth.decorators import login_required
from django.views.decorators.http import require_POST
@login_required
@require_POST
def song_like_view(request):
    if request.method == 'POST':
        user = SiteUser.objects.get(user=request.user)
        pk = request.POST.get('pk', None)
        song = get_object_or_404(Song, pk=pk)

        if song.likes.filter(pk=user.pk).exists():
            song.likes.remove(user)
            song.like_count = song.likes.count()
            song.save(update_fields=['like_count'])
            message = "You unstarred this song.\n {} now has {} stars".format(song.title, song.like_count)
        else:
            song.likes.add(user)
            song.like_count = song.likes.count()
            song.save(update_fields=['like_count'])
            message = "You starred this song.\n {} now has {} stars".format(song.title, song.like_count)
    context = {'message' : message}
    return HttpResponse(json.dumps(context), content_type='application/json')

The url

urlpatterns = path("like/", views.song_like_view, name='like_song'),
  1. The template where the script is called

    <a class="btn btn-sm btn-primary" href="" id="like" name="{{ song.pk }}" value="Like"></i> Unstar</a>
     {% include 'like_script.html' %}

Same button for like and unlike. I hope you can follow the logic to make yours right. Notice that in your view you don't need to include the pk. Just get it from the POST data pk = request.POST.get('pk', None)

chidimo
  • 2,684
  • 3
  • 32
  • 47
  • Hi thank you for reply.Could you give me more detail advice.I'm really news in Django and have no idea where to put the context.Thank you very much! – William Apr 26 '18 at 21:43
  • Formatting the code is proving to be a nightmare. Doesn't work as it should – chidimo Apr 26 '18 at 22:09
  • Thank you for your reply man!It seems not work,it still redirect to another blank page with some message. – William Apr 26 '18 at 23:32
  • Really appreciate for your reply,it is really helpful for me,and guide me fix my code finally! – William Apr 28 '18 at 14:42