~3 min read • Updated Mar 14, 2026
Introduction
Django provides a powerful and flexible API for managing files, including user uploads.
By default, files are stored locally using MEDIA_ROOT and served via MEDIA_URL.
However, Django’s storage system is fully customizable, allowing developers to store files anywhere—from local disk to cloud storage.
Using Files in Models
When you use FileField or ImageField, Django automatically provides a rich API for interacting with the stored file.
Example Model
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")
Accessing File Attributes
car = Car.objects.get(name="57 Chevy")
car.photo.name # 'cars/chevy.jpg'
car.photo.path # '/media/cars/chevy.jpg'
car.photo.url # 'https://media.example.com/cars/chevy.jpg'
The photo attribute is a File object, giving you access to methods like open(), read(), write(), and more.
Renaming a File
You can change the file name by modifying file.name and moving the file manually:
initial_path = car.photo.path
car.photo.name = "cars/chevy_ii.jpg"
os.rename(initial_path, new_path)
car.save()
Saving an Existing File to a FileField
from pathlib import Path
from django.core.files import File
path = Path("/some/external/specs.pdf")
with path.open("rb") as f:
car.specs = File(f, name=path.name)
car.save()
Working with ImageField
Attributes like width and height are available, but the underlying image must be reopened before use:
car.photo.open()
image = Image.open(car.photo)
The File Object
Django internally uses django.core.files.File to represent files.
You can create one manually:
with open("/path/to/hello.world", "w") as f:
myfile = File(f)
myfile.write("Hello World")
Always close files to avoid Too many open files errors.
File Storage
Django delegates file handling to a storage system.
The default is FileSystemStorage, but you can use or create custom storage backends.
Using default_storage
from django.core.files.base import ContentFile
from django.core.files.storage import default_storage
path = default_storage.save("path/to/file", ContentFile(b"new content"))
default_storage.open(path).read() # b'new content'
default_storage.delete(path)
The Built‑in FileSystemStorage
You can override storage for a specific field:
fs = FileSystemStorage(location="/media/photos")
class Car(models.Model):
photo = models.ImageField(storage=fs)
Using a Callable for Dynamic Storage
You can dynamically choose a storage backend at runtime:
def select_storage():
return MyLocalStorage() if settings.DEBUG else MyRemoteStorage()
class MyModel(models.Model):
my_file = models.FileField(storage=select_storage)
The callable is evaluated when the model class is loaded.
Using storages from STORAGES Setting
from django.core.files.storage import storages
def select_storage():
return storages["mystorage"]
class MyModel(models.Model):
upload = models.FileField(storage=select_storage)
Using LazyObject for Test Environments
Because callables are evaluated at import time, overriding STORAGES in tests requires a LazyObject.
class OtherStorage(LazyObject):
def _setup(self):
self._wrapped = storages["mystorage"]
my_storage = OtherStorage()
class MyModel(models.Model):
upload = models.FileField(storage=my_storage)
Conclusion
Django’s file‑handling system is both powerful and flexible. Whether you’re working with simple uploads, custom storage backends, or dynamic storage selection, Django provides clean abstractions that make file management reliable and scalable.
Written & researched by Dr. Shahin Siami