Python and Django - How to use in memory and temporary files
If I understand correctly you are looking for a way to access the uploaded file before it is saved using instance.save()
or similar.
If that is the case, you might try to read the file directly from request:
if my_form.is_valid():
data = request.FILES['myfile'].read()
You can set which upload handler is used for a Django form: https://docs.djangoproject.com/en/1.11/ref/files/uploads/#module-django.core.files.uploadhandler
There are two built in options:
- in memory
- temporary file
The way Django seems to work is by walking through the list of all upload handlers: https://docs.djangoproject.com/en/1.11/topics/http/file-uploads/#upload-handlers
For each upload handler it will check for a specific condition and if that condition is true, it will activate and use that upload handler.
The InMemoryUploadHandler, for example, is activated and used when files are below a certain size. The TemporaryFileUploadHandler is used when files are very large.
You will be able to access the data and files from the request
object.
If you're looking at Python specific (not Django), then it sounds like you may be interested in the tempfile
module:
https://docs.python.org/3/library/tempfile.html
Adapting the example from the document above:
import tempfile
fp = tempfile.TemporaryFile()
fp.write(b'Hello world!')
# Closing automatically deletes the tempfile
fp.close()
You can see this works fairly similarly to generic read/write file operations.
When a file is uploaded Django will do one of two things: store it in memory if the file is small (< 2 MB last time I checked), or store it as a temporary file on disk if it's large. This behavior is configurable via the FILE_UPLOAD_HANDLERS
setting. So, your web server and Django take care of the actual upload and storage, but it's your job to process the file before the request is over, otherwise the file is deleted.
Uploaded files are accessible through the request.FILES
property. Each key in FILES
will match the name of the file input on your <form>
. The value is an UploadedFile
object, which is a stream you can use to read the file data.
For example, say you have an <input name="img" type="file" />
and you want to detect if the image is completely white. You don't need to store the file for this, you just need to load it into memory, process it to get the result and then let it be discarded.
from PIL import Image
def some_view(request):
if request.method == 'POST':
img_file = request.FILES['img']
if img_file.size > 2000000:
return HttpResponseBadRequest()
img = Image.open(img_file)
# analyze the image...
Another possibility is that someone is uploading a backup file that is quite large (lets say 2 GB), and you need to store it somewhere. It's effectively the same thing, except we read the file into memory in chunks, then write each chunk to disk somewhere else so that it's saved after the request finishes.
def some_view(request):
if request.method == 'POST':
backup_file = request.FILES['backup_file']
with open('some/file/name.bak', 'wb+') as destination:
for chunk in backup_file.chunks():
destination.write(chunk)
# file is saved
When the request is over, the uploaded file is stored at some/file/name.bak
.
Whether it's in memory or a temporary file is usually not important because the interface is the same. You can read a temporary file just like you can read an in memory file.