'Django: How to POST div element to views.py without reloading the page?

I have been struggling with this problem for more than four days. I have looked at many documentations but nothing helped me. I am working on Django web application development. The problem is that I have to get the contents(i.e. text inside) of a div element through a form submit (submitted using a button). The catch is that the content inside div element is not fixed. It is initially empty, it changes and shows the info of the actions performed in the page. I am trying to save those info into a list on the server side one-by-one. The ideal solution will be "everytime I click save-info button and the info gets added to a list of info present in views.py (webpage not refreshed on button click)"
I researched about posting div elements to server using JQuery and tried myself but could not be successful. Can someone please suggest how do I achieve the task?

My effort:

    <form method="POST" id = 'notes_form' action="##" >
        {% csrf_token %}
        <div id="notes" cols="5" rows="2"></div>
        <input type="submit" id="note_btn_id" value="save info">
    </form>

    <script>
        $(document).ready(function(){
            $('#notes_form').submit(function(event){
                event.preventDefault();
                var notesForm = $(this);
                var posting = $.post(notesForm.attr('action'),notesForm.serialize());
                
                posting.done(function(data){
                    console.log("SUCCESS");
                });
                posting.fail(function(data){
                    console.log("Try again");
                })
            });
        });
        
    </script>

views.pyComplete view function:

def annotate_view(request):
    try:
        request.session.clear_expired()
        
    except:
        print("Error clearing exp sessions")

    img_path =  request.session.get('img_path_loc') #prev session data
    
    data_pos = []
        
    if request.method == "POST":
        print("request method is POST")

        print("posted contents",request.POST)
        if request.POST.get("note_btn_id"):
            content = request.POST['notes']
            data_pos.append(content)
            print(f"Contents received**: {content}")

        
    return render (request, "workpage/testtemplate.html",{
        'image_locs': img_path, #show the data in page when rendered
        'data_pos': data_pos,
    })

Still the server side is unable to get the "notes" element. It shows error showing "notes" is not present( MultiDictKeyError). Moreover, if I comment out request.POST['notes'], the if request.POST.get("note_btn_id"): statement is always false. What should I do?



Solution 1:[1]

This is a way to achieve what I think you want with the django-braces and Jquery approach.

First, install django-braces. This library is a must in all my django projects, because it gives you few useful mixins, mainly related with permissions.

On urls.py:

path('post/asjson/', views.PostCreateAsJSON.as_view(), name='post-asjson'),

On views.py:

from braces.views import JSONResponseMixin

class PostCreateAsJSON(JSONResponseMixin):
    def post(self, request, *args, **kwargs):
        # Whatever you want to do to create the post.
        # You will have your data on request.POST

On your template, I don't think you really need a form. You are trying to get the content of a DIV when you do click a button, so, maybe you only need this:

<div id="notes">{{ current_content|safe }}</div>
{% csrf_token %}
<button id="note_btn_id">{% trans 'Save' %}</button>

If you add {% csrf_token %} anywhere in your template, you will have this hidden input displayed:

<input type="hidden" name="csrfmiddlewaretoken" value="your_csrf_token_value">

On your javascript file:

$( '#note_btn_id' ).on('click', function(e) {
    e.preventDefault()
    const csrf_token = $( 'input[name=csrfmiddlewaretoken]' ).val()
    const contents = $( '#notes' ).text()
    
    $.ajaxSetup({
        beforeSend: function(xhr, settings) {
            xhr.setRequestHeader('X-CSRFToken', csrf_token)
        }
    })

    $.ajax({
        type: 'post',
        url: 'your_PostCreateAsJSON_URL',
        data: {
            contents: contents
        },
        success: function(data, status, jqXHR) {
            console.log('Here you could update your frontend if needed')
        }
    })
}

Maybe not the best way to use csrf_token, but it works for the example. You can take a look a more in depth explanation on Django CSRF documentation.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1