How to Upload a Photo To Django Using iOS and Django Rest Framework
I recently built an iOS application for fun that I use to take pictures of pages in a book, upload them to Django, and then ocr them for easy retrival. I was frustrated by the lack of documentation on how to upload an image to Django using the Django Rest Framework (DRF), so hopefully this tutorial will clear things up.
This tutorial assumes you have django<1.8, djangorestframework==2.4.2, and django-filter installed.
First, lets create the model that will store uploads:
As you can see, this model has multiple fields that are not really important for this tutorial. All you need to know here is that the owner comes from request.user (the client logged in uploading the image) and that the final image is stored as a url in the url field.
Now lets create the serializer that is going to be used by DRF to handle the upload.
This is a very standard DRF serializer. You can read more about how they work here, but basically serializer can be used to validate data (which I am not doing in this tutorial) and also used to tell the DRF the format and composition of the JSON data returned from the API.
Next, lets create the DSR view to handle the image upload:
This view should be fairly self-explanatory. I’m using TokenAuthentication rather than SessionAuthentication for all of my APIs (I will convert to OAuth and some point). I’m extracting the photo data from the upload in request.FILES. After I find the data, I figured out the file extension being used , and save the file to my local hard drive by writing chucks of the image to a file handle using BufferedWriter. Once the data is on my hard drive, I create a new Upload in the database, and start an OCR task and return HTTP 201 because I just created a new database entry.
The important part of this piece of code are the parser_classes, which tell DRF that I’m uploading using multipart rather than it expecting a regular HTTP POST.
Finally, here is a unit test I used to confirm that the view I just outlined accepts the image data, downloads it locally to a temp file, and returns an HTTP 201.
The actual HTTP POST that uploads the image is utilizing the excellent AFNetworking library.
The most important part of this code is the following
Which is taking the image data from my iPhone that is stored in an NSData object, sticking it in the file parameter in the body (request), and then performing a multipart request
The code that calls this function looks something like this:
I’m using DBCamera to take the photo and initiate the upload. cameraViewController is a method that is called on by DBCamera when the camera has successfully taken the photo. This method simply sets up the HTTP client, adds the current token I have stored in UserDefaults (hacky, I know), and sticks it in an NSData object. One important thing to notice here is that I downsample the image by 50% using UIImageJPEGRepresentation before uploading it, to insure faster uploads (and man did they become much faster using this method).
That is about it. Everything here was taken directly from my project and is working as of 10/11/2015. If you have any questions, feel free to reach out to me on twitter and if you need iOS help, please reach me at firstname.lastname@example.org