Search code examples
iphoneobjective-cdjangodjango-formsnsmutableurlrequest

Upload file from iPhone to Django


Sorry, a beginner's question: I have a very simple function in my Django application with which I can upload a file from a web browser to my server (works perfectly!). Now, instead of the web browser, I would like to use an iPhone.

I got a bit stuck as I don't really know how to provide Django with a valid form, i.e. we need a file name and enctype="multipart/form-data" as far as I understand.

Here is my upload function in Django:

class UploadFileForm(forms.Form):
    file  = forms.FileField()

def handle_uploaded_file(f):
    destination = open('uploads/example.txt', 'wb+')
    for chunk in f.chunks():
        destination.write(chunk)
    destination.close()

def upload_file(request):
    if request.method == 'POST':
        form = UploadFileForm(request.POST, request.FILES)
        if form.is_valid():
            handle_uploaded_file(request.FILES['file'])
            print form
            print request.FILES
            return HttpResponse('Upload Successful')
    else:
        form = UploadFileForm()
    return render_to_response('upload.html', {'form': form})

My template looks like this (upload.html):

<form action="" method="post" enctype="multipart/form-data">
    {{ form.file }}
    {{ form.non_field_errors }}
    <input type="submit" value="Upload" />
</form>

Now, let's suppose that I want to send a simple txt file from my iPhone app to the sever. I don't really know how to:

  1. provide the file name
  2. specify the enctype and
  3. make sure that it's in a format Django can read

This is how far I got:

NSString *fileContents = [self loadTXTFromDisk:@"example.txt"];

NSMutableURLRequest *request = [[NSMutableURLRequest alloc] 
                                initWithURL:[NSURL 
                                             URLWithString:@"http://127.0.0.1:8000/uploadfile/"]];


[request setHTTPMethod:@"POST"];
[request setValue:@"text/xml"   forHTTPHeaderField:@"Content-type"];
[request setValue:[NSString stringWithFormat:@"%d", [fileContents length]] 
                                forHTTPHeaderField:@"Content-length"];
[request setHTTPBody:[fileContents dataUsingEncoding:NSUTF8StringEncoding]];

NSURLConnection *theConnection = [[NSURLConnection alloc] 
                                  initWithRequest:request 
                                  delegate:self];

However, Django will not except this as the form it expects is not valid. Cf. above:

form = UploadFileForm(request.POST, request.FILES)
if form.is_valid(): #this will not be true ...

Solution

  • The enctype from the HTML form should be the Content-Type of the HTTP request. You are currently setting the content type to 'text/xml' instead.

    You will also have to build up the body as a multipart mime object. The answers to this question seem to have some code for that: File Upload to HTTP server in iphone programming

    Your other option, since you have complete control of the client, is to do an HTTP PUT request. That actually looks closer to what you were doing with your original code. Change the method to 'PUT', and don't use a Django form on the other end; just access request.raw_post_data to get the complete file data.