Solution: Uploading files in Django using ajax with no dependency on JQuery

As the title suggests, here is the code before any further explanation.

{% extends 'informations/userpage.html' %}
{% load static %}
{% block redaction %}
<div class="redaction">
    <form method="POST" enctype="multipart/form-data" action="/redaction/" class="article-post">
        {% csrf_token %}
        <div class="article-picture">
            {% if article.image %}
                {{article.image}}
            {% else %}
                <img class="generic-image" src="{% static 'informations/images/none-picture.svg' %}" alt="Image article">
            {% endif %}
                <img class="edit" id="article-image" src="{% static 'informations/images/edit.svg' %}">
        </div>
        <div id="id01" class="modal" style="display: none;">
            <div class="upload-container">
                <input type='file' name="newImage">
                <div class="button" id="uploadImage" name="upload" value="envoyer">Envoyer</div>
            </div>
        </div>
    </form>
    {% csrf_token %}
    <script id="picturesend">
        var csrf_token = document.getElementsByName('csrfmiddlewaretoken').value
    </script>
    <script type="text/javascript"
            id="django-admin-popup-response-constants"
            src="{% static 'informations/redaction.js' %}">
    </script>
</div>
{% endblock %}
var articleImage = document.getElementById('article-image');
var uploadImage = document.getElementById('uploadPic');

uploadImage.addEventListener('click', displayUpload);
articleImage.addEventListener('click', displayUpload);

function displayUpload() {
    var uploadfile = document.getElementById('id01');
    var uploadPicture = document.getElementById('uploadImage');
    uploadPicture.addEventListener('click', uploadFile);
    uploadfile.style.display='block'
}

function uploadFile() {
    var formData = new FormData();
    var file = document.getElementsByName('newImage');
    var image = document.getElementsByClassName('generic-image')[0];
    formData.append('newImage', file);
    var xhr = new XMLHttpRequest();
    xhr.open('POST', '/upload/', true);
    xhr.onload = function () {
        if (xhr.status === 200) {
            console.log(xhr.responseText);
            image.setAttribute('src',JSON.parse(xhr.responseText));
        } else {
            alert('An error occurred!');
        }
    };
    xhr.setRequestHeader('Content-Type', file.type);
    xhr.setRequestHeader('X-CSRFToken', getCookie('csrftoken'));
    xhr.send(formData);
}

My file model

def userDirectoryPath(instance, filename):
    # file will be uploaded to MEDIA_ROOT/user_<id>/<filename>
    return 'user_{0}/{1}'.format(instance.user.username, filename)

class Media(models.Model):
    user = models.ForeignKey(User, null=True , on_delete=models.CASCADE)
    media = models.FileField(upload_to=userDirectoryPath)

My view handling ajax.

@login_required
def upload_media(request):
    user = request.user
    data = {}

    if request.POST:
        newFile = Media()
        newFile.media = request.FILES['newImage']
        newFile.user = user
        newFile.save()
        data.update({"media_url": newFile.media.url})

    return JsonResponse(data)

With that said, I am looking to send files to my server without using jQuery, save them in the database, and return the URL through JsonResponse for further use with JavaScript.

As a beginner in these technologies, I understand that my code may not follow best practices, but I hope it's clear enough.

The issue I am facing is that upon checking the console log, I see an empty object {}. It seems that the POST method is not being properly recognized. I tried using if request.method == 'POST': but the result is the same. I suspect the problem lies in my JavaScript code, but as I am new to AJAX, I have not been able to find a solution without using jQuery.

If anyone has any suggestions or solutions, or knows where I can find help, I would greatly appreciate it. I am open to providing more details if needed. Thank you for your time and any assistance you can offer.

[UPDATE]

Although the condition request.method == "POST" is true, I am encountering an error within the 'if' block with

MultiValueDictKeyError at /upload/ newImage
. This error is reminiscent of when I forgot to add enctype="multipart/form-data" within a <form>. I am currently stuck at this point.

Answer №1

[RESOLVED] After conducting thorough research, reviewing my code, and making multiple attempts, I was able to identify and rectify errors in my code. Below is the revised code snippet that functions correctly:

function uploadFile() {
    var formData = new FormData();
    var file = document.getElementsByName('newImage')[0];
    var image = document.getElementsByClassName('generic-image')[0];
    formData.append('newImage', file.files[0], file.files[0].name);
    var xhr = new XMLHttpRequest();
    xhr.open("POST", '/upload/', true);
    xhr.onload = function () {
        if (xhr.status === 200) {
            console.log(xhr.responseText);
            image.setAttribute('src',JSON.parse(xhr.responseText));
        } else {
            alert('An error occurred!');
        }
    };
    xhr.setRequestHeader('X-CSRFToken', getCookie('csrftoken'));
    xhr.send(formData);
}

The line

javascript xhr.setRequestHeader('Content-Type', file.type);
is unnecessary, and to retrieve the file, you must use the files attribute of your input element.

var file = document.getElementsByName('newImage')[0];
 formData.append('newImage', file.files[0], file.files[0].name);

Since I am uploading only one file at a time, I specify files[0]. I hope that sharing my mistakes proves beneficial to others.

Until next time! Problem solved, at least for file uploading!

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

What is the best approach for fetching a refined selection of items from an array of IDs using GraphQL?

If I have a list of products stored in my database, it might look something like this items: [ { id: '001', name: 'Product 01', description: 'Awesome product' price: 50.00 }, { ...

Automatically showcase images from a directory upon webpage loading

Is there a way to modify my code so that the images from the first directory are displayed on the page when it loads, instead of waiting for a menu option to be clicked? The page looks empty until a menu option is selected, and I would like the images to s ...

Display data on webpage by returning value from PHP through AJAX and passing it into specified ID

I have successfully implemented a post and comment system on my webpage. Each post on my index.php page allows for comments, which are sent along with the post ID to comment.php. The comment is then inserted into the corresponding record in MySql and retur ...

Exploring Django (DRF) - Utilizing get_queryset to include "images" as a supplementary field in the "Product" model

I'm attempting to create a query set that retrieves all Products. Each Product contains one or more ProductImages, and I aim to include them as an additional field "images" for each product. Thus, the desired response looks like [ { id: 1, name: "pro ...

pressing a button unrelated to the 'close' button still triggers the close event

I have a notification bar that features a button in the center that links to another website. There is also a 'close' button on the far right. However, whenever I click the center button, it also triggers the close button. I tried moving the #cl ...

Issue: React build script does not support conversion from 'BigInt' to 'number' error

After developing the UI using create-react-app, I encountered an issue. The UI works fine with the normal npm start command, but when I try to build it with npm run build, I get an error saying 'Conversion from 'BigInt' to 'number' ...

When a user hovers over an li element, jQuery will dynamically adjust the width of the element based

<ul class="level0"> <li class="level1" id="cat2441"></li> <li class="level1" id="cat2450"></li> <li class="level1" id="cat2455"></li> </ul> <div class="alles-zwei" id="new-cat2441"></div> <div ...

On the first load, Next.js retrieves a token from an API and saves it for later use

Currently working on an application with next.js, the challenge lies in retrieving a guest token from an API and storing it in a cookie for use throughout the entire application. My goal is to have this token set in the cookie before any page is loaded. H ...

Display a JSON object on a web browser

I am trying to display a JSON object on a web browser using HTML. The object is already in a text file and has been properly formatted for readability. My goal is to maintain the same formatting when displaying it on the browser. ...

Uploading to a designated folder using Google Script

Looking to create a form for uploading files, photos, and videos to specific folders in Google Drive using Google Apps Script. However, encountering an error "invalid argument listener". Here is the HTML index: <!DOCTYPE html> <html> &l ...

What's the best way to display alert messages using the alert method in Node.js with Jade?

Is there a way to render a 'Jade view' with data? For example, in the following code: app.get('/', function(req, res){ res.render('alert', {msg: 'hi!'}); }); I attempted to write the Jade code below: (alert.ja ...

How can we delete a specific word from a string if it is found in an

Facing a seemingly simple problem that's proving tricky to solve. I have an array of product names and a sentence. The goal is to remove any product names from the sentence if they appear in it. const products = ["premium t-shirt", "t-shirt", "swea ...

What is the best way to set up localStorage with a multi-dimensional array

I am struggling with modifying my local storage and it's taking up a lot of my time. Initially, I set it up like this: localStorage.setItem('example','{"data": []}'); It was working fine, but now I need to structure it like the ...

Utilizing Conditional Styling for an Array of Objects within a Textarea in Angular 6

My array contains objects structured as follows: list =[ { name:"name1", value:true } { name:"name2", value:false } { name:"name3", value:true } { name:"name4", value:false ...

When you refresh the page, the number of items in the cart displayed on the navbar always shows 0

When using my angular application, I encountered a problem with adding movies to a cart. Although I can successfully add them to the cart and see the correct number of movies reflected in the navbar, upon refreshing the page, the count resets to 0. Here i ...

Django model error: maximum recursion depth has been surpassed

While trying to implement the steps outlined in this tutorial, I encountered the following error message upon saving... RuntimeError at /admin/products/product/2/ maximum recursion depth exceeded Can someone shed some light on why this error is occurring ...

Is Jade monitoring *.jade files?

Though I am not sure of the internal workings of Jade, my best guess is that it compiles each template file once and then employs a compiled and cached version for subsequent HTTP requests. One intriguing observation I have made while running my Express a ...

Exploring and accessing elements and nested objects within a dynamically named element in JavaScript using JSON syntax

Receiving a JSON response from an API, here's what the data looks like: [{ "order_id":"1111", "restaurant_id":"ABC", "fullfillment":"Delivery", "order_channel":" ...

MUI Autocomplete causing a never-ending cycle of requests

One of the challenges I'm facing involves an Autocomplete component in my code. Here's a snippet of the code: <Autocomplete filterOptions={(x) => x} options={items} getOptionLabel= ...

How can I pass an array object from an HTML form that adheres to a Mongoose schema

I have this HTML form that I'm using to create a new document in my mongo database. The document represents notes given to a teacher based on various criteria. I am storing the notes in an array within the note property, each object containing the aut ...