Django Book Español - Google Drive
Django Book Español - Google Drive
Experienciaenprogramacin:conceptosbsicoscomovariables,estructurasdecontrol
(ejemplo:if,for,while),estructuradedatos(listas,tuplas,diccionarios),clasesyobjetos,ypor supuestoprogramacinorientadaaobjetos.
Experienciaprogramandoenpython:Djangoesunacoleccindelibrerasescritasenpython.
Entoncesparadesarrollarsitiosusandodjangotienesqueescribircdigoenpython.Encasode quenosepasprogramarenpythonestasdesuerteporqueaprenderaprogramarenpythones unplacer,cosasquetepuedenllevarvariaslneasdecdigoenotroslenguajesconpython puedeshacerlodeunamanerasimpleyenpocaslneas.Sibuscaslibrosparaaprenderpython terecomiendo"pythonparatodos"o"Diveintopython".
Quesunwebframework?
Djangoesunprominentemiembrodeunanuevageneracinde webframeworkspero queesloqueestetrminoprecisamentesignifica? Paracontestarestapregunta,vamosaconsiderareldiseodeunaaplicacinwebescrita enpython sinunframework.Atravsdeestetutorial,vamosatomaresteenfoquede trabajarsinframeworksoatajosydespusvercomoloharamosconatajos. Unadelasmanerasmssimplesydirectasdeconstruirunaaplicacinwebescritaen pythonsinutilizarningnframeworkesusarCGI(CommonGatewayInterface)estndar, quefueunatcnicamuypopularafinalesdelos90'sparadesarrollarpginasweb dinmicasynosimplementeHTMLesttico. Aquunaexplicacindealtoniveldecomofunciona:solocreaunscriptenpythonque imprimaHTML,luegosalvaelscriptenunservidorwebconlaextensin".cgi"yvisitala paginadesdetuexploradorwebfavorito.Yesoestodo. AquunejemplodepythonCGI(supongaquefunciona):
# ! / u s r / b i n / e n v p y t h o n i m p o r t M y S Q L d b p r i n t " C o n t e n t T y p e : t e x t / h t m l \ n " p r i n t " < h t m l > < h e a d > < t i t l e > B o o k s < / t i t l e > < / h e a d > " p r i n t " < b o d y > " p r i n t " < h 1 > B o o k s < / h 1 > " p r i n t " < u l > "
c o n n e c t i o n = M y S Q L d b . c o n n e c t ( u s e r = ' m e ' , p a s s w d = ' l e t m e i n ' , d b = ' m y _ d b ' ) c u r s o r = c o n n e c t i o n . c u r s o r ( ) c u r s o r . e x e c u t e ( " S E L E C T n a m e F R O M b o o k s O R D E R B Y p u b _ d a t e D E S C L I M I T 1 0 " ) f o r r o w i n c u r s o r . f e t c h a l l ( ) : p r i n t " < l i > % s < / l i > " % r o w [ 0 ] p r i n t " < / u l > " p r i n t " < / b o d y > < / h t m l > " c o n n e c t i o n . c l o s e ( )
Comopuedenverloprimeroquehaceesimprimir C o n t e n t T y p e : t e x t / h t m l seguidodeuna lneaenblancodespusimprimiralgodeHTML,haceunaconexinaunabasededatos, obtienealgunosregistrosylosimprimeformateadoconHTML,terminadeimprimirelHTML ycierralaconexin. Conunapginacomoesta,elescribirtododesde0noesnecesariamentemalo.Estecdigo essimpledecomprenderinclusiveunprogramadornovatopuedeleerestas16lneasde cdigodepythonyentendertodo,deprincipioafin.Comopuedenobservarnohaymucho queaprenderynohayotrocdigomsqueleer.Ademsessimpledellevaraproduccin: solosalvaelcdigoenunarchivoquetengalaextensin . c g i ,subeelarchivoalservidor webyvisitalapginadesdetuexplorador. Peroapesardesusimplicidad,esteenfoquetienenmerosproblemasyfastidios.Solo pregntateatimismolassiguientespreguntas:
Qupasacuandomltiplespartesdelaaplicacinnecesitanestarconectadasalabasede
datos?Seguramenteesecdigoparaconectaralabasededatosnonecesitaraserduplicadoen cadascriptCGIquehagamos.Loidealserarefactorizarelcdigoenunafuncincompartida paraconectarnosalabasededatos.
DebeeldesarrolladorrealmentepreocuparseacercadeimprimirlalineaC o n t e n t T y p e y
recordarcerrarlaconexinalabasededatos?Estetipodeasuntosreducelaproductividadde unprogramadoreintroduceoportunidadesparaerrores.
Qupasacuandoelcdigoesreutilizadoenmltiplesambientes,cadaunoconunabasede
datosycontraseasseparadas?Enestepunto,algunasconfiguracionesdeambientes especficossevuelvenesenciales.
Qupasacuandoundiseadorwebsinexperienciacodificandoenpythondesearedisearla
pgina?Uncarctermalpuestoylaaplicacinenterapuedefallar.Idealmente,lalgicadela pginaelobtenerregistrosdelibrosdelabasededatosdeberadeestarseparadadelHTML quedespliegalapgina,entonceseldiseadorpuedeeditarelHTMLsinafectarlalgicadela aplicacin.
EldiseodelpatrnMVC
Vamosaverunrpidoejemploquedemuestraladiferenciaentreelanterioryunenfoque conunwebframework.AquestacomomsomenosseescribiraelanteriorcdigodeCGI usandoDjango.Ylaprimeracosaquenotamosesquedividimostodoen4archivos (m o d e l s . p y , v i e w s . p y , u r l s . p y )yuntemplateHTML(l a t e s t _ b o o k s . h t m l ):
# m o d e l s . p y ( t h e d a t a b a s e t a b l e s ) f r o m d j a n g o . d b i m p o r t m o d e l s c l a s s B o o k ( m o d e l s . M o d e l ) : n a m e = m o d e l s . C h a r F i e l d ( m a x _ l e n g t h = 5 0 ) p u b _ d a t e = m o d e l s . D a t e F i e l d ( )
# l a t e s t _ b o o k s . h t m l ( t h e t e m p l a t e ) < h t m l > < h e a d > < t i t l e > B o o k s < / t i t l e > < / h e a d > < b o d y > < h 1 > B o o k s < / h 1 > < u l > { % f o r b o o k i n b o o k _ l i s t % } < l i > { { b o o k . n a m e } } < / l i > { % e n d f o r % } < / u l > < / b o d y > < / h t m l >
Elarchivov i e w s . p y contienelalgicadelnegocioparalapgina.Lafuncinl a t e s t _ b o o k es
llamadaunavista.
Elarchivou r l s . p y especificaquevistadebeserllamadadadounpatrndeURL.Enestecaso,la
URL/ l a t e s t / sermanejadaporlafuncinl a t e s t _ b o o k s ( ) .Enotraspalabras,situdominioes example.com,cualquieraquevisitehttp://example.com/latest/vaallamaralafuncin l a t e s t _ b o o k s ( ) .
Elarchivol a t e s t _ b o o k s . h t m l esuntemplate(oplantilla)quedescribeeldiseodelapgina,
usandounlenguajedetemplateconbsicassentenciaslgicasejemplo{ % f o r b o o k i n b o o k _ l i s t % } .
Sitomamostodaslaspiezasylasjuntamosaproximadamentesiguenunpatrnllamado MVC(ModelViewController). Laventajaclavedetalenfoqueesqueloscomponentesson looselycoupled.Cadapiezade unaaplicacinwebhechaconDjangotieneunsolopropsitoclaveypuedesercambiado independientementesinafectarlasotraspiezas.Porejemplo,undesarrolladorpuede cambiarlaURLdeciertapartedelaaplicacinsinafectarlasotraspiezasdelaaplicacin. UndiseadorpuedecambiarelHTMLdeuntemplate(oplantilla)sintenerquetocarel cdigodepython.Unadministradordebasededatospuederenombrarunatabladelabase dedatosyespecificarelcambioenunsololugar,envezdetenerquebuscaryreemplazar atravsdeunadocenadearchivos.
LahistoriadeDjango
Antesdeempezarabucearentremscdigo,debemostomarunmomentoparaexplicarla historiadeDjango.Comodijimosanteriormentetevamosamostrarcomohacerlascosas sinusaratajos,ademsvasaentendermejorlosatajos.Similarmente,estilentenderpor qufuecreadoDjango,porquelconocimientodelahistoriatepondrenuncontextode porqueDjangotrabajaenlamaneraenquelohace. Sihasestadoconstruyendoaplicacioneswebporuntiempo,probablementeestas familiarizadoconlosproblemasdelejemploCGIquepresentamosanteriormente.Laruta clsicadeldesarrollowebvamsomenosas:
1. 2. 3. 4. 5. 6.
EstoesprecisamentecomoDjangofuecreado. Djangocrecioriginalmentedeaplicacionesdelmundorealescritasporunequipo desarrollowebenLawrence,Kansas,USA.Djangonacienelotoode2003,cuandolos programadoreswebdelperidico"LawrenceJournalWorld",AdrianHolovatyySimon Willison,empezaronusandopythonparaconstruiraplicaciones. Elequipo"WorldOnline",responsabledelaproduccinymantenimientodevariossitiosde noticiaslocales,prosperadoenunambientededesarrollodictadoporlostiemposlimites delperiodismo.ParalossitiosincluyendoLJWorld.com,Lawrence.comyKUsports.com periodistas(yadministradores)demandabanquefueranaadidascaractersticasy aplicacionesenterasfueranconstruidasenunaintensamenterpidaagenda,comnmente consolodasuhorasparadesarrollarlo.Deestemodo,SimonyAdrianhabandesarrollado unwebframeworkquelesahorrabatiempoesafuelanicamaneraenqueellospudieron construiraplicacionesmanteniblesbajolosestrictostiemposdeentrega. Enelveranodel2005,despusdehabiendodesarrolladoesteframeworkhastaunpunto dondeeficientementeimpulsabalamayoradelossitios"WorldOnline",elequipo,elcual ahoraincluaaJacobKaplanMoss,decidieronliberarelframeworkcomosoftwarede cdigoabierto.LoliberaronenJuliode2005ylollamaronDjango,enhonoralguitarrista dejazzDjangoReinhardt. Ahora,variosaosdespus,Djangoestabienestablecidocomounproyectodesoftware libreconmsdediezmilusuariosycolaboradoresesparcidosatravsdetodoelmundo. DosdelosdesarrolladoresoriginalesdeWordOnline("Losbenevolentesdictadoresdela vida",AdrianyJacob)anproveenunaguacentralparaelcrecimientodelframework, peroesmuchomselesfuerzocolaborativodetodoelequipo. Estahistoriaesrelevanteporqueayudaaexplicar2cosasclave.LaprimeraDjangoesel "lugardulce"(sweetspot).PorqueDjangonacienunambientedenoticias,ofrecevarias caractersticas(comounsitiodeadministracin)quesonparticularmenteadecuadospara sitiosde"contenido"sitioscomoamazon.com,craigslist.orgywashingtonpost.comque ofrecendatosdeunamaneradinmica.ApesardequeDjangoesparticularmentebueno paradesarrollaresetipodesitios,quenoloexcluyedeserunaherramientaefectivapara construircualquiertipodesitiowebdinmico. Elsegundopunto,muestracomolosorgenesdeDjangohanformadolaculturadesu comunidaddesoftwarelibre.PorqueDjangofueextradodesdeelcdigodelmundoreal, envezdeempezarcomounejercicioacadmicooproductocomercial,estasumamente enfocadoenresolverproblemasdedesarrollowebquelosmismosdesarrolladoresde Djangosehanenfrentadoycontinanenfrentando.Comoresultado,elmismoDjangoes activamentemejoradoenunabasecasidiaria.
Iniciando
Djangoes"solo"cdigoenpythonycomopythoncorredondeseaincluyendocelulares.
Instalandopython
EnsimismoDjangoestaescritocompletamenteenpython,entonceselprimerpasoen instalarelframeworkesestarseguroquepythonestainstalado.
Versionesdepython
ElncleodelframeworkDjangofuncionaconcualquierversindepythondesdela2.3hasta la2.7,dependiendodelaversindelframeworklasversionesmsrecientesestndejando dedarsoportealasversionesmsantiguasdepython.Poresoterecomendamosusarde python2.5enadelante. Sinoestassegurocualversindepythoninstalarytieneslalibertaddedecidirqueversin instalar,entoncesterecomendamosinstalarlaultimaversindelaserie2.x.Apesarde queDjangotrabajaigualconcualquierversindepython,lasltimasversionesdepython tienenmejorasderendimientoycaractersticasadicionalesdellenguajequetalvezteguste usarentusaplicaciones.Ademsexistenaddons(oextensiones)detercerosparaDjango podranrequerirversionesmsnuevasquelasversiones2.3o2.4
Djangoypython3.x
Comosaben,pythonestaenunprocesodetransicindondepython3.xintentadesplazar lasversiones2.x,comoyasabencadaversindepythonquecambiaensuprimerdgito tienecambiosimportantesyademsnoescompatibleconversionesanteriores,porloque muchasaplicacionessetienenquereescribiryesoincluyeaDjango. ActualmenteDjangonocorrecompletamenteenpython3.x,afortunadamenteestoseha estadoplaneandoydesarrollandoporaos.AsqueesperamosquemuyprontoDjangose puedacorrercompletamenteenversionesdepython3.x
Instalacin
SiestascorriendoLinuxoMacOSX,probablementeyatienespythoninstalado.Solo escribepythonentuconsola(terminalolneadecomandos)favorita.Sivezalgoparecidoa esto,entoncestienespythoninstaladoentusistema. p y t h o n 2 . 6 . 5 ( r 2 6 5 : 7 9 0 9 6 , M a r 1 9 2 0 1 0 , 2 1 : 4 8 : 2 6 ) [ M S C v . 1 5 0 0 3 2 b i t ( I n t e l ) ] o n w i n 3 2 T y p e " h e l p " , " c o p y r i g h t " , " c r e d i t s " o r " l i c e n s e " f o r m o r e i n f o r m a t i o n .
> > > SieresunusuariodelsistemaoperativoWindows,lomsprobableesquenotengas instaladopython. Decualquierforma,sinecesitasdescargarpythonpuedeshacerlodesdeaqu http://www.python.org/download/.Lasinstruccionessonrpidasyfcilesdeseguir. SiestasenWindows,terecomiendobajarteel.exeo.msiyaquecompilarlopuedeseralgo complicado(porlomenosenWindows).Encambio,siteencuentrasenLinuxytienesun administradordepaquetesterecomiendousarlo,yaqueregularmentelosmdulospara pythontambinpuedesinstalarlodesdetuadministradordepaquetes.Ademsestos paquetessonelegidosparaquetrabajendeunamaneraptimacontudistribucinLinux tambinconeltiempoobtienesactualizacionesparaestospaquetes.Perosinocuentascon unadministradordepaquetes(comoaptget,yum,pacman,)siemprepuedesdescargate elcdigofuentedelinterprete,compilarloeinstalarlo.
InstalandoDjango
Djangotienetpicamente2versionesdisponibles:laltimaversinoficiallanzadayla versinexperimentalllamada"trunk".Laversinquedecidasinstalardependeentus prioridades.QuieresunaversinestableyprobadadeDjangooquieresunaversinque tengalasltimascaractersticasyprobablementepuedascontribuiralmismoframework Django,acostodelaestabilidad? Nosotrosterecomendamosquetepeguesalasversionesoficiales(oestables),pero tambinesimportantesaberquelaversin"trunk"(oversinendesarrollo)existe.
Instalandolaversinoficial
Laltimaversinenelmomentoqueescriboestetutorial,eslaversin1.3.Paradescargar laltimaversinpuedesvisitarhttps://www.djangoproject.com/download/.Paralos usuariosLinuxquetenganadministradordepaquetespuedeninstalarDjangodesdesu administradordepaquetes,porloregularlaversindeDjangoqueinstalaesunaversin estable.Sinotienesaccesoaunadministradordepaquetes,puedesdescargareinstalar Djangomanualmente.Parahaceresovisitenlapaginaanteriorybajenlaltimaversin, despuscorranestoscomandos. t a r x z v f D j a n g o < v e r s i n > . t a r . g z # S u p o n i e n d o q u e e s t a n e n e l d i r e c t o r i o d o n d e l o d e s c a r g a r o n c d D j a n g o * s u d o p y t h o n s e t u p . p y i n s t a l l YlistoadisfrutarDjango.
ProbandoDjango
ParasaberqueefectivamenteinstalamosDjango,abrimoselintrpretedinmicodepython yescribimoslosiguiente:
i m p o r t d j a n g o d j a n g o . V E R S I O N
Ajustandolasbasesdedatos
ParatrabajarconDjangonoesnecesariotenerunabasededatos,peroDjangotiene muchasfuncionesquerequierentenerunabasededatosyseguramentetambinte interesarguardar,obtener,actualizaryborrardatos.Asqueporesoestannecesariauna basededatos. Djangosoporta4motoresparabasededatos:
Primero,vasanecesitarinstalaryconfigurarelservidordebasededatos.Elprocesovamsall
delalcancedeestetutorial,peroafortunadamenteestos4motoresquesoportaDjangotienen muchadocumentacin,unagrancomunidadencadaunadeestasylamayoradeestasson fcilesdeinstalar.
Segundo,vasanecesitarinstalarunalibreradepythonquetepermitaconectarteatubasede
datos.
Empezandounproyecto
Unavezinstaladopython,Djangoyopcionalmentelalibreraparaconectarnosalabasede datos,puedesdarelprimerpasoendesarrollarunaaplicacinenDjangoqueescrearun proyecto UnproyectoesunacoleccindeajustesparaunainstanciadeDjango,incluyendo: configuracindelabasededatos,opcionesespecficasdeDjangoylaaplicacin. NOTA:Parafinesprcticos,nopongastucdigodepythoneneldocumentroot. Loprimeroquevamoshacerescrearundirectorio(ocarpeta)ycorrerelsiguiente comando: d j a n g o a d m i n . p y s t a r t p r o j e c t m y s i t e Estovaacrearunacarpetallamada mysiteentuactualdirectorio. NOTA:ParalosusuariosUnixdjangoadmin.pydebeseestarenel"path"detusistemay ademsdebedetenerpermisosdeejecucinestoencasoquehayasinstaladoDjangode maneramanual.Siloinstalastedesdeunadministradordepaquetesprobablementeel comandonosellamedjangoadmin.pysinodjangoadmin.SiestasusandoWindowsmuy probablementetengasqueaadirpythonalpathyluegoejecutarlosiguiente p y t h o n C : \ r u t a \ a \ d j a n g o \ d j a n g o a d m i n . p y m y s i t e .Decualquiermaneraterecomendamosque instalesEclipse+PyDevparaqueseamsfciltrabajarentuproyecto. Unavezquecomenzamosconnuestroproyectotenemosunaestructuramsomenosas: m y s i t e / _ _ i n i t _ _ . p y m a n a g e . p y s e t t i n g s . p y u r l s . p y
_ _ i n i t _ _ . p y :unarchivoquerequierepythonparaquelacarpetam y s i t e puedasertratado
comounpaquete.Esunarchivovacoygeneralmentenovamosaadirnadaenel.
m a n a g e . p y :esunautilidaddelalneadecomando,conestearchivovamosainteracturarconel
proyectodevariasmaneras.Intentaconp y t h o n m a n a g e . p y h e l p paradarteunaideadeloque puedeshacer.Nunca,peronuncadebesdeeditarestearchivo.
s e t t i n g s . p y :ajustes/configuracionesparaelproyecto.chaleunvistazoalosdiferentestipos
deconfiguracionesdisponiblesyasusvalorespordefecto.
u r l s . p y :lasURLsdelproyectoestnenestearchivo.Bsicamenteestoesuna"tablade
contenidos"paratuproyecto.Porelmomentoestavaco.
Apesardesutamao,estosarchivosconstituyenunaaplicacincompletamentefuncional.
Corriendoelservidordedesarrollo
Lamayoradeltiempovamosacorrerelservidordedesarrolloparavercomovaquedando nuestroproyecto. ElservidordedesarrollodeDjango(tambinllamado"runserver"enhonoralcomandoque lolanza)esunservidorwebintegradoyligeroquepuedesusarparadesarrollartusitio. EstaincluidoenlainstalacindeDjangoentoncespuedesdesarrollarrpidamentetusitio, sinestarteniendoquelidiarconlaconfiguracindeunservidorwebdeproduccin(ejemplo Apache)hastaqueestelistoparalaproduccin.Elservidordedesarrollovigilatucdigoy automticamentelorecarga,haciendofcilparatucambiarelcdigosinlanecesidadde reiniciarnada. Parainiciarelservidor,muvetealdirectoriodetuproyecto(m y s i t e )yejecutaelsiguiente comando: p y t h o n m a n a g e . p y r u n s e r v e r Despusdeberasdeveralgocomoesto: V a l i d a t i n g m o d e l s . . . 0 e r r o r s f o u n d D j a n g o v e r s i o n 1 . 2 . 3 , u s i n g s e t t i n g s ' m y s i t e . s e t t i n g s ' D e v e l o p m e n t s e r v e r i s r u n n i n g a t h t t p : / / 1 2 7 . 0 . 0 . 1 : 8 0 0 0 / Q u i t t h e s e r v e r w i t h C T R L B R E A K . Estolanzaelservidorlocalmenteenelpuerto8000,accesiblesoloparalasconexionesde tupropiacomputadora.Ahoraqueestacorriendo,visitahttp://127.0.0.1:8000/contu navegadorwebfavorito.Entoncesvasaver"WelcometoDjango"enunapaginadetono azul.
Tambinpuedencambiarelpuertopordondeescuchaelservidorwebdelasiguiente manera:
VistasyURLconfs
TuprimerapginahechaconDjango:HolaMundo!
UnavezqueyatenemosinstaladoDjangopodemosempezarajugar.Comoprimerapgina vamoshacerelpopular "Holamundo!" Vamosaverunejemplosencillodecomohacerunhola sinunframework:
Tuprimeravista
Eneldirectorio m y s i t e quehicisteconelcomando djangoadminstartproject,tienesun archivollamado v i e w s . p y .Estemdulodepythoncontendrlasvistasqueharemosdurante estaentrada.Notaquecuandoabrasestearchivoporprimeravezestarvaco.Adems,a Djangonoleimportacomosellameestearchivoperoporconvencinlomantendremos como v i e w s . p y . Nuestravista"Holamundo"esmuysimple,aquestaunejemplodecomoseranuestra funcin: f r o m d j a n g o . h t t p i m p o r t H t t p R e s p o n s e d e f h e l l o ( r e q u e s t ) : r e t u r n H t t p R e s p o n s e ( " H o l a m u n d o " )
Vamosaleerelcdigolneaporlnea: Primero,importamoslaclase H t t p R e s p o n s e ,lacualresideenelmdulo d j a n g o . h t t p . Necesitamosimportarestaclaseporquelavamosausarmsadelanteennuestrocdigo. Segundo,definimosunafuncinllamada h e l l o lafuncinvista. Cadafuncinvistarecibealmenosunparmetrollamado r e q u e s t porconvencin.Estees unobjetoquecontieneinformacinacercadelapeticinwebquefuedisparadaporesta vista,ademsesteobjetoesunainstanciadelaclase d j a n g o . h t t p . H t t p R e q u e s t .Eneste ejemplonovamosahacernadacon r e q u e s t ,peroestesiempredebedeserelprimer parmetroencualquiervista. Notaqueelnombredelafuncinnoimporta,notienequeserllamadadeciertamanera paraqueDjangolareconozca.Laestamosllamando h e l l o ,porqueelnombreclaramente indicalaesenciadelavista,perotambinpudoserllamada h o l a _ h e r m o s o _ b e l l o _ m u n d o o algoigualderepulsivo. Lafuncinesunsimple"oneliner":Simplementeregresaunobjetodelaclase H t t p R e s p o n s e quehasinicializadoconeltexto"Holamundo". Aqulaprincipalleccinesesta:unavistaesunafuncindepythonquetomacomoprimer parmetrounobjeto H t t p R e q u e s t yregresaunainstanciadelaclase H t t p R e s p o n s e .Paraque unafuncinpuedaserunavistaDjango,necesitahacerestas2cosas.(Claroquehay excepcionesyvamosaverestasexcepcionesdespus). Siellectoreslosuficienteagudopudodarsecuentaqueesteesbsicamenteelmodelo clienteservidor.
TuprimerURLconf
Hastaestepuntosicorres p y t h o n m a n a g e . p y r u n s e r v e r otravez,todavavasaverel mensaje"Itworked",sinpistaalgunadenuestro"Holamundo".Yestoesporquenuestro proyecto mysiteannosabedelaexistenciadenuestravista hello.Necesitamosdecirlea DjangoqueestamosactivandoestavistaenunaURLespecfica.(Continuandoconla analogadelosarchivosHTMLestticos,enestemomentotodavanohemossubidonuestro archivoalservidor.)ParaenlazarunavistaaunaURLenparticularusandoDjango,usamos unURLconf. UnURLconfescomounatabladecontenidosparatusitiohechoconDjango.Bsicamente esunatabladerelacionesdondedescribequefuncindebedeserllamadacadavezque visitanciertaURL.Porejemplocuandoalguienvisite f o o llamaalavista f o o _ v i e w ( ) ,que viveenelmdulo v i e w s . p y . Cuandoejecutaste d j a n g o a d m i n s t a r t p r o j e c t ,elscriptcreounURLconfporti automticamente:elarchivo u r l s . p y .Pordefectosevemsomenosas:
f r o m d j a n g o . c o n f . u r l s . d e f a u l t s i m p o r t * # U n c o m m e n t t h e n e x t t w o l i n e s t o e n a b l e t h e a d m i n : # f r o m d j a n g o . c o n t r i b i m p o r t a d m i n # a d m i n . a u t o d i s c o v e r ( ) u r l p a t t e r n s = p a t t e r n s ( ' ' , # E x a m p l e : # ( r ' ^ m y s i t e / ' , i n c l u d e ( ' m y s i t e . f o o . u r l s ' ) ) , # U n c o m m e n t t h e a d m i n / d o c l i n e b e l o w a n d a d d ' d j a n g o . c o n t r i b . a d m i n d o c s ' # t o I N S T A L L E D _ A P P S t o e n a b l e a d m i n d o c u m e n t a t i o n : # ( r ' ^ a d m i n / d o c / ' , i n c l u d e ( ' d j a n g o . c o n t r i b . a d m i n d o c s . u r l s ' ) ) , # U n c o m m e n t t h e n e x t l i n e t o e n a b l e t h e a d m i n : # ( r ' ^ a d m i n / ' , i n c l u d e ( a d m i n . s i t e . u r l s ) ) , )
Estearchivo u r l s . p y pordefectoincluyealgunascaractersticascomentadasusadaspor Django,paraactivarestascaractersticasesfcilsolotienesquedescomentarlaslneas necesariasylisto.Siignoramosloscomentariosentoncestenemosalgomsomenosas. f r o m d j a n g o . c o n f . u r l s . d e f a u l t s i m p o r t * u r l p a t t e r n s = p a t t e r n s ( ' ' , ) Vamosaanalizarlneaporlneaelcdigo.Laprimeralneaimportatodoslosobjetosdeel mdulo d j a n g o . c o n f . u r l s . d e f a u t l s ,lacualeslainfraestructuradelosURLconfsdeDjango. Estotambinincluyeunafuncinllamada p a t t e r n s .Lasegundalneallamaalafuncin p a t t e r n s ysalvasuresultadoenunavariablellamada u r l p a t t e r n s .Lafuncin p a t t e r n s sele pasaunsoloargumentounacadenavaca.(Estosepuedeusarcomoprefijoperolo veremosmsadelante) Elprincipalpuntoanotaraqueslavariable u r l p a t t e r n s ,elcualDjangoesperaencontrar ennuestromdulodeURLconfs.EstavariabledefinelasrelacionesentrelasURLsylas vistasquemanejanestasURLs.PordefectolaURLconfestavaca.AdemssielURLconf estavacoDjangoasumequeacabasdecreartuproyectomostrandoelmensaje"It worked!". Ahoralonicoquetienesquehaceresaadirunatuplaparadefinirlarelacinentreuna URLyunavista. Ejemplo: f r o m d j a n g o . c o n f . u r l s . d e f a u l t s i m p o r t * f r o m m y s i t e . v i e w s i m p o r t h e l l o u r l p a t t e r n s = p a t t e r n s ( ' ' ,
( ' ^ h e l l o / $ ' , h e l l o ) , ) Nosotroshemosquitadoloscomentariosparabrevedad,perosiquierespuedesdejarlos. Hicimos2cambios: Primero,importamoslafuncin h e l l o denuestromdulo m y s i t e . v i e w s .Segundo,aadimos lalnea ( ' ^ h e l l o / $ ' , h e l l o ) ,a u r l p a t t e r n s .Aestalnealavamosallamar U R L p a t t e r n . AhoravamosadiscutirunpocosobrelasintaxisdeunURLpatternporquenoesobvioa primeravista.ApesardequequeremoshacercoincidirlaURL / h e l l o / ,elpatrnseveun pocodiferenteaeso.Vamosaverporqu: Djangoquitalosslash(/ )delfrentedelaURLantesdequelachequeconlosURLpatterns. EstosignificaquenuestroURLpatternnoincluyelosslashdelfrenteentonces / h e l l o / quedara h e l l o / . Lospatronesincluyenuncircunflejo(^ )yelsignodedolar($).Estosoncaracteres especialesdeexpresionesregularesquetienenunsignificadoespecial:Elcircunflejo(^ ) significaque"elpatrnrequierecoincidirdesdeeliniciodelacadena",porelotroladoel signodedolar($ )significaque"requierequeelpatrncoincidaconelfinaldelacadena". Esteconceptosepuedeexplicarmejorconunejemplo.Sienvezdelpatrn ^ h e l l o / $ hubiramosusado ^ h e l l o / (sinelsignodedolaralfinal),entoncescualquierURLque empiececon / h e l l o / coincidira,talcomo / h e l l o / f o o y / h e l l o / b a r ynosolamente / h e l l o / . Igualmentesihubiramosusadolaexpresin h e l l o / $ sinelcircunflejoalprincipioentonces coincidiracualquiercadenaquetermineen h e l l o / como / f o o / b a r / h e l l o / .Sinohubiramos usadonielsignodedolarnielcircunflejosolo h e l l o / entoncescoincidiracualquiercadena quecontenga h e l l o / talcomo / f o o / h e l l o / b a r .Yesporesoquetanimportanteusarel circunflejoyelsignodedolar. LamayoradelosURLpatternsempezarnconuncircunflejoyterminarnconsignode dolarperoesimportantesaberquetambinpodemoshacerpatronesmassofisticados. Hastaestemomentoteestarspreguntandoqupasarasialguienhicieraunapeticinala URL / h e l l o .PorquenuestroURLpatternrequiereunslashalfinal,esaURLnocoincidira.Sin embargo,pordefectocualquierpeticinquenocoincidaconURLpatternynotermineconun slashvaserredireccionadoalamismaURLconunslashalfinal.(Estoesreguladoporla variable A P P E N D _ S L A S H quepuedesencontrarentuarchivodeconfiguracin s e t t i n g s . p y .) OtracosaquedeberasnotaracercadelosURLconfsesquehemospasadolafuncin h e l l o comounobjetosinllamaralafuncin.Estoesunacaractersticaclavedepython(yde muchosotroslenguajesdinmicos):lasfuncionessonobjetosdeprimeraclase,loque significaquepuedespasarloscomosifueracualquierotravariable. ParaprobarnuestroscambiosenelURLconf,iniciaelservidordedesarrollodeDjango,
Nota:Expresionesregulares
Expresionesregulares(oregexes)sonunamaneracompactadeespecificarpatronesen eltexto.MientraslasURLconfsdedjangopermitenexpresionesregularesarbitrariaspara unapoderosacoincidenciadepatronesenlaURL,probablementesolousesunpocas expresionesenlapractica.Aquihayunapequeaseleccindelasexpresionesmas usadas:
Expresin . ( d o t ) \ d [ A Z ] [ a z ] [ A Z a z ] + [ ^ / ] + ? * { 1 , 3 }
Coincide Cualquiercarcter. Unsolodgitodecimal. Cualquiercracterentre A y Z (uppercase) Cualquiercracterentre a y z (lowercase) Cualquiercracterentre a y z (caseinsensitive) Unoomasdelaexpresinprevia(ejemplo: \ d + coincideunooms dgitos) Unoomascaractereshasta(ysinincluir)elslash. Ceroounadelaexpresinprevia(ejemplo: \ d ? coincidecerooun dgito) Ceroomasdelaexpresinprevia(ejemplo: \ d * coincidecero,unoo masdeundgito). Entre1y3(inclusive)delaexpresinprevia(ejemplo: \ d { 1 , 3 } coincide uno,dosotresdgitos)
Paramasexpresionesregularesverhttp://www.djangoproject.com/r/python/remodule/.
Unanotarpidaacercadeerrores404
Hastaestepunto,nuestraURLconfdefineunsoloURLpattern:Elnicoquemanejalas peticionesdelaURL / h e l l o / .PeroquepasacuandolanzasunapeticinaunaURL
Lautilidaddeestapaginanvamasalldeunbsicomensajedeerror404.Ademstedice queURLconfestausandodjangoycadapatrndelaURLconf.Apartirdeesainformacin, deberasdesercapazdededucirporquelapeticinaURLarrojounerror404. Naturalmente,estaesinformacinsensibleypretendidosoloparati,eldesarrolladorweb. SiestefueraunsitioenproduccinenInternet,seguramentenoquerrasqueesta informacinseaexpuestaalpublico.Porestarazn,lapaginaPagenotfoundvaaser mostradasolamentesituproyectodjangoestaenmodo debug. Mstardevamosaexplicar comodesactivarelmododebug.Porahora,solonecesitassaberquecadaproyectodjango estaenmododebuglaprimeravezqueescreado,ysielproyectonoestaenmododebug, djangomostraraundiferentemensaje.
Unanotarpidaacercadelsitioraz
Comoexplicamosenlaultimaseccin,vasaverunmensajedeerror404enelsitioraz http://127.0.0.1:8000/.Djangonoaadenadamagicamentealsitiorazdecualquier maneraesaURLnoesningncasoespecial.Estaentusmanos(omejordichoentus dedos)asignareseURLpattern,justocomocualquierotroURLpatternentuURLconf. ElURLpatternquecoincideconelsitiorazesexactamenteintuitivo,aunque,valelapena mencionarlo.Cuandoestslistoparaimplementarlavistaparatusitioraz,usael URLpattern ^ $ ,quecoincideunacadenavaca.Porejemplo: f r o m m y s i t e . v i e w s i m p o r t h e l l o , m y _ h o m e p a g e _ v i e w u r l p a t t e r n s = p a t t e r n s ( ' ' , ( ' ^ $ ' , m y _ h o m e p a g e _ v i e w ) , # . . . )
ComoDjangoProcesaunaPeticin
Antesdecontinuarconnuestrasegundafuncinvista,vamosapausarunmomentoy aprenderunpocomasacercadecomodjangotrabajo.Especficamente,cuandovesel mensajeHelloWordunavezquevisitashttp://127.0.0.1:800/hello/entunavegadorweb favorito,Quesloquehacedjangodetrsdelasescenas? Todoempiezaconelarchivo s e t t i n g s .Cuandotucorres p y t h o n m a n a g e . p y r u n s e r v e r ,el scriptvaybuscaporunarchivollamadosettings.py.Enlamismacarpetaquemanage.py. Estearchivocontienetodotipodeconfiguracionesparaesteproyectoenparticular,todas lasconfiguracionesestanenmayusculas(omejordichoenuppercase): T E M P L A T E _ D I R S , D A T A B A S E _ N A M E ,etc.Laconfiguracinmsimportanteesunallamada R O O T _ U R L C O N F . R O O T _ U R L C O N F lediceadjangoquemodulodepythondebedeserusadoparaelURLconfde estesitio. Recuardascuandodjangoadminstartprojectcreolosarchivos s e t t i n g s . p y y u r l s . p y ?El archivo s e t t i n g s . p y autogeneradocontieneunaconfiguracinROOT_URLCONFquepor defectoapuntaaunarchivo u r l s . p y tambienautogenerado.Abre s e t t i n g s . p y ymiraporti mismomasomenosdebeversedelasiguientemanera: R O O T _ U R L C O N F = m y s i t e . u r l s Estocorrespondealarchivo m y s i t e / u r l s . p y . CuandounapeticionentraporalgunaURLenparticularporejemplo,unapeticinpara / h e l l o / djangocargaelURLconfqueespecifalaconfiguracin R O O T _ U R L C O N F .Despus checacadaURLpatternenelURLconf,enorden,comparandolaURLconlospatronesuno poruno,hastaqueencuentreunoquecoincida.Cuandoencuentraunoquecoincide,llamaa
lafuncinasociadaaesepatrn,pasandounobjeto H t t p R e q u e s t comoprimerparmetro. (Nosotrosvamosacubrirmasespecificamente H t t p R e q u e s t msadelante). Comovimosennuestroprimerejemplo,unafuncinvistadebederegresarun H t t p R e s p o n s e .Unavezquelavistaregresaelobjeto H t t p R e s p o n s e ,djangoseencargadel resto,convierteelobjetoaunarespuestaHTTPapropiada,concabecerasyelcuerpo.En resumen: 1. Unapeticinentrapor / h e l l o / . 2. DjangodeterminaqueURLconfusarenbasealaconfiguracin R O O T _ U R L C O N F . 3. DjangopasaportodoslosURLpatternsenelURLconfybuscaelprimeroquecoincida con / h e l l o / . 4. Siencuentraunacoincidencia,entoncesllamadalafuncinvistaasociada. 5. Lafuncinvistaregresaun H t t p R e s p o n s e . 6. Djangoconvierteeseobjeto H t t p R e s p o n s e aunaapropiadarespuestaHTTP,lacual resultaenunapaginaweb. AhorasabeslobsicodecomofuncionalaspaginashechasconDjango.Esbastantesimple, realmentesoloescribesfuncionesvistaylasasociasaURLsviaURLconfs.
Tusegundavista:Contenidodinmico
NuestravistaHolamundofueinstructivaendemostrarlobsicodecomofunciona Django,peronofueunejemplodeunapaginawebdinmicaporqueelcontenidodela paginaessiempreelmismo.Cadavezquevisitas/hello/,vasaverlomismoescomosi fueraunarchivoestaticoHTML. Paranuestrasegundavista,vamosacrearalgomasdinmico,unapaginawebque muestrelafechayhoraactual.Estovaaserunagradableysimplepaso,porqueno envuelveningunabasededatosodatosdeentradadelusuariosolodespliegalafechay horadelservidor.EstansolounpocomasemocionantequeelHelloworld,perovaa demostrarmasconceptosquenuestroejemplopasado. Estavistanecesita2cosas:Calcularlafechayhoraactualyregresarun H t t p R e s p o n s e conteniendoesevalor.Sihastenidoexperienciaconpython,probablementesabesque pythonincluyeelmodulo d a t e t i m e paracalcularfechas.Aquestacomolovamosausar: > > > i m p o r t d a t e t i m e > > > n o w = d a t e t i m e . d a t e t i m e . n o w ( ) > > > n o w d a t e t i m e . d a t e t i m e ( 2 0 0 8 , 1 2 , 1 3 , 1 4 , 9 , 3 9 , 2 7 3 1 ) > > > p r i n t n o w 2 0 0 8 1 2 1 3 1 4 : 0 9 : 3 9 . 0 0 2 7 3 1 EstoeslosuficientementesimpleynotienenadaqueverconDjango.Essolocdigoescrito enpython.(Nosotrosqueremoshacernfasisqueessolocdigopythonvs.cdigoquees
f r o m d j a n g o . h t t p i m p o r t H t t p R e s p o n s e i m p o r t d a t e t i m e d e f c u r r e n t _ d a t e t i m e ( r e q u e s t ) : n o w = d a t e t i m e . d a t e t i m e . n o w ( ) h t m l = " < h t m l > < b o d y > I t i s n o w % s . < / b o d y > < / h t m l > " % n o w r e t u r n H t t p R e s p o n s e ( h t m l ) Aligualcomonuestravista h e l l o ,estafuncindebederesidiren v i e w s . p y .Notaquehemos escondidolavista h e l l o enesteejemploporcuestionesdebrevedad,peroasescomose verianuestro v i e w s . p y hastaahora:
f r o m d j a n g o . h t t p i m p o r t H t t p R e s p o n s e i m p o r t d a t e t i m e d e f h e l l o ( r e q u e s t ) : r e t u r n H t t p R e s p o n s e ( " H e l l o w o r l d " ) d e f c u r r e n t _ d a t e t i m e ( r e q u e s t ) : n o w = d a t e t i m e . d a t e t i m e . n o w ( ) h t m l = " < h t m l > < b o d y > I t i s n o w % s . < / b o d y > < / h t m l > " % n o w r e t u r n H t t p R e s p o n s e ( h t m l ) (Deaquenadelante,novamosamostrarcdigodeejemplosanteriores,exceptocuando seanecesario.Asquedeberasdesercapazdedistinguirelnuevocdigovs.elviejo cdigoapartirdelcontextodelalectura.) Ahoravamosaverpasoporpasoloscambiosquehemoshechocon v i e w s . p y paraponerla vista c u r r e n t _ d a t e t i m e . Hemosaadido i m p o r t d a t e t i m e alprincipiodelmduloparapodercalcularfechas. Lanuevafuncin c u r r e n t _ d a t e t i m e calculalafechayhoraactual,comounobjeto d a t e t i m e . d a t e t i m e yloguardaenunavariablelocalllamada n o w . Lasegundalneadecdigodenuestravista,construyelarespuestaHTMLusando formatstringdepython(oformateodecadenasdepython).El % s enelstring representaunplaceholder(oparmetrodesustitucin)yelsimbolode % despus delstringsignificaReemplazael % s conelvalordelavariable n o w .Lavariable n o w
estcnicamenteunobjeto d a t a t i m e ,nounstring,peroelformato % s loconviertea unstring,cuyarepresentacinesalgocomo 2 0 0 8 1 2 1 3 1 4 : 0 9 : 3 9 . 0 0 2 7 3 1 .Entonces esteseraelresultadoennuestrostringquecontieneHTML < h t m l > < b o d y > I t i s n o w 2 0 0 8 1 2 1 3 1 4 : 0 9 : 3 9 . 0 0 2 7 3 1 . < / b o d y > < / h t m l > . (Si,nuestroHTMLesinvlido,peroestamostratandodemantenerelejemplosimple ycorto). Finalmente,lavistaregresaunobjeto H t t p R e s p o n s e quecontienelarespuesta generadatalcomolohicimosenlavistahello.
f r o m d j a n g o . c o n f . u r l s . d e f a u l t s i m p o r t * f r o m m y s i t e . v i e w s i m p o r t h e l l o , c u r r e n t _ d a t e t i m e u r l p a t t e r n s = p a t t e r n s ( ' ' , ( ' ^ h e l l o / $ ' , h e l l o ) , ( ' ^ t i m e / $ ' , c u r r e n t _ d a t e t i m e ) , ) Nosotroshicimos2cambiosaqu.Primeroimportamoslafuncin c u r r e n t _ d a t e t i m e alinicio delmodulo.Segundo,ymsimportante,aadimosunURLpatternquemapealaURL / t i m e / anuestranuevavista.Teempiezasaacostumbraraesto? ConlavistaescritayelURLconfactualizado,encendemosel r u n s e r v e r yvisitamos http://127.0.0.1:8000/time/entunavegadorfavoritoyentoncesdeberasdeponderverla fechayhoraactual.
Lazonahorariadedjango
Dependiendodetucomputadora,lafechaylahorapuedenestarunashorasdesfasadas. Estoesporquedjangoesconsientedelazonahorariaypordefectolazonahorariaes America/Chicago.(Bueno,tenaqueteneralgunaunazonahorariapordefectoyesazona horariaesdonderesidenlosdesarrolladoresoriginales).Situvivesenalgunaotraparte, probablementevasaquerercambiarlaylopuedeshacerdesdeelarchivo s e t t i n g s . p y .
URLconfsyLooseCoupling
AhoraesunbuenmomentopararemarcarunafilosofaclavedetrsdelURLconfsyde djangoengeneral:Elprincipiode loosecoupling(oasociacindifusa).Paraponerlosimple, loosecouplingesunenfoquededesarrollodesoftwarequeaprecialaimportanciadehacer piezasintercambiablesdesoftware.Sidospiezasdesoftwaresonlooselycoupled(o
u r l p a t t e r n s = p a t t e r n s ( ' ' , ( ' ^ h e l l o / $ ' , h e l l o ) , ( ' ^ t i m e / $ ' , c u r r e n t _ d a t e t i m e ) , ( ' ^ a n o t h e r t i m e p a g e / $ ' , c u r r e n t _ d a t e t i m e ) , ) URLconfsyvistasestndifusamenteasociadosyvamosacontinuarhaciendonfasisala importanciadeestafilosofaatravsdeestelibro.
Tuterceravista:URLsdinmicas
Ennuestravista c u r r e n t _ d a t e t i m e ,elcontenidodelapaginalafechayhoraactuales dinamica,perolaURL(/ t i m e / )fueestatica.Enlamayoradelasaplicacionesweb dinamicas,unaURLcontieneparametrosqueafectanlasalidadelapgina.Porejemplo, unatiendadelibrosonlinetalvezledeacadalibrosupropiaURL,como / b o o k s / 2 4 3 / y / b o o k s / 8 1 1 9 6 / . Vamosacrearunaterceravistaquedespliegelafechayhoraactualdesplazadoporun ciertonmerodehoras.Elobjetivoeshacerunsitiodetalmaneraquelapgina / t i m e / p l u s / 1 / despliegelafechayhoraunahoraenelfuturo,lapgina / t i m e / p l u s / 2 / despliegelafechayhora2horasenelfuturo,lapgina / t i m e / p l u s / 3 / despliegelafechay hora3horasenelfuturoyassucesivamente. Unnovatotalvezpensaraencodificarunavistaseparadaparacadadesplazamiento,la cualtalvezresulteenunURLconfcomoeste:
u r l p a t t e r n s = p a t t e r n s ( ' ' , ( ' ^ t i m e / $ ' , c u r r e n t _ d a t e t i m e ) , ( ' ^ t i m e / p l u s / 1 / $ ' , o n e _ h o u r _ a h e a d ) , ( ' ^ t i m e / p l u s / 2 / $ ' , t w o _ h o u r s _ a h e a d ) , ( ' ^ t i m e / p l u s / 3 / $ ' , t h r e e _ h o u r s _ a h e a d ) , ( ' ^ t i m e / p l u s / 4 / $ ' , f o u r _ h o u r s _ a h e a d ) , ) Claramente,estetipodepensamientoesdefectuoso.Nosolamenteresultaenunaserade funcionesredundantes,sinoqueademslaaplicacinestafundamentalmentelimitadaa soportarsolounrangopredefinidodehorasuno,dos,tresocuatrohoras.Sinosotros decidimoscrearunapaginaquedespliegueeltiempo cincohorasenelfuturo,tendramos quecrearunavistaseparadayagregaranuestroURLconfelURLpatternecesario,adems deladuplicacin.Entoncesnecesitamoshacerunpocodeabstraccinaqu.
UnpocoacercadeprettyURLs
Situhasexperimentadoenotraplataformadedesarrolloweb,talcomoPHPoJava,tal vezestespensandoHey,vamosausarunquerystring!algocomo / t i m e / p l u s ? h o u r s = 3 ,encuallashorasserandesignadasporelparmetro h o u r s enel querystringdelaURL(lapartedespuesdel ? ). Tu puedeshaceresocondjango(ytelovamosenelcapitulo7),perounadelas filosofiasqueformanelnucleodedjangoesquelaURLdebedeserhermosa.LaURL / t i m e / p l u s / 4 / ismuchomaslimpia,simple,legible,fcildepasarselaaalguienymas bonitaqueunquerystring.PrettyURLs(oURLsbonitasoamigables)sonuna caractersticadelacalidaddeunaaplicacinWeb. ElsistemadeURLconfdedjangofomentaelusodeprettyURLshaciendomsfcileluso deprettyURLsquenohacerlo. Entonces,Comodiseamosnuestraaplicacinparaquemanejedesplazamientos arbitrarios?Laclaveesusaruna wildcard(ocomodn)enelURLpatterns.Como mencionamosanteriormente,unURLpatternesunaexpresinregularyporlotanto, podemosusarelpatrn \ d + paracoincidirunoomasdgitos:
Nota
Cuandoconstruimosaplicacionesweb,siempreesimportanteconsiderarhastalamsdescabellada entradaposible,ydecidirsinuestraaplicacindeberasoportaresaentradaono.Nosotrosdecidimos limitareldesplazamientoa99horasyevitarnosposiblesentradasdescabelladas.
Undetalleimportantequetenemosqueintroduciraqueselcarcterrantesdeliniciodel stringquecontienelaexpresinregular.Estolediceapythonqueelstringesunraw string(ocadenacruda)cuyocontenidonodebedeinterpretarlosbackslashes(o diagonalesinversas \ ).Enlosstringnormales,losbackslashessonusadospararepresentar caracteresespecialestalcomoenelstring \ n ,elcualesunstringdeunsolocarcter quecontieneunanuevalinea.Cuandoaadesuna r antesdeunacadenaloquehaceses convertiresacadenaunrawstring(ocadenacruda),yentoncespythonnoaplicael escapadodecaracteresespeciales.entonces, r \ n esahoraunstringde2caracteres quecontieneunliteralmenteunbackslash(\ )yuna n .Existeunacolisinnaturalentreel usodebackslashesenlosstringnormalesdepythonylosbackslashesquenecesitalas expresionesregulares,poresorecomendamosfuertementeelusoderawstrings (cadenascrudas)cuandoestasescribiendoalgunaexpresinregular.Desdeahora,todoslos URLpatternssernrawstrings. Ahoraquehemosdesignadounawildcard(comodn)paralaURL,necesitamosunamanera depasarlosdatosquecaptureesawildcardanuestravista,paraquepodamosusaruna solavistaparaunnumeroarbitrariodehorasdesplazadas.Nosotroshacemosestoponiendo parentesisalrededordelpatrnquequeremoscapturarenelURLpattern.Enelcasode nuestroejemplo,nosotrosqueremossalvarcualquiernumeroquefueintroducidoenlaURL, entoncesvamosaponerparentesisalrededordeel \ d { 1 , 2 } ,delasiguientemanera:
Ordendecodificacin
Enesteejemplo,nosotrosescribimosprimeroelURLpatternydespueslavista,peroen losejemplosprevios,nosotrosescribimosprimerolavistaydespuselURLpattern.Cual tcnicaesmejor? Bueno,cadadesarrolladoresdiferente. Siereseltipodepersonaquevetododemaneramuygeneral,talveztengamssentido paratiescribirtodaslasURLpatternsentuaplicacinalmismotiempo,aliniciodetu proyectoyluegocodificarlasvistas.Estotienelaventajadedarteunalistadetareasque debesdehaceryesencialmentedefineslosparmetrosrequeridosporlasvistasquevas anecesitarescribir. Siporlocontrarioeresmsdeltipodeprogramadorquelegustaempezardeabajohacia arriba,talvezprefierasescribirtusvistasprimeroydespusanclarlasaunaURL.Esto tambinestabien. Alfinal,usaslatcnicaalaquemejorseadaptetucerebro.Ambosenfoquesson perfectamentevlidos. h o u r s _ a h e a d ismuysimilaralavista c u r r e n t _ d a t e t i m e queescribimosantes,conuna diferenciaclave:tomaunargumentoextra,elnumerodehorasadesplazar.Aquesta comoseveraelcdigo: f r o m d j a n g o . h t t p i m p o r t H t t p 4 0 4 , H t t p R e s p o n s e i m p o r t d a t e t i m e d e f h o u r s _ a h e a d ( r e q u e s t , o f f s e t ) : t r y : o f f s e t = i n t ( o f f s e t ) e x c e p t V a l u e E r r o r : r a i s e H t t p 4 0 4 ( ) d t = d a t e t i m e . d a t e t i m e . n o w ( ) + d a t e t i m e . t i m e d e l t a ( h o u r s = o f f s e t ) h t m l = " < h t m l > < b o d y > I n % s h o u r ( s ) , i t w i l l b e % s . < / b o d y > < / h t m l > " % ( o f f s e t , d t ) r e t u r n H t t p R e s p o n s e ( h t m l )
Vamosaexplorarestecdigolneaporlnea: Lavista, h o u r s _ a h e a d ,toma dosparmetros: r e q u e s t y o f f s e t ,quesonlapeticiny eldesplazamientorespectivamente. r e q u e s t esunobjeto H t t p R e q u e s t ,justocomoenlasvistas h e l l o y c u r r e n t _ d a t e t i m e .Lovamosadecirotravez:Cadavista siempretomaun objeto H t t p R e q u e s t comosuprimerparmetro. offseteselstringcapturadoporlosparentesisenelURLpattern.Porejemplo, silaURLfuera / t i m e / p l u s / 3 / ,entonceseloffset(desplazamiento)serala cadena 3 .SilaURLfuera / t i m e / p l u s / 2 1 / ,entoncesel o f f s e t seralacadena 2 1 .Notaquelosvalorescapturadossiempreson stringsynoenteros, inclusosielstringestacompuestodepurosdigitos,como 2 1 . (Tecnicamente,losvalorescapturadossiempresern objetosUnicode,no planasysimplesbytestrings,peronotepreocupessobreesto,essolouna aclaracinporelmomento.) Nosotrosdecidimosanuestravariable o f f s e t ,perotupuedesnombrarla comotuquieras,clarosiempreycuandoseaunidentificadorvlidoen python.Elnombredelavariablenoimportatodoloqueimportaesel segundoargumento,despusde r e q u e s t .(Tambinesposibleusarun keyword(palabraclaveoargumentoopcional),envezdeunargumento posicionalenelURLconf.VamosacubrirestoenVistasyURLconfs avanzados) Laprimeracosaquehacemosenlavistaesllamaralafuncin i n t ( ) con o f f s e t comoparmetro.Estotrataconvertirelstringaunentero. Notaquepythonvaalanzarunaexcepcin V a l u e E r r o r sillamasa i n t ( ) conun parmetroquenopuedeserconvertidoaunentero,comoporejemploelstringfoo. Enesteejemplosiencontramosunaexcepcindetipo V a l u e E r r o r ,nosotroslanzamos unaexcepcin d j a n g o . h t t p . H t t p 4 0 4 ,lacual,comotepuedesimaginar,resultaenuna pginadeerror404Pagenotfound. Lectoresastutossepreguntaran:Comopodramosalcanzarelcasodonde V a l u e E r r o r eslanzado,sidecualquiermodo,dadalaexpresinregularennuestro URLpattern ( \ d { 1 , 2 } ) capturasolamentedigitos,yporlotanto o f f s e t solovaa serunstringcompuestodedigitos?Larespuestaes,novamosahacerlo,porqueel URLpatternproveeunamodestoperoutilniveldevalidacin, peroaunasseguimos checandoporelerror V a l u e E r r o r encasoqueestavistallegeaserllamadade algunaotramanera.Ademsesunabuenapracticaimplementarvistasdetal maneraquenotenganquehacerningunasuposicindelosparametrosquevana recibir.Loosecoupling(asociacindifusa),recuerdas? Enlasiguientelneadevista,nosotroscalculamoslafechayhoraactualyaadimos elnmeroapropiadodehoras.Comoyahemosvisto d a t a t i m e . d a t e t i m e . n o w ( ) dela vista c u r r e n t _ d a t e t i m e elnuevoconceptoaquesquepuedesejecutararitmticade fecha/horacreandounobjeto d a t e t i m e . t i m e d e l t a ysumandoloconunobjeto d a t e t i m e . d a t e t i m e .Nuestroresultadoesalmacenadoenlavariable d t . Estalneatmbienmuestraporquellamamosa i n t ( ) con o f f s e t lafuncin d a t e t i m e . t i m e d e l t a requierequeelparmetro h o u r s seaunentero. Luego,construimoselHTMLquedesplegaraestavista,talcomohicimosenlavista
ConesavistayURLconfescrita,iniciamoselservidordedesarrollodedjango(amenosque yaestecorriendo),yvisitamos h t t p : / / 1 2 7 . 0 . 0 . 1 : 8 0 0 0 / t i m e / p l u s / 3 / paraverificarque funcione.Luegoprobamos h t t p : / / 1 2 7 . 0 . 0 . 1 : 8 0 0 0 / t i m e / p l u s / 5 / .Despues h t t p : / / 1 2 7 . 0 . 0 . 1 : 8 0 0 0 / t i m e / p l u s / 2 4 / .Finalmente,visitamos h t t p : / / 1 2 7 . 0 . 0 . 1 : 8 0 0 0 / t i m e / p l u s / 1 0 0 / paraverificarqueelpatronentuURLconfsoloacepte numerosdeunoodosdigitosDjangodeberadesplegarelerrorPagenotfound(pagina noencontrada)enestecaso,justocomolovimosenlaseccinUnanotarpidaacercade laserrores404.LaURL h t t p : / / 1 2 7 . 0 . 0 . 1 : 8 0 0 0 / t i m e / p l u s / (sinningunahoradesignada) tambiendeberadearrojarunerror404.
Laspaginasdeerroresamigablesdedjango
Tomaunmomentoparaadmirarlafinaaplicacinquehemoshechohastaelmomento ahoravamosaromperla!Vamosaintroducirdeliberadamenteerroresennuestroarchivo v i e w s . p y ,comentandolaslineasde o f f s e t = i n t ( o f f s e t ) enlavista h o u r s _ a h e a d : d e f h o u r s _ a h e a d ( r e q u e s t , o f f s e t ) : # t r y : # o f f s e t = i n t ( o f f s e t ) # e x c e p t V a l u e E r r o r : # r a i s e H t t p 4 0 4 ( ) d t = d a t e t i m e . d a t e t i m e . n o w ( ) + d a t e t i m e . t i m e d e l t a ( h o u r s = o f f s e t ) h t m l = " < h t m l > < b o d y > I n % s h o u r ( s ) , i t w i l l b e % s . < / b o d y > < / h t m l > " % ( o f f s e t , d t ) r e t u r n H t t p R e s p o n s e ( h t m l ) Cargaelservidordedesarolloyentraa / t i m e / p l u s / 3 / .Vasaverunapginadeerrorcon unasustancialcantidaddeinformacin,incluyendounmensajedeerror T y p e E r r o r desplegadoalmeroinicio: " u n s u p p o r t e d t y p e f o r t i m e d e l t a h o y r s c o m p o n e n t : u n i c o d e " Qupaso?Bueno,lafuncin d a t e t i m e . t i m e d e l t a esperaqueelparmetros h o u r s seaun entero,ynosotroscomentamosunpocodecdigoqueconvertia o f f s e t enunentero.Eso causoque d a t e t i m e . t i m e d e l t a lanzarael T y p e E r r o r .Eseltpicoerrorqueleocurrea cualquierprogramadorenalgnpunto. ElpuntodeesteejemplofuedemostrarlaspaginasdeerrordeDjango.Tomatetiempopara explorarlapaginadeerroryconocerunpocolavariadainformacinqueofrece. Aquhayunpardecosasquenotar: Alprincipiodelapgina,vasaverinformacinclaveacercadelaexcepcin:eltipo delaexcepcin,losparametrosdelaexcepcin(enestecasoelmensaje " u n s u p p o r t e d t y p e " ),elarchivoenelquefuelanzadalaexcepcinyelnmerode linea. Debajodelainformacinclavedelaexcepcin,lapginamuestratodoel
"traceback"(eltracebackeselrastrodeorigendelaexcepcin).Estoessimilaral estandartracebackdelaconsolainteractivadepython,exceptoqueestaesmas interactiva.Paracadanivel("frame")enlapila,djangodespliegaelnombredel archivo,elnombredelafuncinometodo,elnmerodelineayelcdigofuentede esalnea. Daclickenlalnea"sourcecode"(engrisoscuro)yvasavervariaslineasdesde antesydespusdelalneaerronea,paradarteuncontexto. Daclicken"Localvars"debajodecualquierframeparaverunatabladetodaslas variableslocalesysusvalores,eneseframeenelmomentojustodondela excepcinfuelanzada.Estainformacindedepuracinpuedeserdegranayuda. Notaellink"Switchtocopyandpasteview"(cambiaalavistaparacopiarypegar), debajodelacabeceraconeltexto"Traceback".Daclickeneselinkyeltraceback vaacambiaraunaversinalternativaquepuedesercopiadaypegadafcilmente. Usaestocuandoquierascompartireltracebackdelaexcepcinconotraspersonas paraobtenersoportetcnicocomoenelcanalIRCdedjangooenlalistade correosdedjango. Siguiente,laseccin"RequestInformation"(informacindelapeticin)incluye informacinacercapeticinwebqueingresa:GET,POST,COOKIE,metainformacin, talescomocabecerasCGIyFILES.ElapendiceGtieneunacompletareferenciade todalainformacinquecontieneunobjetoRequest. Debajodelaseccin"Requestinformation",laseccinde"Settings"(ajustes)lista todoslosajustesdeestaparticularinstalacindedjango.(Nosotrosyamencionamos ROOT_URLCONF,yvamosamostrartevariosajustesdedjangoalolargodellibro. TodoslosajustessoncubiertosendetalleenelapndiceD.) Lapginadeerrordedjangoescapazdedesplegarmasinformacinenciertoscasos especiales,talcomoelcasodeerrordesintaxis.Vamosaveresomasadelante,cuando hablemossobreelsistemade"templates"(plantillas)dedjango. Porahora,descomentalaslineasde o f f s e t = i n t ( o f f s e t ) paraquelavistafuncione apropiadamenteotravez.Ereseltipodeprogramadorquelegustadepurarconlaayuda desentencias p r i n t cuidadosamentecolocadas?Siesas,puedesusarlapaginadeerrorde djangoparahacereso.soloquesinlassentencias p r i n t .Encualquierpuntodetuvista, temporalmenteinserta a s s e r t F a l s e paralanzarunapginadeerror.Entonces,puedesver lasvariableslocalesyestadodelprograma.Aquhayunejemplo,usandolavista h o u r s _ a h e a d :
d e f h o u r s _ a h e a d ( r e q u e s t , o f f s e t ) : t r y : o f f s e t = i n t ( o f f s e t ) e x c e p t V a l u e E r r o r : r a i s e H t t p 4 0 4 ( ) d t = d a t e t i m e . d a t e t i m e . n o w ( ) + d a t e t i m e . t i m e d e l t a ( h o u r s = o f f s e t ) a s s e r t F a l s e h t m l = " < h t m l > < b o d y > I n % s h o u r ( s ) , i t w i l l b e % s . < / b o d y > < / h t m l > " % ( o f f s e t , d t ) r e t u r n H t t p R e s p o n s e ( h t m l )
Plantillas(capitulo4,zerokillex)
Enelcaptuloanterior,pudohabernotadoalgoespecialencmosedevolvieltextoen nuestroejemplodelavista.Esdecir,elHTMLfueincrustradodirectamenteenelcdigo pythoncomosigue: d e f c u r r e n t _ d a t e t i m e ( r e q u e s t ) : n o w = d a t e t i m e . d a t e t i m e . n o w ( ) h t m l = " < h t m l > < b o d y > I t i s n o w % s . < / b o d y > < / h t m l > " % n o w r e t u r n H t t p R e s p o n s e ( h t m l ) Aunquestatcnicafueconvenienteparaelpropsitodelaexplicacinencomolasvistas trabajan,noesunabuenaideaincrustrarHTMLdirectamenteennuestrasvistas.Heaqu porqu: Cualquiercambioeneldiseodelapginarequiereuncambioenelcdigopython. Eldiseodeunsitiowebtiendeacambiarconmsfrecuenciaqueelcdigo subyacentedepython,porloqueseraconvenientesieldiseopudieracambiarsin necesidaddemodificarelcdigopython. EscribircdigopythonydisearenHTMLsondosdiciplinadistintas,ymuchos entornosprofesionalesdedesarrollowebdividenestasresponsabilidadesentre distintaspersonas(oinclusoentredepartamentos).Losdiseadoresyautores HTML/CSSnodeberanestarobligadoseditarelcdigopythonparallevaracabosu trabajo. Esmseficientesilosprogramadorespuedentrabajarelcdigopythonylos diseadorestrabajarconlaplantillaalmismotiempo,enlugardeunapersona esperarqueotrotermineeditarunsoloarchivoquecontienepythonyHTML.
Porestasrazones,esmuchomslimpioymantenibleseparareldiseodepginasdelcdigopython. EstolopodemoslograrconelsistemadeplantillasdeDjango,elcualdiscutiremosenestecaptulo.
Fundamentosdelsistemadeplantillas
UnaplantillaDjangoesunacadenadetextodestinadoasepararlapresentacindeldocumentodesus datos.Unaplantilladefinelosmarcadoresdeposicinyvariosfragmentosdelalgicabsica(etiquetas deplantillas)queregulancomoeldocumentodebesermostrado.Usualmente,lasplantillasson utilizadasparaproducirHTML,perolasplantillasDjangosonigualmentecapacesdegenerarcualquier
< h t m l > < h e a d > < t i t l e > O r d e r i n g n o t i c e < / t i t l e > < / h e a d > < b o d y > < h 1 > O r d e r i n g n o t i c e < / h 1 > < p > D e a r { { p e r s o n _ n a m e } } , < / p > < p > T h a n k s f o r p l a c i n g a n o r d e r f r o m { { c o m p a n y } } . I t ' s s c h e d u l e d t o s h i p o n { { s h i p _ d a t e | d a t e : " F j , Y " } } . < / p > < p > H e r e a r e t h e i t e m s y o u ' v e o r d e r e d : < / p > < u l > { % f o r i t e m i n i t e m _ l i s t % } < l i > { { i t e m } } < / l i > { % e n d f o r % } < / u l > { % i f o r d e r e d _ w a r r a n t y % } < p > Y o u r w a r r a n t y i n f o r m a t i o n w i l l b e i n c l u d e d i n t h e p a c k a g i n g . < / p > { % e l s e % } < p > Y o u d i d n ' t o r d e r a w a r r a n t y , s o y o u ' r e o n y o u r o w n w h e n t h e p r o d u c t s i n e v i t a b l y s t o p w o r k i n g . < / p > { % e n d i f % } < p > S i n c e r e l y , < b r / > { { c o m p a n y } } < / p > < / b o d y > < / h t m l >
EstaplantillaesunHTMLbsicoconalgunasvariablesyetiquetasvertidasenel.Analicemossuspartes: Cualquiertextorodeadoporunpardellaves(porejemplo,{ { p e r s o n _ n a m e } } )esunavariable. Estosignifica insertarelvalordelavariableconelnombredado .(Cmoindicamoslosvalores delasvariables?Msadelantehablaremosdeello.) Cualquiertextoqueestarodeadodeunallaveyelsignodeporcentaje(porejemplo,{ % i f o r d e r e d _ w a r r a n t y % } )esunaetiquetadeplantilla.Ladefiniciondeunaetiquetaesbastante amplio:unaetiquetaledicealsistemadeplantillahazalgo. Estaplantilladeejemplocontieneunaetiquetaf o r ({ % f o r i t e m i n i t e m _ l i s t % } )yuna etiquetaif({ % i f o r d e r e d _ w a r r a n t y % } ). Unaetiquetaforfuncionamuysimilaraladeclaracinforenpython,permitiendoiterarsobre cadaelementodeunasecuencia.Unaetiquetaif,comosepuedeesperar,actacomouna declaracinlgica.Enestecasoparticular,laetiquetacompruebasielvalordelavariable
o r d e r e d _ w a r r a n t y evalaaT r u e .Silohace,elsistemadeplantillamostrartodoentre{ % i f o r d e r e d _ w a r r a n t y % } y{ % e l s e % } .Sino,elsistemadeplantillamostrartodoentre{ % e l s e % } y{ % e n d i f % } .Tengaencuentaque{ % e l s e % } esopcional. Finalmente,elsegundoprrafodeestaplantillacontieneunejemplodeunfiltro,queesla formamsconvenientedemodificarelformatodeunavariable.Enesteejemplo,{ { s h i p _ d a t e | d a t e : F j , Y } } ,estamospasandolavariables h i p _ d a t e alfiltrodate,indicando alfiltrodateelargumentoFj,Y.Elfiltrodateformatealasfechasenunformatodado,segn loespecificadoenelargumento.Losfiltrosestanenlazadoutilizandoelcarcterdebarravertical (|),comoreferenciaalastuberas(pipe)enUnix. CadaplantillaDjangotieneaccesoavariasetiquetasyfiltrosincorporadas,deloscualesmuchosse discutenenlasprximassecciones.ElApndiceFcontieneunalistacompletadeetiquetasyfiltros,yes recomendablefamiliarizarseconlalistaparaqueconozcaloqueesposible.Tambinesposiblecrearsus propiosfiltrosyetiquetasmsdetallesenelcaptuloPlantillasavanzadas.
Utilizandoelsistemadeplantilla
EntremosenelsistemadeplantillasdeDjangoparaquepuedasvercmofuncionaperotodavano vamosaintegrarloenlavistaquecreamosenelcaptuloanterior.Nuestroobjetivoaquesmostrar cmoelsistemafunciona,independientementedelrestodeDjango.(Dichodeotromodo: habitualmenteutilizarselsistemadeplantilladentrodeunavistadeDjango,peroqueremosdejarclaro queelsistemadeplantillaesslounalibreradepythonquesepuedeutilizarencualquierlugar,noslo enlasvistasdeDjango.) EstaeslaformamsbsicaquepuedesutilizarelsistemadeplantilladeDjangoenelcdigopython: 1. CrearunobjetoT e m p l a t e proporcionandoelcdigopurodelaplantillacomounacadenade texto. 2. Invocarelmtodor e n d e r ( ) delobjetoT e m p l a t e conunconjuntodevariables(elcontexto). Estodevuelveunaplantillacompletamenterepresentadacomounacadena,contodassus variablesyetiquetasdeplantillaevaluadadeacuerdoalcontexto. Encdigo,asescomoluce:
> > > f r o m d j a n g o i m p o r t t e m p l a t e > > > t = t e m p l a t e . T e m p l a t e ( ' M y n a m e i s { { n a m e } } . ' ) > > > c = t e m p l a t e . C o n t e x t ( { ' n a m e ' : ' A d r i a n ' } ) > > > p r i n t t . r e n d e r ( c ) M y n a m e i s A d r i a n . > > > c = t e m p l a t e . C o n t e x t ( { ' n a m e ' : ' F r e d ' } ) > > > p r i n t t . r e n d e r ( c ) M y n a m e i s F r e d .
Lasiguientesseccionesdescribencadaparteconmuchomsdetalle.
CreandoobjetosTemplate
LaformamsfcildecrearunobjetoT e m p l a t e esconunainstanciadirectamentedeella.Laclase T e m p l a t e resideenelmdulod j a n g o . t e m p l a t e ,yelconstructortomaunargumento,elcdigopurode laplantilla.Veamosenelintrpreteinteractivodepythoncmoestofuncionaencdigo. Desdeeldirectoriodelproyectom y s i t e creadopord j a n g o a d m i n . p y s t a r t p r o j e c t (comoexplicenel captulo2:Iniciando),escribep y t h o n m a n a g e . p y s h e l l parainiciarelintrpreteinteractivo.
Unsmboloespecialdepython Siustedanteshautilizadopython,puedequesepregunteporquestamosutilizandop y t h o n m a n a g e . p y s h e l l enlugardeslop y t h o n .Amboscomandosinicianelintrpreteinteractivo depython,peroelcomandom a n a g e . p y s h e l l tieneunaimportantedistincin:antesde iniciarelintrprete,estelediceaDjangocularchivodeconfiguracinutilizar.Muchaspartes deDjango,incluyendoelsistemadeplantilla,sebasanentusconfiguraciones,ynosers capazdeutilizarlosamenosqueelframeworkconozcacualconfiguracinutilizar. Sitienescuriosidad,heaqucmofuncionaeneltrasfondo.Djangobuscaenelentornouna variablellamadaD J A N G O _ S E T T I N G S _ M O D U L E ,quedebeestardeclaradaalarutadeimportacin detus e t t i n g s . p y .Porejemplo,D J A N G O _ S E T T I N G S _ M O D U L E podraestarestablecidoa m y s i t e . s e t t i n g s ,asumiendoquem y s i t e estaenlarutadepython.Cuandoseejecuta pythonmanage.pyshell,elcomandoseencargadeestablecerD J A N G O _ S E T T I N G S _ M O D U L E por ti.Leanimamosaqueutilicep y t h o n m a n a g e . p y s h e l l enestosejemplosconelfinde minimizarlacantidaddeajustesyconfiguracionesquetienesquehacer. AmedidaquesefamiliariceconDjango,esposiblequedejesdeusarm a n a g e . p y s h e l l y configuresmanualmenteD J A N G O _ S E T T I N G S _ M O D U L E entuarchivo. b a s h _ p r o f i l e uotro archivodeconfiguracindelentornodelaconsola. Repasemosalgunosconceptosbsicosdelsistemadeplantilla:
> > > f r o m d j a n g o . t e m p l a t e i m p o r t T e m p l a t e > > > t = T e m p l a t e ( ' M y n a m e i s { { n a m e } } . ' ) > > > p r i n t t
Siustedestsiguiendodeformainteractiva,versalgocomoesto:
< d j a n g o . t e m p l a t e . T e m p l a t e o b j e c t a t 0 x b 7 d 5 f 2 4 c >
El0xb7d5f24cserdiferentecadavez,ynoesrelevanteespropiodepython(laidentidaddelobjeto Templateenpython,siteinteresasaberlo). CuandosecreaunobjetoTemplate,elsistemadeplantillacompilaelcdigocrudoenunointerno,de formaoptimizada,listoparareproducir.Perosielcdigodetuplantillaincluyeerroresdesintaxis,la invocacinaTemplate()levantarunaexcepcindeTemplateSyntaxError.
> > > f r o m d j a n g o . t e m p l a t e i m p o r t T e m p l a t e > > > t = T e m p l a t e ( ' { % n o t a t a g % } ' ) T r a c e b a c k ( m o s t r e c e n t c a l l l a s t ) : F i l e " < s t d i n > " , l i n e 1 , i n ? . . . d j a n g o . t e m p l a t e . T e m p l a t e S y n t a x E r r o r : I n v a l i d b l o c k t a g : ' n o t a t a g '
Eltrminoblocktagaquserefierea{%notatag%}.Blocktagytemplatetagsonsinnimos.El sistemalevantaunaexcepcinTemplateSyntaxErrorencualquieradelossiguientescasos: Etiquetasnovlidas Argumentosnovlidosparaetiquetasvlidas
Interpretandoplantillas
UnavezobtienesunobjetoTemplate,puedespasarledatosindicandouncontexto.Uncontextoes simplementeunconjuntodenombresdevariablesenlaplantillaysusvaloresasociados.Unaplantilla lasutilizaparallenarsusvariablesyevaluarsusetiquetas. UncontextoesrepresentadoenDjangoporlaclaseContext,queresideenelmdulodjango.template. Suconstructortomaunargumentoopcional:undiccionariodeclavesasociadasavalores.Ejecuteel mtodorender()delobjetoTemplateconelcontextoparallenarlaplantilla:
...theproductsinevitablystopworking.</p> ...{%endif%} ... ...<p>Sincerely,<br/>{{company}}</p>""" >>>t=Template(raw_template) >>>importdatetime >>>c=Context({'person_name':'JohnSmith', ...'company':'OutdoorEquipment', ...'ship_date':datetime.date(2009,4,2), ...'ordered_warranty':False}) >>>t.render(c) u"<p>DearJohnSmith,</p>\n\n<p>ThanksforplacinganorderfromOutdoor Equipment.It'sscheduledto\nshiponApril2,2009.</p>\n\n\n<p>You didn'torderawarranty,soyou'reonyourownwhen\ntheproducts inevitablystopworking.</p>\n\n\n<p>Sincerely,<br/>OutdoorEquipment </p>" Analicemosporpartecadaunadelasinstrucciones: Primero,importamoslaclaseTemplateyContext,queambosconvivenenelmdulo django.template. Guardamoseltextocrudodenuestraplantillaenlavariableraw_template.Tengaencuentaque usamostriplecomillasparadesignarlacadena,yaqueadmitemltipleslneasencambio,las cadenasentrecomillassimplesnoadmitemltipleslneas. Acontinuacin,creamosunobjetoTemplate,t,proporcionandoraw_templatealconstructor Template. Importamoselmdulodatetimedelalibreraestndardepython,yaquelonecesitamosenla siguientesentencia. LuegocreamoselobjetocdeContext.ElconstructorContexttomaundiccionariodepython queasocialasvariablesconvalores.Aqu,porejemplo,especificamosqueperson_namees JohnSmith,companyesOutdoorEquipment,yassucesivamente. Finalmente,invocamoselmtodorender()ennuestroobjetoTemplatepasndoleelcontexto. Estedevuelvelaplantillaanalizadaesdecir,sereemplazanlasvariablesdelaplantillaconel valoractualdelasvariables,yejecutalasetiquetasdelaplantilla. NotequeelprrafoYoudidntorderawarrantyfuemostradoporquelavariable ordered_warrantyfueevaluadocomofalso(False).Tambinnotarquelafecha,April2,2009,es mostradadeacuerdoalacadenadeformatoFj,Y.(Msadelanteexplicaremoslacadenade formatoparaelfiltrodate.) Sieresnuevoenpython,seestarpreguntandoporquestasalidaincluyeelcarctersaltode lneaonewline(\n)enlugardemostrarelsalto.Esdebidoaunasitulezaenelintrprete interactivodepython:lainvocacindet.render(c)devuelveunacadena,ypordefectoel intrpreteinteractivomuestralarepresentacin delacadena,enlugardelvalorimpresodela cadena.Sideseasverlacadenaconlossaltosdelneascomorealmentedebenenlugardelos caracteres\n,utilicelasentenciaprint:printt.render(c). EstossonlosfundamentosdelusodelsistemadeplantillasenDjango:sloescribeunaplantillaen texto,creaunobjetoTemplate,creauncontextoContext,einvocaelmtodorender().
Mltiplescontextos,lamismaplantilla
UnaveztengasunobjetoTemplate,sepuedeprocesarmltiplescontextosatravsdeeste.Por ejemplo:
Bsquedadevariableenelcontexto
Enlosejemploshastaelmomento,hemospasadosimplesvaloresenloscontextosmayormente strings,enadicinaundatetime.date.Sinembargo,elsistemadeplantillasmanejaelegantemente estructurasdedatosmscomplejos,talescomolistas,diccionarios,yobjetospersonalizados. ElpuntoclaveparanavegarsobreestructurasdedatoscomplejosenlasplantillasdeDjangoesel carcterdepunto(.).Utilizandoelpuntopuedesaccesaralasclavesdediccionarios,atributos,mtodos, olosndicesdeunobjeto. Estoseilustramejorenvariosejemplos.Porejemplo,supongamosquepasamosundiccionarioauna plantilla.Paraaccesarlosvaloresdeesediccionarioporsuclave,utilizamoselpunto:
>>>fromdjango.templateimportTemplate,Context >>>importdatetime >>>d=datetime.date(1993,5,2) >>>d.year 1993 >>>d.month 5 >>>d.day 2 >>>t=Template('Themonthis{{date.month}}andtheyearis{{ date.year}}.') >>>c=Context({'date':d}) >>>t.render(c) u'Themonthis5andtheyearis1993.'
Esteotroejemploutilizaunaclasepersonalizada,demostrandoqueconelpuntotepermiteaccedera objetosarbitrarios:
>>>t.render(Context({'var':'123'})) u'123123True'
Notequenoseincluyelosparntesisenlainvocacindelosmtodos.Adems,noesposiblepasar argumentosalosmtodossolopuedesinvocarmtodosquenorequierenargumentos.(Luego explicarmosestafilosofaenestecaptulo.) Finalmente,lospuntostambinseutilizanparaaccesarlosndicesdelaslistas,porejemplo:
Silaexcepcintieneelatributosilent_variable_failure,lavariableenlaplantillaseproyecta comounstringvaco,porejemplo:
>>>t=Template("Mynameis{{person.first_name}}.") >>>classPersonClass3: ...deffirst_name(self): ...raiseAssertionError,"foo" >>>p=PersonClass3() >>>t.render(Context({"person":p})) Traceback(mostrecentcalllast): ... AssertionError:foo >>>classSilentAssertionError(AssertionError): ...silent_variable_failure=True >>>classPersonClass4: ...deffirst_name(self): ...raiseSilentAssertionError >>>p=PersonClass4() >>>t.render(Context({"person":p})) u'Mynameis.'
Lainvocacinaunmtodoslofuncionarsielmtodonorequiereargumentos.Delo contrario,elsistemapasaralsiguientetipodebsqueda(ndicesdelistas). Obviamente,algunosmtodostienenefectossecundarios,yseralomstonto,yposiblemente inclusounfallodeseguridad,permitiralsistemadeplantillasaccederaellos. Digamos,porejemplo,tienesunobjetoBankAccountquetieneunmtododelete().Siuna plantillaincluyealgocomo{{account.delete}},dondeaccountesunobjetoBankAccount,el objetoseraeliminadocuandolaplantillaseanaliza. Paraevitaresto,establezcaelatributoalters_datadelafuncin.
Cmosemanejanlasvariablesnovlidas?
Pordefecto,siunavariablenoexiste,elsistemadeplantillalopresentacomounstringvacio,fallando silenciosamente.Porejemplo:
JugandoconobjetosContext
Lamayoradelasveces,instanciarslosobjetosContextpasandoundiccionariocompletoaContext(). PerotambinpuedesagregaryeliminarelementosdelobjetoContextunavezhasidoinstanciado utilizandolasintaxisestndarparadiccionarioenpython:
>>>fromdjango.templateimportContext >>>c=Context({"foo":"bar"}) >>>c['foo'] 'bar' >>>delc['foo'] >>>c['foo'] Traceback(mostrecentcalllast): ... KeyError:'foo' >>>c['newvariable']='hello' >>>c['newvariable'] 'hello'
Filtrosyetiquetasbsicasdelasplantillas
Comohemosmencionadoanteriormente,elsistemadeplantillasvieneconetiquetasyfiltros incorporados.Enlasseccionessiguientesseproporcionaunresumendelosfiltrosyetiquetasms comunes.
Etiquetas
if/else
Laetiqueta{%if%}evalaunavariable,ysidichavariableesTrue(esdecir,queexiste,noesta vaca,ynoesunbooleanFalse),laplantillamostrartodoentre{%if%}y{%endif%}.Porejemplo:
Truthinessdepython EnpythonyenelsistemadeplantillasdeDjango,lossiguientesobjetosevalanaFalseenel contextodeBoolean: Unalistavaca([]) Unatuplavaca(()) Undiccionariovaco({}) Unstringvaco('') Cero(0) ElobjetoespecialNone ElobjetoFalse(obviamente) ObjetospersonalizadosquedefinensupropiocomportamientoenelcontextoBoolean(unuso avanzadodepython) TodolodemsevalaaTrue. Laetiqueta{%if%}aceptaoperadoresand,or,onotparacomprobarmltiplesvariables,oparanegar unadeterminadavariable.Porejemplo:
{%ifathlete_listandcoach_list%} Bothathletesandcoachesareavailable. {%endif%} {%ifnotathlete_list%} Therearenoathletes. {%endif%} {%ifathlete_listorcoach_list%} Therearesomeathletesorsomecoaches. {%endif%} {%ifnotathlete_listorcoach_list%} Therearenoathletesortherearesomecoaches. {%endif%}
{%ifathlete_listandcoach_listorcheerleader_list%}
Elusodelosparntesisparacontrolarelordendelasoperacionesnoesadimisible.Sivesquenecesitas parntesis,serecomiendarealizarlaoperacindelaplantillaypasarelresultadocomounavariable dedicadaalaplantilla.Obien,simplementepuedesanidarlaetiqueta{%if%}as:
{%ifathlete_listorcoach_listorparent_listorteacher_list%}
Tampocoexistelaetiqueta{%elif%}.Puedeslograrlomismoanidandolaetiqueta{%if%}.
for
Laetiqueta{%for%}permiteiterarsobrecadaelementodeunasecuencia.Aligualquelasentencia fordepython,lasintaxisesforXinY,dondeYeslasecuenciaarecorreryXeselnombredelavariable autilizarenunpuntodeterminadodelbucle.Cadavezqueseatraviesaelciclo,elsistemadeplantilla procesartodoentre{%for%}y{%endfor%}. Porejemplo,podrasutilizarlosiguienteparamostrarunalistadeatletasdadalavariableathlete_list:
<ul>
{%forlinkinlinks%}{{link}}{%ifnotforloop.last%}|{%endif %}{%endfor%}
Elcdigodeplantillaanteriormostraraalgocomolosiguiente:
Link1|Link2|Link3|Link4
Otrousocomnesponerunacomaentreunalistadepalabras:
{%forcountryincountries%} <table>
ifequal/ifnotequal
ElsistemadeplantilladeDjango,deliberadamente,noesunlenguajedeprogramacincompletoypor tantonotepermiteejecutararbitrariamentecdigopython.(Mssobreestasideasenlaseccin Filosofasylimitaciones.)Entodocaso,esbastantecomnelrequisitodecomparardosvaloresdentro delaplantillaymostraralgosisoniguales.Djangoproporcionalaetiqueta{%ifequal%}paraeste propsito. Laetiqueta{%ifequal%}comparadosvaloresymuestratodoentre{%ifequal%}y{%endifequal %}silosvaloressoniguales.Esteejemplocomparalasvariablesuserycurrentuser:
Comentarios
JustocomoenHTMLopython,ellenguajedeplantilladeDjangopermitecomentarios.Paradesignarun comentario,utilizalaetiqueta{##}:
{#Thisisacomment#}
Elcomentarionoserimpresocuandolaplantillaseinterpreta.Loscomentariosconestasintaxisno puedenabarcarmltipleslneas.Estalimitacinmejoraelrendimientoalprocesarlaplantilla.Enla siguienteplantilla,elresultadoseverexactamenteigualcomoenlaplantilla(enotraspalabras,la etiquetadecomentarionoseprocesacomouncomentario):
Filtros
Comoseexplicaliniciodelcaptulo,losfiltrosenlaplantillasonformassimplesdealterarelvalordelas variablesantesdesermostrado.Losfiltrosutilizanelcarcterpipe(tuberaobarravertical)deesta manera:
{{name|lower}}
Elejemplomuestraelvalordelavariable{{name}}despusdeserfiltradaatravsdelfiltrolower,el cualconvierteeltextoenminscula.Losfiltrostambinpuedenserencadenadosesdecir,puedenser utilizadosenconjuntodetalmaneraqueelresultadodeunfiltroseaplicaalsiguiente.Heaquun ejemploquetomaelprimerelementodeunalistaylaconvierteamaysculas.
{{my_list|first|upper}}
Algunosfiltrospuedentomarargumentos.Unargumentodefiltrovienedespusdedospuntosy siempreencomillasdobles.Porejemplo:
{{bio|truncatewords:"30"}}
Estomuestralasprimeras30palabrasdelavariablebio.Lasiguientelistasonalgunosdelosfiltrosms importantes.ElApndiceFcubreelresto. addslashes:agregabackslashes(barrainvertida)antecualquierbackslash,comillasimple,o comilladoble.Estoestilsi,porejemplo,eltextoproducidoesparaincluirenunstringde JavaScript. date:formateaobjetosdateodatetimedeacuerdoaunformatodadoenelparmetro.Elstring deformatosedefineenelApndiceF.
{{pub_date|date:"Fj,Y"}}
length:devuelvelalongituddelvalor.Paraunalista,estedevuelveelnmerodeelementos. Paraunstring,devuelveelnmerodecaracteres.(Expertosenpython,tomannotadequeesto funcionaencualquierobjetopythonquesabecomodeterminarsulongitudesdecir,cualquier objetoquetengaelmtodo__len__.)
Filosofasylimitaciones
AhoraquetienesunaideadellenguajedeplantillaenDjango,debemossealaralgunaslimitaciones intencional,juntoconalgunasfilosofasdeporqufuncionadelaformaenquefunciona. Msquecualquierotrocomponentedeaplicacionesweb,lasintaxisdelaplantillaesaltamente subjetivo,ylasopinionesentrelosprogramadoresvaranampliamente.Elhechodequepythonporsi solotienedocenas,sinocientos,delenguajesdeplantillasopensource(cdigoabierto),apoyaneste punto.Cadaunofueprobablementecreadoporquelosdesarrolladoresconsideralossistemasde plantillasexistentescomoinadecuados.(Dehecho,sedicequeesunritoparadesarrolladoresen pythonescribirsupropiolenguajedeplantilla!Siannolohashecho,considralo.Esunejercicio divertido.) Conestoenmente,puedequeinteresesaberqueDjangonoleobligautilizarsupropiosistemade
plantillas.DebidoqueDjangointentaserunframeworkcompletoqueproporcionatodaslaspiezas necesariasparaqueeldesarrolladorwebseaproductivo,muchasvecesesmsconvenienteutilizarel sistemadeplantilladeDjangoquecualquierotralibreradeplantillasenpython,peroenningnsentido esunrequisitoestricto.Comoseverenlaprximaseccin,Utilizandoplantillasenlasvistas,esmuy fcilutilizarotrolenguajedeplantillaenDjango. Anas,esclaroquetenemosunafuertepreferenciaporlaformaenqueellenguajedeplantillasde Djangofunciona.Elsistemadeplantillatienesusfundamentosencmoserealizaeldesarrolloweben WorldOnlinemslaexperienciacombinadadeloscreadoresdeDjango.Estassonalgunasdeesas filosofas: Lalgicadelnegociodebeserseparadodelalgicadepresentacin.Losdesarrolladoresde Djangovenelsistemadeplantillacomounaherramientaquecontrolalapresentacinylalgica depresentacinrelacionadaaestayesoestodo.Elsistemadeplantillanodeberaadherir funcionalidadesquevanmsalldeesteobjetobsico. Porestarazn,esimposibleinvocarcdigopythondirectamentedentrodelasplantillasde Django.Todaprogramacinestafundamentalmentelimitadaalmbitodeloquepuede realizarlaetiquetadeplantilla.Esposibleescribiretiquetaspersonalizadasquerealicecosas arbitrarias,perolasetiquetasdefbricaenelsistemadeplantilladeDjangointencionalmente prohibelaejecuccinarbitrariadecdigopython. LasintaxisdebeserdisociadadeHTML/XML.AunqueelsistemadeplantilladeDjangoseutiliza principalmenteparaproducirHTML,estadiseadaparaqueseautilizableconformatosnoHTML, talcomotextoplano.AlgunossistemasdeplantillasestanbasadosenXML,ubicandolalgicade laplantillaentreetiquetasyatributosXML,peroDjangoevitadeliberadamenteestalimitacin. ElrequisitodegenerarXMLvlidoalescribirunaplantillaintroduceunmundodeerrores humanosque,alanalizarlosmensajesdeerror,sondedifcilcomprensin.Elusodeunmotor XMLparaparsearlasplantillasincurrenenunnivelinaceptabledesobrecargaalprocesarla plantilla. SeasumequelosdiseadoresestnfamiliarizadoconcdigoHTML.Elsistemadeplantillano estadiseadoparaquelasplantillasnecesariamentesemuestrenmuybienenloseditores WYSIWYGcomoDreamweaver.Esunalimitacinmuygraveynopermitiraquelasintaxissea tanamigablecomoes.Djangoesperaquelosautoresdeplantillassesientancmodosaleditar directamenteHTML. Seasumequelosdiseadoresnosonprogramadoresenpython.Losautoresdesistemasde plantillasreconocenquelasplantillasparalaspginaswebsonmsamenudoescritopor diseadores,noprogramadores,yporlotantonodebeasumirelconocimientoenpython. Sinembargo,elsistematambinintentaacomodaralosequipospequeosenquelasplantillas soncreadasporprogramadoresdepython.Esteofreceunaformadeextenderlasintaxisdel sistemaescribiendocdigopuroenpython.(MsdetallesenelcaptuloPlantillasavanzadas.) Elobjetivonoesinventarunlenguajedeprogramacin.Elobjetivoesofrecerslolasuficiente funcionalidadprogramtica,talescomobuclesycondicionales,quesonesencialespararealizar decisionesenlapresentacin.
Utilizandoplantillasenlasvistas
Hasaprendidolosaspectosbsicosdelusodelsistemadeplantillaahorautilicemoseseconocimientos paracrearunavista.Recordemoslavistacurrent_datetimeenmysite.views,queiniciamosenel captuloanterior.Heaquelcdigo:
fromdjango.httpimportHttpResponse
fromdjango.templateimportTemplate,Context fromdjango.httpimportHttpResponse importdatetime defcurrent_datetime(request): now=datetime.datetime.now() #Simplewayofusingtemplatesfromthefilesystem. #ThisisBADbecauseitdoesn'taccountformissingfiles! fp=open('/home/djangouser/templates/mytemplate.html') t=Template(fp.read()) fp.close() html=t.render(Context({'current_date':now})) returnHttpResponse(html)
Sinembargo,esteenfoquenoeseleganteporvariasrazones:
Cargandoplantilla
DjangoproporcionaunapotenteyconvenienteAPIparacargarplantillasdelsistemadearchivos,conel objetivodeeliminarlaredundanciatantoalcargarplantillascomoenlaplantillaensmisma.Conelfin deutilizarestaAPI,primeronecesitarsindicarleaDjangodndeestnalmacenadoslasplantillas.El lugarparahacerestoesenelarchivodeconfiguracioneselarchivosettings.pyquehemos mencionadoenelcaptuloanterior,cuandohablamossobreROOT_URLCONF.Siestassiguiendolos ejercicios,abreelarchivosettings.pyylocalizalaconfiguracinTEMPLATE_DIRS.Pordefecto,esuna tuplavaca,probablementeconalgunoscomentariosautogenerados:
TEMPLATE_DIRS=( '/home/django/mysite/templates', )
Hayalgunascosasatenerencuenta: Sepuedeindicarcualquierdirectorioquedesees,siempreycuandoeldirectorioylasplantillas enellasseanlegibleporlacuentadeusuarioenlaqueelservidorwebseejecuta.Sinopuedes pensarporunlugarapropiadoparaubicarlasplantillas,lerecomendamoscreareldirectorio templatesdentrodelproyectoesdecir,dentrodeldirectoriomysitequesecreenelcaptulo Iniciando. SiTEMPLATE_DIRScontieneunslodirectorio,noolvideslacomaalfinaldelstring!Larazn deestoesporquepythonrequiereunacomadentrodeunatupladeunsloelementopara eliminarlaambigedadconunaexpresinenparntesis.Setratadeunerrorcomnenlos novatos.
TEMPLATE_DIRS=( 'C:/www/django/templates', )
Lomssimpleesutilizarrutasabsolutasesdecir,rutasdedirectoriosquecomienzanenla razdelsistemadearchivos.Sinembargo,siquieresserunpocomsflexibleydesacoplado, puedestomarventajadelfactorqueelarchivodeconfiguracindeDjangoessimplemente cdigopythonyconstruirdinmicamenteelcontenidodeTEMPLATE_DIRS.Porejemplo:
returnHttpResponse(html)
Enesteejemplo,utilizamoslafuncindjango.template.loader.get_template()enlugarmanualmente cargarlaplantilladesdeelsistemadearchivos.Lafuncinget_template()tomaelnombredelaplantilla comoargumento,determinadndelaplantillaresideenelsistemadearchivos,abreelarchivo,y devuelveunobjetoTemplatecompilado. Enesteejemplo,nuestraplantillaescurrent_datetime.html,peronohaynadaespecialenlaextensin .html.Puedesasignarlealaplantillacualquierextensinquehagamssentidoatuaplicacin,opuedes prescindircompletamentedelaextensin. Paradeterminarlalocalizacindelaplantillaenelsistemadearchivos,get_template()combinael directoriodeplantillaenTEMPLATE_DIRSconelnombredelaplantillaindicadaenget_template().Por ejemplo,siTEMPLATE_DIRSesestablecidoa/home/django/mysite/templates,lainvocacina get_template()buscaralaplantilla/home/django/mysite/templates/current_datetime.html. Siget_template()nopuedeencontrarlaplantillaconelnombreindicado,selevantaunaexcepcin TemplateDoesNotExist.Paravercomoluce,iniciaelservidordedesarrolloenDjangoejecutandopython manage.pyrunserverdentrodeldirectoriodelproyectoDjango.Entonces,apuntaelnavegadorhaciala pginaqueactivalavistacurrent_datetime(esdecir,http://127.0.0.1:8000/time/).Asumiendoquela configuracinDEBUGestestablecidaaTrueyannosehacreadolaplantillacurrent_datetime.html, deberasobservarunapginadeerrordeDjangoresaltandoelerrorTemplateDoesNotExist.
Figura41:Pginadeerrormostradacuandolaplantillanopuedeserlocalizada.
<html><body>Itisnow{{current_date}}.</body></html>
Recargalapginaentunavegadorweb,ydeberasverlapginacompletamenteprocesada.
render_to_response()
Weveshownyouhowtoloadatemplate,fillaContextandreturnanHttpResponseobjectwiththe resultoftherenderedtemplate.Weveoptimizedittouseget_template()insteadofhardcoding templatesandtemplatepaths.Butitstillrequiresafairamountoftypingtodothosethings.Because thisissuchacommonidiom,Djangoprovidesashortcutthatletsyouloadatemplate,renderitand returnanHttpResponseallinonelineofcode. Thisshortcutisafunctioncalledrender_to_response(),whichlivesinthemoduledjango.shortcuts. Mostofthetime,youllbeusingrender_to_response()ratherthanloadingtemplatesandcreating ContextandHttpResponseobjectsmanuallyunlessyouremployerjudgesyourworkbytotallinesof codewritten,thatis. Herestheongoingcurrent_datetimeexamplerewrittentouserender_to_response():
Subdirectories in get_template()
Itcangetunwieldytostoreallofyourtemplatesinasingledirectory.Youmightliketostoretemplates insubdirectoriesofyourtemplatedirectory,andthatsfine.Infact,werecommenddoingsosome moreadvancedDjangofeatures(suchasthegenericviewssystem,whichwecoverinChapter11) expectthistemplatelayoutasadefaultconvention. Storingtemplatesinsubdirectoriesofyourtemplatedirectoryiseasy.Inyourcallstoget_template(), justincludethesubdirectorynameandaslashbeforethetemplatename,likeso:
t=get_template('dateapp/current_datetime.html')
Becauserender_to_response()isasmallwrapperaroundget_template(),youcandothesamething withthefirstargumenttorender_to_response(),likethis:
returnrender_to_response('dateapp/current_datetime.html', {'current_date':now})
Theresnolimittothedepthofyoursubdirectorytree.Feelfreetouseasmanysubdirectoriesasyou like.
{%include'nav.html'%} {%include"nav.html"%}
Thisexampleincludesthecontentsofthetemplateincludes/nav.html:
{%include'includes/nav.html'%}
Thisexampleincludesthecontentsofthetemplatewhosenameiscontainedinthevariable template_name:
{%includetemplate_name%}
Asinget_template(),thefilenameofthetemplateisdeterminedbyaddingthetemplatedirectory fromTEMPLATE_DIRStotherequestedtemplatename. Includedtemplatesareevaluatedwiththecontextofthetemplatethatsincludingthem.Forexample, considerthesetwotemplates:
#mypage.html <html> <body> {%include"includes/nav.html"%} <h1>{{title}}</h1> </body> </html> #includes/nav.html <divid="nav"> Youarein:{{current_section}} </div>
Ifyourendermypage.htmlwithacontextcontainingcurrent_section,thenthevariablewillbeavailable intheincludedtemplate,asyouwouldexpect. If,inan{%include%}tag,atemplatewiththegivennameisntfound,Djangowilldooneoftwo
Template Inheritance
OurtemplateexamplessofarhavebeentinyHTMLsnippets,butintherealworld,youllbeusing DjangostemplatesystemtocreateentireHTMLpages.ThisleadstoacommonWebdevelopment problem:acrossaWebsite,howdoesonereducetheduplicationandredundancyofcommonpage areas,suchassitewidenavigation? Aclassicwayofsolvingthisproblemistouseserversideincludes,directivesyoucanembedwithinyour HTMLpagestoincludeoneWebpageinsideanother.Indeed,Djangosupportsthatapproach,withthe {%include%}templatetagjustdescribed.ButthepreferredwayofsolvingthisproblemwithDjangois touseamoreelegantstrategycalledtemplateinheritance. Inessence,templateinheritanceletsyoubuildabaseskeletontemplatethatcontainsallthecommon partsofyoursiteanddefinesblocksthatchildtemplatescanoverride. Letsseeanexampleofthisbycreatingamorecompletetemplateforourcurrent_datetimeview,by editingthecurrent_datetime.htmlfile:
<!DOCTYPEHTMLPUBLIC"//W3C//DTDHTML4.01//EN"> <htmllang="en"> <head> <title>Thecurrenttime</title> </head> <body> <h1>Myhelpfultimestampsite</h1> <p>Itisnow{{current_date}}.</p> <hr> <p>Thanksforvisitingmysite.</p> </body> </html>
Thatlooksjustfine,butwhathappenswhenwewanttocreateatemplateforanotherviewsay,the hours_aheadviewfromChapter3?Ifwewantagaintomakeanice,valid,fullHTMLtemplate,wed createsomethinglike:
<!DOCTYPEHTMLPUBLIC"//W3C//DTDHTML4.01//EN"> <htmllang="en"> <head> <title>{%blocktitle%}{%endblock%}</title> </head> <body> <h1>Myhelpfultimestampsite</h1> {%blockcontent%}{%endblock%} {%blockfooter%} <hr> <p>Thanksforvisitingmysite.</p> {%endblock%}
</body> </html>
Thistemplate,whichwellcallbase.html,definesasimpleHTMLskeletondocumentthatwelluseforall thepagesonthesite.Itsthejobofchildtemplatestooverride,oraddto,orleavealonethecontentsof theblocks.(Ifyourefollowingalong,savethisfiletoyourtemplatedirectoryasbase.html.) Wereusingatemplatetagherethatyouhaventseenbefore:the{%block%}tag.Allthe{%block %}tagsdoistellthetemplateenginethatachildtemplatemayoverridethoseportionsofthe template. Nowthatwehavethisbasetemplate,wecanmodifyourexistingcurrent_datetime.htmltemplateto useit:
followingthreelevelapproach: 1. Createabase.htmltemplatethatholdsthemainlookandfeelofyoursite.Thisisthestuffthat rarely,ifever,changes. 2. Createabase_SECTION.htmltemplateforeachsectionofyoursite(e.g.,base_photos.html andbase_forum.html).Thesetemplatesextendbase.htmlandincludesectionspecificstyles/design. 3. Createindividualtemplatesforeachtypeofpage,suchasaforumpageoraphotogallery.These templatesextendtheappropriatesectiontemplate. Thisapproachmaximizescodereuseandmakesiteasytoadditemstosharedareas,suchas sectionwidenavigation. Herearesomeguidelinesforworkingwithtemplateinheritance: Ifyouuse{%extends%}inatemplate,itmustbethefirsttemplatetaginthattemplate. Otherwise,templateinheritancewontwork. Generally,themore{%block%}tagsinyourbasetemplates,thebetter.Remember,child templatesdonthavetodefineallparentblocks,soyoucanfillinreasonabledefaultsinanumberof blocks,andthendefineonlytheonesyouneedinthechildtemplates.Itsbettertohavemore hooksthanfewerhooks. Ifyoufindyourselfduplicatingcodeinanumberoftemplates,itprobablymeansyoushouldmove thatcodetoa{%block%}inaparenttemplate. Ifyouneedtogetthecontentoftheblockfromtheparenttemplate,use{{block.super}},which isamagicvariableprovidingtherenderedtextoftheparenttemplate.Thisisusefulifyouwantto addtothecontentsofaparentblockinsteadofcompletelyoverridingit. Youmaynotdefinemultiple{%block%}tagswiththesamenameinthesametemplate.This limitationexistsbecauseablocktagworksinbothdirections.Thatis,ablocktagdoesntjust provideaholetofill,italsodefinesthecontentthatfillstheholeintheparent.Ifthereweretwo similarlynamed{%block%}tagsinatemplate,thattemplatesparentwouldntknowwhichone oftheblockscontenttouse. Thetemplatenameyoupassto{%extends%}isloadedusingthesamemethodthat get_template()uses.Thatis,thetemplatenameisappendedtoyourTEMPLATE_DIRSsetting. Inmostcases,theargumentto{%extends%}willbeastring,butitcanalsobeavariable,ifyou dontknowthenameoftheparenttemplateuntilruntime.Thisletsyoudosomecool,dynamic stuff.
Noprestaratencinaestebloque,esdeusopersonalmientrassetrabajaelcapitulo H1TheDjangoBook H2Chapter4:Templates H3TemplateSystemBasics H3UsingtheTemplateSystem H4CreatingTemplateObjects H4RenderingaTemplate H4MultipleContexts,SameTemplate H4ContextVariableLookup H5MethodCallBehavior H5HowInvalidVariablesAreHandled H4PlayingwithContextObjects H3BasicTemplateTagsandFilters H4Tags H5if/else1 H5for2
H5ifequal/ifnotequal H5Comments H4Filters H3PhilosophiesandLimitations H3UsingTemplatesinViews H3TemplateLoading H4render_to_response()9 H4Thelocals()Trick H4Subdirectoriesinget_template() H4TheincludeTemplateTag H3TemplateInheritance3 H3Whatsnext?3 H4Aboutthiscommentsystem #code iterator=document.createNodeIterator(document.body,NodeFilter.SHOW_ELEMENT, function(node){ if(/h\d/i.test(node.nodeName))returnNodeFilter.FILTER_ACCEPT returnNodeFilter.FILTER_SKIP },true) while(iter=iterator.nextNode()){ for(vartimes=iter.nodeName.match(/\d/)[0]1,space=""times>0times) space+="\t" console.log(space,iter.nodeName,iter.textContent) }
Captulo 5: Modelos
Enelcaptulo3,cubrimoslosconceptosfundamentalesdelacreacindesitiosWebdinmicoscon Django:lacreacindevistasyURLconfs.Comoexplicamos,unavistaesresponsabledeimplementar algunalgicaarbitraria,ydespusdevolverunarespuesta.Enunodelosejemplos,nuestralgica arbitrariafuecalcularlafechayhoraactuales. EnaplicacionesWebmodernas,lalgicaarbitrariaamenudoinvolucrainteraccinconunabasede datos.Detrsdeescena,unsitioWebimpulsadoporunabasededatosseconectaaunservidordebase dedatos,recuperaalgunosdatosdeesta,ymuestraestosdatosenunapginaWeb.Elsitiotambin podraproporcionarfuncionesalosvisitantesdelsitioparapoblarlabasededatosellosmismos. MuchossitiosWebcomplejosproporcionanunacombinacindelosdos.Amazon.com,porejemplo,esun buencasodeunsitioimpulsadoporunabasededatos.Cadapginadeproductoesbsicamenteesuna consultaenlabasededatosdeproductosdeAmazonformateadacomoHTML,ycuandoenvasuna resea,esinsertadaenlabasededatosdelasreseas. DjangoesadecuadoparacrearsitiosWebimpulsadosporbasesdedatos,yaqueincluyeherramientas pararealizarconsultasalabasededatosdeunamanerafcilperopoderosa.Estecaptuloexplicaesta
f r o m d j a n g o . s h o r t c u t s i m p o r t r e n d e r _ t o _ r e s p o n s e i m p o r t M y S Q L d b d e f b o o k _ l i s t ( r e q u e s t ) : d b = M y S Q L d b . c o n n e c t ( u s e r = ' m e ' , d b = ' m y d b ' , p a s s w d = ' s e c r e t ' , h o s t = ' l o c a l h o s t ' ) c u r s o r = d b . c u r s o r ( ) c u r s o r . e x e c u t e ( ' S E L E C T n a m e F R O M b o o k s O R D E R B Y n a m e ' ) n a m e s = [ r o w [ 0 ] f o r r o w i n c u r s o r . f e t c h a l l ( ) ] d b . c l o s e ( ) r e t u r n r e n d e r _ t o _ r e s p o n s e ( ' b o o k _ l i s t . h t m l ' , { ' n a m e s ' : n a m e s } )
Estamaneradeabordarelproblemafunciona,perohayalgunosproblemasquesaltanalavista inmediatamente:
Estamosescribiendodirectamenteenelcdigolosparmetrosdelaconeccionalabasededatos.Lo
ideal,esponerestosparmetrosenelarchivodeconfiguracindenuestroproyectoDjango.
Werehavingtowriteafairbitofboilerplatecode:creatingaconnection,creatingacursor,
executingastatement,andclosingtheconnection.Ideally,allwedhavetodoisspecifywhich resultswewanted.
IttiesustoMySQL.If,downtheroad,weswitchfromMySQLtoPostgreSQL,wellhavetousea
differentdatabaseadapter(e.g.,psycopgratherthanMySQLdb),altertheconnectionparameters, anddependingonthenatureoftheSQLstatementpossiblyrewritetheSQL.Ideally,the databaseserverwereusingwouldbeabstracted,sothatadatabaseserverchangecouldbemadein asingleplace.(ThisfeatureisparticularlyrelevantifyourebuildinganopensourceDjango applicationthatyouwanttobeusedbyasmanypeopleaspossible.) Asyoumightexpect,Djangosdatabaselayeraimstosolvetheseproblems.Heresasneakpreviewof howthepreviousviewcanberewrittenusingDjangosdatabaseAPI:
django.shortcutsimportrender_to_response frommysite.books.modelsimportBook
Captulo6:ElsitioadmindeDjango
Paraciertaclasedesitiosweb,una interfazdeadmin(ointerfazdeadministracin)es parteesencialdelainfraestructura.Estaesunainterfazweb,limitadaalos administradoresdelsitio,quepermiteaadir,editaryborrarcontenidodelsitio.Algunos ejemploscomunes:lainterfazqueusascuandocreasunaentradaenunblog,elsitioque losadministradoresusanparamoderarloscomentarios,lasherramientasqueusantus clientesparaactualizarsusitiowebquetulesconstruiste. Hayunproblemaconlasinterfacesdeadministracin:Esaburridoconstruirlas.El desarrollowebesdivertidocuandoestasdesarrollandounafuncionalidadqueseenfrentaal pblico,peroconstruirinterfacesdeadministracinessiemprelomismo.Tienesque autentificarusuarios,desplegarymanejarlosformularios,validarlaentrada,etc.Es aburridoyrepetitivo. Entonces,Cualeselenfoquededjangoparaesteaburrimientoytareasrepetitivas?El enfoqueesquedjangoteproveedetodoentansolounpardelineasdecdigo,no menos.Condjango,construirinterfacesdeadministracinesunproblemaresuelto. Estecaptuloesacercadelainterfazdeadministracinautomticadedjango.Esta caracterstica,funcionadelasiguientemanera:Leelametadataentumodeloparaproveer unalistaparaproduccinypoderosainterfazquelosadministradoresdesitiospueden empezarausarinmediatamente.Aqu,vamosahablardecomoactivar,usarypersonalizar estacaracterstica. Notaquenosotrosrecomendamosqueleasestecaptuloinclusivesinotienesintensiones deusarelsitiodeadministracindedjango,porqueaquintroducimosalgunosconceptos queaplicaparatododjango,apesardelnousodelsitiodeadministracin.