4

In this project i am using a different flow approach. I am not using the traditional django forms neither the django templates tags. I am using Vanilla javascript fetch for all data manipulation. All my fecth configuration are okay i have added enctype="multipart/form-data" and {% csrf_token %} to my form and this is my html corresponding the issue at hand:

<input style="cursor: pointer" type="file" placeholder="Aucun Fichier" id="image_upload" value="Choisir Fichier" name="image_upload" class="img_class" />.

My problem now is that i want to upload an image file to my server. For that purpose i have the following code:

//My event listener submit_btn.addEventListener("click", (event) => { event.preventDefault(); const user = new Users(); user_image_upload = image_upload.value user_image_file_field = image_file_field.files[0] ... // My object i send to the server post_user_info_object = { obj_user_image_upload: user_image_upload, obj_image_file_field: user_image_file_field, .... } } 

When i post the form this is my image printed on the javascript console:

My image information appearing as an array of object with only one element: element 0

Next, when it reaches the server this is how it looks like (i'm posting the code first before the image):

@login_required def edit_profile(request): if request.user.is_authenticated: if request.method == 'POST' or request.method == 'FILES': data = json.loads(request.body.decode("utf-8")) print("Data: ", data) raw_image_file = data["obj_image_file_field"] print('image file: ', raw_image_file) ... 

And the following is the image of the console printout showing the result:

My image element is circled in red and is empty, yet it contains value on the javascript side

Here is the code sending to the server:

class Users { // Sending user info to server async postUserInfo (token, data_elements) { const options = { method: 'POST', body: JSON.stringify(data_elements), headers: { 'Content-type': 'application/json; charset-UTF-8', 'X-CSRFToken': token } } let result = await fetch ('http://127.0.0.1:8000/accounts/edit-profile/', options); let data = await result.json(); return data; } } 

An here is my init code where i run everything:

submit_btn.addEventListener("click", (event) => { event.preventDefault(); const user = new Users(); user_image_file_field = image_file_field.files[0] post_user_info_object = { obj_image_file_field: user_image_file_field } user.postUserInfo(csrftoken, post_user_info_object) .then(user => { console.log(user) window.location.assign('http://127.0.0.1:8000/accounts/edit-profile/') }) .catch(err => console.log(err)); }) 

I have visited virtually all the ressources talking about uploading images with django via fecth but all of the do so using forms and abstract this particular process i am trying to achieve

Please help me on how exactly i should get that image on the django view side, and also why it is empty on the django side while it has value on the javascript side

2
  • i wonder if anyone can see this question. please help. i really cannot figure out a way can i receive at least a clue? Commented Mar 19, 2021 at 19:31
  • more insight to help those currently seeking for this answer: stackoverflow.com/a/75688576/5176969 Commented Mar 9, 2023 at 18:20

1 Answer 1

6

I have been working on a similar problem and here's how I managed to make it work.

First of all, you should not use JSON object to send files to the server. So this part won't work

body: JSON.stringify(data_elements)

There are several ways to encode an image to be able to send it to the server (like encoding it to base64) but the easiest way that I found is just to use the FormData() object

Here's a snippet of my code

let formData = new FormData() formData.append('image', e.target.files[0]) formData.append('account', currentAccount.username) fetch('/api/post/add', { method: 'POST', body: formData }).then( response => response.json()) .then( response => { console.log(response) }) 

You can do async/await instead of promises but you get the idea.

IMPORTANT NOTE: The content type when using FormData is 'Content-Type': 'multipart/form-data' however, you should NOT define ANY content type in this particular request cause it will mess it up. Let the browser define the content type. Why? Read the reason here.

The backend Django part.

Again, we're not dealing with JSON so you can't use

data = json.loads(request.body.decode("utf-8"))

Here's how it should look like:

def add_image(request): if request.user.is_authenticated: if request.method == 'POST': image = request.FILES.get("image") account = request.POST.get("account") 
Sign up to request clarification or add additional context in comments.

3 Comments

For more clarification here, would like to ask whether based on this solution, I would have to then do 2 different sending of data right? because I have all the text data in an object and so the image would have to be in separate handling (formdata) and not in the object where the rest of the data is. The reason is that actually when I look at my flow, I do not use formdata() to send. I break every piece with vanilla js and pack it into an object...so can I do 2 separate requests: one with my object containing the rest of the data and another one with formdata containing only the image binary?
@vially well, you definitely can. although why would you? you can also put text data in a FormData() object by itself or along with the image data just like how I appended the image file and the account username string in my example. but if you really want to do 2 separate requests, you can.
I have come back here to give more insight for those who are currently seeking for the way around this: stackoverflow.com/a/75688576/5176969

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.