Di seguito trovi una guida pratica e aggiornata per caricare file in modo sicuro ed efficiente usando ModelForm, gli upload handlers predefiniti e le impostazioni consigliate.
1) Configurazione di base: MEDIA_ROOT e MEDIA_URL
Django salva i file caricati usando lo storage predefinito (filesystem locale, a meno di override). Aggiungi in settings.py:
# settings.py
MEDIA_URL = "/media/"
MEDIA_ROOT = BASE_DIR / "media"
# Limiti consigliati
DATA_UPLOAD_MAX_MEMORY_SIZE = 10 * 1024 * 1024 # 10 MB per la request in memoria
FILE_UPLOAD_MAX_MEMORY_SIZE = 2 * 1024 * 1024 # 2 MB: sopra questo usa file temporanei su disco
FILE_UPLOAD_PERMISSIONS = 0o644 # permessi sicuri per i file salvati
2) URL di sviluppo per servire i media
In sviluppo (non in produzione), esponi MEDIA_URL aggiungendo in urls.py del progetto:
# urls.py (progetto)
from django.conf import settings
from django.conf.urls.static import static
from django.urls import path, include
urlpatterns = [
path("", include("app.urls")),
]
if settings.DEBUG:
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
3) Modello con FileField/ImageField
Definisci il campo e, se vuoi, personalizza la cartella di destinazione con upload_to (può essere una stringa o una callable per path dinamici):
# app/models.py
from django.db import models
from django.utils import timezone
def upload_to_docs(instance, filename):
ts = timezone.now().strftime("%Y%m%d_%H%M%S")
return f"uploads/docs/{ts}_{filename}"
class Document(models.Model):
title = models.CharField(max_length=200)
file = models.FileField(upload_to=upload_to_docs) # o ImageField per immagini
uploaded_at = models.DateTimeField(auto_now_add=True)
def __str__(self):
return self.title
4) ModelForm e validazioni
Usa un ModelForm e valida dimensione e tipo MIME in modo esplicito (mai fidarsi solo dell’estensione):
# app/forms.py
from django import forms
from .models import Document
ALLOWED_MIME = {"application/pdf", "text/plain"}
MAX_MB = 5
class DocumentForm(forms.ModelForm):
class Meta:
model = Document
fields = ["title", "file"]
def clean_file(self):
f = self.cleaned_data["file"]
# Dimensione
if f.size > MAX_MB * 1024 * 1024:
raise forms.ValidationError(f"Il file supera {MAX_MB} MB.")
# Tipo MIME (usa content_type dell'UploadedFile)
if getattr(f, "content_type", None) not in ALLOWED_MIME:
raise forms.ValidationError("Tipo di file non consentito.")
return f
5) View sincrona o asincrona
Le view classiche gestiscono request.FILES. In Django 5.2 puoi anche scrivere view async, ma la maggior parte dei casi va bene la vista standard:
# app/views.py
from django.shortcuts import render, redirect
from .forms import DocumentForm
def upload_view(request):
if request.method == "POST":
form = DocumentForm(request.POST, request.FILES)
if form.is_valid():
form.save()
return redirect("upload_ok")
else:
form = DocumentForm()
return render(request, "app/upload.html", {"form": form})
6) Template: multipart e csrf_token
Ricorda l’attributo enctype="multipart/form-data" sul form, altrimenti i file non vengono inviati:
<!-- app/templates/app/upload.html -->
<h1>Carica documento</h1>
<form method="post" enctype="multipart/form-data">
{% csrf_token %}
{{ form.as_p }}
<button type="submit">Carica</button>
</form>
7) Visualizzare e scaricare i file caricati
Dopo il salvataggio, il campo fornisce url e path:
<p>Titolo: {{ obj.title }}</p>
<p><a href="{{ obj.file.url }}" download>Scarica file</a></p>
8) Storage alternativi (S3, GCS, ecc.)
Per ambienti cloud usa un backend di storage compatibile (per esempio django-storages) e configura le credenziali. Il resto del codice applicativo resta invariato grazie all’API dello storage di Django.
9) Comprendere gli upload handlers
Di default Django usa due gestori: MemoryFileUploadHandler (per file piccoli, in RAM) e TemporaryFileUploadHandler (per file grandi, su disco temporaneo). Puoi sostituirli o aggiungerne di personalizzati con FILE_UPLOAD_HANDLERS se ti servono stream particolari o quote.
# settings.py (opzionale)
FILE_UPLOAD_HANDLERS = [
"django.core.files.uploadhandler.MemoryFileUploadHandler",
"django.core.files.uploadhandler.TemporaryFileUploadHandler",
]
10) Sicurezza: regole essenziali
- Valida sempre dimensione e MIME; rinomina i file sul server (lo fa già l’esempio via
upload_to). - Non eseguire mai file caricati (niente preview server-side di HTML/JS non sanificati).
- Isola i media dal codice applicativo; in produzione fai servire i media dal web server o CDN, non da Django.
- Per immagini, usa librerie che verificano i formati effettivi (es. Pillow) e considera una scansione antivirus su backend.
11) Esempio minimo completo: URL e pagina di esito
# app/urls.py
from django.urls import path
from .views import upload_view
from django.views.generic import TemplateView
urlpatterns = [
path("upload/", upload_view, name="upload"),
path("upload-ok/", TemplateView.as_view(template_name="app/ok.html"), name="upload_ok"),
]
<!-- app/templates/app/ok.html -->
<h2>Upload completato!</h2>
<p>Il file è stato salvato correttamente.</p>
12) Check-list di produzione
- Usa uno storage esterno (S3/GCS/Azure) con CDN.
- Imposta CORS/headers corretti per i download.
- Logga tentativi falliti e conserva metadati (IP, user agent) secondo le norme privacy.
- Dimensiona
DATA_UPLOAD_MAX_MEMORY_SIZEeFILE_UPLOAD_MAX_MEMORY_SIZEin base al carico.
Conclusione
Con Django l’upload è semplice grazie a ModelForm e agli upload handlers predefiniti che gestiscono in memoria i file piccoli e su disco quelli grandi. Aggiungi limiti, validazioni e uno storage adeguato per un flusso robusto e sicuro.