Django FileResponse
last modified November 13, 2026 Python 3.15
Django FileResponse tutorial shows how to send a file with FileResponse in Django. The examples use Django 6.1 and Python 3.15, and the environment is managed with uv.
Django
Django is a high-level Python web framework that encourages rapid development and clean, pragmatic design. It is maintained by the Django Software Foundation. If you are new to the framework, start with the Django introduction article.
Django FileResponse
FileResponse is a subclass of StreamingHttpResponse
optimized for binary files. It streams the file in chunks, so a large file is
not loaded into memory, and it closes the file when the response is finished.
It accepts any file-like object opened in binary mode and sets the
Content-Type, Content-Length, and
Content-Disposition headers from the file name when it can.
from django.http import FileResponse
response = FileResponse(open('myfile.png', 'rb'))
With the as_attachment parameter set to True, the
browser offers the file for download instead of displaying it; the
filename parameter sets the suggested file name.
Creating the project
In the following example, we create a Django application that sends an image
to the client. The image is located in the images directory in the
project root directory. We use a PNG file named sunset.png; any
image will do if we change the file name in the view.
$ mkdir fileresponse $ cd fileresponse $ uv init --bare $ uv add django $ uv run django-admin startproject config .
We create a project directory, initialize it with uv, and install Django into a
project-local virtual environment. The last command creates the Django project
inside the current directory; the dot at the end prevents Django from
creating an extra config directory level. All commands are run
with uv run, so there is no need to activate the environment.
We also create the images directory and an app named
sendfile, which contains the functionality to send the image.
$ mkdir images $ uv run python manage.py startapp sendfile
The startapp command creates the sendfile package.
After we copy the image into images, the project has the
following structure; the hidden .venv directory is not shown.
. ├── config │ ├── asgi.py │ ├── __init__.py │ ├── settings.py │ ├── urls.py │ └── wsgi.py ├── images │ └── sunset.png ├── manage.py ├── pyproject.toml ├── sendfile │ ├── admin.py │ ├── apps.py │ ├── __init__.py │ ├── migrations │ │ └── __init__.py │ ├── models.py │ ├── tests.py │ └── views.py └── uv.lock
Registering the app
Django only knows about the apps listed in the INSTALLED_APPS setting, so a newly created app must be registered there.
...
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'sendfile',
]
...
Inside the settings.py file, we add the sendfile app
to INSTALLED_APPS.
URL configuration
The URL configuration maps request paths to view functions. This time the views live in the sendfile app, so we import them from there.
from django.contrib import admin
from django.urls import path
from sendfile.views import download_file, send_file
urlpatterns = [
path('admin/', admin.site.urls),
path('', send_file, name='send_file'),
path('download/', download_file, name='download_file'),
]
We add two routes: the root path displays the image and download/
sends it as an attachment. Both call functions from the sendfile
app. The module docstring generated by Django is omitted from the listing.
The views
The views are plain Python functions that return a FileResponse.
from django.conf import settings
from django.http import FileResponse
def send_file(request):
path = settings.BASE_DIR / 'images' / 'sunset.png'
return FileResponse(open(path, 'rb'))
def download_file(request):
path = settings.BASE_DIR / 'images' / 'sunset.png'
return FileResponse(open(path, 'rb'), as_attachment=True,
filename='sunset.png')
Inside send_file, we build the path to the image from
settings.BASE_DIR, the project root directory, so the view works no
matter which directory the server was started from. We open the file in binary
mode and return it in a FileResponse; Django guesses the
image/png content type from the file name. The
download_file view sets as_attachment=True and the
filename.
Running the application
We start the development server.
$ uv run python manage.py runserver
We navigate to http://127.0.0.1:8000/ and see the image in the
browser. In a terminal, we can check the headers of both routes with
curl; the -I option sends a HEAD request and prints
only the headers. The inline disposition makes the browser display
the file, the attachment disposition makes it download the file. The length depends on the image used.
$ curl -sI http://127.0.0.1:8000/ | grep -E '^Content-(Type|Length|Disposition)' Content-Type: image/png Content-Length: 20175 Content-Disposition: inline; filename="sunset.png" $ curl -sI http://127.0.0.1:8000/download/ | grep -E '^Content-(Type|Length|Disposition)' Content-Type: image/png Content-Length: 20175 Content-Disposition: attachment; filename="sunset.png"
Source
Django documentation: FileResponse objects
In this article we have sent an image from a Django app with FileResponse, both inline and as a download. Text responses are covered in Django HttpResponse and JSON responses in Django JsonResponse.
Author
List all Django tutorials.