ZetCode

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.

config/settings.py
...
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.

config/urls.py
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.

sendfile/views.py
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

I am Jan Bodnar, a programmer and technical writer. I have been writing programming tutorials at ZetCode since 2007 and have published eight e-books. See about the author.

List all Django tutorials.