How to upload multiple images to Django? - javascript

I am trying to send some data from the client side (react native) that includes a few images so I append them to formdata and successfully send it through a post request but I am having trouble figuring out how to handle it on the server side.
My react code:
const post = async () => {
const token = await getToken();
const [description, setDescription] = useState('');
const formData = new FormData();
images.forEach((image) => {
formData.append(`images`, {
uri: image,
type: 'image/jpeg',
name: image,
});
});
formData.append('description', description);
console.log('formdata:', formData);
try {
await axios.post(URL, formData._parts, {
headers: {
'Content-Type': 'multipart/form-data',
Authorization: token,
},
});
} catch (e) {
console.log(e);
}
};
when i console log formData._parts on client side i get:
formdata: [["images", {"name": "/Library/Developer/CoreSimulator/Devices/123.jpg", "type": "image/jpeg", "uri": "/Library/Developer/CoreSimulator/Devices/123.jpg"}], ["images", {"name": "/Library/Developer/CoreSimulator/Devices/456.jpg", "type": "image/jpeg", "uri": "/Library/Developer/CoreSimulator/Devices/456.jpg"}], ["description", "Test"]]
It post request only works whenn i send formData._parts but not when i send just formData
on my server side (django/drf):
models.py:
class Post(models.Model):
user_id = models.ForeignKey(
User, on_delete=models.CASCADE, default=None
)
images = models.FileField(
max_length=3000, default=None, null=True, blank=True, upload_to='media/post_images')
description = models.TextField(null=False, default=None)
date = models.DateTimeField(editable=False, auto_now_add=True)
serializers.py:
class PostSerializer(serializers.ModelSerializer):
images = serializers.FileField()
class Meta:
model = Post
fields = "__all__"
views.py
class PostView(APIView):
serializer_class = PostSerializer
parser_classes = (MultiPartParser, FormParser)
def post(self, request, format=None):
form_data = request.data
images = form_data.get('images')
description = form_data.get('description')
user_id = self.request.user
print(form_data)
post = Post.objects.create(
images=images, description=description, user_id=user_id)
post.save()
serializer = PostSerializer(post)
return Response(serializer.data, status=status.HTTP_201_CREATED)
when i print the form_data in python i get:
<QueryDict: {'0': ['images'], '1.uri': ['/Library/Developer/CoreSimulator/Devices/123.jpg'], '1.type': ['image/jpeg'], '1.name': ['/Library/Developer/CoreSimulator/Devices/123.jpg'], '1.0': ['images'], '1.1.uri': ['/Library/Developer/CoreSimulator/Devices/456.jpg'], '1.1.type': ['image/jpeg'], '1.1.name': ['/Library/Developer/CoreSimulator/Devices/456.jpg'], '2.0': ['description'], '2.1': ['Test']}>
How can i extract the data and save it to the database?

Django is handling that for you. You can try to access your images with:
request.FILES.getlist("images")
This will give you a list of all the images that are found in the submitted form.
EDIT:
For the Backend actually being able to read the data, it obviously also has to be send. To append the data you can use something like this:
var formData = new FormData();
formData.append('avatar', {uri: this.state.avatar.uri, name: 'yourname.jpg', type: 'image/jpg'});
let response = await fetch(url, {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'multipart/form-data',
'Authorization': ' Token '+accessToken,
},
body: formData
});

Related

Getting empty data field at backend when parsing formData using fetch

I am trying to send input fields' data to back end using fetch. I used formData.append to combine the data. when the fetch runs on backend I am getting empty list.
async function autosave()
{
let formdata =new FormData();
let blogImage = document.querySelector("#blog_image").files[0];
let imageName = document.querySelector("#blog_image").files[0].name;
let blogTitle = blog_title.value.trim();
let contentType = document.querySelector("#content_type").checked;
let blogId = document.querySelector("#id_val").value;
let blogContent = editorbody.innerHTML;
// console.log(document.querySelector("#blog_image").files[0])
formdata.append("blog_image", blogImage, imageName)
formdata.append("blog_title", blogTitle);
formdata.append("content_type", contentType)
formdata.append("blog_id", blogId);
formdata.append("content",blogContent)
await fetch("/blog/autosave/",{
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
'mode':'no-cors'
},
method: "POST",
body:JSON.stringify(formdata)
}).then((res) => {return res.json()})
.then((data) => {
if (data.status == 200){
// function savesuccessFun();
console.log("Blog saved successfully");
}
else{
// savefailFun();
console.log("Opps blog can not be saved");
}
}).catch(err => console.log(err));
I know only front end. at back end we are getting data using data = json.loads(request.body)
NOTE: I mage should not be send in base64 format.
All variables are taking data from form fields.

Why am I getting a 500 when uploading file via the browser but not via Postman? [duplicate]

Using raw HTML when I post a file to a flask server using the following I can access files from the flask request global:
<form id="uploadForm" action='upload_file' role="form" method="post" enctype=multipart/form-data>
<input type="file" id="file" name="file">
<input type=submit value=Upload>
</form>
In flask:
def post(self):
if 'file' in request.files:
....
When I try to do the same with Axios the flask request global is empty:
<form id="uploadForm" enctype="multipart/form-data" v-on:change="uploadFile">
<input type="file" id="file" name="file">
</form>
uploadFile: function (event) {
const file = event.target.files[0]
axios.post('upload_file', file, {
headers: {
'Content-Type': 'multipart/form-data'
}
})
}
If I use the same uploadFile function above but remove the headers json from the axios.post method I get in the form key of my flask request object a csv list of string values (file is a .csv).
How can I get a file object sent via axios?
Add the file to a formData object, and set the Content-Type header to multipart/form-data.
var formData = new FormData();
var imagefile = document.querySelector('#file');
formData.append("image", imagefile.files[0]);
axios.post('upload_file', formData, {
headers: {
'Content-Type': 'multipart/form-data'
}
})
Sample application using Vue. Requires a backend server running on localhost to process the request:
var app = new Vue({
el: "#app",
data: {
file: ''
},
methods: {
submitFile() {
let formData = new FormData();
formData.append('file', this.file);
console.log('>> formData >> ', formData);
// You should have a server side REST API
axios.post('http://localhost:8080/restapi/fileupload',
formData, {
headers: {
'Content-Type': 'multipart/form-data'
}
}
).then(function () {
console.log('SUCCESS!!');
})
.catch(function () {
console.log('FAILURE!!');
});
},
handleFileUpload() {
this.file = this.$refs.file.files[0];
console.log('>>>> 1st element in files array >>>> ', this.file);
}
}
});
https://codepen.io/pmarimuthu/pen/MqqaOE
If you don't want to use a FormData object (e.g. your API takes specific content-type signatures and multipart/formdata isn't one of them) then you can do this instead:
uploadFile: function (event) {
const file = event.target.files[0]
axios.post('upload_file', file, {
headers: {
'Content-Type': file.type
}
})
}
Sharing my experience with React & HTML input
Define input field
<input type="file" onChange={onChange} accept ="image/*"/>
Define onChange listener
const onChange = (e) => {
let url = "https://<server-url>/api/upload";
let file = e.target.files[0];
uploadFile(url, file);
};
const uploadFile = (url, file) => {
let formData = new FormData();
formData.append("file", file);
axios.post(url, formData, {
headers: {
"Content-Type": "multipart/form-data",
},
}).then((response) => {
fnSuccess(response);
}).catch((error) => {
fnFail(error);
});
};
const fnSuccess = (response) => {
//Add success handling
};
const fnFail = (error) => {
//Add failed handling
};
This works for me, I hope helps to someone.
var frm = $('#frm');
let formData = new FormData(frm[0]);
axios.post('your-url', formData)
.then(res => {
console.log({res});
}).catch(err => {
console.error({err});
});
this is my way:
var formData = new FormData(formElement);
// formData.append("image", imgFile.files[0]);
const res = await axios.post(
"link-handle",
formData,
{
headers: {
"Content-Type": "multipart/form-data",
},
}
);
How to post file using an object in memory (like a JSON object):
import axios from 'axios';
import * as FormData from 'form-data'
async function sendData(jsonData){
// const payload = JSON.stringify({ hello: 'world'});
const payload = JSON.stringify(jsonData);
const bufferObject = Buffer.from(payload, 'utf-8');
const file = new FormData();
file.append('upload_file', bufferObject, "b.json");
const response = await axios.post(
lovelyURL,
file,
headers: file.getHeaders()
).toPromise();
console.log(response?.data);
}
There is an issue with Axios version 0.25.0 > to 0.27.2 where FormData object in a PUT request is not handled correctly if you have appended more than one field but is fine with one field containing a file, POST works fine.
Also Axios 0.25.0+ automatically sets the correct headers so there is no need to specify Content-Type.
For me the error was the actual parameter name in my controller... Took me a while to figure out, perhaps it will help someone. Im using Next.js / .Net 6
Client:
export const test = async (event: any) => {
const token = useAuthStore.getState().token;
console.log(event + 'the event')
if (token) {
const formData = new FormData();
formData.append("img", event);
const res = await axios.post(baseUrl + '/products/uploadproductimage', formData, {
headers: {
'Authorization': `bearer ${token}`
}
})
return res
}
return null
}
Server:
[HttpPost("uploadproductimage")]
public async Task<ActionResult> UploadProductImage([FromForm] IFormFile image)
{
return Ok();
}
Error here because server is expecting param "image" and not "img:
formData.append("img", event);
public async Task<ActionResult> UploadProductImage([FromForm] IFormFile image)

Axios POST request: Content-type is set, but inside spring it's empty

I'm sending video as POST request using Axios with 'Content-Type': 'multipart/form-data', but inside Spring I see the following error:
"[org.springframework.web.HttpMediaTypeNotSupportedException: Content type '' not supported]"
The Axios code :
async function uploadPost() {
const type = 'video/mp4';
let data = new FormData();
const videoUri = imagePreview;
data =
('video',
{
name: 'mobile-video-upload',
type,
videoUri,
});
axios({
method: 'post',
url: 'http://localhost:8080/post/upload',
body: data,
headers: {
'Content-Type': 'multipart/form-data',
},
}).catch(function(error) {
console.log(error);
});
The function inside Spring :
#CrossOrigin
#ResponseBody
#RequestMapping(value = "/post/upload", method = RequestMethod.POST, consumes = "multipart/form-data")
public String create(#RequestParam("file") MultipartFile file) {
Thanks in advance.
Assuming Spring code to be correct, please try with minor changes with Axios.
const axios = require('axios')
const qs = require('querystring')
....... other code .....
const config = {
headers: {
'Content-Type': 'multipart/form-data'
}
}
axios.post(url, qs.stringify(requestBody), config)
.then((result) => {
// Do somthing
})
.catch((err) => {
// Do somthing
})

How to recive uploded file in nodejs

i have a redux-from submission, console log look like this
{
id: "x",
parentId: "b",
editing: true,
logo: FileList,
}
Logo FileList contains my uploaded file name and file, i think
0: File(19355) {name: "11964821.jpeg", lastModified: ......
using fetch to send to nodejs, image contain my files and above data
function Update(image) {
const requestOptions = {
method: 'POST',
headers: { ...authHeader(), 'Content-Type': 'application/x-www-form-urlencoded' },
body: JSON.stringify(image)
};
return fetch(`${apiUrl}/API`, requestOptions).then(handleResponse)
.then( data => { return data; });
}
but this data not receiving nodejs, because is tried re.file etc.. its shows undefined
app.post('/image', upload.single('logo'), function (req, res, next) {
})
include formdata
const onSubmit = (image, dispatch)=>{
var formData = new FormData();
formData.append('logo',image.logo[0]);
var imageNew = {...image,formData};
dispatch(imageActions.companyProfileLogoUpdate(imageNew)) ;
}
now log is
formData: FormData {}
id: "5c66478b0814720a4365fe72"
logo: FileList {0: File(19355), length: 1}
parentId: "5c66478b0814720a4365fe71"
let formData = new FormData();
formData.append('logo' , {{your image file}}
// upload file as
let result = await sendServerRequestForForm(url,formData);
function sendServerRequestForForm(url,data) {
var promise = new Promise(function(resolve) {
resolve($.ajax({
url,
method : 'POST',
data,
processData: false,
contentType: false,
success: function(data) {
return data
},
error: function (err) {
try{
let responseStatus = err.responseJSON
// watch your response
}catch (e) {
console.log('Field to get response');
}
}
}));
});
return promise
}
for fetch API you can try this
let formData = new FormData();
formData.append('logo', fileList[0]);
fetch(url, {
method: 'post',
body: data,
})
.then(…);
move formData to fetch file and remove header content type, Try this
function Update(image) {
var formData = new FormData();
formData.append('logo',image.logo[0]);
const requestOptions = {
method: 'POST',
headers: { ...authHeader() },
body: formData
};
return fetch(`${apiUrl}/API`, requestOptions).then(handleResponse)
.then( data => { return data; });
}
First thing is for using fetch api for post content-type header should match typeof body. since your body is json stringified your contentType header should be 'application/json' . more about this .
Second. since you want to upload an image which a file you should use FormData without requirement of setting contentType: like below:
let formData = new FormData();
formData.append('logo', image.logo[0]);
const requestOptions = {
method: 'POST',
body: formData
};
fetch(`${apiUrl}/API`, requestOptions)
.then(handleResponse)...

Sending image and JSON simultaneously

I want to pass JSON object and image at the same time from react to my django rest api.
I've tried some solutions from this forum and tutorials but nothing worked in my case. Previously I have been using JSON.stringify on state fields and that worked but i couldn't pass image and now i ended up on something like this.
postData.js
let formData = new FormData();
const { title, description, image, ingredient, step } = this.state;
formData.append('image', image);
formData.append('title', title);
formData.append('description', description);
formData.append('ingredient', ingredient);
formData.append('step', step);
let conf = {
method: 'post',
body: formData,
headers: new Headers({
'Content-Type': 'multipart/form-data',
'Accept': 'application/json'
})
};
fetch('http://127.0.0.1:8000/api/', conf)
.then(res => {
this.props.history.push('/');
})
.catch(err=>{console.log(err)})
serializers.py
class RecipeSerializer(serializers.ModelSerializer):
ingredient = IngredientSerializer(many=True, required=False)
step = StepSerializer(many=True, required=False)
class Meta:
model=models.Recipe
fields=('id', 'title', 'description', 'image', 'ingredient', 'step', )
def create(self, validated_data):
ingredient_data = validated_data.pop('ingredient')
step_data = validated_data.pop('step')
recipe = models.Recipe.objects.create(**validated_data)
for ingredient in ingredient_data:
models.Ingredient.objects.create(recipe=recipe, **ingredient)
for step in step_data:
models.Step.objects.create(recipe=recipe, **step)
return recipe
views.py
class ListRecipes(generics.ListCreateAPIView):
queryset = Recipe.objects.all()
serializer_class = RecipeSerializer
class DetailRecipe(generics.RetrieveUpdateDestroyAPIView):
queryset = Recipe.objects.all()
serializer_class = RecipeSerializer
I always get POST http://127.0.0.1:8000/api/ 400 (Bad Request) error.
--EDIT--
I changed the code and created new endpoint for uploading images and technically it works but I'm trying to append image and created recipe id to FormData() and when I log it to the console it contains both of them but when I'm printing it on the backend it contains only image.
postData.js
formData.append('id', this.state.id);
formData.append('image', image, image.name);
for(let key of formData.entries()){
console.log(key);
}
let data = {
method: 'post',
body: formData,
headers: new Headers({
'Accept': 'application/json'
})
};
fetch('http://127.0.0.1:8000/api/images/', data)
.then(res => {
console.log(res);
})
.catch(err=>{
console.log(err);
})
serializers.py
class ImageSerializer(serializers.ModelSerializer):
class Meta:
model = models.Image
fields = ('id', 'image', )
def create(self, validated_data):
print(validated_data)
recipe = models.Recipe.objects.get(id=validated_data.id)
image = models.Image.objects.create(recipe=recipe, **validated_data)
return image
You should add the DRF MultiPartParser to your views' parser_classes

Categories

Resources