Django provides specialized model fields for handling file uploads. These fields integrate seamlessly with Django's storage system and provide built-in validation and security features.
The FileField is the base field for handling file uploads:
from django.db import models
class Document(models.Model):
title = models.CharField(max_length=200)
file = models.FileField(upload_to='documents/')
uploaded_at = models.DateTimeField(auto_now_add=True)
def __str__(self):
return self.title
The ImageField extends FileField with image-specific validation:
from django.db import models
class Profile(models.Model):
user = models.OneToOneField('auth.User', on_delete=models.CASCADE)
avatar = models.ImageField(
upload_to='avatars/',
default='avatars/default.jpg',
help_text='Upload a profile picture'
)
bio = models.TextField(blank=True)
ImageField automatically validates that uploaded files are valid images:
from PIL import Image
from django.core.exceptions import ValidationError
def validate_image_size(image):
"""Custom validator for image dimensions"""
if image:
with Image.open(image) as img:
if img.width > 1920 or img.height > 1080:
raise ValidationError('Image dimensions cannot exceed 1920x1080 pixels.')
class Photo(models.Model):
title = models.CharField(max_length=100)
image = models.ImageField(
upload_to='photos/',
validators=[validate_image_size]
)
Create dynamic upload paths based on model data:
def user_directory_path(instance, filename):
"""File will be uploaded to MEDIA_ROOT/user_<id>/<filename>"""
return f'user_{instance.user.id}/{filename}'
def date_directory_path(instance, filename):
"""Organize files by date"""
from datetime import datetime
return f'uploads/{datetime.now().strftime("%Y/%m/%d")}/{filename}'
class UserFile(models.Model):
user = models.ForeignKey('auth.User', on_delete=models.CASCADE)
file = models.FileField(upload_to=user_directory_path)
class DatedUpload(models.Model):
name = models.CharField(max_length=100)
file = models.FileField(upload_to=date_directory_path)
Implement custom validation for file types and sizes:
import os
from django.core.exceptions import ValidationError
def validate_file_extension(value):
"""Validate file extension"""
ext = os.path.splitext(value.name)[1]
valid_extensions = ['.pdf', '.doc', '.docx', '.txt']
if not ext.lower() in valid_extensions:
raise ValidationError('Unsupported file extension.')
def validate_file_size(value):
"""Validate file size (max 5MB)"""
filesize = value.size
if filesize > 5 * 1024 * 1024: # 5MB
raise ValidationError("File size cannot exceed 5MB.")
class Document(models.Model):
title = models.CharField(max_length=200)
file = models.FileField(
upload_to='documents/',
validators=[validate_file_extension, validate_file_size]
)
# In views or templates
document = Document.objects.get(pk=1)
# File URL
file_url = document.file.url
# File path
file_path = document.file.path
# File name
filename = document.file.name
# File size
file_size = document.file.size
# Check if file exists
if document.file:
print(f"File exists: {document.file.name}")
from django.core.files import File
from django.core.files.base import ContentFile
# Assign existing file
with open('/path/to/file.pdf', 'rb') as f:
document = Document()
document.title = "My Document"
document.file.save('document.pdf', File(f))
# Create file from content
content = b"This is file content"
document = Document()
document.title = "Generated Document"
document.file.save('generated.txt', ContentFile(content))
Handle multiple file types in a single model:
class Article(models.Model):
title = models.CharField(max_length=200)
content = models.TextField()
# Different file types
featured_image = models.ImageField(
upload_to='articles/images/',
blank=True,
null=True
)
pdf_version = models.FileField(
upload_to='articles/pdfs/',
blank=True,
null=True,
validators=[validate_pdf_extension]
)
attachments = models.ManyToManyField(
'Attachment',
blank=True
)
class Attachment(models.Model):
name = models.CharField(max_length=100)
file = models.FileField(upload_to='attachments/')
uploaded_at = models.DateTimeField(auto_now_add=True)
class MediaFile(models.Model):
file = models.FileField(
upload_to='media/',
max_length=255, # Max filename length
blank=True, # Allow empty in forms
null=True, # Allow NULL in database
default='default.jpg', # Default file
help_text='Upload a file', # Form help text
verbose_name='Media File' # Admin display name
)
from django.core.files.storage import default_storage
from myapp.storage import CustomStorage
class Document(models.Model):
# Use default storage
file1 = models.FileField(upload_to='docs/')
# Use custom storage
file2 = models.FileField(
upload_to='docs/',
storage=CustomStorage()
)
upload_to to organize filesNow that you understand file fields in models, let's explore the File object and how Django handles uploaded files internally.
Working with Files
Django provides powerful tools for handling file uploads, storage, and management. Whether you're dealing with user-uploaded images, documents, or any other file type, Django's file handling system offers flexibility, security, and scalability.
The File Object
Django's file handling system centers around the File object, which provides a consistent interface for working with files regardless of their storage backend. Understanding the File object is crucial for advanced file manipulation and custom storage implementations.