CPC464
CPC464

Reputation: 63

How to to access Ajax POST request from Javascript in Django

I am sending an Ajax POST request to Django from a Javascript modal. The csrf token is included correctly (after much headache...) but for whatever reason, I cannot 'fetch' the request data in my views.py. I have added some comments in the code to indicate what seems to be working

I have been reading everything I could find on this, but still couldn't find the error so any input would be highly appreciated. Thanks!

Javascript

function getMenuItem(id){
    console.log(id); // menuitem id prints correctly

    // Open request to get menuitem
    const request = new XMLHttpRequest();
    request.open('POST', '/menuitem');

    // Include csrf token in header so Django will accept the request
    const header =  "X-CSRFToken"
    const token = Cookies.get('csrftoken'); // Using the js-cookie library
    console.log(token); // token prints correctly
    request.setRequestHeader(header, token);

    // Send request
    request.send(id);

    //Once request is received parse it and insert result in DOM
    request.onload = () => {
        const received = request.responseText;
        console.log(received); // Prints the debug message from Django
        const parsed = JSON.parse(received);
        document.getElementById('menuItem').innerHTML = parsed;
    };
};

views.py

def menuitem(request):
    if request.method == 'POST':
        id = request.body # I have also tried HttpRequest.body  
        print(id) # Does not print 
        menuitem = MenuConfiguration.objects.filter(id=id).all()
        menuitem = serializers.serialize('json', menuitem)
        menuitem = json.loads(menuitem)

        return menuitem

Traceback

Traceback (most recent call last):
  File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/django/core/handlers/exception.py", line 34, in inner
    response = get_response(request)
  File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/django/utils/deprecation.py", line 93, in __call__
    response = self.process_response(request, response)
  File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/django/middleware/clickjacking.py", line 26, in process_response
    if response.get('X-Frame-Options') is not None:
AttributeError: 'list' object has no attribute 'get'
[11/Apr/2019 06:10:18] "POST /menuitem HTTP/1.1" 500 54835

Upvotes: 0

Views: 955

Answers (2)

CPC464
CPC464

Reputation: 63

I made it work with the below adjustments, so now the request is sent correctly and processed by Django and the query result is received by the JS. I had to make a slight hack to remove [] from the response text object in order to enable JSON.parse to process it.

I have a new problem though, which is; getting the values of foreign keys included in the query (i.e. not just the keys as it is the case now). I will post a separate question about that, but please leave a comment if you have a solution for this off the cuff

Javascript

function getMenuItem(id){
    console.log(id);

    // Open request to get menuitem
    const request = new XMLHttpRequest();
    request.open('POST', '/menuitem');

    // Include csrf token in header so Django will accept the request
    const header =  "X-CSRFToken";
    const token = Cookies.get('csrftoken'); //Using the js-cookies library
    request.setRequestHeader(header, token);

    // Formdata object to structure data as if submitted from a form
    const data = new FormData();
    data.append('id', id);

    // Send request
    request.send(data);

    console.log("Request sent");

    //Once request is received parse it and insert result in DOM
    request.onload = () => {
        const received = request.responseText;
        console.log("Data as received:  " + received);

        // Remove [] from response text
        removedfirst = received.substring(1);
        removedlast = removedfirst.substring(0, removedfirst.length-1);
        console.log("Data with [] removed: " + removedlast);

        // Parse to JS object
        const parsed = JSON.parse(received);
        console.log("Output of JSON.parse:");
        console.log(parsed);

        // Insert value into DOM
        document.getElementById('outputField').innerHTML = parsed[0].fields.base;
    };
};  

views.py

def menuitem(request):
    if request.method == 'POST':
        # Get product id from request
        id = request.POST.get('id')

        # Retrieve data for specific product id
        menuitem = MenuConfiguration.objects.filter(id=id).all()

        # Turn query response into JSON 
        data = serializers.serialize('json', menuitem)

        # Return a HttpResponse containing the JSON data
        return HttpResponse(data, content_type='application/json')

Output from JS console:

console logs

Upvotes: 1

Will Keeling
Will Keeling

Reputation: 23004

There's a few things to address here.

In your Javascript code you should send the id value correctly encoded as a form parameter using the key=val syntax:

request.send("id=" + id);

Then in your view, you should retrieve the value from the POST dictionary:

if request.method == 'POST':
    id = POST['id']  # Retrieve the value of the id parameter

Lastly your view must return an HttpResponse. Since you're looking to return JSON, you should pass that into the HttpResponse and set the content_type argument to application/json:

if request.method == 'POST':
    id = POST['id']
    menuitem = MenuConfiguration.objects.filter(id=id).all()
    data = serializers.serialize('json', menuitem)

    # Return a HttpResponse containing the JSON data
    return HttpResponse(data, content_type='application/json')  

Upvotes: 0

Related Questions