Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

django RequestFactory file upload

Tags:

django

testing

I try to create a request, using RequestFactory and post with file, but I don't get request.FILES.

    from django.test.client import RequestFactory
    from django.core.files import temp as tempfile

    tdir = tempfile.gettempdir()
    file = tempfile.NamedTemporaryFile(suffix=".file", dir=tdir)
    file.write(b'a' * (2 ** 24))
    file.seek(0)
    post_data = {'file': file}

    request = self.factory.post('/', post_data)
    print request.FILES  # get an empty request.FILES : <MultiValueDict: {}>

How can I get request.FILES with my file ?

like image 842
sam Avatar asked Jan 26 '13 19:01

sam


4 Answers

I made a few tweaks to @Einstein 's answer to get it to work for a test that saves the uploaded file in S3:

request = request_factory.post('/')
with open('my_absolute_file_path', 'rb') as f:
    request.FILES['my_file_upload_form_field'] = f
    request.FILES['my_file_upload_form_field'].read()
    f.seek(0)
    ...
  • Without opening the file as 'rb' I was getting some unusual encoding errors with the file data
  • Without f.seek(0) the file that I uploaded to S3 was zero bytes
like image 66
Mark Chackerian Avatar answered Nov 02 '22 23:11

Mark Chackerian


If you open the file first and then assign request.FILES to the open file object you can access your file.

request = self.factory.post('/')
with open(file, 'r') as f:
    request.FILES['file'] = f
    request.FILES['file'].read()

Now you can access request.FILES like you normally would. Remember that when you leave the open block request.FILES will be a closed file object.

like image 23
Einstein Avatar answered Nov 02 '22 22:11

Einstein


You need to provide proper content type, proper file object before updating your FILES.

from django.core.files.uploadedfile import File
# Let django know we are uploading files by stating content type
content_type = "multipart/form-data; boundary=------------------------1493314174182091246926147632"
request = self.factory.post('/', content_type=content_type)
# Create file object that contain both `size` and `name` attributes 
my_file = File(open("/path/to/file", "rb"))
# Update FILES dictionary to include our new file
request.FILES.update({"field_name": my_file})

the boundary=------------------------1493314174182091246926147632 is part of the multipart form type. I copied it from a POST request done by my webbrowser.

like image 2
Ramast Avatar answered Nov 02 '22 22:11

Ramast


All the previous answers didn't work for me. This seems to be an alternative solution:

from django.core.files.uploadedfile import SimpleUploadedFile
with open(file, "rb") as f:
    file_upload = SimpleUploadedFile("file", f.read(), content_type="text/html")
    data = {
        "file" : file_upload
    }
    request = request_factory.post("/api/whatever", data=data, format='multipart')
like image 1
Chris Maes Avatar answered Nov 02 '22 21:11

Chris Maes