how to use ajax function to send form without page getting refreshed, what am I missing?Do I have to use rest-framework for this?

后端 未结 11 2148
花落未央
花落未央 2021-01-05 03:37

I\'m trying to send my comment form using ajax, right now when user inserts a comment then whole page gets refreshed. I want this to be inserted nicely without page getting

相关标签:
11条回答
  • 2021-01-05 04:03

    This is general structure of your comment app. I am assuming you are using Django REST Framework

    - Comment
        - models.py
        - forms.py
        - views.py
    
    • Comment Model (models.py)

      from django.db import models
      
      class Comment(models.Model):
          user = models.ForeignKey(MyProfile)
          post = models.ForeignKey(Post)
          parent = models.ForeignKey("self")
          text = models.TextField()
          path = ...
          ...
      
    • Comment Form (forms.py)

      from django import forms
      from .models import Comment
      
      class CommentForm(forms.ModelForm):
      
          class Meta:
              model = Comment
              fields = ('text', 'post_id', 'parent_id')
      
          post_id = forms.HiddenInput()
          parent_id = forms.HiddenInput()
      
          def __init__(self, *args, **kwargs):
              super().__init__(*args, **kwargs)
      
              self.fields['text'].label = _('Comment')
              self.fields['post_id'].value = self.instance.post.id
              self.fields['parent_id'].value = self.instance.parent.id
      
              self.helper = FormHelper()
              self.helper.form_show_labels = False
              self.helper.layout = Layout(
                  ManageFieldsWrapper(
                      crispy_fields.Field('text')
                  ),
                  crispy_fields.SubmitField(submit_label='Leave your thoughts')
              )
      
    • Comment form view and api view (views.py)

      from rest_framework.views import APIView
      from rest_framework.response import Response
      from rest_framework import status
      from django.http import HttpResponseRedirect
      from django.views.generic.edit import CreateView
      from .forms import CommentForm
      from .models import Comment
      
      
      class CommentFormView(CreateView):
          form_class = CommentForm
      
      
      class CommentAPISubmitView(APIView):
          def post(self, request, format=None):
              #... Your checks goes here ...
              form = CommentForm(request.POST or None)
              if form.is_valid():
                  #... Your saving logic here ..
                  return HttpResponseRedirect(redirect_url)
              else:
                  return HttpResponseRedirect(origin_path)
      
              return Response(status=status.HTTP_400_BAD_REQUEST)
      
    • Finally client side code AJAX/JQuery

      $(document).ready(function() {
          $("#commentForAjax").submit(function( event ) {
              $.ajax({
                  type:'POST',
                  url:'comment/create/',
                  data:{
                      post_id:$('#post_id').val(),
                      origin_path:$('#origin_path').val(),
                      parent_id:$('#parent_id').val(),
                      csrfmiddlewaretoken:$('input[name=csrfmiddlewaretoken]').val()
                  },
                  success: function(response){
      
                  }
              });
              event.preventDefault()
          });
      });
      
    0 讨论(0)
  • 2021-01-05 04:08

    As per your current code It seems like it will always get redirect because after validating the comment form and updating it into database you are returning HttpResponseRedirect which is designed to redirect.

    I think what you want is to update the comment into database and get a success response.

    So to achieve this you need to change the response type, I would suggest return JsonResponse and based on the json response you can update the html as well, I am sure returning json response won't cause redirect your html.

    Let me know if it's clear to you.

    Thanks.

    0 讨论(0)
  • 2021-01-05 04:13

    In your javascript, you call for the class .commentForAjax. You should call the ID:

    $(document).on('submit','#commentForAjax', function(e){
        // ...
    });
    

    Hope this helps. R

    0 讨论(0)
  • 2021-01-05 04:18

    see official document of submit() and serialize() and modify your ajax all like this :

    <script>
         $('#commentForAjax' ).submit(function(e){
          e.preventDefault();
    
          $.ajax({
            type:'POST',
            url:'comment/create/',  // make sure , you are calling currect url
            data:$(this).serialize(),
            success:function(json){              
              alert(json.message); 
              if(json.status==200){
                 var comment = json.comment;
                 var user = json.user;
                 /// set `comment` and `user` using jquery to some element
               }             
            },
            error:function(response){
              alert("some error occured. see console for detail");
            }
          });
         });

    At backend side you are returning HttpResponseRedirect() which will redirect your ajax call to some url(status code=302). I will suggest to return any json response.

    For Django 1.7+ add line from django.http import JsonResponse to return json response

    For pre Django 1.7 use return HttpResponse(json.dumps(response_data), content_type="application/json")

    Modify this portion of your views.py to return Json response

    def comment_create_view(request):
    # you are calling this url using post method 
    if request.method == "POST" and request.user.is_authenticated():
        parent_id = request.POST.get('parent_id')
        post_id = request.POST.get("post_id")
        origin_path = request.POST.get("origin_path")
        try:
            post = Post.objects.get(id=post_id)
        except:
            # you should return from here , if post does not exists
            response = {"code":400,"message":"Post does not exists"}
            return HttpResponse(json.dumps(response), content_type="application/json")
    
        parent_comment = None
        if parent_id is not None:
            try:
                parent_comment = Comment.objects.get(id=parent_id)
            except:
                parent_comment = None
    
            if parent_comment is not None and parent_comment.post is not None:
                post = parent_comment.post
    
        form = CommentForm(request.POST)
      if form.is_valid():
            comment_text = form.cleaned_data['comment']
            if parent_comment is not None:
                # parent comments exists
                new_comment = Comment.objects.create_comment(
                    user=MyProfile.objects.get(user=request.user),
                    path=parent_comment.get_origin, 
                    text=comment_text,
                    post = post,
                    parent=parent_comment
                    )
                response = {"status":200,"message":"comment_stored",
                 "user":new_comment.user, 
                 "comment":comment_text,
                }
                return HttpResponse(json.dumps(response), content_type="application/json")
            else:
                new_comment = Comment.objects.create_comment(
                    user=MyProfile.objects.get(user=request.user),
                    path=origin_path, 
                    text=comment_text,
                    post = post
                    )
                response = {"status":200,"message":"new comment_stored",
                 "user":new_comment.user,
                 "comment":comment_text,}
                return HttpResponse(json.dumps(response), content_type="application/json")
        else:
            messages.error(request, "There was an error with your comment.")
            response = {"status":400,"message":"There was an error with your comment."}
            return HttpResponse(json.dumps(response), content_type="application/json")
    

    You don't have to use rest-framework. But if you use rest-framework for this purpose , it will be easy to implement.

    0 讨论(0)
  • 2021-01-05 04:20

    This is the easiest example of how to implement Ajax forms in conjunction with Django:

    You can use Ajax Post to send JSON to Django and then handle the arguments as a dict(). Here is an example:

    In browser (JQuery/JavaScript):

        function newModule() {
    
            var my_data = $("#my_element").val(); // Whatever value you want to be sent.
    
            $.ajax({
                url: "{% url 'modules' %}",       // Handler as defined in Django URLs. 
                type: "POST",                     // Method.
                dataType: "json",                 // Format as JSON (Default).
                data: {
                    path: my_data,                // Dictionary key (JSON). 
                    csrfmiddlewaretoken: 
                             '{{ csrf_token }}'   // Unique key.
                },
    
                success: function (json) {
    
                    // On success do this.
    
                },
    
                error: function (xhr, errmsg, err) {
    
                    // On failure do this. 
    
                }
    
            });
    

    In server engine (Python):

    def handle(request):
    
        # Post request containing the key.  
        if request.method == 'POST' and 'my_data' in request.POST.keys():
    
            # Retrieving the value.
            my_data = request.POST['my_data']
    
        # ...
    
    0 讨论(0)
  • 2021-01-05 04:21

    After completely reviewing your code and discussing with OP in length. I've managed to resolve the OPs issue.

    1. After removing HttpResponseRedirect I first converted it to JsonResponse and made changes accordingly.

      response_data = {
                           "status":200, "message":"comment_stored", 
                           "parent": True, 
                           "parent_id": parent_comment.id,
                           "comment_count": parent_comment.comment_count()
                       }
      return JsonResponse(response_data)
      
    2. Next step was to simply perform DOM manipulation to display the data fetched from the response. But turns out this was more complicated than expected. So, to simplify it I simply separated the template into 2 parts - one will be the main part and the other containing the HTML of only the comment.

      Using django.template.loader.render_to_string I generated the required HTML to display the comment and sent with the response as a string in JSON.

      html = render_to_string('main/child_comment.html', 
                                       {'comment': [new_comment], 
                                        'user': request.user, 
                                        'comment_form':comment_form
                              })
      response_data = { 
                          "status":200, "message":"comment_stored", 
                          "comment":html, 
                          "parent": True, "parent_id": parent_comment.id,
                          "comment_count": parent_comment.comment_count()
                      }
      return JsonResponse(response_data)
      
    3. Finally, after minor changes (not relevant to the current issue) mainly in the DOM manipulation scripts and in one of the form models, the code worked as expected.

      $('form').submit(function(e) {
          e.preventDefault();
          if ($(this).parents("tr") != 0) {
              parent_id = $(this).parents("tr").attr("id").split("_")[1];
              data_str = $(this).serialize() + "&parent_id=" + parent_id;
          } else {
              data_str = $(this).serialize();
          }
          $(this).parents("tr").attr("id").split("_")[1]
          $.ajax({
              type: 'POST',
              url: '{% url 'comment_create' %}',
              data: data_str,
              success: function(json) {
                  alert(json.message);
                  if (json.status == 200) {
                      var comment = json.comment.trim();
                      var user = json.user;
                      if (!json.parent) {
                          $(comment).insertBefore('.table tr:first');
                      } else {
                          $(comment).insertBefore('#comment_' + json.parent_id + ' #child_comment:first');
                          $(".replies").text("답글" + json.comment_count + "개 모두 보기");
                      }
                  }
      
              },
              error: function(response) {
                  alert("some error occured. see console for detail");
              }
          });
      });
      
    4. BONUS: There was another minor issue which we had faced but I won't discuss it here. I've written a separate answer for it.

    0 讨论(0)
提交回复
热议问题