I've been banging my head against the wall trying to get the original scenario (APIView with POST handler using MultiPartParser) to work, and I finally got it done.
I'm going to summarize everything I found as succinctly as possible, then explain:
To handle properly a mixed HTML form which includes data AND files, you need to use 2 parsers at the same time: MultiPartParser and FormParser.
request.FILES['file'] will come empty if your form doesn't include enctype="multipart/form-data"
If you are using Postman (like you were, and like I was), and you are NOT using FileUploadParser and PUT method, you NEED to add a Key to the file being sent in the form-data, and this Key must be the same you are trying to read from the request.FILES['file'] dictionary (so the key in Postman should be 'file').
This will make it work.
Now, I'll go in some detail for those who still need it:
- In the initial solution posted by @nabiharaza he switches from MultiPartParser to FileUploadParser to make it work. This is fine if you don't intend to send additional form stuff with the file. But if you are sending mixed form data, you must use MultiPartParser and FormParser, like this:
class FileUploadAPI(APIView):
parser_classes = [MultiPartParser, FormParser]
def post(self, request, filename, format=None):
# etc etc
- When you use MultiPartParser, you are going to get a dictionary (MultiValueDict) on
request.FILES, which you can access by key. But Django Documentation warns us that if we don't have the enctype set to multipart/form-data the dictionary will come empty. That's the main issue here.
Note that request.FILES will only contain data if the request method
was POST, at least one file field was actually posted, and the
that posted the request has the attribute
enctype="multipart/form-data". Otherwise, request.FILES will be empty.
(from the Django Docs link above).
In HTML, it would look like this:
<form method="post" action="{% url catalog_create_ajax_upload %}" enctype="multipart/form-data" id="create-form">
But there is one more thing (see what I did here? :D) for those of us using Postman:
- On Postman, when you use the POST method, and select a file in the form-data section, it automatically creates a form with the
enctype="multipart/form-data" attribute, so you don't need to add it manually by yourself. But you still need to set the KEY corresponding to the file (this is not mandatory for the PUT method handled by FileUploadParser because of how it works). If you check the original screenshot from @nabiharaza, you will notice that there isn't a key associated to the file Robbie_Lisa-Branch.xlsx.
So, even if everything else is correct, the request.FILES dictionary will come empty, and the request.FILES['file'] access will throw an Exception.
If you add the file key to Postman, it will work like a charm :)

Of course, if you have several files or you want to use something_else instead of file you can, but you need to match it in your dictionary access to request.FILES['something_else'].
I hope this is helpful for anyone trying to get this working and still struggling. I found bits and pieces of this info scattered all around the web (StackOverflow included) but not together on a single place.
Have fun!
I am using Postman to send an excel file and then reading it.Can you export the postman request as cURL and include it in the question? There are many ways to send a file to a server, and the way you access the file depends on how the file is being sent.curl --location 'http://localhost:8000/amm-api/upload/upload_workbook/' \ --form '=@"/Users/razan/Projects/HTS/ags-carmax/Robbie_Lisa-Branch.xlsx"'