Django REST Framework upload image: The submitted data was not a file
The problem that you are hitting is that Django REST framework expects files to be uploaded as multipart form data, through the standard file upload methods. This is typically a file
field, but the JavaScript Blob
object also works for AJAX.
You are looking to upload the files using a base64 encoded string, instead of the raw file, which is not supported by default. There are implementations of a Base64ImageField
out there, but the most promising one came by a pull request.
Since these were mostly designed for Django REST framework 2.x, I've improved upon the one from the pull request and created one that should be compatible with DRF 3.
serializers.py
from rest_framework import serializers
class Base64ImageField(serializers.ImageField):
"""
A Django REST framework field for handling image-uploads through raw post data.
It uses base64 for encoding and decoding the contents of the file.
Heavily based on
https://github.com/tomchristie/django-rest-framework/pull/1268
Updated for Django REST framework 3.
"""
def to_internal_value(self, data):
from django.core.files.base import ContentFile
import base64
import six
import uuid
# Check if this is a base64 string
if isinstance(data, six.string_types):
# Check if the base64 string is in the "data:" format
if 'data:' in data and ';base64,' in data:
# Break out the header from the base64 content
header, data = data.split(';base64,')
# Try to decode the file. Return validation error if it fails.
try:
decoded_file = base64.b64decode(data)
except TypeError:
self.fail('invalid_image')
# Generate file name:
file_name = str(uuid.uuid4())[:12] # 12 characters are more than enough.
# Get the file name extension:
file_extension = self.get_file_extension(file_name, decoded_file)
complete_file_name = "%s.%s" % (file_name, file_extension, )
data = ContentFile(decoded_file, name=complete_file_name)
return super(Base64ImageField, self).to_internal_value(data)
def get_file_extension(self, file_name, decoded_file):
import imghdr
extension = imghdr.what(file_name, decoded_file)
extension = "jpg" if extension == "jpeg" else extension
return extension
This should be used in replacement of the standard ImageField
provided by Django REST framework. So your serializer would become
class ImageSerializer(serializers.ModelSerializer):
image = Base64ImageField(
max_length=None, use_url=True,
)
class Meta:
model = Image
fields = ("id", 'image', 'owner', 'time_created', )
This should allow you to either specify a base64-encoded string, or the standard Blob
object that Django REST framework typically expects.
The submitted data was not a file. Check the encoding type on the form in DRF 3
From Django Docs -
If you intend to allow users to upload files, you must ensure that the
environment used to run Django is configured to work with non-ASCII
file names. If your environment isn’t configured correctly, you’ll
encounter UnicodeEncodeError exceptions when saving files with file
names that contain non-ASCII characters.
Thus adding this method to the model solved my problem :
class Product(models.Model):
item_category_choices = (
('Make Up','Make Up'),
('Skin Care','Skin Care'),
('Fragrance','Fragrance'),
('Personal Care','Personal Care'),
('Hair Care','Hair Care'),
)
item_name = models.CharField(max_length=50,verbose_name='Product Name')
item_image = models.ImageField(verbose_name='Product Image')
item_thumb = models.ImageField(verbose_name='Product Thumb')
item_description = models.TextField(verbose_name='Product Descriptions')
item_mass = models.CharField(max_length=10,verbose_name='Product Weight')
item_category = models.CharField(max_length=20, choices = item_category_choices,verbose_name='Product Category')
item_sub_category = models.CharField(max_length=20,verbose_name='Product Sub Category')
item_est_price = models.DecimalField(max_digits=12,decimal_places=2,verbose_name='East Product Price')
item_wst_price = models.DecimalField(max_digits=12,decimal_places=2,verbose_name='West Product Price')
def __unicode__(self):
return (self.item_name)
def image_img(self):
if self.item_image:
return u'<img src="%s" width="50" height="50" />' % self.item_image.url
else:
return '(Sin imagen)'
image_img.short_description = 'Thumb'
image_img.allow_tags = True
Django Rest Framework - The submitted data was not a file. Check the encoding type on the form
You can put your data in a FormData
object instead of using a regular object. This way axios will send the data as multipart/form-data
instead of as JSON.
const formData = FormData();
formData.append("title", title);
formData.append("content", content);
formData.append("author", author);
formData.append("countries", countries);
formData.append("image", image);
axios.post("http://localhost:8000/api/v1/reports/", formData, {
headers: { Authorization: `Token ${token}` }
});
POST image to django rest API always returns 'No file was submitted'
I had a similar problem: I used the same Django endpoint to upload a file using axios
1) from the client side and 2) from the server side. From the client side it worked without any problem, but from the server side, the request body was always empty.
My solution was to use the following code:
const fileBuffer = await readFile(file.filepath)
const formData = new FormData()
formData.append('file', fileBuffer, file.originalFilename)
const response = await fetch(
urlJoin(BACKEND_URL),
{
method: 'POST',
body: formData,
headers: {
...formData.getHeaders(),
},
}
)
A few relevant references that I found useful:
- This blog post, even though it seems the author manages to send form data from the server side using axios, I did not manage to reproduce it on my case.
- This issue report in the axio repository, where one comment suggests to use
fetch
.
Related Topics
What Is the Best (Idiomatic) Way to Check the Type of a Python Variable
Sorting by a Custom List in Pandas
How to Parse a Website Using Selenium and Beautifulsoup in Python
Multiprocessing.Dummy in Python Is Not Utilising 100% Cpu
Force Numpy Ndarray to Take Ownership of Its Memory in Cython
How to Filter a Date of a Datetimefield in Django
How to Round the Minute of a Datetime Object
Typeerror: Worker() Takes 0 Positional Arguments But 1 Was Given
Configuring So That Pip Install Can Work from Github
Pandas Dataframe Concat VS Append
Importing from a Relative Path in Python
How to Decorate an Instance Method with a Decorator Class
Not All Parameters Were Used in the SQL Statement (Python, MySQL)
What's the Best Practice Using a Settings File in Python