← Tutte le guide

Django: only(), defer() e values_list() per leggere meno dati

20 ottobre 2026 · 2 min di lettura

Di default Model.objects.all() legge tutte le colonne di ogni riga. Se il modello ha un campo di testo lungo e a te serve solo il titolo, stai spostando dati che butterai via.

class Articolo(models.Model):
    titolo = models.CharField(max_length=100)
    corpo = models.TextField()      # 2.000 caratteri per riga nel test

Le tre opzioni

Articolo.objects.only("titolo")         # istanze del modello, solo titolo (+ pk)
Articolo.objects.defer("corpo")         # istanze del modello, tutto tranne corpo
Articolo.objects.values_list("titolo", flat=True)   # niente modelli, solo valori

Misure

20.000 righe, SQLite in memoria, Django 4.2.30, Python 3.9.6, list(...) del queryset, migliore di 5 esecuzioni (script verifica/only_values.py). I tempi variano di run in run, conta l'ordine di grandezza:

  • all(): circa 970 ms, picco di memoria circa 50 MB
  • only("titolo"): circa 590 ms, circa 9 MB
  • defer("corpo"): circa 380 ms, circa 9 MB
  • values_list("titolo"): circa 29 ms, circa 2,4 MB
  • values_list("titolo", flat=True): circa 57 ms, circa 2,4 MB (nella stessa misura la differenza con la forma a tuple è rumore)

Tutte e cinque eseguono una sola query. only e defer sono equivalenti nel risultato (memoria identica); la differenza di tempo tra i due in questa misura è rumore, non una regola.

La trappola: i campi differiti

Se carichi con only("titolo") e poi tocchi a.corpo, Django fa una query per ogni oggetto:

for a in Articolo.objects.only("titolo")[:200]:
    a.corpo

Risultato misurato: 201 query (1 + 200). È un N+1 creato da te. Se non sei sicuro di non toccare quel campo, non differire.

Quale scegliere

  • Ti servono solo dei valori (liste, esportazioni, in su ID, autocomplete): values_list. È la più veloce perché non costruisce istanze del modello.
  • Ti servono gli oggetti (metodi, __str__, template) ma non una colonna pesante: defer() sulla colonna pesante, che è il caso più leggibile.
  • Poche colonne leggere su un modello largo: only().
  • Poche righe e modello piccolo: lascia stare, l'ottimizzazione prematura costa più di quello che risparmia. Misura prima, ad esempio con CaptureQueriesContext e time.perf_counter.

Se il problema sono le query moltiplicate e non le colonne, vedi il problema N+1.