How can I send localstorage data from JavaScript ajax call and print return data from views in Django template

I have stored some data on localStorage( Itemnames and ItemIds), As shown on this image:LocalStorage console.log
now I want to send itemid’s to django views from ajax. Filter the products having those id, and return back to template.

I am trying to pass data to views on this way:

$(document).ready(function() {
    var compare = localStorage.getItem("comparisionItems");
    var compareObj = JSON.parse(compare);
    
    
    console.log(compare)
    console.log(compareObj)
    
   
      
      $.ajax({
        url: './compare',
        type: "POST",
        data: {'compare_id': compareObj },
        headers: { "X-CSRFToken": $.cookie("csrftoken") },
        dataType: "json",
        success: function (data) {
            console.log(data)
            
        },
        error: function () {
            alert("Some problem on passing data");
        }
        
    });
});

And my views is :

def compare(request):
is_ajax = request.headers.get('X-Requested-With') == 'XMLHttpRequest'
if is_ajax and request.method == "POST":
    compare_id= request.POST.getlist('compare_id[itemIds]')
    product = get_object_or_404(Products, id=compare_id)
    context={ 'product':product}
    return render (request, './compare.html', context)

My views is failing to render expected record. I think I am messed with passing and getting data-types.

Any help will be highly appreciated.

See the docs for the HttpRequest object

request.POST is used to access HTML form data. To access a JSON submission, use request.body

I tried this way too :

def compare(request):

is_ajax = request.headers.get('X-Requested-With') == 'XMLHttpRequest'

if is_ajax and request.method == "POST":

    data = json.loads(request.body)

    compare_ids = data['compare_id']['itemIds'] if 'itemIds' in data['compare_id'] else []

    products = Products.objects.filter(id__in=compare_ids)

    context={'products':products}

    return render(request,'./compare.html', context) 

Still I am getting error

What error are you getting?
(Please post the complete traceback)

Also, as a side note, that is_ajax setting and conditional is likely superfluous - I personally wouldn’t bother with it.

TypeError at /products/compare

string indices must be integers

Request Method: POST
Request URL: http://127.0.0.1:8000/products/compare
Django Version: 3.2.8
Exception Type: TypeError
Exception Value: string indices must be integers
Exception Location: I:\Projects\djangovenv\Office\bahri\ecommerce\views.py, line 146, in compare
Python Executable: I:\Projects\djangovenv\Scripts\python.exe
Python Version: 3.8.3

Ok, it would have been better to have the traceback from the console log, but I think we can work with this.

What is line 146?

compare_ids = data[‘compare_id’][‘itemIds’] if ‘itemIds’ in data[‘compare_id’] else []

Ok, so in your test case, what specifically is the value of request.body, and therefore data at the line prior to that?
(What does your post request look like?)

{‘compare_id’: ‘{“images”:["/media/products/testimg.jpg","/media/products/testimg2.jpg"],“itemIds”:[“4”,“1”]}’}

This is what passed

I checked printing the value assigned to data, I dont know how can I achieve the task now, could you please guide me?

Assuming that there’s nothing being misrepresented by the print function, it looks like the value part of the object you’re passing is being processed as a string rather than as a nested object.

That gives me a couple ideas you could try - and in no particular order -

  • Set the contentType in your AJAX call to application/json, and processData to false. (See jQuery.ajax() | jQuery API Documentation)

  • Instead of setting data to {'compare_id': compareObj }, just set it to compareObj. That also means that your references in your view will change from data['compare_id']['itemIds'] to data['itemIds'].

  • Call json.loads on data[‘compare_id’].

Superficially, I think any one of these would be enough - the choice comes down to what you’re comfortable with. However, it’s possible that you may need to do both of the first two together to get it to work.

Side note: One of the quickest / easiest ways to see what’s being passed is to look at the network tab within your browser’s developer tools. It’ll show you exactly what’s being sent. Also, if you’re going to be working with AJAX calls on a regular basis, you’re going to find it extremely useful to get comfortable with running your code in the context of a debugger.

I got the id passed to my product variable doing following method:
I passed data to ajax without json.parse, in my context I passed : data: compare,
and updated views as following:

def compare(request):
    is_ajax = request.headers.get('X-Requested-With') == 'XMLHttpRequest'
    if is_ajax and request.method == "POST":             
        data = json.loads(request.body)     
        compare_ids = data['itemIds']      
        products = Products.objects.filter(id__in=compare_ids)      
        context={'products':products}
               return render(request,'./ecommerce/compare.html', context)
    else:
     return render(request,'./ecommerce/compare.html')

Now,
When I print data on html template by doing {{product.name}} it shows blank. I think I should do something with if/else, could you please help me with this?

When you’re posting code here, you need to surround the code with lines of three backtick - ` characters. That means you’ll have a line of ```, then your code, then another line of ```. That forces the forum software to maintain the formatting of your code, which is critical with Python.

corrected, could you please help now?

I don’t see anything wrong with your view. (I’ll assume the first return statement is indented properly.)
Next steps I would take would be to verify that compare_ids is a list of the right datatypes matching your id field of Products and that your products queryset is returning the expected results.

If both of those are correct, then we’d need to see the compare.html template to see how you’re trying to render the data.

Compare.html has simple logic, when the page loads it will send the post data from ajax as shown above and then I am trying to print the product on template via:
{% for products in products %}
{{product.name}}
{% endfor %}

I think first when page loads before sending data will be GET, and then when it sends data it will get records from POST and it should print that data, I am assuming this.
Should I do something on my views to achieve return on this way?

This line is incorrect. Look at it carefully, keeping in mind that the following line is:

sorry I am doing correctly {{products.name}} or {{product.name}} if variable is product. I am aware of this, but data is not showing while on console.log network shows 200 status code. So I think I should do something with views, is there anything that I need to do there?

The fragment you’ve referenced is not the line I pointed out as having the problem.

What specifically is this line doing?

{% for product in products%}

{{product.name}}
{% endfor%}

its what actually I am doing, though its just showing white space