You need to set the filename on the response:
response = HttpResponse(data, content_type = 'application/force-download')
response['Content-Disposition'] = 'attachment; filename="{}"'.format(filename)
return response
In this post, we will look at how to download a file with Django. Specifically how to let users download ImageField or FileField content.,As mentioned previously, FileField downloads work mostly the same. The difference is that we don't have to open the file.,This won’t download the file; rather the browser will open it in a new tab in most cases. A similar thing will also happen for other file types that browsers can preview.,If your web app provides images that it generated, and aren’t saved as file, you can still make them available to download without saving them first. But FileResponse won’t help there.
return FileResponse(model.image.open())
return FileResponse(model.image.open(), as_attachment = True)
return FileResponse(model.image.open(), as_attachment = True, filename = "Export.png")
extension = pathlib.Path(model.image.name).suffix
filename_with_extension = "{0}{1}".format(filename, extension)
return FileResponse(model.image.open(), as_attachment = True, filename = filename_with_extension)
response = HttpResponse(content_type = 'image/png')
image.save(response, 'png')
response['Content-Disposition'] = 'attachment; filename={0}'.format("Export.png")
return response
return FileResponse(model.file, as_attachment = True)
The file is saved as part of saving the model in the database, so the actual file name used on disk cannot be relied on until after the model has been saved.,While ImageField non-image data attributes, such as height, width, and size are available on the instance, the underlying image data cannot be used without reopening the image. For example:,Most of the time you’ll use a File that Django’s given you (i.e. a file attached to a model as above, or perhaps an uploaded file).,Closing files is especially important when accessing file fields in a loop over a large number of objects. If files are not manually closed after accessing them, the risk of running out of file descriptors may arise. This may lead to the following error:
from django.db
import models
class Car(models.Model):
name = models.CharField(max_length = 255)
price = models.DecimalField(max_digits = 5, decimal_places = 2)
photo = models.ImageField(upload_to = 'cars')
specs = models.FileField(upload_to = 'specs')
>>> car = Car.objects.get(name="57 Chevy")
>>> car.photo
<ImageFieldFile: cars/chevy.jpg>
>>> car.photo.name
'cars/chevy.jpg'
>>> car.photo.path
'/media/cars/chevy.jpg'
>>> car.photo.url
'http://media.example.com/cars/chevy.jpg'
>>> import os >>> from django.conf import settings >>> initial_path = car.photo.path >>> car.photo.name = 'cars/chevy_ii.jpg' >>> new_path = settings.MEDIA_ROOT + car.photo.name >>> # Move the file on the filesystem >>> os.rename(initial_path, new_path) >>> car.save() >>> car.photo.path '/media/cars/chevy_ii.jpg' >>> car.photo.path == new_path True
>>> from pathlib
import Path
>>>
from django.core.files
import File
>>>
path = Path('/some/external/specs.pdf') >>>
car = Car.objects.get(name = '57 Chevy') >>>
with path.open(mode = 'rb') as f:
...car.specs = File(f, name = path.name)
...car.save()
>>> from PIL import Image
>>> car = Car.objects.get(name='57 Chevy')
>>> car.photo.width
191
>>> car.photo.height
287
>>> image = Image.open(car.photo)
# Raises ValueError: seek of closed file.
>>> car.photo.open()
<ImageFieldFile: cars/chevy.jpg>
>>> image = Image.open(car.photo)
>>> image
<PIL.JpegImagePlugin.JpegImageFile image mode=RGB size=191x287 at 0x7F99A94E9048>
>>> from django.core.files import File # Create a Python file object using open() >>> f = open('/path/to/hello.world', 'w') >>> myfile = File(f)
By default, django.core.files.storage.FileSystemStorage deals with conflicting filenames by appending an underscore and a random 7 character alphanumeric string to the file. For instance, if you try to create hello.txt when it already exists, it will rename it as e.g. hello_a12mkj3.txt.,A Django storage backend that names files by hash value.,Set DEFAULT_FILE_STORAGE to 'django_hashedfilenamestorage.storage.HashedFilenameFileSystemStorage',This gives you hashed filenames, backed on Django’s FileSystemStorage storage class.
The easiest way to install django-hashedfilenamestorage is to use pip:
pip install django - hashedfilenamestorage
You can define a new underlying storage class by using HashedFilenameMetaStorage to wrap it:
from django.core.files.storage
import get_storage_class
from django_hashedfilenamestorage.storage
import HashedFilenameMetaStorage
HashedFilenameMyStorage = HashedFilenameMetaStorage(
storage_class = get_storage_class('myapp.storage.MyStorage'),
)
You'll need to figure out a way to determine the desired filename (e..g, by storing it in the database as well for lookups).,Django models.FileField - store only the file name not any paths or folder references,how to change the name of a file and the storage location on upload in django,How to prevent Django from changing file name when a file with that name already exists?
You need to set the filename on the response:
response = HttpResponse(data, content_type = 'application/force-download')
response['Content-Disposition'] = 'attachment; filename="{}"'.format(filename)
return response
It tells a browser to treat a response as a downloadable file. Have you noticed that we also include Content-Type header? This one tells what kind of file we are sending to the browser or in other words its mime type. If the header is not set Django will set it to text/html. mimetypes.guess_type is a handy function which tries to guess the mime type of the file, however if you know the mime type of your file(s) beforehand, it is better to set this manually.,In order to create a download link, we need to create a Django view that would serve the files:,Once you've done this, add a line to urlpatterns in urls.py, which references the view.,OpenAPI 3 support in Django Rest Framework is still a work in progress. Things are moving quickly so there's not a lot of up to date info about this topic. It's not clear which features of OpenAPI 3 spec are supported in DRF and researching this info on your own
In order to create a download link, we need to create a Django view that would serve the files:
# views.py import mimetypes ... def download_file(request): # fill these variables with real values fl_path = ‘/file/path ' filename = ‘downloaded_file_name.extension’ fl = open(fl_path, 'r’) mime_type, _ = mimetypes.guess_type(fl_path) response = HttpResponse(fl, content_type = mime_type) response['Content-Disposition'] = "attachment; filename=%s" % filename return response ...
Once you've done this, add a line to urlpatterns
in urls.py
, which references the view.
# urls.py
...
path(‘<str:filepath>/‘, views.download_file)
...
It works because we send the following HTTP header to a browser:
Content - Disposition: attachment;
filename