I 10 errori principali che fanno gli sviluppatori di Django
Pubblicato: 2022-03-11In questo tutorial, esamineremo alcuni errori comuni che vengono spesso commessi dagli sviluppatori Django e i modi per evitarli. Questo tutorial è utile anche se sei uno sviluppatore esperto di Django perché gli errori, come il mantenimento di impostazioni ingestibili di grandi dimensioni o i conflitti di denominazione nelle risorse statiche, non si limitano solo ai nuovi sviluppatori che fanno il loro primo tentativo con Django.
Django è un framework Web Python gratuito e open source che risolve in modo utile le sfide di sviluppo comuni e consente di creare applicazioni flessibili e ben strutturate. Django ha molte funzionalità moderne pronte all'uso. Per me personalmente, le funzionalità Admin, Object Relational Mapping (ORM), Routing e Templating hanno reso Django la mia prima scelta perché le applicazioni richiedono molto lavoro e, sebbene mi piaccia il mio lavoro quanto qualsiasi sviluppatore potrebbe, voglio spendere il minor tempo possibile su questi compiti ripetitivi di base. Django ti permette di fare tutto questo senza compromettere la flessibilità.
La funzione killer di Django è una potente interfaccia di amministrazione configurabile che si costruisce automaticamente (automaticamente?) dallo schema dei tuoi modelli e dai modelli del pannello di amministrazione, facendoti sentire come un mago. Attraverso l'interfaccia di amministrazione, un utente può configurare molte cose tra cui l'elenco di controllo di accesso (ACL), autorizzazioni e azioni a livello di riga, filtri, ordini, widget, moduli, URL helper aggiuntivi e qualsiasi altra cosa tu possa immaginare. Credo che ogni applicazione richieda un pannello di amministrazione, se non ancora, è semplicemente una questione di tempo prima che la tua applicazione di base ne abbia bisogno. Con l'amministratore di Django, puoi crearne uno in modo rapido e flessibile.
Django ha un potente ORM che funziona con tutti i principali database pronti all'uso. Dal momento che è pigro, colpisce il tuo database solo quando ne hai bisogno, a differenza di altri ORM. Supporta tutte le principali istruzioni (e funzioni) SQL che puoi utilizzare dal tuo codice sorgente Python e si sente molto a suo agio grazie alle funzionalità di Python.
Il motore di creazione di modelli di Django è molto flessibile e potente allo stesso tempo. Puoi utilizzare molti filtri e tag standard, nonché creare nuovi filtri e tag personalizzati per il tuo progetto. Django supporta altri motori di modelli e modelli Django e fornisce un'API per una facile integrazione di altri motori di modelli tramite funzioni di scelta rapida standard per l'elaborazione dei modelli.
Django ha molte altre grandi funzionalità come un router URL in grado di analizzare le richieste in arrivo e creare nuovi URL da uno schema di router. Nel complesso, il framework Django è un'esperienza piacevole e ogni volta che hai bisogno di aiuto, leggi la documentazione.
Errore n. 1: utilizzo dell'ambiente Python del sistema globale per le dipendenze del progetto
Non utilizzare l'ambiente globale di Python per le dipendenze del progetto, poiché può produrre conflitti di dipendenza. Python non può utilizzare più versioni di pacchetti contemporaneamente. Questo può essere un problema se progetti diversi richiedono versioni incompatibili diverse dello stesso pacchetto.
Questo errore viene solitamente commesso dai nuovi sviluppatori Python e Django che non conoscono le funzionalità di isolamento dell'ambiente di Python.
Esistono molti modi per isolare il tuo ambiente, ma i modi più comuni sono:
- virtualenv: un pacchetto Python che genera una cartella dell'ambiente Python e contiene script per [dis]attivare l'ambiente e gestire i pacchetti Python installati nell'ambiente. Questo è il mio metodo preferito perché è il modo più semplice per svolgere il lavoro. Di solito creo l'ambiente vicino alla cartella del progetto.
- virtualenvwrapper: un pacchetto Python che si installa a livello globale e fornisce un set di strumenti per creare/eliminare/attivare/ecc. ambienti virtuali. Tutti gli ambienti virtuali sono archiviati in una cartella (che può essere sovrascritta tramite la variabile di ambiente WORKON_HOME). Non vedo alcun vantaggio nell'usare
virtualenvwrapper
invece divirtualenv
. - Macchine virtuali (VM): non c'è isolamento maggiore di un'intera macchina virtuale dedicata alla tua applicazione. Ci sono molti strumenti tra cui scegliere, tra cui VirtualBox (gratuito), VMware, Parallels e Proxmox (il mio preferito e ha una versione gratuita). In combinazione con uno strumento di automazione VM come Vagrant, questa può essere una soluzione estremamente potente.
- Contenitori: negli ultimi anni ho utilizzato Docker in quasi tutti i progetti, specialmente in ogni nuovo progetto che parto da zero. Docker è uno strumento straordinario che offre molte funzionalità e molti strumenti di terze parti per l'automazione dei container. Ha una funzione di memorizzazione nella cache dei livelli che rende estremamente veloce la ricostruzione dei contenitori. Nei container, utilizzo l'ambiente Python del sistema globale, perché ogni container ha il proprio filesystem e i progetti sono isolati ad alto livello. Docker consente ai nuovi membri del team di iniziare a lavorare sul progetto più velocemente, soprattutto se hanno esperienza Docker.
Se me lo chiedi, preferisco il pacchetto Python virtualenv
e i contenitori Docker per l'isolamento e la gestione delle dipendenze del progetto.
Errore n. 2: non bloccare le dipendenze del progetto in un file requirements.txt
Ogni nuovo progetto Python dovrebbe iniziare con un file Requirements.txt e un nuovo ambiente isolato. Normalmente installi tutti i pacchetti tramite pip/easy_install
ma non dimentichi mai di aggiungerli anche al tuo file requirements.txt
. Ciò rende più semplice ( possibile essere più appropriato) distribuire il progetto sui server o per un membro del team eseguire il bootstrap del progetto sulla propria macchina.
Inoltre, è altrettanto importante aggiungere la versione specifica delle tue dipendenze nel tuo file requirements.txt
. Di solito, versioni differenti di un pacchetto forniscono moduli, funzioni e parametri di funzione differenti; anche una modifica minore della versione in una dipendenza può interrompere il tuo pacchetto. Questo è un problema molto serio se il tuo progetto è attivo e hai implementazioni regolarmente programmate poiché, senza il controllo delle versioni, il tuo sistema di build installerà sempre l'ultima versione disponibile del pacchetto.
Appunta sempre i tuoi pacchetti per la produzione! Personalmente, uso uno strumento molto carino chiamato pip-tools che mi aiuta a farlo. Fornisce una serie di strumenti da riga di comando che aiutano a gestire le dipendenze. Genera automaticamente un requirements.txt
che blocca non solo le tue dipendenze ma l'intero albero delle dipendenze, che include le dipendenze delle tue dipendenze.
A volte, vuoi aggiornare solo alcuni pacchetti dall'elenco delle dipendenze (ad esempio, solo Django/Flask/qualsiasi framework o utilità), se hai usato "pip freeze" non sai quali dipendenze sono per quali pacchetti, quindi impossibile aggiornare una dipendenza. Con pip-tools, tuttavia, blocca automaticamente i pacchetti a seconda della dipendenza bloccata, quindi risolve automaticamente quali pacchetti devono essere aggiornati. Come bonus, sai anche esattamente da quale pacchetto proviene da quale dipendenza a causa di come li contrassegna con commenti nel file requirements.txt
.
Per essere più cauti, è una buona idea eseguire anche il backup dei file di origine delle dipendenze! Conserva una copia nel tuo file system, una cartella gestita da Git, una cartella S3, FTP, SFTP, ovunque, ma tienila a portata di mano. Ci sono stati casi in cui un pacchetto relativamente minore non elencato ha rotto un gran numero di pacchetti su npm. Pip fornisce in modo utile lo strumento per scaricare tutte le dipendenze richieste come file di origine, per saperne di più eseguendo pip help download
.
Errore n. 3: usare funzioni Python vecchio stile invece di viste basate su classi
A volte è una buona idea usare una piccola funzione Python nel file views.py
di un'applicazione, specialmente per i test o le viste di utilità, ma in generale dovresti usare le viste basate su classi (CBV) nelle tue applicazioni.
I CBV sono viste generiche che forniscono classi astratte che implementano attività di sviluppo web comuni create da professionisti e coprono tutti i comportamenti comuni. Hanno una straordinaria API strutturata e puoi utilizzare tutti i vantaggi della programmazione orientata agli oggetti quando usi i CBV. Rende il codice sorgente più chiaro e leggibile. Dimentica la fatica di usare le funzioni di visualizzazione standard di Django per elenchi, operazioni CRUD, elaborazione di moduli, ecc. Devi semplicemente estendere il CBV adatto per la tua vista e sovrascrivere le proprietà o le funzioni della classe (di solito una funzione restituisce una proprietà e puoi aggiungere qualsiasi logica lì cosa crea spaghetti dal tuo codice sorgente in caso di utilizzo di funzioni di visualizzazione anziché CBV) che configurano il comportamento di visualizzazione.
Ad esempio, puoi avere diversi mix-in nel tuo progetto che sovrascrivono i comportamenti CBV di base per la creazione di contesti di visualizzazione, il controllo dell'autorizzazione a livello di riga, la creazione automatica di percorsi di modello dalla struttura dell'applicazione, l'integrazione della cache intelligente e altro ancora.
Ho creato il pacchetto denominato Django Template Names, che standardizza i nomi dei modelli per le visualizzazioni in base al nome di un'applicazione e al nome di una classe di visualizzazione. Lo uso tutti i giorni e mi fa risparmiare molto tempo per inventare nomi. Metti semplicemente il mixin nel tuo CBV — class Detail(TemplateNames, DetailView):
— e inizierà a funzionare! Naturalmente, puoi ignorare le mie funzioni e aggiungere modelli reattivi per dispositivi mobili, modelli diversi per agenti utente o qualsiasi altra cosa tu voglia.
Errore n. 4: scrivere opinioni grasse e modelli magri
Scrivere la logica dell'applicazione nelle viste anziché nei modelli significa che hai scritto il codice che appartiene al tuo modello nella vista, rendendolo "grasso" e il tuo modello "magro".
Dovresti scrivere modelli grassi, viste magre.
Rompi la logica in piccoli metodi sui tuoi modelli. Ciò ti consente di utilizzarlo più volte da più origini (interfaccia utente dell'interfaccia di amministrazione, interfaccia utente front-end, endpoint API, viste multiple) in poche righe di codice invece di copiare e incollare tonnellate di codice. Quindi la prossima volta che invii un'e-mail a un utente, estendi il modello con una funzione e-mail invece di scrivere questa logica nel tuo controller.
Ciò rende anche più semplice eseguire il test unitario del codice perché puoi testare la logica dell'e-mail in un unico posto, anziché ripetutamente in ogni controller in cui ciò avviene.
Puoi leggere di più sul problema nel progetto Django Best Practices. La soluzione è semplice: scrivi modelli grassi e viste scarne, quindi facciamolo nel tuo prossimo progetto (o refactoring quello attuale).
Errore n. 5: un file di impostazioni enorme e ingestibile
Anche il nuovo file delle impostazioni del progetto Django ha molte impostazioni. In un progetto reale, un file delle impostazioni cresce fino a oltre 700 righe di configurazione e diventerà difficile da mantenere, soprattutto quando gli ambienti di sviluppo, produzione e staging necessitano di configurazioni personalizzate.

Puoi dividere il file di configurazione manualmente e creare caricatori personalizzati, ma voglio presentarti un pacchetto Python carino e ben testato, Django Split Settings, di cui sono co-autore.
Il pacchetto fornisce due funzioni, optional
e include
, che supportano i caratteri jolly per i percorsi e importano i file di configurazione nello stesso contesto, semplificando la creazione della configurazione utilizzando le voci di configurazione dichiarate nei file caricati in precedenza. Non influisce sulle prestazioni di Django e puoi usarlo in qualsiasi progetto.
Dai un'occhiata all'esempio di configurazione minima:
from split_settings.tools import optional, include include( 'components/base.py', 'components/database.py', 'components/*.py', # the project different envs settings optional('envs/devel/*.py'), optional('envs/production/*.py'), optional('envs/staging/*.py'), # for any local settings optional('local_settings.py'), )
Errore n. 6: applicazione all-in-one, struttura dell'applicazione errata e posizionamento errato delle risorse
Qualsiasi progetto Django è costituito da più applicazioni. Nella notazione Django, un'applicazione è un pacchetto Python che contiene almeno i file __init__.py
e models.py
; nelle ultime versioni di Django, models.py
non è più richiesto. __init__.py
è sufficiente.
Le applicazioni Django possono contenere moduli Python, moduli specifici di Django (viste, URL, modelli, amministrazione, moduli, tag modello, ecc.), file statici, modelli, migrazioni di database, comandi di gestione, unit test e altro ancora. Dovresti dividere le tue applicazioni monolitiche in piccole applicazioni riutilizzabili usando una logica semplice. Dovresti essere in grado di descrivere l'intero scopo dell'app in una o due brevi frasi. Ad esempio: "Consente agli utenti di registrarsi e attivare il proprio account tramite e-mail".
È una buona idea chiamare la cartella del progetto project
e posizionare le applicazioni in project/apps/
. Quindi, inserisci tutte le dipendenze dell'applicazione nelle rispettive sottocartelle.
Esempi:
- File statici:
project/apps/appname/static/appname/
- Tag modello:
project/apps/appname/templatetags/appname.py
- File modello:
project/apps/appname/templates/appname/
Prefissare sempre il nome dell'applicazione nelle sottocartelle perché tutte le cartelle statiche vengono unite in un'unica cartella e, se due o più applicazioni avevano un file js/core.js
, l'ultima applicazione in settings.INSTALLED_APPLICATIONS
sovrascriverà le precedenti. Una volta ho riscontrato questo bug nel mio progetto attuale e ho perso circa sei ore di debug fino a quando mi sono reso conto che un altro sviluppatore aveva sovrascritto static/admin/js/core.js
perché il team stava implementando un pannello di amministrazione SPA personalizzato e chiamava i propri file allo stesso modo.
Ecco una struttura di esempio per un'applicazione portale che ha molte risorse e moduli Python.
root@c5b96c395cfb:/test# tree project/apps/portal/ project/apps/portal/ ├── __init__.py ├── admin.py ├── apps.py ├── management │ ├── __init__.py │ └── commands │ ├── __init__.py │ └── update_portal_feeds.py ├── migrations │ └── __init__.py ├── models.py ├── static │ └── portal │ ├── css │ ├── img │ └── js ├── templates │ └── portal │ └── index.html ├── templatetags │ ├── __init__.py │ └── portal.py ├── tests.py ├── urls.py └── views.py 11 directories, 14 files
Usando una tale struttura, puoi in qualsiasi momento esportare l'applicazione in un altro pacchetto Python e riutilizzarla. Puoi persino pubblicarlo in PyPi come pacchetto open source o spostarlo in un'altra cartella.
Ti ritroverai con una struttura di progetto come questa:
root@c5b96c395cfb:/test# tree -L 3 . ├── deploy │ ├── chef │ └── docker │ ├── devel │ └── production ├── docs ├── logs ├── manage.py ├── media ├── project │ ├── __init__.py │ ├── apps │ │ ├── auth │ │ ├── blog │ │ ├── faq │ │ ├── pages │ │ ├── portal │ │ └── users │ ├── conf │ ├── settings.py │ ├── static │ ├── templates │ ├── urls.py │ └── wsgi.py └── static └── admin ├── css ├── fonts ├── img └── js 25 directories, 5 files
In un progetto reale, ovviamente, sarà più complesso, ma questa struttura rende le cose più semplici e pulite.
Errore n. 7: STATICFILES_DIRS
e STATIC_ROOT
sviluppatori Django principianti
I file statici sono risorse che non cambiano attraverso l'uso dell'app, ad esempio JavaScript, CSS, immagini, caratteri, ecc. In Django, vengono "raccolti" solo in una directory pubblica durante il processo di distribuzione.
In modalità di sviluppo python manage.py runserver
Django cerca i file statici usando l'impostazione STATICFILES_FINDERS
. Per impostazione predefinita, tenta di trovare il file statico richiesto nelle cartelle elencate nell'impostazione STATICFILES_DIRS
. In caso di errore, Django prova a trovare il file utilizzando django.contrib.staticfiles.finders.AppDirectoriesFinder
, che cerca nella cartella static
di ogni applicazione installata nel progetto. Ciò consente di scrivere applicazioni riutilizzabili fornite con i propri file statici.
In produzione, servi la tua statica utilizzando un server web autonomo come Nginx. Il server Web non sa nulla della struttura delle applicazioni del progetto Django o delle cartelle in cui sono distribuiti i file statici. Fortunatamente, Django fornisce il comando di gestione collect static python manage.py collectstatic
, che esamina STATICFILES_FINDERS
e copia tutti i file statici dalle applicazioni static
cartelle e cartelle elencate in STATICFILES_DIRS
nella directory specificata nell'impostazione STATIC_ROOT
. Ciò consente la risoluzione delle risorse di file statici utilizzando la stessa logica del server in modalità di sviluppo Django e ha tutti i file statici in un'unica posizione per il tuo server web.
Non dimenticare di eseguire collectstatic
nel tuo ambiente di produzione!
Errore n. 8: STATICFILES_STORAGE
predefinito, Django Templates Loader in produzione
STATICFILES_STORAGE
Parliamo della gestione degli asset dell'ambiente di produzione. Possiamo fornire la migliore esperienza utente se utilizziamo una politica "gli asset non scadono mai" (su cui puoi leggere di più qui). Significa che tutti i nostri file statici dovrebbero essere memorizzati nella cache dai browser Web per settimane, mesi o addirittura anni. In altre parole, i tuoi utenti dovrebbero scaricare le tue risorse solo una volta!
È fantastico e possiamo farlo con poche righe nella configurazione di Nginx per la nostra cartella dei file statici, ma per quanto riguarda l'invalidazione della cache? Se l'utente scaricherà le nostre risorse solo una volta, cosa succede se hai aggiornato il logo, i caratteri, JavaScript o il colore del testo per una voce in un menu? Per aggirare questo, dovresti generare URL e nomi di file univoci per i nostri file statici su ogni distribuzione!
Possiamo farlo semplicemente usando ManifestStaticFilesStorage come STATICFILES_STORAGE
(attenzione, l'hashing è abilitato solo in modalità DEBUG=false
) ed eseguendo il comando di gestione collectstatic
discusso sopra. Ciò ridurrà il conteggio delle richieste di risorse per il tuo sito Web di produzione e renderà il tuo sito Web molto più veloce.
Caricatore di modelli Django memorizzato nella cache
Un'altra caratteristica interessante di Django è il caricatore di modelli memorizzato nella cache, che non ricarica e non analizza i file di modello su ogni rendering di modello. L'analisi dei modelli è un'operazione molto costosa e utilizza molte risorse. Per impostazione predefinita, i modelli Django vengono analizzati su ogni richiesta, ma questo è negativo, soprattutto durante la produzione, dove puoi elaborare migliaia di richieste in un breve lasso di tempo.
Dai un'occhiata alla sezione di configurazione di cached.Loader
per un buon esempio e dettagli su come farlo. Non utilizzare il caricatore in modalità sviluppo perché non ricarica i modelli analizzati dal file system; dovrai riavviare il tuo progetto usando python manage.py startapp
ad ogni modifica del modello. Questo può essere fastidioso durante lo sviluppo, ma è perfetto per l'ambiente di produzione.
Errore n. 9: script Python puri per programmi di utilità o script
Django fornisce una funzionalità molto interessante chiamata Management Commands. Usalo invece di reinventare le ruote e scrivere script Python grezzi per le utilità del tuo progetto.
Inoltre, controlla il pacchetto Django Extensions, che è una raccolta di estensioni personalizzate per Django. Forse qualcuno ha già implementato i tuoi comandi! Ci sono già molti comandi di attività comuni.
Errore n. 10: reinventare la ruota
Django e Python hanno migliaia di soluzioni pronte per l'uso. Prova a cercare su Google prima di scrivere qualcosa che non sia unico; probabilmente esiste già una soluzione ricca di funzionalità.
Cerca solo di rendere le cose semplici. Google prima di tutto! Installa, configura, estendi e integra nel tuo progetto se trovi un pacchetto di buona qualità e, naturalmente, contribuisci all'open source quando ne hai la possibilità.
Per cominciare, ecco un elenco dei miei pacchetti pubblici per Django:
- L'URL delle macro di Django semplifica la scrittura (e la lettura) dei modelli URL nelle applicazioni Django utilizzando le macro.
- Django Templates Names è un piccolo mix-in che ti consente di standardizzare facilmente i nomi dei tuoi modelli CBV.
- django-split-settings ti consente di organizzare le impostazioni di Django in più file e directory. Sovrascrivi e modifica facilmente le impostazioni. Utilizzare i caratteri jolly nei percorsi dei file delle impostazioni e contrassegnare i file delle impostazioni come facoltativi.
Non ripeterti (SECCO)!
Mi piace molto la metodologia DRY; ecco perché ho creato lo scheletro di Django come strumento pratico che ha alcune caratteristiche davvero ordinate fuori dagli schemi:
- Immagini Docker per sviluppo/produzione, gestite da docker-compose, che consente di orchestrare facilmente un elenco di contenitori.
- Script Fabric semplice per la distribuzione in produzione.
- Configurazione per il pacchetto Django Split Settings con impostazioni per sorgenti di base e locali.
- Webpack integrato nel progetto - Solo la cartella
dist
verrà raccolta da Django sul comandocollectstatic
. - Configurate tutte le impostazioni e le funzionalità di base di Django come modelli Django memorizzabili nella cache in produzione, file statici con hash, barra degli strumenti di debug integrata, registrazione, ecc.
È uno scheletro Django pronto per l'uso per il tuo prossimo progetto da zero e, si spera, ti farà risparmiare un sacco di tempo avviando il tuo progetto. Webpack ha una configurazione di base minima, ma ha anche SASS installato preconfigurato per gestire i file .scss
.