A volte capita di avere la necessità di creare dei nomi univoci per i file caricati sul backend di un applicativo, ignorando il nome del file di origine.

Fortunatamente il parametro upload_to dei FileField può accettare una funzione del tipo f(instance, filename) . Quindi risulta semplice implementare una funzione come questa:

I problemi iniziano a sorgere nel momento in cui si vuole utilizzare questa funzione per creare dei file all’interno di una struttura di sottocartelle.

Qualcosa del tipo:

  • cartella_1/6edb6b71-7fe2-4f31-8c96-b419b5e5b8b1.jpg
  • cartella_2/b096bc42-7bcc-4f87-86c6-c1a51c3e040e.mp4

Implementare una funzione per ogni path necessario è una soluzione poco manutenibile. Fortunatamente le funzioni in python sono oggetti, e come tali possono essere utilizzati come valori di ritorno in altre funzioni.

La prima idea che mi è venuta è stata quella di implementare una funzione di questo tipo:

Perfetta, no? No.

Purtroppo dopo aver utilizzato questa funzione in un progetto ci siamo resi conto che django continuava a ricreare sempre le stesse migrazioni nei modelli che utilizzavano questa funzione.

Questo succedeva perché django non riusciva a ricostruire la funzione definita all’interno serializzandola correttamente nelle migrazioni.

Fortunatamente è possibile serializzare classi custom aggiungendo un semplice decoratore.

La versione aggiornata della funzione, a questo punto trasformata in classe, è la seguente

Per usarla

In questo modo django serializza correttamente la funzione all’interno delle migrazioni e tutto funziona esattamente come voluto.