0

I am using Ajax to to send a get request from the sever, i am querying and getting a particular product from the product model, i want to return result as JavaScript objects but its return this '{' as i try to access the first value from the responseText[0]. How can i convert data return to js object. here is my code

views.py

def edit_product(request):
    product_id = request.GET.get('product_id')
    print('THIS IS PRODUCT ID ', product_id)
    product = Product.objects.get(pk=product_id)
    data = [
    {
        'name':product.name,
        'brand':product.brand,
        'price':product.price,
        'description':product.description 

    }
]
return HttpResponse(data)

ajax.js

function getProductEditId(product_id){
            //alert(id)

document.getElementById('gridSystemModalLabel').innerHTML='<b> Edit product </b>';
            //change modal header from Add product to  Edit product
            var request = new XMLHttpRequest();
            request.open('GET', '/edit_product/?product_id=' + product_id, true);
            request.onload = function(){
                console.log('hello world', product_id)
                //var data = request.responseText
                var data = JSON.parse(JSON.stringify(request.responseText));
                console.log(data[0])

            }
            request.send();

        }
ade desmond
  • 432
  • 1
  • 8
  • 24
  • get rid of `JSON.stringify` - i expect `request.responseText` is already a `JSON` – messerbill Jan 04 '19 at 21:03
  • **Do not send your JSON data in a list `[...]`** It's known to be [insecure](https://stackoverflow.com/q/3503102/1925257). Send it in a dict `{...}`. – xyres Jan 04 '19 at 21:06
  • @xyres the JSON array vulnerability [was fixed ages ago](https://security.stackexchange.com/questions/155518/why-json-hijacking-attack-doesnt-work-in-modern-browsers-how-was-it-fixed) – ic3b3rg Jan 04 '19 at 21:17
  • `JSON.parse(request.responseText)` should work – ic3b3rg Jan 04 '19 at 21:19
  • @ic3b3rg I'd err on the side of caution, for a user might be running an old browser. Interestingly, I've also never come across a third-party API that sends JSON data in an array. – xyres Jan 04 '19 at 21:34
  • @xyres that issue affected FF 1.5 and 2b - *no one* is using those browsers - claiming JSON arrays are a security vulnerability is FUD - I use JSON arrays all the time – ic3b3rg Jan 04 '19 at 21:38
  • JSON.parse(request.responseText) does not work here is the error i get VM4496:1 Uncaught SyntaxError: Unexpected token ' in JSON at position 1 at JSON.parse () at XMLHttpRequest.request.onload – ade desmond Jan 05 '19 at 04:49

1 Answers1

1

A HTTP response can not contain a dictionary, you can pass data through a specific format, like for example JSON. Django offers some convenience for that with the JsonResponse [Django-doc]:

from django.http import JsonResponse

def edit_product(request):
    product_id = request.GET.get('product_id')
    print('THIS IS PRODUCT ID ', product_id)
    product = Product.objects.get(pk=product_id)
    data = [
        {
            'name':product.name,
            'brand':product.brand,
            'price':product.price,
            'description':product.description 
        }
    ]
    return JsonResponse(data, safe=False)

But as the code hints, this is not safe, since an array at the root level was a famous JSON hijacking exploit.

It is typically better to just pass a dictionary (so no list), and then the safe=False parameter can be removed. Although it is not really "safe" to then just assume that all security exploits are gone.

Alternatively, you can use json.dumps [Python-doc] (which is more or less what JsonResponse does internally), but then you thus will probably end with duplicate code.

At the JavaScript side, you then only need to parse the JSON blob to a JavaScript object:

//change modal header from Add product to  Edit product
var request = new XMLHttpRequest();
request.open('GET', '/edit_product/?product_id=' + product_id, true);
request.onreadystatechange = function() {
    console.log('hello world', product_id)
    if(this.status == 200 && this.readyState == 4) {
        var data = JSON.parse(this.responseText);
        console.log(data[0])
    }
}

It is also not very clear to me why you encapsulate the data in a list here: if the response always contains one element, it makes more sense to just pass the dictionary.

Willem Van Onsem
  • 443,496
  • 30
  • 428
  • 555
  • It is also worth mentioning that `JsonResponse` won't convert `data` to JSON if it's not a dict (unless it is given `safe=False` parameter). Otherwise it will raise error. – xyres Jan 04 '19 at 21:12
  • @xyres: well a problem with the `safe` parameter, is that it gives a false impression that the data is safe then. But it is not said that other exploits could not eventually redefine the root `Object` call. Google for example uses `while(1);` at the top of a JSON to "trick" malicious scripts in getting stuck in an infinite loop. – Willem Van Onsem Jan 04 '19 at 21:24
  • Using a list because i want to be able access the data in javascript objects like this data[0].name, if i use just a dict calling that same code return undefine , so please if there a better way i can avoid this list it will be fine . – ade desmond Jan 05 '19 at 05:12
  • Thanks everyone i finally got it right i remove the list and contain my data in a dict. To access data i just use data.name and it works. Thanks once again – ade desmond Jan 05 '19 at 05:19