bytes.cat

La wiki d'FP d'informàtica

Eines de l'usuari

Eines del lloc


Barra lateral

ASIX Administració de Sistemes Informàtics i Xarxes
Tots els mòduls del cicle
MP01 Implantació de sistemes operatius
Totes les UFs del modul
MP02 Gestió de bases de dades
Totes les UFs del modul
MP03 Programació bàsica
Totes les UFs del modul
MP04 Llenguatges de marques i sistemes de gestió d'informació
Totes les UFs del modul
MP05 Fonaments de maquinari
Totes les UFs del modul
MP06 Administració de sistemes operatius
Totes les UFs del modul
MP07 Planificació i administració de xarxes
Totes les UFs del modul
MP08 Serveis de xarxa i Internet
Totes les UFs del modul
MP09 Implantació d'aplicacions web
Totes les UFs del modul
MP10 Administració de sistemes gestors de bases de dades
Totes les UFs del modul
MP11 Seguretat i alta disponibilitat
Totes les UFs del modul
MP12 Formació i orientació laboral
Totes les UFs del modul
MP13 Empresa i iniciativa emprenedora
Totes les UFs del modul
MP14 Projecte
Totes les UFs del modul
DAM Desenvolupament d’aplicacions multiplataforma
Tots els mòduls del cicle
MP01 Sistemes informàtics
Totes les UFs del modul
MP02 Bases de dades
Totes les UFs del modul
MP03 Programació bàsica
Totes les UFs del modul
MP04 Llenguatges de marques i sistemes de gestió d'informació
Totes les UFs del modul
MP05 Entorns de desenvolupament
Totes les UFs del modul
MP06 Accés a dades
Totes les UFs del modul
MP07 Desenvolupament d’interfícies
Totes les UFs del modul
MP08 Programació multimèdia i dispositius mòbils
Totes les UFs del modul
MP09 Programació de serveis i processos
Totes les UFs del modul
MP10 Sistemes de gestió empresarial
Totes les UFs del modul
MP11 Formació i orientació laboral
Totes les UFs del modul
MP12 Empresa i iniciativa emprenedora
Totes les UFs del modul
MP13 Projecte de síntesi
Totes les UFs del modul
MPDual Mòdul Dual / Projecte
DAW Desenvolupament d’aplicacions web
Tots els mòduls del cicle
MP01 Sistemes informàtics
Totes les UFs del modul
MP02 Bases de dades
Totes les UFs del modul
MP03 Programació
Totes les UFs del modul
MP04 Llenguatge de marques i sistemes de gestió d’informació
Totes les UFs del modul
MP05 Entorns de desenvolupament
Totes les UFs del modul
MP06 Desenvolupament web en entorn client
Totes les UFs del modul
MP07 Desenvolupament web en entorn servidor
Totes les UFs del modul
MP08 Desplegament d'aplicacions web
Totes les UFs del modul
MP09 Disseny d'interfícies web
Totes les UFs del modul
MP10 Formació i Orientació Laboral
Totes les UFs del modul
MP11 Empresa i iniciativa emprenedora
Totes les UFs del modul
MP12 Projecte de síntesi
Totes les UFs del modul
SMX Sistemes Microinformàtics i Xarxes
Tots els mòduls del cicle
MP01 Muntatge i manteniment d’equips
Totes les UFs del modul
MP02 Sistemes Operatius Monolloc
Totes les UFs del modul
MP03 Aplicacions ofimàtiques
Totes les UFs del modul
MP04 Sistemes operatius en xarxa
Totes les UFs del modul
MP05 Xarxes locals
Totes les UFs del modul
MP06 Seguretat informàtica
Totes les UFs del modul
MP07 Serveis de xarxa
Totes les UFs del modul
MP08 Aplicacions Web
Totes les UFs del modul
MP09 Formació i Orientació Laboral
Totes les UFs del modul
MP10 Empresa i iniciativa emprenedora
Totes les UFs del modul
MP11 Anglès
Totes les UFs del modul
MP12 Síntesi
Totes les UFs del modul
CETI Ciberseguretat en Entorns de les Tecnologies de la Informació
Tots els mòduls del cicle
CiberOT Ciberseguretat en Entorns d'Operació
Tots els mòduls del cicle
django

Django Web Framework

Django és un framework per a aplicacions web en Python.

És conegut com The framework for perfectionists with deadlines per la seva rapidesa de desenvolupament.

En aquest article tractarem els temes de l'entorn d'execució d'un projecte Django, per tal que es pugui posar en producció de forma segura.

Django té una documentació excel·lent, en particular el Tutorial Django.

Referències:


Articles sobre Django en aquesta wiki

2022/02/17 09:39 ENRIC MIEZA SANCHEZ
2023/04/19 17:22 ENRIC MIEZA SANCHEZ
2021/08/20 10:53 ENRIC MIEZA SANCHEZ
2022/02/07 18:53 ENRIC MIEZA SANCHEZ
2023/06/23 08:47 David Lozano
2023/05/11 16:14 ENRIC MIEZA SANCHEZ
2019/11/11 15:21 ENRIC MIEZA SANCHEZ
2021/11/24 10:54 ENRIC MIEZA SANCHEZ
2021/11/29 21:25 ENRIC MIEZA SANCHEZ
2023/03/23 17:19 ENRIC MIEZA SANCHEZ
2023/06/30 11:35 Miquel Àngel Amorós
2023/06/27 11:11 MIKEL LOPEZ VILLARROYA
2023/06/28 20:31 EVA BARBEITO ANDRADE
2022/02/11 18:07 ENRIC MIEZA SANCHEZ
2023/07/06 07:02 RAQUEL ALAMAN NAVAS
2023/06/24 10:21 JORDI GUAL PURTI
2021/12/28 12:04 ENRIC MIEZA SANCHEZ


Introducció per a DevOps

Desenvolupar un projecte (en Django o en molts altres frameworks) és una tasca força diferent a la de construir la infraestructura correcta per a posar el projecte en producció, ja sigui directament en un servidor propi o de forma dockeritzada en contenidors. Això darrer és el què farem en aquest article, que és la feina més pròpia del DevOps.

Prepar un projecte Django per a què sigui segur implica diverses coses:

  1. Configurar un virtualenv amb les llibreries adequades (requirements.txt).
  2. Crear el projecte amb les versions adequades i actualitzades.
  3. Tenir el projecte sota un VCS (sistema de versionat) com Git.
  4. Configurar les dades sensibles del projecte (contrasenyes, tokens, etc.) perquè no es publiquin al repositori de codi.
  5. Habilitar configuració de l'app mitjançant variables d'entorn, enlloc de fitxers.
  6. Fer un README per facilitar la clonació i posta en marxa del projecte.
  7. Configurar la BD adequadament.
  8. Configurar el servidor d'arxius estàtics.
  9. Posar el projecte en producció amb un servidor d'aplicacions (uWSGI) + un servidor web (Nginx) per als arxius estàtics.


Entorn Python Venv

Per treballar en Python ens convé una eina d'entorn que ens aïlli les diferents versions de llibreries que farem servir, i no tenir incompatibilitats entre les diferents aplicacions que puc tenir (ni tampoc amb el sistema operatiu, que té les seves pròpies versions de les llibreries).

A l'article Python venv teniu detalls a fons de com utilitzar aquestes eines.

Resumidament, necessitem crear l'entorn virtual, entrar-hi i instal·lar Django:

$ python3 -m venv env
$ source env/bin/activate
(env) $ pip install django


Quickstart: crear projecte mínim

Crearem un projecte Django i provarem si funciona simplement amb:

(env) $ django-admin startproject myproject
(env) $ cd myproject
(env) $ ./manage.py runserver 0.0.0.0:8000

I per comprovar-ho accedeix amb el navegador a http://localhost:8000.

Si volem endinsar-nos a la programació amb Django es recomana seguir l'excel·lent tutorial oficial Django.

Per entrar al admin panel de Django cal fer migració (crea BD) i crear un usuari:

(env) $ ./manage.py migrate
(env) $ ./manage.py createsuperuser

Visita el admin panel a http://localhost:8000/admin/


ORM, models i migracions

Un Object-Relational Mapper és una eina que facilita l'accés a dades mapejant les taules i relacions en objectes (classes) del llenguatge de programació. Això permet una abstracció de la base de dades concreta que s'està emprant i no haver d'utilitzar SQL, sinó crides a mètodes dels objectes instanciats.

Un model, en el context d'un ORM, és una class que està mapejada a una taula de la base de dades. Així, per exemple, es pot crear la següent class a l'arxiu models.py de Django:

from django.db import models
 
class Llibre (models.Model):
    titol = models.CharField(max_length=100)
    autor = models.CharField(max_length=200)
    resum = models.TextField(null=True,blank=True)
    data_edicio = models.DateField()

Per crear un llibre i guardar-lo a la taula, enlloc d'emprar SQL, amb el ORM faríem:

llibre = Llibre()
llibre.titol = "El mag del Kremlin"
llibre.autor = "Giuliano da Empoli"
import datetime
llibre.data_edicio = datetime.datetime(2023, 3, 29)
# per persistir l'objecte a la BD cal cridar el mètode save()
llibre.save()

En el context dels frameworks de desenvolupament, una eina de migració gestiona les versions i evolució dels esquemes de les bases de dades.

Durant el desenvolupament convé planificar amb anterioritat l'esquema de la base de dades per tal que pateixi el mínim de modificacions. Cada cop que es modifica la base de dades hi ha un gran risc de que parts del codi deixin de funcionar o de que perdem dades en el canvi (migració) d'una versió de l'esquema a la següent. Malgrat tot, preveure totes les situacions es fa impossible i aplicar canvis a l'esquema de la base de dades es fa imprescindible, per molt que es vulgui minimitzar. L'ús d'eines de migració milloren aquesta gestió i permeten una transició ordenada i, sobretot, automatitzada, d'un esquema al següent.

El mecanisme és simple: cal un arxiu de migració que realitzi els canvis a la BD a cada evolució. Cada migració pot implicar un canvi simple com afegir o esborrar una columna fins a grans canvis com afegir multitud de taules i relacions.

Tenim dos exemples complementaris i paradigmàtics en la gestió de les migracions: els dels frameworks Django i Laravel:

  • En Laravel el desenvolupador ha d'escriure un script de migració per aplicar els canvis explícits a la base de dades, com eliminar una columna o crear noves taules i relacions.
  • En Django el desenvolupador modifica directament el model amb l'ORM. Amb la instrucció makemigrations l'arxiu de migració es genera automàticament. El framework analitza el codi del model actual i l'anterior, i genera les ordres adequades dins un script de migració.

En el projecte que estavem desenvolupant, podem crear models i després realitzar les migracions executant:

(env1) $ ./manage.py makemigrations
(env1) $ ./manage.py migrate

Veurem que ara apareix un arxiu db.sqlite3 a l'arrel del projecte on s'hauran creat algunes taules, en particular users i groups, que son objectes builtin de Django (venen predefinits tot i que es poden modificar). SQLite és un SGBD senzill per BD locals en un sol arxiu amb propòsits de desenvolupament (no és apta per a desplegament).

Per visualitzar les taules podem crear un superusuari i entrar a l'admin panel:

(env1) $ ./manage.py createsuperuser
(env1) $ ./manage.py runserver

Entrem a http://localhost:8000/admin/ amb l'usuari i contrasenya creats i podrem veure, crear i modificar usuaris i grups i les diferents característiques d'aquests.


Crear repositori Git

Anem a Github (o a Gitlab, Bitbucket, etc.) i fem crear un nou repositori. Si ho feu a la web, ella mateix ens donarà la «xuleta» de com inicialitzar el nostre projecte i connectar-lo al repo remot.

No pugeu res al repositori remot fins que hagueu configurat correctament el projecte amb el .gitignore com es descriu més avall.

En particular, prengueu cura de no fer cap git add . (afegeix tots els arxius) fins no tenir el .gitignore a l'arrel.

Teniu articles amb informació extensa sobre el sistema de control de versions i de Git en particular.

Configurar .gitignore

Abans d'entrar tots els arxius ens convé crear un arxiu .gitignore a l'arrel del nostre repositori (si esteu seguint el tutorial Django oficial, seria la carpeta mysite). Aquest li dirà a la instrucció git add que ignori els arxius que compleixi amb determinats patrons.

En particular, NO volem que entrin al repo:

  • Arxius que continguin contrasenyes i altra informació sensible que no volem que es publiqui.
  • El fitxer de la BD de SQLite (db.sqlite)
  • Els arxius transitoris d'execució accelerada de Python (els arxius .pyc)
  • Les carpetes de virtualenv. El virtualenv es crearà de nou cada cop que clonem un repositori.

Una versió mínima dels arxius i carpetes que NO volem que es pugin al repo seria aquest:

.gitignore
*.pyc
/env/
/venv/
/static/*
/media/*
.env
db.sqlite3
.coverage
__pycache__

Pujar els arxius

Si tens correctament ajustat el .gitignore, ja pots afegir tots els arxius al repositori local i pujar-los al repo remot:

(env) $ git init
(env) $ git branch -m main
(env) $ git add .
(env) $ git commit -am "primer commit"

Aquí hauries de enllaçar el teu repositori local amb el remot (per ex. de Github):

(env) $ git remote add origin https://github.com/...
(env) $ git push -u origin main


requirements.txt

Podem afegir llibreries que necessitem al nostre entorn. Ens serà convenient, de cara a clonar i/o portar a producció el projecte, que sapiguem exactament les versions que necessitem. Podem saber les versions que tenim a l'actual venv amb:

(env) $ pip freeze

Hi ha un consens en utilitzar l'arxiu requirements.txt per a aquest objectiu. Per tant, cada cop que afegim noves dependències, caldrà afegir-les a aquest arxiu, de forma manual, o bé amb l'anterior instrucció.

Afegim una llibreria (necessitarem django-environ més endavant):

(env) $ pip install django-environ 

Veiem que ara tenim la llibreria afegida amb:

(env) $ pip freeze

I ara volquem tota aquesta info a requirements.txt:

(env) $ pip freeze > requirements.txt

Quan necessitis carregar les llibreries a l'instal·lar un nou repo, ho pots fer així:

(env) $ pip install -r requirements.txt

No oblidis afegir l'arxiu requirements.txt a git amb git add i pujar-ho al teu repo remot.


Versions

L'elecció de versions del projecte és molt important. Si examinem el contingut de requirements.txt (generat amb pip freeze) veurem que ens mostra les versions de tots els paquets que tenim instal·lats en el virtualenv. En el meu cas (Desembre 2021) em surten aquestes:

asgiref==3.4.1
Django==3.2.9
django-environ==0.8.1
mysqlclient==2.1.0
pytz==2021.3
sqlparse==0.4.2

En algun cas es poden trobar problemes per fer funcionar un projecte, si el sistema operatiu és diferent. En aquests casos potser és millor simplificar el requirements.txt posant els packages imprescindibles i deixar que el propi gestor pip trobi les dependències. En aquest cas no ho faríem amb el pip freeze, sinó que crearíem el fitxe a mà:

django==3.2
django-environ
mysqlclient

Hem de tenir en compte el cicle de vida de les versions de Django que fem servir. Les versions LTS són les Long Term Service que ens donaran cobertura durant més temps. Podem veure la política de versions a la web de descàrrega de Django:

Ara utilitzarem la 3.2 (LTS) però caldrà tenir cura d'actualitzar a la següent LTS (4.2) abans de que el suport de l'actual 3.2 finalitzi, com a màxim durant el primer trimestre de 2023.


Variables d'entorn amb django-environ

És important que les dades sensibles com passwords, keys, tokens, etc. no es pugin al VCS.

Si heu pujat el vostre repositori a un Github públic és fàcil que hagueu rebut un email de Gitguardian o del mateix Github (dependabot) dient-vos que la vostra clau de seguretat del projecte Django no és bo que estigui a l'arxiu settings.py, que és on apareix inicialment.

Quan després configurem una base de dades MySQL haurem de configurar usuari i contrasenya al mateix arxiu settings.py, amb el què encara rebrem més emails.

Instal·lem django-environ per facilitar que més tard puguem passar aquestes dades sensibles a l'aplicació mitjançant les variables d'entorn, i així no posar-les en arxius. En producció es passaran aquests valors com a variables d'entorn (per exemple, en utilitzar Docker).

En development, per facilitar el treball diari, posarem les dades sensibles a l'arxiu .env. Aquest arxiu carregarà els continguts com a variables d'entorn just abans d'engegar l'aplicació (quan fem ./manage.py runserver).

Si no ho heu fet abans:

(env) $ pip install django-environ

Retirarem les dades sensibles de settings.py i les situarem a l'arxiu .env (que ja em marcat com a exclòs al .gitignore) i que simula la càrrega de variables d'entorn com quan estiguem en mode de producció.

Mireu la documentació "quickstart" de Django-environ per ajustar el settings.py, traient la configuració de les variables:

  • SECRET_KEY
  • DEBUG

Més endavant ajustarem la info de la base de dades.

Crea l'arxiu .env amb les variables d'entorn, en aquest cas SECRET_KEY i també DEBUG.

Per comprovar que funciona bé, mira de canviar el valor de DEBUG de True a False. Si visitem una URL errònia el missatge que dona hauria de ser ben diferent (amb DEBUG=True hauria de donar més detalls de l'error).

Un parell de bones pràctiques:

  • Afegir .env al .gitignore per tal de no pujar per error l'arxiu de variables d'entorn a producció.
  • Crear un arxiu d'exemple amb les variables d'entorn necessàries per facilitar la posada en marxa, però enlloc d'anomenar-lo .env, que es diugui .env.example

Per fer una llista com ALLOWED_HOSTS dins el .env podem seguir aquest fil amb possibles solucions. Potser la més elegant és fer-ho com a list:

settings.py
ALLOWED_HOSTS = env.list('ALLOWED_HOSTS')
.env
ALLOWED_HOSTS=localhost,127.0.0.1,mysite.com


Utilitzant MySQL

Per defecte, Django utilitza la BD SQLite, però ens cal una BD apta per a producció com MySQL o PostgreSQL. A la doc oficial de Django tenim com utilitzar els diversos SGBD més habituals.

Per utilitzar MySQL caldrà instal·lar els binaris necessaris al sistema operatiu. Per a Ubuntu:

$ sudo apt install libmysqlclient-dev python3-dev python3-mysqldb gcc pkgconf

I també els connectors del virtualenv de Python:

(env) $ pip install mysqlclient

Com que estem utilitzant django-environ (veure secció anterior), caldrà que ajustem settings.py per a que la info de la BD la prenguem del .env.

La pàgina quickstart de django-environ explica com configurar la BD amb una DATABASE_URL, enlloc de configurar paràmetre per paràmetre.

Ajusta la variable de la BD d'aquesta manera:

DATABASE_URL='mysql://usuari:contrasenya@host:port/nom_db'

Per veure si la configuració de la BD funciona, pots fer (si la BD està buida crearà les taules):

(env) $ ./manage.py migrate

Si vols utilitzar SQLite enlloc de MySQL, la variable a utilitzar seria:

DATABASE_URL=sqlite:///db.sqlite3


Django en producció

Ja hem configurat el nostre projecte adientment, ara ens queda portar-lo a producció amb un servidor d'aplicacions. Molts tutorials posen en marxa Django amb el propi servidor de desenvolupament (el ./manage.py runserver) però això no és una bona pràctica. El servidor de desenvolupament no està pensat per gestionar adequadament el multithreading i altres implicacions en producció.

Necessitem un servidor d'aplicacions específic, com cal, per posar Django en producció de forma segura.

WSGI significa «Web Server Gateway Interface» i és una especificació standard per al desplegament d'aplicacions web sobre servidors web com Apache o Nginx. Veurem a continuació alguns servidors que segueixen aquest patró.

Servidor d'aplicacions uWSGI

uWSGI (doc oficial) funciona en pur Python. Podem seguir el tutorial per Django amb uWSGI i Nginx de la documentació oficial.

Assegura't que tens instal·lades les dependències per compilar packages:

(env) $ sudo apt install gcc build-essential python3-dev

En realitat la seva instal·lació i posta en marxa és molt senzilla:

(env) $ pip install uwsgi
(env) $ uwsgi --http :8000 --module mysite.wsgi

Substitueix mysite pel nom del teu projecte (potser és myproject?).

Veuràs que a l'executar Django amb el servidor d'aplicacions de producció uWSGI (o amb qualsevol altre) la ruta /admin no es veurà correctament. Falten els arxius estàtics: CSS, JavaScript i imatges. Això és normal. Segueix llegint per saber com s'ha d'instal·lar correctament.


Arxius estàtics

Si has posat en marxa el projecte amb un servidor de producció (no amb el servidor de development) veuràs que si intentes accedir al panell d'administració /admin no es veu correctament. Falten els arxius estàtics, imatges i CSS, que cal servir amb un servidor web com Apache o Nginx, que son molt més eficients que forçar a Django a fer-ho.

Per recopilar tots els arxius estàtics caldrà ajustar la variable STATIC_ROOT i STATIC_URL a settings.py:

STATIC_ROOT = 'static/'
STATIC_URL = '/static/'

I recopilar els arxius estàtics amb la instrucció:

(env) $ ./manage.py collectstatic

Veurem que a l'arrel del projecte s'haurà creat la carpeta static amb els arxius estàtics com imatges i fulles d'estil CSS.

Afegeix static/ al .gitignore.

Configurar Nginx per a servir arxius estàtics

Un cop recopilats els arxius estàtics a la carpeta static/ ens caldrà servir aquests arxius amb un Nginx, que és força més lleuger que l'Apache.

Django no ha de servir mai arxius estàtics, ja que és menys eficient que el Web Server, que està pensat per a això específicament. El següent diagrama mostra com es durà a terme la posada en producció final:

Segueix la secció de Nginx del tutorial oficial de Django amb uWSGI i Nginx per finalitzar la configuració del servidor web amb connexió a uWSGI.

Fixa't que en aquesta configuració final Nginx servirà el nostre projecte al port 8000 i que uWSGI posarà en marxa la site a través de socket i al port 8001:

(env) $ uwsgi --socket :8001 --module mysite.wsgi

Canvia la configuració per tal que escolti al port 80 i que respongui al domini mysite.polls. Recorda modificar l'arxiu /etc/polls per tal que el navegador miri localhost quan anem a mysite.polls.

Comprova que accedint al panell d'administració /admin es visualitzen els CSS correctament.

Troubleshooting (possibles errades):

  • Revisa que has parat (stop) i inhabilitat Apache (possible col·lisió de ports).
  • Revisa la configuració de mysite.conf de Nginx. Millor que deixis només activada el mysite i desactivis la default (links simbòlics).
  • Revisa els errors de Nginx amb sudo journalctl -xeu nginx.service
  • Si no veus el CSS fes CTRL+u , mira el codi font i clica un arxiu CSS aviam quin error et dona.
  • Comprova que has afegit STATIC_ROOT = BASE_DIR / 'static/' al settings.css
  • Comprova que has executat ./manage.py collectstatic i que no dona errors.
  • Si tens un Internal Server Error probablement hagis fet malament la comanda uwsgi (hauràs posat mysite.wsgi quan en realitat la teva carpeta es diu diferent de mysite).

Si no veus els arxius estàtics perquè et dona un error FORBIDDEN, revisa que els permisos de tot el path fins a les carpetes static i media hi pot accedir l'usuari de NGINX (www-data). Ja saps que està prohibidíssim posar permisos 777, busca una solució raonable i segura.

Engegant Django app amb Supervisor

Supervisord

Si has fet l'exercici anterior veuràs que uWSGI només està actiu si l'executes. El què voldrem ara és que la nostra webapp s'executi amb l'arrencada del computador. Una bona eina per aconseguir això és http://supervisord.org

Instal·la i configura http://supervisord.org per tal que a l'arrencar la màquina també funcioni la nostra webapp mysite.

/etc/supervisord/conf.d/polls.conf
[program:polls]
directory=/home/user/dev/mysite
command=/home/user/dev/djenv/bin/uwsgi --socket :8001 --module mysite.wsgi

Cal recarregar supervisord:

$ sudo supervisorctl reload

Comprovem si està en marxa:

$ sudo supervisorctl status


Més Django

Pots continuar a l'article Django Docker per dockeritzar la nostra webapp.

Altres parts de Django interessants:


django.txt · Darrera modificació: 2024/01/30 17:04 per enric_mieza_sanchez