Search code examples
pythondjangourllib2urllib

uploading files with urllib to a FileField model in Django


I have a django file model that has a models.FileField field and a form that is used to upload files to the server:

class UploadFile(model.Model):
    filename = models.FileField(upload_to='uploads')
    description = models.CharField(max_length=38, blank=True)

class UploadFileForm(ModelForm):
    class Meta:
        model = UploadFile
        fields = ('filename', 'description')

This is how the view function looks like:

def upload_file(request):
    if request.method == 'POST':
        form = UploadFileForm(request.POST, request.FILES)
        if form.is_valid():
            new_file = form.save()

Now I would like to have a python script that uses only the standard library to upload files to the UploadFile model using the view function above. However this code does not work because the POST request does not have a FILES method.

import urllib, urllib2
data = urllib.urlencode({'filename': open(uploadfile, "rb"),
                        'description': 'upload test'})
post_req = urllib2.Request(upload_file_url, data)
result = urllib2.urlopen(post_req)

How could I add a FILES method to the POST request to upload files using a python script? I have also tried to write a different view function that does not used the form but it is not working either.


Solution

  • To see whether your django view works, you could test it using a browser:

    <FORM action="{{ upload_file_url }}"
          enctype="multipart/form-data"
          method="POST">
      Description: <INPUT type="text" name="description" value="upload test"><BR>
      File to upload: <INPUT type="file" name="filename"><BR>
      <INPUT type="submit" value="Send">
    </FORM>
    

    It is complicated to replicate it programmatically using only stdlib.

    To upload files as multipart/form-data you could use requests library:

    import requests
    
    response = requests.post(upload_file_url,
                             files={'filename': open(uploadfile,'rb'),
                                    'description': 'upload test'})
    print response.content
    

    Or urllib2 and poster libraries:

    import urllib2
    
    import poster.encode
    import poster.streaminghttp
    
    opener = poster.streaminghttp.register_openers()
    
    params = {'filename': open(uploadfile,'rb'), 'description': 'upload test'}
    datagen, headers = poster.encode.multipart_encode(params)
    response = opener.open(urllib2.Request(upload_file_url, datagen, headers))
    print response.read()