Repere Django: Șabloanele salvează linii (Partea a 2-a)
Publicat: 2022-03-10Unele abordări simple pentru construirea de site-uri web necesită ca un dezvoltator să scrie manual fiecare linie de HTML. Pe de altă extremă, creatorii comerciali de site-uri fără cod creează automat tot codul HTML pentru utilizator, adesea în detrimentul lizibilității codului rezultat. Modelarea se află la mijlocul acestui spectru, dar mai aproape de HTML scris de mână decât, de exemplu, generarea structurii paginii într-o aplicație cu o singură pagină folosind React sau o bibliotecă similară. Acest punct favorabil pe continuum oferă multe dintre beneficiile HTML manual de la zero (cod semantic/lizibil, control deplin asupra structurii paginii, încărcare rapidă a paginii) și adaugă separarea preocupărilor și concizie, totul în detrimentul petrecerii timpului scris. HTML modificat manual. Acest articol demonstrează utilizarea șablonului Django pentru a scrie pagini complexe.
Subiectul de astăzi se aplică dincolo de cadrul Django. Flask (un alt cadru web) și Pelican (un generator de site-uri static) sunt doar două dintre multe alte proiecte Python care folosesc aceeași abordare a șabloanelor. Jinja2 este motorul de șabloane pe care îl folosesc toate cele trei cadre, deși puteți utiliza unul diferit modificând setările proiectului (strict vorbind, Jinja2 este un superset de șabloane Django). Este o bibliotecă independentă pe care o puteți încorpora în propriile proiecte chiar și fără un cadru, așa că tehnicile din acest articol sunt în general utile.
Părțile anterioare din serie:
- Repere Django: Modele de utilizator și autentificare (Partea 1)
- Repere Django: modele, administrator și valorificarea bazei de date relaționale (partea 3)
- Repere Django: dispute active statice și fișiere media (partea a 4-a)
Redare pe partea serverului
Un șablon este doar un fișier HTML în care HTML a fost extins cu simboluri suplimentare. Amintiți-vă ce înseamnă HTML: H yper T ext M arkup Language. Jinja2, limbajul nostru de șabloane, pur și simplu adaugă limbajului cu simboluri suplimentare semnificative de marcare. Aceste structuri suplimentare sunt interpretate atunci când serverul redă șablonul pentru a oferi utilizatorului o pagină HTML simplă (adică simbolurile suplimentare din limbajul de șablon nu ajung în rezultatul final).
Redarea pe server este procesul de construire a unei pagini web ca răspuns la o solicitare. Django folosește redarea pe partea de server pentru a furniza pagini HTML către client. La sfârșitul execuției sale, o funcție de vizualizare combină cererea HTTP, unul sau mai multe șabloane și, opțional, datele accesate în timpul execuției funcției pentru a construi o singură pagină HTML pe care o trimite ca răspuns către client. Datele trec din baza de date, prin vizualizare și în șablon pentru a ajunge la utilizator. Nu vă faceți griji dacă această explicație abstractă nu are pe deplin sens, vom apela la un exemplu concret pentru restul acestui articol.
Configurare
Pentru exemplul nostru, vom lua o pagină web destul de complexă, Porniți șablonul de administrator al Bootstrap și vom rescrie HTML-ul ca șablon Jinja2. Rețineți că biblioteca cu licență de MIT utilizează un sistem de șabloane diferit (bazat pe JavaScript și Pug) pentru a genera pagina pe care o vedeți, dar abordarea lor diferă substanțial de șablările în stil Jinja2, așa că acest exemplu este mai mult o inginerie inversă decât o traducere. de excelentul lor proiect open-source. Pentru a vedea pagina web pe care o vom construi, puteți arunca o privire la previzualizarea live a Start Bootstrap.
Am pregătit un exemplu de aplicație pentru acest articol. Pentru a rula proiectul Django pe propriul computer, porniți mediul virtual Python 3 și apoi executați următoarele comenzi:
pip install django git clone https://github.com/philipkiely/sm_dh_2_dashboard.git cd sm_dh_2_dashboard python manage.py migrate python manage.py createsuperuser python manage.py loaddata employee_fixture.json python manage.py runserver
Apoi, deschideți browserul web și navigați la https://127.0.0.1:8000
. Ar trebui să vedeți aceeași pagină ca și previzualizarea, care se potrivește cu imaginea de mai jos.
Deoarece acest tutorial este axat pe frontend, aplicația Django de bază este foarte simplă. Aceasta poate părea o mulțime de configurații pentru prezentarea unei singure pagini web și, pentru a fi corect, este. Cu toate acestea, această configurație poate suporta și o aplicație mult mai robustă.
Acum, suntem gata să trecem prin procesul de transformare a acestui fișier HTML de 668 de linii într-un site Django arhitecturat corespunzător.
Șablonare și moștenire
Primul pas în refactorizarea a sute de linii de HTML în cod curat este împărțirea elementelor în propriile șabloane, pe care Django le va compune într-o singură pagină web în timpul etapei de randare.
Aruncă o privire în pagini/șabloane . Ar trebui să vedeți cinci fișiere:
- base.html , șablonul de bază pe care îl va extinde fiecare pagină web. Conține
<head>
cu titlul, importurile CSS etc. - navbar.html , HTML-ul pentru bara de navigare de sus, o componentă care trebuie inclusă acolo unde este necesar.
- footer.html , codul pentru subsolul paginii, o altă componentă care trebuie inclusă acolo unde este necesar.
- sidebar.html , HTMl pentru bara laterală, o a treia componentă care trebuie inclusă atunci când este necesar.
- index.html , codul unic pentru pagina principală. Acest șablon extinde șablonul de bază și include cele trei componente.
Django asamblează aceste cinci fișiere precum Voltron pentru a reda pagina de index. Cuvintele cheie care permit acest lucru sunt {% block %}
, {% include %}
și {% extend %}
. În base.html :
{% block content %} {% endblock %}
Aceste două linii lasă spațiu pentru alte șabloane care extind base.html pentru a-și insera propriul HTML. Rețineți că content
este un nume variabil, puteți avea mai multe blocuri cu nume diferite într-un șablon, oferind flexibilitate șabloanelor copil. Vedem cum să extindem acest lucru în index.html :
{% extends "base.html" %} {% block content %} <!-- HTML Goes Here --> {% endblock %}
Folosirea cuvântului cheie extends
cu numele șablonului de bază oferă paginii de index structura sa, scutindu-ne de copierea în antet (rețineți că numele fișierului este o cale relativă în formă de șir de ghilimele duble). Pagina de index include toate cele trei componente care sunt comune pentru majoritatea paginilor de pe site. Aducem acele componente cu etichete include
, după cum urmează:
{% extends "base.html" %} {% block content %} {% include "navbar.html" %} {% include "sidebar.html" %} <!--Index-Specific HTML--> {% include "footer.html" %} <!--More Index-Specific HTML--> {% endblock %}
În general, această structură oferă trei beneficii cheie în ceea ce privește scrierea paginilor individual:
- Cod USCAT (nu te repeta).
Prin factorizarea codului comun în fișiere specifice, putem schimba codul într-un singur loc și reflectăm acele modificări pe toate paginile. - Lizibilitate crescută
În loc să defilați printr-un fișier gigant, puteți izola componenta specifică care vă interesează. - Separarea preocupărilor
Codul pentru, să zicem, bara laterală trebuie să fie acum într-un singur loc, nu pot exista etichete descript
necinstite care plutesc în partea de jos a codului sau alte amestecări între ceea ce ar trebui să fie componente separate. Eliminarea pieselor individuale forțează această practică bună de codificare.
Deși am putea salva și mai multe linii de cod prin introducerea componentelor specifice în șablonul base.html , păstrarea lor separată oferă două avantaje. Primul este că putem să le încorporam exact acolo unde le aparțin într-un singur bloc (acest lucru este relevant doar pentru footer.html care intră în div
-ul principal al blocului de content
). Celălalt avantaj este că, dacă ar fi să creăm o pagină, să zicem o pagină de eroare 404, și nu am vrea bara laterală sau subsolul, le-am putea lăsa afară.
Aceste capacități sunt egale pentru cursul de șabloane. Acum, ne întoarcem la etichete puternice pe care le putem folosi în index.html pentru a oferi funcții dinamice și pentru a salva sute de linii de cod.
Două etichete fundamentale
Aceasta este foarte departe de o listă exhaustivă de etichete disponibile. Documentația Django despre șabloane oferă o astfel de enumerare. Pentru moment, ne concentrăm pe cazurile de utilizare pentru două dintre cele mai comune elemente ale limbajului de șabloane. În propria mea muncă, practic folosesc doar etichetele for
și if
în mod regulat, deși zecile sau mai multe alte etichete furnizate au propriile lor cazuri de utilizare, pe care vă încurajez să le examinați în referința șablonului.
Înainte de a ajunge la etichete, vreau să fac o notă despre sintaxă. Eticheta {% foo %}
înseamnă că „foo” este o funcție sau altă capacitate a sistemului de șabloane în sine, în timp ce eticheta {{ bar }}
înseamnă că „bar” este o variabilă transmisă în șablonul specific.
Pentru bucle
În restul index.html , cea mai mare secțiune de cod cu câteva sute de linii este tabelul. În loc de acest tabel codificat, putem genera tabelul dinamic din baza de date. Reamintim python manage.py loaddata employee_fixture.json
din pasul de configurare. Această comandă a folosit un fișier JSON, numit Django Fixture, pentru a încărca toate cele 57 de înregistrări ale angajaților în baza de date a aplicației. Folosim vizualizarea din views.py pentru a transmite aceste date șablonului:
from django.shortcuts import render from .models import Employee def index(request): return render(request, "index.html", {"employees": Employee.objects.all()})
Al treilea argument pozițional de render
este un dicționar de date care este pus la dispoziție șablonului. Folosim aceste date și eticheta for
pentru a construi tabelul. Chiar și în șablonul original din care am adaptat această pagină web, tabelul de angajați a fost codificat. Noua noastră abordare reduce sute de rânduri de rânduri repetitive de tabel codificate. index.html conține acum:
{% for employee in employees %} <trv <td>{{ employee.name }}</td> <td>{{ employee.position }}</td> <td>{{ employee.office }}</td> <td>{{ employee.age }}</td> vtd>{{ employee.start_date }}</td> <td>${{ employee.salary }}</td> </tr> {% endfor %}
Avantajul mai mare este că acest lucru simplifică foarte mult procesul de actualizare a tabelului. În loc să solicite unui dezvoltator să editeze manual codul HTML pentru a reflecta o creștere a salariului sau o nouă angajare, apoi să introducă această modificare în producție, orice administrator poate folosi panoul de administrare pentru a face actualizări în timp real (https://127.0.0.1/admin, utilizați acreditările pe care le-ați creat cu python manage.py createsuperuser
pentru a le accesa). Acesta este un avantaj al utilizării Django cu acest motor de randare în loc de a-l folosi singur într-un generator de site static sau altă abordare de șabloane.
Dacă Altceva
Eticheta if
este o etichetă incredibil de puternică care vă permite să evaluați expresiile din șablon și să ajustați HTML în consecință. Liniile precum {% if 1 == 2 %}
sunt perfect valide, chiar dacă puțin inutile, deoarece evaluează la același rezultat de fiecare dată. Unde eticheta if
strălucește este atunci când interacționați cu datele transmise în șablon de vizualizare. Luați în considerare următorul exemplu din sidebar.html :
<div class="sb-sidenav-footer"> <div class="small"> Logged in as: </div> {% if user.is_authenticated %} {{ user.username }} {% else %} Start Bootstrap {% endif %} </div>
Rețineți că întregul obiect utilizator este trecut în șablon în mod implicit, fără ca noi să specificăm nimic în vizualizare pentru a face acest lucru. Acest lucru ne permite să accesăm starea de autentificare a utilizatorului (sau lipsa acesteia), numele de utilizator și alte caracteristici, inclusiv urmărirea relațiilor cu chei străine pentru a accesa datele stocate într-un profil de utilizator sau alt model conectat, toate din fișierul HTML.
S-ar putea să vă îngrijoreze că acest nivel de acces ar putea prezenta riscuri de securitate. Cu toate acestea, rețineți că aceste șabloane sunt pentru un cadru de randare pe partea de server. După construirea paginii, etichetele s-au consumat de la sine și sunt înlocuite cu HTML pur. Astfel, dacă o instrucțiune if
introduce date într-o pagină în anumite condiții, dar datele nu sunt utilizate într-o anumită instanță, atunci acele date nu vor fi trimise deloc către client, deoarece instrucțiunea if
este evaluată pe partea serverului. Aceasta înseamnă că un șablon construit corespunzător este o metodă foarte sigură de a adăuga date sensibile la pagini fără ca aceste date să părăsească serverul, dacă nu este necesar. Acestea fiind spuse, utilizarea șablonului Django nu elimină necesitatea de a comunica informațiile sensibile într-o manieră sigură, criptată, înseamnă pur și simplu că verificările de securitate precum user.is_authenticated
pot avea loc în siguranță în HTML, deoarece sunt procesate pe partea serverului.
Această caracteristică are o serie de alte cazuri de utilizare. De exemplu, într-o pagină de pornire generală a unui produs, este posibil să doriți să ascundeți butoanele „înregistrare” și „conectare” și să le înlocuiți cu un buton „deconectare” pentru utilizatorii conectați. O altă utilizare comună este afișarea și ascunderea mesajelor de succes sau de eroare pentru operațiuni precum trimiterea formularelor. Rețineți că, în general, nu veți ascunde întreaga pagină dacă utilizatorul nu este conectat. O modalitate mai bună de a schimba întreaga pagină web pe baza stării de autentificare a utilizatorului este să o gestionați în funcția corespunzătoare din views.py .
Filtrare
O parte a sarcinii vizualizării este de a formata datele în mod corespunzător pentru pagină. Pentru a realiza acest lucru, avem o extensie puternică pentru etichete: filtre. Există multe filtre disponibile în Django pentru a efectua acțiuni precum justificarea textului, formatarea datelor și adăugarea de numere. Practic, vă puteți gândi la un filtru ca la o funcție care este aplicată variabilei dintr-o etichetă. De exemplu, dorim ca numerele noastre de salariu să citească „1.200.000 USD” în loc de „1200000”. Vom folosi un filtru pentru a face treaba în index.html :
<td>${{ employee.salary|intcomma }}</td>
Caracterul conductei |
este filtrul care aplică comanda intcomma
variabilei employee.salary
. Caracterul „$” nu provine din șablon, pentru un element ca cel care apare de fiecare dată, este mai ușor să-l lipiți în afara etichetei.
Rețineți că intcomma
ne cere să includem {% load humanize %}
în partea de sus a index.html și 'django.contrib.humanize',
în INSTALLED_APPS
în settings.py . Acest lucru se face pentru dvs. în exemplul de aplicație furnizat.
Concluzie
Redarea pe partea serverului cu motorul Jinja2 oferă instrumente cheie pentru crearea unui cod front-end curat, adaptabil și receptiv. Separarea paginilor în fișiere permite componentele DRY cu compoziție flexibilă. Etichetele oferă capabilități fundamentale pentru afișarea datelor transmise din baza de date prin funcții de vizualizare. Făcută corect, această abordare poate crește viteza, capacitățile SEO, securitatea și capacitatea de utilizare a site-ului și este un aspect de bază al programării în Django și cadre similare.
Dacă nu ați făcut acest lucru deja, consultați exemplul de aplicație și încercați să adăugați propriile etichete și filtre folosind lista completă.
Django Highlights este o serie care introduce concepte importante de dezvoltare web în Django. Fiecare articol este scris ca un ghid independent pentru o fațetă a dezvoltării Django menită să ajute dezvoltatorii și designerii front-end să ajungă la o înțelegere mai profundă a „cealaltă jumătate” a bazei de cod. Aceste articole sunt în mare parte construite pentru a vă ajuta să înțelegeți teoria și convenția, dar conțin câteva exemple de cod, care sunt scrise în Django 3.0.
Părțile anterioare din serie:
- Repere Django: Modele de utilizator și autentificare (Partea 1)
- Repere Django: modele, administrator și valorificarea bazei de date relaționale (partea 3)
- Repere Django: dispute active statice și fișiere media (partea a 4-a)