Punti salienti di Django: la creazione di modelli salva le linee (parte 2)
Pubblicato: 2022-03-10Alcuni approcci senza fronzoli alla creazione di siti Web richiedono che uno sviluppatore scriva a mano ogni riga di HTML. All'altro estremo, i costruttori di siti commerciali senza codice creano automaticamente tutto l'HTML per l'utente, spesso a scapito della leggibilità del codice risultante. Il template si trova a metà di quello spettro, ma più vicino all'HTML scritto a mano che, diciamo, alla generazione della struttura della pagina in un'applicazione a pagina singola usando React o una libreria simile. Questo punto debole nel continuum offre molti dei vantaggi dell'HTML manuale da zero (codice semantico/leggibile, controllo completo sulla struttura della pagina, caricamento rapido delle pagine) e aggiunge separazione delle preoccupazioni e concisione, il tutto a scapito di dedicare un po' di tempo alla scrittura HTML modificato a mano. Questo articolo mostra l'utilizzo del modello Django per scrivere pagine complesse.
L'argomento di oggi si applica oltre il framework Django. Flask (un altro framework Web) e Pelican (un generatore di siti statici) sono solo due di molti altri progetti Python che utilizzano lo stesso approccio alla creazione di modelli. Jinja2 è il motore di creazione di modelli utilizzato da tutti e tre i framework, sebbene sia possibile utilizzarne uno diverso modificando le impostazioni del progetto (in senso stretto, Jinja2 è un superset di modelli Django). È una libreria indipendente che puoi incorporare nei tuoi progetti anche senza un framework, quindi le tecniche di questo articolo sono ampiamente utili.
Parti precedenti della serie:
- Punti salienti di Django: modelli utente e autenticazione (parte 1)
- Punti salienti di Django: modelli, amministrazione e sfruttamento del database relazionale (parte 3)
- Punti salienti di Django: gestione di risorse statiche e file multimediali (parte 4)
Rendering lato server
Un modello è solo un file HTML in cui l'HTML è stato esteso con simboli aggiuntivi. Ricorda cosa significa HTML: Hyper Text Markup L anguage . Jinja2, il nostro linguaggio di creazione di modelli, si aggiunge semplicemente al linguaggio con ulteriori simboli di markup significativi. Queste strutture aggiuntive vengono interpretate quando il server esegue il rendering del modello per servire una semplice pagina HTML all'utente (vale a dire, i simboli aggiuntivi dal linguaggio dei modelli non vengono inseriti nell'output finale).
Il rendering lato server è il processo di costruzione di una pagina Web in risposta a una richiesta. Django utilizza il rendering lato server per fornire pagine HTML al client. Al termine della sua esecuzione, una funzione di visualizzazione combina la richiesta HTTP, uno o più modelli e, facoltativamente, i dati a cui si accede durante l'esecuzione della funzione per costruire un'unica pagina HTML che invia come risposta al client. I dati passano dal database, attraverso la vista e nel modello per raggiungere l'utente. Non preoccuparti se questa spiegazione astratta non ha del tutto senso, passeremo a un esempio concreto per il resto di questo articolo.
Impostare
Per il nostro esempio, prenderemo una pagina web abbastanza complessa, avviare il modello di amministrazione di Bootstrap e riscriveremo l'HTML come un modello Jinja2. Nota che la libreria con licenza MIT utilizza un sistema di modelli diverso (basato su JavaScript e Pug) per generare la pagina che vedi, ma il loro approccio differisce sostanzialmente dal modello in stile Jinja2, quindi questo esempio è più un reverse engineering che una traduzione del loro eccellente progetto open source. Per vedere la pagina web che andremo a costruire, puoi dare un'occhiata all'anteprima live di Start Bootstrap.
Ho preparato un'applicazione di esempio per questo articolo. Per far funzionare il progetto Django sul tuo computer, avvia il tuo ambiente virtuale Python 3 ed esegui i seguenti comandi:
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
Quindi, apri il tuo browser web e vai a https://127.0.0.1:8000
. Dovresti vedere la stessa pagina dell'anteprima, corrispondente all'immagine qui sotto.
Poiché questo tutorial è incentrato sul frontend, l'app Django sottostante è molto semplice. Questo può sembrare un sacco di configurazione per presentare una singola pagina web, e ad essere onesti lo è. Tuttavia, questa configurazione potrebbe supportare anche un'applicazione molto più robusta.
Ora, siamo pronti per seguire il processo di trasformazione di questo file HTML di 668 righe in un sito Django adeguatamente progettato.
Modellistica ed eredità
Il primo passo nel refactoring di centinaia di righe di HTML in codice pulito è dividere gli elementi nei propri modelli, che Django comporrà in un'unica pagina web durante la fase di rendering.
Dai un'occhiata a pagine/modelli . Dovresti vedere cinque file:
- base.html , il modello di base che estenderà ogni pagina web. Contiene il
<head>
con il titolo, le importazioni CSS, ecc. - navbar.html , l'HTML per la barra di navigazione in alto, un componente da inserire dove necessario.
- footer.html , il codice per il footer della pagina, altro componente da inserire dove necessario.
- sidebar.html , l'HTML per la sidebar, un terzo componente da inserire quando richiesto.
- index.html , il codice univoco della pagina principale. Questo modello estende il modello di base e include i tre componenti.
Django assembla questi cinque file come Voltron per eseguire il rendering della pagina dell'indice. Le parole chiave che lo consentono sono {% block %}
, {% include %}
e {% extend %}
. In base.html :
{% block content %} {% endblock %}
Queste due righe lasciano spazio ad altri modelli che estendono base.html per inserire il proprio HTML. Nota che il content
è un nome variabile, puoi avere più blocchi con nomi diversi in un modello, dando flessibilità ai modelli figlio. Vediamo come estenderlo in index.html :
{% extends "base.html" %} {% block content %} <!-- HTML Goes Here --> {% endblock %}
L'uso della parola chiave extends
con il nome del modello di base conferisce alla pagina indice la sua struttura, evitandoci di copiare nell'intestazione (notare che il nome del file è un percorso relativo in forma di stringa tra virgolette). La pagina indice include tutti e tre i componenti comuni alla maggior parte delle pagine del sito. Introduciamo quei componenti con tag di include
come di seguito:
{% extends "base.html" %} {% block content %} {% include "navbar.html" %} {% include "sidebar.html" %} <!--Index-Specific HTML--> {% include "footer.html" %} <!--More Index-Specific HTML--> {% endblock %}
Nel complesso, questa struttura offre tre vantaggi chiave rispetto alla scrittura delle pagine individualmente:
- Codice DRY (non ripetere te stesso).
Scomponendo il codice comune in file specifici, possiamo modificare il codice in un solo posto e riflettere tali modifiche in tutte le pagine. - Maggiore leggibilità
Invece di scorrere un file gigante, puoi isolare il componente specifico che ti interessa. - Separazione degli interessi
Il codice per, diciamo, la barra laterale ora deve essere in un posto, non possono esserci tag discript
canaglia che fluttuano nella parte inferiore del codice o altre mescolanze tra quelli che dovrebbero essere componenti separati. Scomporre i singoli pezzi forza questa buona pratica di codifica.
Anche se potremmo salvare ancora più righe di codice inserendo i componenti specifici nel modello base.html , tenerli separati offre due vantaggi. Il primo è che siamo in grado di incorporarli esattamente dove appartengono in un singolo blocco (questo è rilevante solo per footer.html che va all'interno del div
principale del blocco di content
). L'altro vantaggio è che se dovessimo creare una pagina, diciamo una pagina di errore 404, e non vogliamo la barra laterale o il piè di pagina, potremmo lasciarli fuori.
Queste capacità sono standard per il corso per la creazione di modelli. Ora passiamo a potenti tag che possiamo utilizzare nel nostro index.html per fornire funzionalità dinamiche e salvare centinaia di righe di codice.
Due tag fondamentali
Questo è molto lontano da un elenco esaustivo di tag disponibili. La documentazione di Django sulla creazione di modelli fornisce tale enumerazione. Per ora, ci stiamo concentrando sui casi d'uso per due degli elementi più comuni del linguaggio dei modelli. Nel mio lavoro, fondamentalmente uso solo il tag for
e if
su base regolare, sebbene la dozzina o più di altri tag forniti abbiano i propri casi d'uso, che ti incoraggio a rivedere nel riferimento del modello.
Prima di arrivare ai tag, voglio prendere nota della sintassi. Il tag {% foo %}
significa che "foo" è una funzione o un'altra capacità del sistema di creazione di modelli stesso, mentre il tag {{ bar }}
significa che "bar" è una variabile passata al modello specifico.
Per i loop
Nel restante index.html , la sezione di codice più grande di diverse centinaia di righe è la tabella. Invece di questa tabella hardcoded, possiamo generare la tabella dinamicamente dal database. Richiama python manage.py loaddata employee_fixture.json
dal passaggio di configurazione. Quel comando utilizzava un file JSON, chiamato Django Fixture, per caricare tutti i 57 record dei dipendenti nel database dell'applicazione. Usiamo la vista in views.py per passare questi dati al modello:
from django.shortcuts import render from .models import Employee def index(request): return render(request, "index.html", {"employees": Employee.objects.all()})
Il terzo argomento posizionale di cui eseguire il render
è un dizionario di dati reso disponibile al modello. Usiamo questi dati e il tag for
per costruire la tabella. Anche nel modello originale da cui ho adattato questa pagina web, la tabella dei dipendenti era codificata. Il nostro nuovo approccio taglia centinaia di righe di righe di tabelle hardcoded ripetitive. index.html ora contiene:
{% 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 %}
Il vantaggio più grande è che ciò semplifica notevolmente il processo di aggiornamento della tabella. Anziché fare in modo che uno sviluppatore modifichi manualmente l'HTML per riflettere un aumento di stipendio o una nuova assunzione, quindi inserire tale modifica in produzione, qualsiasi amministratore può utilizzare il pannello di amministrazione per effettuare aggiornamenti in tempo reale (https://127.0.0.1/admin, utilizzare le credenziali che hai creato con python manage.py createsuperuser
per accedere). Questo è un vantaggio nell'usare Django con questo motore di rendering invece di usarlo da solo in un generatore di siti statici o in un altro approccio di creazione di modelli.
Se altro
Il tag if
è un tag incredibilmente potente che ti consente di valutare le espressioni all'interno del modello e di adattare l'HTML di conseguenza. Righe come {% if 1 == 2 %}
sono perfettamente valide, anche se un po' inutili, poiché danno ogni volta lo stesso risultato. Il punto in cui il tag if
brilla è quando si interagisce con i dati passati nel modello dalla vista. Considera il seguente esempio da 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>
Nota che l'intero oggetto utente viene passato al modello per impostazione predefinita, senza che noi specifichiamo nulla nella vista per farlo accadere. Ciò ci consente di accedere allo stato di autenticazione dell'utente (o alla sua mancanza), al nome utente e ad altre funzionalità, incluse le relazioni di chiave esterna per accedere ai dati archiviati in un profilo utente o in un altro modello connesso, il tutto dal file HTML.
Potresti essere preoccupato che questo livello di accesso possa comportare rischi per la sicurezza. Tuttavia, ricorda che questi modelli sono per un framework di rendering lato server. Dopo aver costruito la pagina, i tag si sono consumati e vengono sostituiti con puro HTML. Pertanto, se un'istruzione if
introduce dati in una pagina in alcune condizioni, ma i dati non vengono utilizzati in una determinata istanza, tali dati non verranno affatto inviati al client, poiché l'istruzione if
viene valutata lato server. Ciò significa che un modello costruito correttamente è un metodo molto sicuro per aggiungere dati sensibili alle pagine senza che i dati lascino il server a meno che non sia necessario. Detto questo, l'uso del modello Django non elimina la necessità di comunicare informazioni sensibili in modo sicuro e crittografato, significa semplicemente che i controlli di sicurezza come user.is_authenticated
possono essere eseguiti in modo sicuro nell'HTML poiché viene elaborato lato server.
Questa funzione ha una serie di altri casi d'uso. Ad esempio, nella home page di un prodotto generale, potresti voler nascondere i pulsanti "registrati" e "accedi" e sostituirli con un pulsante "esci" per gli utenti che hanno effettuato l'accesso. Un altro uso comune è mostrare e nascondere i messaggi di successo o di errore per operazioni come l'invio di moduli. Nota che generalmente non nasconderesti l'intera pagina se l'utente non ha effettuato l'accesso. Un modo migliore per modificare l'intera pagina Web in base allo stato di autenticazione dell'utente è gestirlo nella funzione appropriata in views.py .
Filtraggio
Parte del lavoro della vista consiste nel formattare i dati in modo appropriato per la pagina. Per fare ciò, abbiamo una potente estensione ai tag: i filtri. Ci sono molti filtri disponibili in Django per eseguire azioni come giustificare il testo, formattare le date e aggiungere numeri. Fondamentalmente, puoi pensare a un filtro come a una funzione che viene applicata alla variabile in un tag. Ad esempio, vogliamo che i nostri numeri di stipendio leggano "$ 1.200.000" invece di "1200000". Useremo un filtro per portare a termine il lavoro in index.html :
<td>${{ employee.salary|intcomma }}</td>
Il carattere pipe |
è il filtro che applica il comando intcomma
alla variabile employee.salary
. Il carattere “$” non proviene dal template, per un elemento come quello che appare ogni volta, è più semplice incollarlo fuori dal tag.
Nota che intcomma
ci richiede di includere {% load humanize %}
nella parte superiore del nostro index.html e 'django.contrib.humanize',
nelle nostre INSTALLED_APPS
in settings.py . Questo viene fatto per te nell'applicazione di esempio fornita.
Conclusione
Il rendering lato server con il motore Jinja2 fornisce strumenti chiave per la creazione di codice front-end pulito, adattabile e reattivo. La separazione delle pagine in file consente componenti ASCIUTTI con una composizione flessibile. I tag forniscono funzionalità fondamentali per la visualizzazione dei dati passati dal database tramite le funzioni di visualizzazione. Fatto bene, questo approccio può aumentare la velocità, le capacità SEO, la sicurezza e l'usabilità del sito ed è un aspetto fondamentale della programmazione in Django e framework simili.
Se non l'hai già fatto, controlla l'applicazione di esempio e prova ad aggiungere i tuoi tag e filtri usando l'elenco completo.
Django Highlights è una serie che introduce importanti concetti di sviluppo web in Django. Ogni articolo è scritto come guida autonoma a un aspetto dello sviluppo di Django inteso ad aiutare gli sviluppatori e i progettisti front-end a raggiungere una comprensione più profonda dell'"altra metà" della base di codice. Questi articoli sono costruiti principalmente per aiutarti a comprendere la teoria e le convenzioni, ma contengono alcuni esempi di codice, che sono scritti in Django 3.0.
Parti precedenti della serie:
- Punti salienti di Django: modelli utente e autenticazione (parte 1)
- Punti salienti di Django: modelli, amministrazione e sfruttamento del database relazionale (parte 3)
- Punti salienti di Django: gestione di risorse statiche e file multimediali (parte 4)