Repere Django: dispute active statice și fișiere media (partea a 4-a)

Publicat: 2022-03-10
Rezumat rapid ↬ Dezvoltatorii și designerii front-end creează elemente statice uimitoare pentru aplicații web. Astăzi, ne concentrăm asupra a ceea ce se întâmplă după ce remedierea rapidă a stilului sau grafica frumoasă pe care tocmai ați terminat-o este împinsă să stăpânească. De asemenea, vom investiga gestionarea fișierelor pe care utilizatorii le încarcă, numite fișiere media. Împreună, vom dezvolta o intuiție pentru strategiile disponibile pentru dezvoltatorii Django pentru a furniza aceste fișiere utilizatorilor din întreaga lume într-o manieră sigură, performantă și rentabilă.

Site-urile web Django implică o mulțime de fișiere. Nu este doar cod sursă pentru configurație, modele, vizualizări și șabloane, ci și active statice: CSS și JavaScript, imagini, pictograme. De parcă asta nu ar fi fost deja suficient, uneori vin utilizatorii și doresc să-și încarce propriile fișiere pe site-ul dvs. web. Este suficient pentru a face orice dezvoltator neîncrezător. Fișiere peste tot!

Iată unde mi-aș dori să pot spune (fără avertismente): „Nu-ți face griji, Django te sprijină!” Dar, din păcate, atunci când aveți de-a face cu active statice și fișiere media, există o mulțime de avertismente de rezolvat.

Astăzi, vom aborda stocarea și servirea fișierelor atât pentru implementări cu un singur server, cât și pentru implementări scalabile, luând în considerare factori precum compresia, stocarea în cache și disponibilitatea. De asemenea, vom discuta despre costurile și beneficiile CDN-urilor și ale soluțiilor dedicate de stocare a fișierelor.

Notă : Acesta nu este un tutorial despre cum să implementați un site Django pe o anumită platformă. În schimb, ca și celelalte articole din seria Django Highlights (a se vedea mai jos), este conceput ca un ghid pentru dezvoltatorii și designerii front-end pentru a înțelege alte părți ale procesului de creare a unei aplicații web. Astăzi, ne concentrăm asupra a ceea ce se întâmplă după ce remedierea rapidă a stilului sau grafica frumoasă pe care tocmai ați terminat-o este împinsă să stăpânească. Împreună, vom dezvolta o intuiție pentru strategiile disponibile pentru dezvoltatorii Django pentru a furniza aceste fișiere utilizatorilor din întreaga lume într-o manieră sigură, performantă și rentabilă.

Părțile anterioare din serie:

  • Partea 1: Modele de utilizator și autentificare
  • Partea 2: Șablonul salvează linii
  • Partea 3: Modele, administrare și valorificarea bazei de date relaționale
Mai multe după săritură! Continuați să citiți mai jos ↓

Definiții

Cei mai mulți dintre acești termeni sunt destul de simpli, dar merită să acordați un moment pentru a stabili un vocabular comun pentru această discuție.

Cele trei tipuri de fișiere dintr-o aplicație Django live sunt:

  1. Cod sursa
    Fișierele Python și HTML care sunt create cu framework-ul Django. Aceste fișiere sunt nucleul aplicației. Fișierele de cod sursă sunt în general destul de mici, măsurate în kiloocteți.
  2. Fișiere statice
    Denumite și „active statice”, aceste fișiere includ CSS și JavaScript, ambele scrise de dezvoltatorul aplicației și biblioteci terțe, precum și fișiere PDF, instalatoare de software, imagini, muzică, videoclipuri și pictograme. Aceste fișiere sunt utilizate numai pe partea clientului. Fișierele statice variază de la câțiva kilobytes de CSS la gigabytes de video.
  3. Fișiere media
    Orice fișier încărcat de un utilizator, de la imagini de profil la documente personale, se numește fișier media. Aceste fișiere trebuie să fie stocate și recuperate în siguranță și fiabil pentru utilizator. Fișierele media pot fi de orice dimensiune, utilizatorul poate încărca câțiva kilobytes de text simplu pe câțiva gigabytes de video. Dacă vă aflați la ultimul capăt al acestei scale, probabil că aveți nevoie de un sfat mai specializat decât este pregătit să vă ofere acest articol.

Cele două tipuri de implementări Django sunt:

  1. cu un singur server
    O implementare Django pe un singur server este exact ceea ce sună: totul trăiește pe un singur server. Această strategie este foarte simplă și seamănă foarte mult cu mediul de dezvoltare, dar nu poate gestiona eficient cantități mari sau inconsecvente de trafic. Abordarea cu un singur server este aplicabilă numai pentru proiecte de învățare sau demonstrative, nu pentru aplicații reale care necesită timp de funcționare fiabil.
  2. Scalabil
    Există o mulțime de moduri diferite de a implementa un proiect Django care îi permite să se extindă pentru a satisface cererea utilizatorilor. Aceste strategii implică adesea rotirea în sus și în jos a numeroase servere și utilizarea unor instrumente precum echilibrarea încărcăturii și bazele de date gestionate. Din fericire, putem îngloba în mod eficient tot ceea ce este mai complex decât o implementare pe un singur server în această categorie, în sensul acestui articol.

Opțiunea 1: Django implicit

Proiectele mici beneficiază de o arhitectură simplă. Gestionarea implicită de către Django a activelor statice și a fișierelor media este doar atât: simplă. Pentru fiecare, aveți un folder rădăcină care stochează fișierele și locuiește chiar lângă codul sursă de pe server. Simplu. Aceste foldere rădăcină sunt generate și gestionate în principal prin configurația yourproject/settings.py .

Active statice

Cel mai important lucru de înțeles atunci când lucrați cu fișiere statice în Django este comanda python manage.py collectstatic . Această comandă parcurge folderul static al fiecărei aplicații din proiectul Django și copiază toate activele statice în folderul rădăcină. Rularea acestei comenzi este o parte importantă a implementării unui proiect Django. Luați în considerare următoarea structură de directoare:

 - 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 - ...

De asemenea, presupuneți următoarele setări în project/settings.py :

 STATIC_URL = "/static/" STATIC_ROOT = "/path/on/server/to/djangoproject/static"

Rularea python manage.py collectstatic va crea următorul folder pe server:

 - /path/on/server/to/djangoproject/static - app1 - style.css - script.js - img.jpg - app2 - style.css - image.png

Observați că în fiecare folder static, există un alt folder cu numele aplicației. Acest lucru este pentru a preveni conflictele de spațiere a numelor după ce fișierele statice sunt colectate; după cum puteți vedea în structura de fișiere de mai sus, aceasta păstrează distincte app1/style.css și app2/style.css . De aici, aplicația va căuta fișiere statice în această structură la STATIC_ROOT în timpul producției. Ca atare, faceți referire la fișierele statice, după cum urmează, într-un șablon în app1/templates/ :

 {% load static %} <link rel="stylesheet" type="text/css" href="{% static "app1/style.css" %}">

Django își dă seama automat de unde să obțină fișierul static în dezvoltare pentru a modela acest comportament, nu trebuie să rulați collectstatic în timpul dezvoltării.

Pentru mai multe detalii, consultați documentația Django.

Fișiere media

Imaginați-vă un site de rețea profesional cu o bază de date de utilizatori. Fiecare dintre acești utilizatori ar avea un profil asociat, care ar putea conține, printre altele, o imagine de avatar și un document de CV. Iată un scurt exemplu de model al acestor informații:

 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)

Pentru ca acest lucru să funcționeze, aveți nevoie de următoarele opțiuni în project/settings.py , la fel ca în cazul activelor statice:

 MEDIA_URL = "/media/" MEDIA_ROOT = "/path/on/server/to/media"

Un ImageField moștenește de la FileField , deci împărtășește aceiași parametri și capacități. Ambele câmpuri au un argument opțional upload_to , care preia un șir care este o cale și îl adaugă la MEDIA_ROOT pentru a stoca fișierul, care este apoi accesibil prin aceeași cale deasupra MEDIA_URL . Argumentul upload_to poate lua și o funcție care returnează un șir, așa cum este demonstrat cu funcția avatar_path .

Asigurați-vă că omiteți directorul fișierelor media și conținutul acestuia din controlul versiunilor. Conținutul său poate intra în conflict atunci când doi dezvoltatori testează aceeași aplicație pe mașini diferite și, spre deosebire de activele statice, nu face parte din aplicația Django implementabilă.

Opțiunea 2: Django cu servicii

Filosofia mea călăuzitoare este să folosesc instrumentele pentru ceea ce sunt cei mai buni. Django este un cadru uimitor și oferă instrumente excelente pentru autentificarea utilizatorului, randarea pe server, lucrul cu modele și formulare, funcții administrative și zeci de alte aspecte esențiale ale construirii de aplicații web. Cu toate acestea, instrumentele sale pentru manipularea activelor statice și a fișierelor media nu sunt, în opinia mea, potrivite pentru producția pe site-uri scalabile. Dezvoltatorii de bază Django recunosc că mulți oameni aleg abordări alternative pentru gestionarea acestor fișiere în producție; cadrul este foarte bun pentru a vă ieși din cale atunci când o faceți. Majoritatea site-urilor Django destinate utilizării generale vor dori să încorporeze active statice și să gestioneze fișierele media folosind aceste abordări non-specifice Django.

Active statice pe un CDN

În timp ce proiectele mici și mijlocii pot scăpa fără unul, o CDN (rețea de livrare de conținut) este ușor de utilizat și îmbunătățește performanța aplicațiilor de orice dimensiune. Un CDN este o rețea de servere, în general la nivel mondial, care distribuie și servește conținut web, mai ales active statice. CDN-urile populare includ Cloudflare CDN, Amazon CloudFront și Fastly. Pentru a utiliza un CDN, încărcați fișierele statice, apoi faceți referire la ele în aplicație după cum urmează:

 <link rel="stylesheet" type="text/css" href="https://cdn.example.com/path/to/your/files/app1/style.css">

Acest proces este ușor de integrat cu scripturile dvs. de implementare Django. După ce rulați comanda python manage.py collectstatic , copiați directorul generat în CDN-ul dvs. (un proces care variază substanțial în funcție de serviciul pe care îl utilizați), apoi eliminați activele statice din pachetul de implementare Django.

În dezvoltare, veți dori să accesați diferite copii ale activelor dvs. statice decât în ​​producție. În acest fel, puteți face modificări la nivel local fără a afecta locul de producție. Puteți fie să utilizați active locale, fie să rulați oa doua instanță a CDN-ului pentru a livra fișierele. Configurați yourproject/settings.py cu o variabilă personalizată, cum ar fi CDN_URL , și utilizați acea valoare în șabloane pentru a vă asigura că utilizați versiunea corectă a materialelor în dezvoltare și producție.

O notă finală este că multe biblioteci pentru CSS și JavaScript au CDN-uri gratuite pe care majoritatea site-urilor web le pot folosi. Dacă încărcați, de exemplu, Bootstrap 4 sau underscore.js, puteți săriți peste bătaia de cap de a vă folosi propria copie în dezvoltare și cheltuielile de a vă servi propriile copii în producție folosind aceste CDN-uri publice.

Fișiere media cu un depozit de fișiere dedicat

Niciun site Django de producție nu ar trebui să stocheze fișierele utilizatorului într-un folder simplu /media/ undeva pe serverul care rulează site-ul. Iată trei dintre numeroasele motive pentru care nu:

  1. Dacă trebuie să măriți site-ul adăugând mai multe servere, aveți nevoie de o modalitate de a copia și sincroniza fișierele încărcate pe acele servere.
  2. Dacă un server se blochează, codul sursă este copiat de rezervă în sistemul dvs. de control al versiunilor, dar fișierele media nu sunt copiate în mod implicit, cu excepția cazului în care v-ați configurat serverul pentru a face acest lucru, dar pentru acest efort ar fi mai bine să utilizați un server dedicat. depozit de fișiere.
  3. În cazul unei activități rău intenționate, este oarecum mai bine să păstrați fișierele încărcate de utilizator pe un server separat de cel care rulează aplicația, deși acest lucru nu înlătură în niciun caz cerința de a valida fișierele încărcate de utilizator.

Integrarea unei terțe părți pentru a stoca fișierele încărcate de utilizator este foarte ușoară. Nu trebuie să modificați nimic în codul dvs., cu excepția posibilității de a elimina sau de a modifica valoarea upload_to a FileField -urilor din modelele dvs. și de a configura câteva setări. De exemplu, dacă intenționați să vă stocați fișierele în AWS S3, ați dori să faceți următoarele, care este foarte similar cu procesul de stocare a fișierelor cu Google Cloud, Azure, Backblaze sau servicii concurente similare.

Mai întâi, va trebui să instalați bibliotecile boto3 și django-storages storages. Apoi, trebuie să configurați un bucket și un rol IAM pe AWS, care nu intră în domeniul de aplicare al acestui articol, dar puteți vedea instrucțiuni pentru aici. Odată ce toate acestea sunt configurate, trebuie să adăugați trei variabile la proiectul/settings.py :

 DEFAULT_FILE_STORAGE = "storages.backends.s3boto3.S3Boto3Storage" AWS_STORAGE_BUCKET_NAME = "BUCKET_NAME" AWS_S3_REGION_NAME = "us-east-2"

În plus, va trebui să configurați accesul la acreditările la compartimentul dvs. AWS. Unele tutoriale vor demonstra adăugarea unui ID și a unei chei secrete la fișierul de setări sau ca variabile de mediu, dar acestea sunt practici nesigure. În schimb, utilizați django-storages cu AWS CLI pentru a configura cheile, așa cum este descris aici. S-ar putea să fiți interesat și de documentația django-storages .

Nu doriți ca fișierele media de dezvoltare sau testare să se amestece cu încărcările de la utilizatori reali. Evitarea acestui lucru este destul de simplă: configurați mai multe compartimente, una pentru dezvoltare (sau una pentru fiecare dezvoltator), una pentru testare și una pentru producție. Apoi, tot ce trebuie să schimbați este setarea AWS_STORAGE_BUCKET_NAME per mediu și sunteți gata.

Performanță și disponibilitate

Există numeroși factori care afectează performanța și fiabilitatea site-ului dvs. Iată câteva dintre cele importante atunci când luați în considerare fișierele statice și media, care contează, indiferent de abordarea pe care o luați pentru a le gestiona.

Cost

Servirea fișierelor unui utilizator costă bani din două motive: stocare și lățime de bandă. Trebuie să plătiți furnizorului de găzduire pentru a stoca fișierele pentru dvs., dar trebuie să le plătiți și pentru a servi fișierele. Lățimea de bandă este substanțial mai costisitoare decât stocarea (de exemplu, AWS S3 percepe 2,3 cenți pe gigaoctet pentru stocare, față de 9 cenți per gigaoctet de transfer de date pe Internet la momentul scrierii). Economia unui depozit de fișiere precum S3 sau un CDN este diferită de economia unei gazde generalizate precum o picătură Digital Ocean. Profitați de specializare și de economiile de scară prin mutarea fișierelor costisitoare în servicii concepute pentru acestea. În plus, multe magazine de fișiere și CDN-uri oferă planuri gratuite, astfel încât site-urile care ar putea fi suficient de mici pentru a scăpa fără a le folosi să poată face acest lucru și să profite de beneficii fără costuri suplimentare de infrastructură.

Compresie și transcodare

Majoritatea problemelor cauzate de elementele statice, cum ar fi fotografiile și videoclipurile, se datorează faptului că sunt fișiere mari. Desigur, dezvoltatorii abordează acest lucru încercând să facă aceste fișiere mai mici. Există mai multe moduri de a face acest lucru folosind o combinație de compresie și transcodare în două categorii generale: fără pierderi și cu pierderi. Compresia fără pierderi păstrează calitatea originală a activelor, dar oferă scăderi relativ modeste ale dimensiunii fișierului. Compresia cu pierderi, sau transcodarea într-un format cu pierderi, permite dimensiuni mult mai mici ale fișierelor în detrimentul pierderii unei părți din calitatea artefactului original. Un exemplu în acest sens este transcodarea video la o rată de biți mai mică. Pentru detalii, consultați acest articol despre optimizarea difuzării videoclipurilor. Când difuzați fișiere mari pe web, vitezele lățimii de bandă necesită adesea să serviți artefacte foarte comprimate, necesitând compresie cu pierderi.

Cu excepția cazului în care ești YouTube, compresia și transcodarea nu se întâmplă din mers. Elementele statice ar trebui să fie formatate corespunzător înainte de implementare și puteți aplica restricții de bază privind tipul de fișier și dimensiunea fișierelor la încărcările utilizatorilor pentru a asigura o compresie suficientă și o formatare adecvată în fișierele media ale utilizatorilor dvs.

Minificare

În timp ce fișierele JavaScript și CSS nu sunt de obicei la fel de mari ca imaginile, ele pot fi adesea comprimate pentru a se stoarce în mai puțini octeți. Acest proces se numește minificare. Minimizarea nu modifică codificarea fișierelor, acestea sunt în continuare text și un fișier redus trebuie încă să fie cod valid pentru limba sa originală. Fișierele minimizate își păstrează extensiile originale.

Principalul lucru eliminat într-un fișier minificat este spațiul alb inutil, iar din perspectiva computerului aproape toate spațiile albe din CSS și JavaScript sunt inutile. Schemele de minimizare scurtează, de asemenea, numele variabilelor și elimină comentariile.

Minificarea în mod implicit ofusca codul; ca dezvoltator, ar trebui să lucrați exclusiv cu fișiere care nu sunt reduse. Unele etape automate din timpul procesului de implementare ar trebui să reducă fișierele înainte de a fi stocate și servite. Dacă utilizați o bibliotecă furnizată de un CDN terță parte, asigurați-vă că utilizați versiunea redusă a bibliotecii respective, dacă este disponibilă. Fișierele HTML pot fi reduse, dar, deoarece Django folosește randarea pe server, costul de procesare pentru a face acest lucru din mers ar depăși cel mai probabil scăderea mică a dimensiunii paginii.

Disponibilitate globală

Așa cum este nevoie de mai puțin timp pentru a trimite o scrisoare către vecinul tău decât pentru a o trimite în țară, la fel durează mai puțin timp pentru a transmite date în apropiere decât în ​​întreaga lume. Unul dintre modalitățile prin care un CDN îmbunătățește performanța paginii este prin copierea activelor pe servere din întreaga lume. Apoi, atunci când un client face o solicitare, primește activele statice de la cel mai apropiat server (numit adesea nod edge), scăzând timpii de încărcare. Unul dintre avantajele utilizării unui CDN cu un site Django este decuplarea distribuției globale a activelor dvs. statice de distribuția globală a codului dvs.

Memorarea în cache pe partea clientului

Ce este mai bun decât să ai un fișier static pe un server lângă utilizatorul tău? Fișierul static este deja stocat pe dispozitivul utilizatorului! Memorarea în cache este procesul de stocare a rezultatelor unui calcul sau unei cereri, astfel încât acestea să poată fi accesate în mod repetat și mai rapid. La fel cum o foaie de stil CSS poate fi stocată în cache în întreaga lume într-un CDN, aceasta poate fi stocată în cache în browserul clientului prima dată când acesta încarcă o pagină de pe site-ul dvs. Apoi, foaia de stil este disponibilă pe dispozitivul însuși în solicitările ulterioare, astfel încât clientul face mai puține solicitări, îmbunătățind timpul de încărcare a paginii și scăzând utilizarea lățimii de bandă.

Browserele efectuează propriile operațiuni de stocare în cache, dar dacă site-ul dvs. se bucură de trafic substanțial, vă puteți optimiza comportamentul de stocare în cache la nivelul clientului folosind cadrul de cache al Django.

În concluzie

Din nou, filosofia mea călăuzitoare este să folosesc instrumentele pentru ceea ce sunt cei mai buni. Proiectele cu un singur server și implementările scalabile mici, cu numai active statice ușoare, pot folosi gestionarea încorporată a activelor statice Django, dar majoritatea aplicațiilor ar trebui să separe activele pentru a fi servite printr-un CDN.

Dacă proiectul dvs. este destinat oricărui tip de utilizare a cuvintelor reale, nu stocați fișiere media cu metoda implicită a Django, ci folosiți un serviciu. Cu suficient trafic, unde „suficient trafic” este un număr relativ mic la scara Internetului, complicațiile suplimentare ale arhitecturii, procesului de dezvoltare și implementării merită mai mult decât performanța, fiabilitatea și economiile de costuri ale utilizării unui CDN separat și soluție de stocare a fișierelor pentru fișiere statice și, respectiv, media.

Lectură recomandată

  • Partea 1: Modele de utilizator și autentificare
  • Partea 2: Șablonul salvează linii
  • Partea 3: Modele, administrare și valorificarea bazei de date relaționale