I am trying to upload an image with other form data using Django & React.
I get 400 Bad Request.
First API should create a new product without an image then the second one will edit the product and add an image to it.
when i create a product in the client side ,I get 200 status to the first API and 400 to the second one.
Using FileReader allowed the browser to read the url of the image.
Here is My code:
React
export default function Add(){
let [formData , setFormData] = useState({namee: '',price: ''})
let [files , setFiles] = useState(null)
const handleInputChange = (event) => {
const { name , value } = event.target
setFormData({...formData, [name] : value})
}
const handleImageChange = (event) => {
const file = event.target.files[0]
const reader = new FileReader()
reader.addEventListener("load", function() {
console.log(reader.result)
setFiles(reader.result)
})
reader.readAsDataURL(file)
}
const handleSubmit = (event) => {
event.preventDefault()
const { namee, price } = formData
const formDataObj1 = new FormData()
const formDataObj2 = new FormData()
formDataObj1.append('namee', namee)
formDataObj1.append('price', price)
formDataObj2.append('image', files)
if(files){
fetch('http://127.0.0.1:8000/add' ,
{
method: "POST",
body: formDataObj1,
}
)
.then(response => {
if(response.ok){
fetch('http://127.0.0.1:8000/addimage',
{
method: "PUT",
body: formDataObj2,
})
.then(response => {
console.log(response)
if(response.ok){
alert('Your Product has been added :)')
}
else{
console.error('Form submission failed.')
}
})
.catch(error => {
console.log(error)
})
}
else{
console.error('Form submission failed.')
}
})
.catch(error => {
console.log('Form submission failed.' , error)
})
}
else{
console.log('files is empty')
}
}
const imgStyle = {
marginBottom: '10px'
}
return (
<div className="c3">
<div id="info" className="center">
<h1>Product</h1>
<form onSubmit={handleSubmit} >
<div className="txt_field">
<input type="text" name="namee" value={formData.namee} onChange={handleInputChange} required/>
<span></span>
<label>Name</label>
</div>
<div className="txt_field">
<input type="number" name="price" value={formData.price} onChange={handleInputChange} required/>
<span></span>
<label>Price</label>
</div>
<div style={imgStyle}>
<input type="file" name="image" onChange={handleImageChange} required/>
<span></span>
</div>
<input type="submit" value="Confirm" className="ss"/>
</form>
</div>
</div>
)
}
Django
class AddProduct(generics.CreateAPIView):
serializer_class = ProductSerializer
def post(self , request , format=None):
name = request.data['namee']
price = request.data['price']
Product.objects.create(name=name, price=price)
return Response('product successfuly added', status=status.HTTP_200_OK)
class AddProductImage(APIView):
serializer_class = AddImageProSerializer
parser_classes = ( MultiPartParser, parsers.JSONParser)
def put(self , request ):
product = Product.objects.last()
serializer = AddImageProSerializer(data=request.data , instance = product)
serializer.is_valid(raise_exception=True)
serializer.save()
return Response(serializer.data, status=status.HTTP_200_OK)
2
Answers
Rather than develop and debug both sides at once I have found it helpful to use something like httpie to test the Django API. This allows you to confirm that it is responding as expected. Once that is working you can use the settings from httpie in your react app.
I have mainly used axios (rather than fetch) with Django model viewsets (rather than an api view). In that case if your model has a FileField or ImageField Django will simply "handle" the upload by default.
Django is expecting a multipart upload since you are sending form data and a file. This needs to be set in the headers on the client side (fetch or axios) which I notice you are not doing. You could start by fixing that. If that doesn’t work and you want more help, consider posting the pertinent info from urls.py, models.py, and serializers.py in addition to the views.py info you have already posted.