xdan
xdan

Reputation: 103

How can I read a file from ajax call in Django?

I'm working in Django. I need to upload a txt file and print its content in a table. I've tried many things but none of them work. Someone recommended that I just print the table in an ajax call, but it's not working. Here's what I'm trying:

I'm showing a form to upload the file:

class UploadFileForm(forms.Form):
    file = forms.FileField(label = "File:")

I'm returning the form in a view:

def upload(request):
    form = UploadFileForm()
    return render(request, 'upload.html', {'form': form})

I'm printing the form in the template:

<form method="post" enctype="multipart/form-data">
    {% csrf_token %}
    {{ form.as_p }}            
</form>

Then I have a button to confirm the upload:

<button id="upload">Upload file</button>

And here's where I try to print the table in a fetch, which is not working:

var upload = document.getElementById("upload");
upload.addEventListener("click", function(){
    const url = "{% url 'table' %}";
    fetch(url, {method:'POST'}).then(response => response.json()).then(function(data){
        var table = document.getElementById('table');
        tableRow1.innerHTML = data.tableHTML;
    })
})

The url 'table' goes to this function:

def table(request):
    data = file_to_HTML(request.FILES['file'])
    json_response = {"tableHTML":data}
    return JsonResponse(json_response)

The problem here is that the table isn't printed at all and I get the following error:

Internal Server Error: /table/
Traceback (most recent call last):
  File "C:\Users\Daniel\miniconda3\envs\env1\lib\site-packages\django\utils\datastructures.py", line 78, in __getitem__
    list_ = super().__getitem__(key)
KeyError: 'file'

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "C:\Users\Daniel\miniconda3\envs\env1\lib\site-packages\django\core\handlers\exception.py", line 34, in inner
    response = get_response(request)
  File "C:\Users\Daniel\miniconda3\envs\env1\lib\site-packages\django\core\handlers\base.py", line 115, in _get_response
    response = self.process_exception_by_middleware(e, request)
  File "C:\Users\Daniel\miniconda3\envs\env1\lib\site-packages\django\core\handlers\base.py", line 113, in _get_response
    response = wrapped_callback(request, *callback_args, **callback_kwargs)
  File "C:\Users\Daniel\miniconda3\envs\env1\lib\site-packages\django\views\decorators\csrf.py", line 54, in wrapped_view
    return view_func(*args, **kwargs)
  File "C:\Users\Daniel\Trabajo\module1\app1\views.py", line 22, in table
    data_list = read_bank_file(request.FILES['file'])
  File "C:\Users\Daniel\miniconda3\envs\env1\lib\site-packages\django\utils\datastructures.py", line 80, in __getitem__
    raise MultiValueDictKeyError(key)
django.utils.datastructures.MultiValueDictKeyError: 'file'

I don't know what is going on here. If someone can help me print the table, I would really appreciate it. Printing it in a different page is fine, I just can't print it at all.

Upvotes: 2

Views: 765

Answers (2)

xdan
xdan

Reputation: 103

I solved it by using JQuery and changing a bunch of stuff in the ajax call:

-Trigger the call when the form is submitted, and use event.preventDefault() to stop it from being actually submitted.

-Sending the form to Django inside a FormData object.

-Using processData: false and contentType: false.

Here's the full Ajax call:

$("#formulario").submit(function(event){
    event.preventDefault();
    var formData = new FormData(this);
    $.ajax({
        url : "{% url 'table' %}",
        type: "POST",
        processData: false,
        contentType: false,
        data: formData,
        success: function (data){
            $("#tableData").append(data.tableHTML);
        }
    })
});

Upvotes: 2

Shayestehhs
Shayestehhs

Reputation: 3

For getting files from the request you can do something like this.

Update

def get_file_data_from_ajax(request):
    if not request.is_ajax():
        return BadRequest

    form = forms.UploadFileForm(request.POST, request.FILES or None)
    if not form.is_valid():
        return BadRequest

    info_form = form.save(commit=False)
    info_form.user = request.user if requset.user.is_authenticated else None
    info_form.is_active = True
    info_form.save(commit=True)

    return JsonResponse({'status':'form is valid'})

Upvotes: 0

Related Questions