De vegades, necessitaràs executar un tros de codi cada vegada que Django realitza una petició. Aquest codi podria necessitar modificar la petició abans que la vista la processi, o potser vol obtenir informació sobre aquesta per a temes de depuració, etc.
Les eines d'intermediaris de Django són essencialment un conjunt de pedaços dins del processat de peticions i respostes de Django. És un sistema lleuger de baix nivell per a modificar globalment les entrades i sortides de Django.
Cada component intermediari és responsable de fer la seva funció específica. Si estàs llegint aquest llibre de principi a final -- em sap greu pels postmodernistes - ja hauràs vist intermediaris nombroses vegades.
Aquest capítol entra en profunditat en el què és un intermediari i com funciona, i explica com pots escriure els teus propis intermediaris.
Els intermediaris actualment són increïblement simples. Un component d'intermediari és simplement una classe Python que segueix una certa API. Abans d'entrar dins dels aspectes formals de com és aquesta API, mira un exemple molt simple.
Els llocs amb molt de trànsit sovint necessiten desplegar Django entre un proxy de balanceig (mireu el Capítol 21). Això pot causar un petites complicacions, una de les quals és que cada IP d'una petició remota (request.META["REMOTE_IP"]) serà la IP del balancejador de càrrega, no la IP actual que fa la petició. Els balancejadors de càrrega tracten això amb una capçalera especial, X-Forwarded-For, per a l'adreça IP de la petició actual.
Així aquí hi ha un tros d'un intermediari que permet als llocs que s'executen a través d'un proxy vegin l'adreça IP correcta en la variable request.META["REMOTE_IP"]:
class SetRemoteAddrFromForwardedFor(object):
def process_request(self, request):
try:
real_ip = request.META['HTTP_X_FORWARDED_FOR']
except KeyError:
pass
else:
# HTTP_X_FORWARDED_FOR can be a comma-separated list of IPs.
# Take just the first one.
real_ip = real_ip.split(",")[0]
request.META['REMOTE_ADDR'] = real_ip
Si això està instal·lat (mireu el següent codi), cada valor X-Forwarded-For de la petició serà automàticament afegit dins de request.META["REMOTE_IP"]. Simple, oi?
En efecte, aquesta és una necessitat prou normal que aquesta peça de mitjancer és una part ja existent de Django; aquest intermediari és a django.middleware.http, i en pots llegir una mica més a continuació.
D'entre tots els lectors, els lineals, segurament ja tenen experiència amb això; molts dels exemples en el capítols previs només funcionen si has activa un intermediari. Tanmateix, per als que no en tenen experiència ho tornarem a explicar.
Per activar un intermediari, afegeix-lo en la llista MIDDLEWARE_CLASSES en el teu mòdul de paràmetres. En el paràmetre MIDDLEWARE_CLASSES, cada intermediari està representat per una cadena: el camí Python sencer al nom de la classe de l'intermediari. Per exemple, aquest és la llista per defecte:
MIDDLEWARE_CLASSES = ( 'django.middleware.common.CommonMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware', 'django.contrib.auth.middleware.AuthenticationMiddleware', 'django.middleware.doc.XViewMiddleware', )
Una instal·lació Django no necessita cap intermediari -- p.e. MIDDLEWARE_CLASSES poden estar buides, si ho vols -- però és molt recomanable que utilitzis CommonMiddleware.
L'ordre és important. En les fases de petició i vista, Django aplica els intermediaris en l'ordre de la llista, i en les fases de resposta i excepció, Django aplica els intermediaris en l'ordre invers. És a dir, Django tracta les MIDDLEWARE_CLASSES com una llista ordenada al voltant d ela funció vista: en la petició, aquest passa de dalt a baix cap a la vista, i en la resposta aquest va de baix cap a dat.
Ara que coneixem que és un intermediari i com instal·lar-lo, farem una ullada a tots els mètodes disponibles que les classes intermediari poden definir.
Si les classes intermediaries defineixen un inicialitzador (p.e. un mètode __init__), aquest no ha de tenir argument (a banda del self).
Per raons de rendiment, les classe d'intermediari només s'inicialitzen una vegada en processos llargs; això vol dir que no pots comptar el nombre de cops que es crida a l'inicialitzador, només un cop quan s'engega el servidor.
Les classes intermediari també poden utilitzar l'inicialitzador per eliminar-se ells mateixos del llistat. Si un inicialitzador llença una excepció django.exceptions.MiddlewareNotUsed, Django eliminarà aquesta peça de la llista d'intermediaris. Pots usar-ho per comprovar si hi ha un programari que en depengui, o si el servidor s'executa en mode de depuració, o qualsevol altre situació que pugui ser susceptible de desactivar l'intermediari.
Aquest mètode s'executa tant aviat quan es rep una petició, i abans que es resolgui la URL per determinar quina vista executar. Se li passa un objecte HttpRequest, el qual pots modificar.
process_request() ha de retornar o un None o un objecte HttpResponse. Si retorna None, Django continua processant aquesta petició, executant qualsevol altra intermediari i després la vista apropiada.
Si un intermediari de petició retorna un objecte HttpResponse, Django no executa cap altre intermediari ni vista, sinó que retornarà aquesta resposta.
Aquest mètode es crida després que els intermediaris de petició s'han executat, i després que la URL s'ha resolt en una vista, però abans que la vista s'executi.
Els arguments passats a aquesta vista són:
| Argument | Explicació |
|---|---|
| request | L'objecte HttpRequest. |
| view | La funció python que Django quan acabi amb aquest petició. És la funció, no el nom de la funció en una cadena. |
| args | La llista dels arguments per ordre que es passaran a la vista, no s'inclou l'argument request (que sempre és el primer argument de la vista). |
| kwargs | El diccionari dels arguments amb clau que seran passats a la vista. |
Igual que process_request(), process_view() han de retornar un objecte None o un HttpResponse. Si retorna un None, Django continuarà processant aquesta petició, executant qualsevol altre intermediari de vista i després la vista indicada.
Si un intermediari de vista retorna un objecte HttpResponse, Django no executarà cap més intermediari ni la pròpia vista; retornarà aquesta resposta.
Aquest mètode és cridat després que la funció vista hagi estat executada i la resposta s'hagi generat. Aquí és on l'intermediari pot modificar la sortida d'una resposta; comprimir la sortida (mireu a continuació) és un ús obvi per un intermediari de resposta.
Els paràmetres són bastant auto-explicatoris -- request és l'objecte de petició, i response és la resposta retornada per la vista.
A diferència dels intermediaris de petició i vista que podien retornar None, process_response() ha de retornar un objecte HttpResponse. Aquesta resposta podria ser la original passada en la funció (possiblement modificada), o una de nova.
Aquest mètode només s'executa si alguna cosa va malament i una vista llença una excepció, excepte les excepcions Http404. Pots utilitzar aquest pedaç per enviar notificacions d'error, enviar informació a un registre, o fins i tot intentar recuperar l'error.
Els paràmetres a aquesta funció són el propi objecte petició, i l'excepció.
process_exception() pot retornar un HttpResponse que serà usat com la resposta que es mostrarà en el navegador, o pot retornar None per continuar amb la captura d'excepcions de Django.
Ho deixem aquí. Els exemples són massa senzills.