Punti salienti di Django: gestione di risorse statiche e file multimediali (parte 4)
Pubblicato: 2022-03-10I siti Web Django coinvolgono molti file. Non è solo codice sorgente per la configurazione, modelli, viste e template, ma anche asset statici: CSS e JavaScript, immagini, icone. Come se non bastasse, a volte gli utenti arrivano e vogliono caricare i propri file sul tuo sito web. È abbastanza per rendere incredulo qualsiasi sviluppatore. File ovunque!
Ecco dove vorrei poter dire (senza avvertimenti): "Non preoccuparti, Django ti copre le spalle!" Ma sfortunatamente, quando si ha a che fare con risorse statiche e file multimediali, ci sono molti avvertimenti da affrontare.
Oggi ci occuperemo dell'archiviazione e della pubblicazione di file sia per distribuzioni a server singolo che scalabili, tenendo conto di fattori come compressione, memorizzazione nella cache e disponibilità. Discuteremo anche dei costi e dei vantaggi delle CDN e delle soluzioni di archiviazione di file dedicate.
Nota : questo non è un tutorial su come distribuire un sito Django su una piattaforma specifica. Invece, come gli altri articoli della serie Django Highlights (vedi sotto), è inteso come una guida per sviluppatori e designer front-end per comprendere altre parti del processo di creazione di un'applicazione web. Oggi ci concentriamo su cosa succede dopo che l'hotfix di stile o la bella grafica appena terminata sono stati spinti a padroneggiare. Insieme, svilupperemo un'intuizione per le strategie a disposizione degli sviluppatori Django per fornire questi file agli utenti di tutto il mondo in modo sicuro, efficiente e conveniente.
Parti precedenti della serie:
- Parte 1: modelli utente e autenticazione
- Parte 2: la creazione di modelli salva le linee
- Parte 3: Modelli, amministrazione e sfruttamento del database relazionale
Definizioni
La maggior parte di questi termini sono piuttosto semplici, ma vale la pena dedicare un momento a stabilire un vocabolario condiviso per questa discussione.
I tre tipi di file in un'applicazione Django live sono:
- Codice sorgente
I file Python e HTML creati con il framework Django. Questi file sono il cuore dell'applicazione. I file del codice sorgente sono generalmente piuttosto piccoli, misurati in kilobyte. - File statici
Chiamati anche "risorse statiche", questi file includono CSS e JavaScript, entrambi scritti dallo sviluppatore dell'applicazione e da librerie di terze parti, nonché PDF, programmi di installazione di software, immagini, musica, video e icone. Questi file vengono utilizzati solo sul lato client. I file statici vanno da pochi kilobyte di CSS a gigabyte di video. - File multimediali
Qualsiasi file caricato da un utente, dalle immagini del profilo ai documenti personali, è chiamato file multimediale. Questi file devono essere archiviati e recuperati in modo sicuro e affidabile per l'utente. I file multimediali possono essere di qualsiasi dimensione, l'utente potrebbe caricare un paio di kilobyte di testo in chiaro su pochi gigabyte di video. Se sei all'ultima estremità di questa scala, probabilmente hai bisogno di una consulenza più specializzata di quella che questo articolo è pronto a fornire.
I due tipi di implementazioni Django sono:
- Server singolo
Una distribuzione Django a server singolo è esattamente ciò che sembra: tutto vive su un unico server. Questa strategia è molto semplice e ricorda da vicino l'ambiente di sviluppo, ma non è in grado di gestire in modo efficace quantità di traffico elevate o incoerenti. L'approccio a server singolo è applicabile solo per progetti di apprendimento o dimostrativi, non per applicazioni di parole reali che richiedono un tempo di attività affidabile. - scalabile
Esistono molti modi diversi per distribuire un progetto Django che gli consente di scalare per soddisfare la domanda degli utenti. Queste strategie spesso implicano l'attivazione e disattivazione di numerosi server e l'utilizzo di strumenti come bilanciatori di carico e database gestiti. Fortunatamente, possiamo raggruppare in modo efficace tutto ciò che è più complesso di una distribuzione a server singolo in questa categoria ai fini di questo articolo.
Opzione 1: Django predefinito
I piccoli progetti beneficiano di un'architettura semplice. La gestione predefinita di Django di risorse statiche e file multimediali è proprio questo: semplice. Per ciascuno, hai una cartella principale che memorizza i file e risiede proprio accanto al codice sorgente sul server. Semplice. Queste cartelle radice vengono generate e gestite principalmente tramite la configurazione yourproject/settings.py .
Risorse statiche
La cosa più importante da capire quando si lavora con file statici in Django è il comando python manage.py collectstatic
. Questo comando esplora la cartella statica di ciascuna app nel progetto Django e copia tutte le risorse statiche nella cartella principale. L'esecuzione di questo comando è una parte importante della distribuzione di un progetto Django. Considera la seguente struttura di directory:
- project - project - settings.py - urls.py - ... - app1 - static/ - app1 - style.css - script.js - img.jpg - templates/ - views.py - ... - app2 - static/ - app2 - style.css - image.png - templates/ - views.py - ...
Assumi anche le seguenti impostazioni in project/settings.py :
STATIC_URL = "/static/" STATIC_ROOT = "/path/on/server/to/djangoproject/static"
L'esecuzione del comando python manage.py collectstatic
creerà la seguente cartella sul server:
- /path/on/server/to/djangoproject/static - app1 - style.css - script.js - img.jpg - app2 - style.css - image.png
Nota che all'interno di ogni cartella statica c'è un'altra cartella con il nome dell'app. Questo serve a prevenire conflitti di spazio dei nomi dopo che i file statici sono stati raccolti; come puoi vedere nella struttura del file sopra, ciò mantiene distinti app1/style.css e app2/style.css . Da qui, l'applicazione cercherà i file statici in questa struttura in STATIC_ROOT
durante la produzione. Pertanto, fai riferimento ai file statici come segue in un modello in app1/templates/ :
{% load static %} <link rel="stylesheet" type="text/css" href="{% static "app1/style.css" %}">
Django scopre automaticamente da dove ottenere il file statico durante lo sviluppo per modellare questo comportamento, non è necessario eseguire collectstatic
durante lo sviluppo.
Per maggiori dettagli, vedere la documentazione di Django.
File multimediali
Immagina un sito di networking professionale con un database di utenti. Ciascuno di questi utenti avrebbe un profilo associato, che potrebbe contenere, tra le altre cose, un'immagine avatar e un documento di curriculum. Ecco un breve modello di esempio di tali informazioni:
from django.db import models from django.contrib.auth.models import User def avatar_path(instance, filename): return "avatar_{}_{}".format(instance.user.id, filename) class Profile(models.Model): user = models.OneToOneField(User, on_delete=models.CASCADE) resume = models.FileField(upload_to="path/string") avatar = models.ImageField(upload_to=avatar_path)
Affinché funzioni, sono necessarie le seguenti opzioni in project/settings.py , come con le risorse statiche:
MEDIA_URL = "/media/" MEDIA_ROOT = "/path/on/server/to/media"
Un ImageField
eredita da FileField
, quindi condivide gli stessi parametri e capacità. Entrambi i campi hanno un argomento upload_to
facoltativo, che prende una stringa che è un percorso e la aggiunge a MEDIA_ROOT
per archiviare il file, che è quindi accessibile dallo stesso percorso sopra MEDIA_URL
. L'argomento upload_to
può anche accettare una funzione che restituisce una stringa, come dimostrato con la funzione avatar_path
.
Assicurati di omettere la directory dei file multimediali e il relativo contenuto dal controllo della versione. Il suo contenuto può entrare in conflitto quando due sviluppatori testano la stessa applicazione su macchine diverse e, a differenza delle risorse statiche, non fa parte dell'applicazione Django distribuibile.
Opzione 2: Django con servizi
La mia filosofia guida è usare gli strumenti per ciò che sanno fare meglio. Django è un framework straordinario e fornisce ottimi strumenti pronti all'uso per l'autenticazione dell'utente, il rendering lato server, l'utilizzo di modelli e moduli, funzioni amministrative e dozzine di altri aspetti essenziali della creazione di applicazioni Web. Tuttavia, i suoi strumenti per la gestione di risorse statiche e file multimediali non sono, a mio avviso, adatti per la produzione su siti scalabili. Gli sviluppatori principali di Django riconoscono che molte persone scelgono approcci alternativi per gestire questi file in produzione; il quadro è molto bravo a toglierti di mezzo quando lo fai. La maggior parte dei siti Django destinati all'uso generale vorranno incorporare risorse statiche e gestire i file multimediali utilizzando questi approcci non specifici di Django.
Risorse statiche su una CDN
Mentre i progetti di piccole e medie dimensioni possono farcela senza, una CDN (rete di distribuzione dei contenuti) è facile da usare e migliora le prestazioni di applicazioni di qualsiasi dimensione. Una CDN è una rete di server, generalmente in tutto il mondo, che distribuisce e fornisce contenuti Web, principalmente risorse statiche. Le CDN popolari includono Cloudflare CDN, Amazon CloudFront e Fastly. Per utilizzare una CDN, carichi i tuoi file statici, quindi nella tua applicazione fai riferimento a loro come segue:

<link rel="stylesheet" type="text/css" href="https://cdn.example.com/path/to/your/files/app1/style.css">
Questo processo è facile da integrare con gli script di distribuzione di Django. Dopo aver eseguito il comando python manage.py collectstatic
, copia la directory generata sulla tua CDN (un processo che varia sostanzialmente in base al servizio che stai utilizzando), quindi rimuovi le risorse statiche dal pacchetto di distribuzione Django.
In fase di sviluppo, ti consigliamo di accedere a copie diverse delle tue risorse statiche rispetto a quelle in produzione. In questo modo è possibile apportare modifiche localmente senza influire sul sito di produzione. Puoi utilizzare risorse locali o eseguire una seconda istanza della rete CDN per distribuire i file. Configura yourproject/settings.py con alcune variabili personalizzate, come CDN_URL
e utilizza quel valore nei tuoi modelli per assicurarti di utilizzare la versione corretta delle risorse in fase di sviluppo e produzione.
Un'ultima nota è che molte librerie per CSS e JavaScript hanno CDN gratuiti che la maggior parte dei siti Web può utilizzare. Se stai caricando, ad esempio, Bootstrap 4 o underscore.js, puoi saltare il fastidio di utilizzare la tua copia in fase di sviluppo e le spese per servire le tue copie in produzione utilizzando queste CDN pubbliche.
File multimediali con un archivio di file dedicato
Nessun sito Django di produzione dovrebbe archiviare i file utente in una semplice cartella /media/ da qualche parte sul server che esegue il sito. Ecco tre dei tanti motivi per non farlo:
- Se devi ampliare il sito aggiungendo più server, hai bisogno di un modo per copiare e sincronizzare i file caricati su quei server.
- Se un server si arresta in modo anomalo, viene eseguito il backup del codice sorgente nel tuo sistema di controllo della versione, ma i file multimediali non vengono sottoposti a backup per impostazione predefinita, a meno che tu non abbia configurato il tuo server per farlo, ma per questo sarebbe meglio usare un archivio di file.
- In caso di attività dannosa, è un po' meglio mantenere i file caricati dall'utente su un server separato da quello che esegue l'applicazione, sebbene ciò non elimini in alcun modo l'obbligo di convalidare i file caricati dall'utente.
L'integrazione di una terza parte per archiviare i file caricati dagli utenti è davvero semplice. Non è necessario modificare nulla nel codice, tranne forse rimuovere o modificare il valore upload_to
di FileField
nei modelli e configurare alcune impostazioni. Ad esempio, se stavi pianificando di archiviare i tuoi file in AWS S3, vorresti eseguire quanto segue, che è molto simile al processo di archiviazione dei file con Google Cloud, Azure, Backblaze o servizi simili concorrenti.
Per prima cosa, dovrai installare le librerie boto3
e django-storages
storages . Quindi, devi configurare un bucket e un ruolo IAM su AWS, che non rientra nell'ambito di questo articolo, ma puoi vedere le istruzioni qui. Una volta che tutto è configurato, devi aggiungere tre variabili al tuo project/settings.py :
DEFAULT_FILE_STORAGE = "storages.backends.s3boto3.S3Boto3Storage" AWS_STORAGE_BUCKET_NAME = "BUCKET_NAME" AWS_S3_REGION_NAME = "us-east-2"
Inoltre, dovrai configurare l'accesso delle credenziali al tuo bucket AWS. Alcuni tutorial dimostreranno l'aggiunta di un ID e di una chiave segreta al file delle impostazioni o come variabili di ambiente, ma si tratta di pratiche non sicure. Utilizza invece django-storages
con l'AWS CLI per configurare le chiavi, come descritto qui. Potresti anche essere interessato alla documentazione django-storages
.
Non vuoi che lo sviluppo o il test dei file multimediali vengano confusi con i caricamenti degli utenti effettivi. Evitarlo è piuttosto semplice: imposta più bucket, uno per lo sviluppo (o uno per ogni sviluppatore), uno per i test e uno per la produzione. Quindi, tutto ciò che devi modificare è l'impostazione AWS_STORAGE_BUCKET_NAME
per ambiente e sei a posto.
Prestazioni e disponibilità
Ci sono numerosi fattori che influenzano le prestazioni e l'affidabilità del tuo sito web. Eccone alcuni importanti quando si considerano i file statici e multimediali che contano indipendentemente dall'approccio adottato per gestirli.
Costo
Servire file a un utente costa per due motivi: spazio di archiviazione e larghezza di banda. Devi pagare il provider di hosting per archiviare i file per te, ma devi anche pagarli per servire i file. La larghezza di banda è sostanzialmente più costosa dello storage (ad esempio, AWS S3 addebita 2,3 centesimi per gigabyte per lo storage rispetto a 9 centesimi per gigabyte di trasferimento dati su Internet al momento della scrittura). L'economia di un archivio di file come S3 o CDN è diversa dall'economia di un host generalizzato come una gocciolina di Digital Ocean. Approfitta della specializzazione e delle economie di scala spostando file costosi su servizi progettati per loro. Inoltre, molti archivi di file e CDN offrono piani gratuiti in modo che i siti che potrebbero essere abbastanza piccoli da potersi allontanare senza utilizzarli possono invece farlo e trarne vantaggio senza costi di infrastruttura aggiuntivi.
Compressione e Transcodifica
La maggior parte dei problemi causati da risorse statiche come foto e video è dovuta al fatto che sono file di grandi dimensioni. Naturalmente, gli sviluppatori affrontano questo problema cercando di ridurre questi file. Esistono diversi modi per farlo utilizzando un mix di compressione e transcodifica in due categorie generali: lossless e lossy. La compressione senza perdita di dati mantiene la qualità originale delle risorse ma fornisce riduzioni relativamente modeste delle dimensioni del file. La compressione con perdita, o transcodifica in un formato con perdita, consente file di dimensioni molto più piccole a scapito della perdita di parte della qualità dell'artefatto originale. Un esempio di ciò è la transcodifica del video a un bitrate inferiore. Per i dettagli, consulta questo articolo sull'ottimizzazione della pubblicazione dei video. Quando si servono file di grandi dimensioni sul Web, le velocità della larghezza di banda spesso richiedono la pubblicazione di artefatti altamente compressi, che richiedono una compressione con perdita di dati.
A meno che tu non sia YouTube, la compressione e la transcodifica non avvengono al volo. Le risorse statiche devono essere formattate in modo appropriato prima della distribuzione ed è possibile applicare restrizioni di base sul tipo di file e sulla dimensione del file sui caricamenti degli utenti per garantire una compressione sufficiente e una formattazione appropriata nei file multimediali degli utenti.
Minimizzazione
Sebbene i file di JavaScript e CSS di solito non siano grandi quanto le immagini, spesso possono essere compressi per spremere in un minor numero di byte. Questo processo è chiamato minimizzazione. La minimizzazione non modifica la codifica dei file, sono ancora testo e un file minimizzato deve ancora essere un codice valido per la sua lingua originale. I file minimizzati mantengono le loro estensioni originali.
La cosa principale rimossa in un file ridotto sono gli spazi bianchi non necessari e dal punto di vista del computer quasi tutti gli spazi bianchi in CSS e JavaScript non sono necessari. Gli schemi di minimizzazione abbreviano anche i nomi delle variabili e rimuovono i commenti.
La minimizzazione per impostazione predefinita offusca il codice; come sviluppatore, dovresti lavorare esclusivamente con file non minimizzati. Alcuni passaggi automatici durante il processo di distribuzione dovrebbero ridurre al minimo i file prima che vengano archiviati e serviti. Se stai utilizzando una libreria fornita da una CDN di terze parti, assicurati di utilizzare la versione ridotta di tale libreria, se disponibile. I file HTML possono essere minimizzati, ma poiché Django utilizza il rendering lato server, il costo di elaborazione per farlo al volo molto probabilmente supererebbe la piccola riduzione delle dimensioni della pagina.
Disponibilità globale
Proprio come per inviare una lettera al tuo vicino ci vuole meno tempo che per inviarla in tutto il paese, così ci vuole meno tempo per trasmettere dati nelle vicinanze che in tutto il mondo. Uno dei modi in cui una CDN migliora le prestazioni della pagina è copiare le risorse sui server di tutto il mondo. Quindi, quando un client effettua una richiesta, riceve le risorse statiche dal server più vicino (spesso chiamato nodo perimetrale), diminuendo i tempi di caricamento. Uno dei vantaggi dell'utilizzo di una CDN con un sito Django è disaccoppiare la distribuzione globale delle risorse statiche dalla distribuzione globale del codice.
Cache lato client
Cosa c'è di meglio che avere un file statico su un server vicino al tuo utente? Avere il file statico già memorizzato sul dispositivo dell'utente! La memorizzazione nella cache è il processo di memorizzazione dei risultati di un calcolo o di una richiesta in modo che sia possibile accedervi ripetutamente più rapidamente. Proprio come un foglio di stile CSS può essere memorizzato nella cache in tutto il mondo in una CDN, può essere memorizzato nella cache nel browser del client la prima volta che caricano una pagina dal tuo sito. Quindi, il foglio di stile è disponibile sul dispositivo stesso nelle richieste successive, quindi il client sta effettuando meno richieste, migliorando il tempo di caricamento della pagina e diminuendo l'utilizzo della larghezza di banda.
I browser eseguono le proprie operazioni di memorizzazione nella cache, ma se il tuo sito riceve un traffico notevole, puoi ottimizzare il comportamento della memorizzazione nella cache lato client utilizzando il framework della cache di Django.
In conclusione
Ancora una volta, la mia filosofia guida è usare gli strumenti per ciò che sanno fare meglio. I progetti a server singolo e le piccole implementazioni scalabili con solo asset statici leggeri possono utilizzare la gestione degli asset statici incorporata di Django, ma la maggior parte delle applicazioni dovrebbe separare gli asset da servire su una CDN.
Se il tuo progetto è destinato a qualsiasi tipo di uso di parole reali, non archiviare file multimediali con il metodo predefinito di Django, utilizza invece un servizio. Con traffico sufficiente, dove "traffico sufficiente" è un numero relativamente piccolo sulla scala di Internet, le complicazioni aggiuntive all'architettura, al processo di sviluppo e all'implementazione valgono più che per le prestazioni, l'affidabilità e il risparmio sui costi dell'utilizzo di un CDN separata e soluzione di archiviazione file rispettivamente per file statici e multimediali.
Lettura consigliata
- Parte 1: modelli utente e autenticazione
- Parte 2: La creazione di modelli salva le linee
- Parte 3: Modelli, amministrazione e sfruttamento del database relazionale