I've got a react frontend with django backend trying to upload some images to django api enpoint I have 1 model in django but i want to first upload an image and then submit the rest of the data, the issue is when i try to upload the photos i get an error response photos [ "The submitted data was not a file. Check the encoding type on the form." ] I am using Dropzone to upload photos by the way Here is the react component handling uplaod
function ImageUploader() {
const [fileNames, setFileNames] = useState([]);
const handleDrop = async (acceptedFiles) => {
try {
// Create a new FormData object to send files
const formData = new FormData();
acceptedFiles.forEach((file) => {
// Append each file to the FormData object
formData.append('photos', file);
});
// Make a POST request to your photo upload endpoint
//axios.defaults.headers.post['Content-Type'] = 'multipart/form-data';
const response = await axios.post('http://localhost:8000/api/quotes/create/', formData, {
headers: {
'Accept': 'application/json',
'Content-Type': 'multipart/form-data',
},
});
// Handle the response (e.g., show success message)
console.log('Upload successful:', response.data.message);
// Update the list of file names for display
setFileNames(acceptedFiles.map((file) => file.name));
} catch (error) {
console.error('Upload failed:', error);
}
};
return (
<div className="App">
<Dropzone
onDrop={handleDrop}
accept={{ mimeType: ["image/jpeg", "image/png"] }}
minSize={1024}
maxSize={3072000}
>
Then in django i have this view
class QuoteCreateAPIView(APIView):
def post(self, request, format=None):
# Determine the current stage based on the presence of 'photos' field
if 'photos' in request.data:
# Stage 1: Upload Photos
serializer = QuoteSerializer(data={'photos': request.FILES.getlist('photos')}, partial=True)
else:
# Stage 2: Submit Remaining Data
serializer = QuoteSerializer(data=request.data, partial=True)
if serializer.is_valid():
# Check if 'photos' are being submitted in Stage 2, and update the 'photos' field accordingly
if 'photos' not in serializer.validated_data:
serializer.validated_data['photos'] = Quote.objects.get(pk=request.data['quote_id']).photos
# Create or update the Quote instance
try:
quote_id = request.data.get('quote_id')
if quote_id:
quote = Quote.objects.get(pk=quote_id)
serializer.update(quote, serializer.validated_data)
else:
serializer.save()
return Response(serializer.data, status=status.HTTP_201_CREATED)
except Quote.DoesNotExist:
return Response({'message': 'Quote not found'}, status=status.HTTP_404_NOT_FOUND)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
Quote model
class Quote(models.Model):
quote_id = models.CharField(max_length=10, unique=True, default=get_unique_quote_id)
name = models.CharField(max_length=255)
phone = models.CharField(max_length=255)
email = models.EmailField(max_length=255)
# area = models.CharField(max_length=255)
make = models.ForeignKey(CarMake, on_delete=models.CASCADE, null=True) #
model = models.ForeignKey(CarModel, on_delete=models.CASCADE, null=True) #
variant = models.ForeignKey(ModelVariant, on_delete=models.CASCADE, null=True)
year = models.IntegerField(default=0) #
price = models.IntegerField(default=0) #
mileage = models.IntegerField(default=0) #
fuel = models.CharField(max_length=255, default='') #
transmission = models.CharField(max_length=255, default='') #
papers = models.CharField(max_length=3, default='') #
runner = models.CharField(max_length=3, default='') #
smashed = models.CharField(max_length=3, default='') #
financed = models.CharField(max_length=3, default='') #
warranty = models.CharField(max_length=3, default='') #
condition = models.CharField(max_length=255, default='') #
comments = models.TextField(max_length=1000, default='') #
photos = models.ImageField(upload_to='photos/', ) #
date_time = models.DateTimeField(auto_now_add=True, null=True)
def __str__(self):
return '%s' %(self.name)
And a serializer
class QuoteSerializer(serializers.ModelSerializer):
make = serializers.CharField()
model = serializers.CharField()
variant = serializers.CharField(required=False)
class Meta:
model = Quote
fields = '__all__'
extra_kwargs = {
'quote_id': {'required': False},
'name': {'required': False},
'phone': {'required': False},
'email': {'required': False},
'make': {'required': False},
'model': {'required': False},
'variant': {'required': False},
'year': {'required': False},
'price': {'required': False},
'milage': {'required': False},
'fuel': {'required': False},
'transmission': {'required': False},
'papers': {'required': False},
'runner': {'required': False},
'smashed': {'required': False},
'financed': {'required': False},
'warranty': {'required': False},
'condition': {'required': False},
'comments': {'required': False},
}
def create(self, validated_data):
make_name = validated_data.pop('make')
model_name = validated_data.pop('model')
variant_name = validated_data.pop('variant', None)
make, _ = CarMake.objects.get_or_create(make=make_name)
model, _ = CarModel.objects.get_or_create(model=model_name, make=make)
variant, _ = ModelVariant.objects.get_or_create(variant=variant_name, make=make, model=model)
quote = Quote.objects.create(make=make, model=model, variant=variant, **validated_data)
return quote
The photos i am testing with are definitely fine
in Network requests i am seeing this
Content-Disposition: form-data; name="photos"; filename="bmw116i.jpeg" Content-Type: image/jpeg
and i printed requests.data in the view function which seems to return this
<QueryDict: {'photos': [<InMemoryUploadedFile: bmw116i.jpeg (image/jpeg)>]}>