0% encontró este documento útil (0 votos)
414 vistas

Django Book Español - Google Drive

Este documento introduce Django como un framework web para Python. Explica que Django separa las aplicaciones web en modelos (bases de datos), vistas (lógica de negocio) y URLs, lo que evita duplicar código y permite que diseñadores modifiquen el diseño sin afectar la lógica. También compara un ejemplo simple de CGI en Python con uno usando Django, mostrando cómo Django divide el código para hacerlo más mantenible y reutilizable.

Cargado por

José G. Yzarra
Derechos de autor
© Attribution Non-Commercial (BY-NC)
Nos tomamos en serio los derechos de los contenidos. Si sospechas que se trata de tu contenido, reclámalo aquí.
Formatos disponibles
Descarga como PDF, TXT o lee en línea desde Scribd
0% encontró este documento útil (0 votos)
414 vistas

Django Book Español - Google Drive

Este documento introduce Django como un framework web para Python. Explica que Django separa las aplicaciones web en modelos (bases de datos), vistas (lógica de negocio) y URLs, lo que evita duplicar código y permite que diseñadores modifiquen el diseño sin afectar la lógica. También compara un ejemplo simple de CGI en Python con uno usando Django, mostrando cómo Django divide el código para hacerlo más mantenible y reutilizable.

Cargado por

José G. Yzarra
Derechos de autor
© Attribution Non-Commercial (BY-NC)
Nos tomamos en serio los derechos de los contenidos. Si sospechas que se trata de tu contenido, reclámalo aquí.
Formatos disponibles
Descarga como PDF, TXT o lee en línea desde Scribd
Está en la página 1/ 60

IntroduccinaDjango:

Estetutorialestbasadoenel"Djangobook".Cualquierduda,comentarioosugerencia aqu.Antesqueempiecesaleerestegrandiosotutorial,voyanecesitarquecumplascon unospequeosrequisitos.

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.

Estosproblemassonprecisamentelosproblemasqueunwebframeworktrataderesolver. Unwebframeworkproveedeunainfraestructuraparaprogramartusaplicaciones,adems dequetepuedesconcentrarenescribircdigolimpioymanteniblesintenerquereinventar larueda.EnpocaspalabrasesoesloqueDjangohace.

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 ( )

# v i e w s . p y ( t h e b u s i n e s s l o g i c ) 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 f r o m m o d e l s i m p o r t B o o k d e f l a t e s t _ b o o k s ( r e q u e s t ) : b o o k _ l i s t = B o o k . o b j e c t s . o r d e r _ b y ( ' p u b _ d a t e ' ) [ : 1 0 ] r e t u r n r e n d e r _ t o _ r e s p o n s e ( ' l a t e s t _ b o o k s . h t m l ' , { ' b o o k _ l i s t ' : b o o k _ l i s t } )

# u r l s . p y ( t h e U R L c o n f i g u r a t i o n ) 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 * i m p o r t v i e w s u r l p a t t e r n s = p a t t e r n s ( ' ' , ( r ' ^ l a t e s t / $ ' , v i e w s . l a t e s t _ b o o k s ) , )

# 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 >

Otravez,notepreocupesdelasintaxissolotratadeentendereldiseogeneral.La principalcosaanotaraqueslaseparacindeasuntos: Elarchivom o d e l s . p y contieneunadescripcindelastablasdelabasededatos,representadas


porunaclase.Estaclaseesllamadaunmodelo.Usndolapuedescrear,obtener,actualizary borrarregistrosentubasededatosusandosimplecdigopythonenvezdeescribiruna sentenciaSQLquepuedeserrepetitiva.

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.

Escribeunaaplicacinwebdesde0 Escribeotraaplicacinwebdesde0 Datecuentaquelaaplicacindelpaso1compartemuchoencomnconlaaplicacindelpaso2 Refactorizaelcdigoentonceslaaplicacin1y2puedencompartirelcdigo Repitelospasosdel2al4variasveces Datecuentaquehasinventadounframework

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.

PeroestecaptulosolocubreescenarioscomunesparainstalacionesdeDjango.Vamosa asumirqueestasinstalndoloenunescritorio/laptoposervidor. Despus(varioscaptulosmsadelante)veremoscomollevaraproduccinunsitiohecho conDjango.

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:

PostgreSQL(http://www.postgresql.org/) SQLite3(http://www.sqlite.org/) MySQL(http://www.mysql.com/) Oracle(http://www.oracle.com/)

Sinoestasatadoaalgnsistemaviejoytieneslalibertaddeescogerunabasededatoste recomendamosPostgreSQL,quelogratenerunbuenbalanceentrecosto,caractersticas, velocidadyestabilidad. Ajustarlabasededatosesprocesode2pasos:

Primero,vasanecesitarinstalaryconfigurarelservidordebasededatos.Elprocesovamsall
delalcancedeestetutorial,peroafortunadamenteestos4motoresquesoportaDjangotienen muchadocumentacin,unagrancomunidadencadaunadeestasylamayoradeestasson fcilesdeinstalar.

Segundo,vasanecesitarinstalarunalibreradepythonquetepermitaconectarteatubasede
datos.

SisoloestasjugandooprobandoDjangoynoquieresinstalarunabasededatoste recomendamosusarSQLite.SQLiteeselnicomotordebasededatosquesoportaDjango quenorequieredeningunainstalacin,claroesosiestasusandounaversindepython2.5 enadelante. EnWindows,obtenerunalibreraparatrabajarconunabasededatospuedeserfrustante, afortunadamenteexisteunalistadelibrerasparapythoncompiladasenbinarios(.exe)que puedesconseguiraquhttp://www.lfd.uci.edu/~gohlke/pythonlibs/. Librerasdepythonrecomendadasparaconectarnosalabasededatos:

PostgreSQL:psycopg2 SQLite3:norequeridoparapython2.5enadelante. MySQL:MySQLdb Oracle:cx_Oracle

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:

p y t h o n m a n a g e . p y r u n s e r v e r 8 0 8 0 Inclusivepuedenadmitirotrasconexionesquenoseandesucomputadora: p y t h o n m a n a g e . p y r u n s e r v e r 0 . 0 . 0 . 0 : 8 0 0 0 Obviamenteesteservidorwebrpidoyligeroessoloparahacerpruebasdemaneralocaly nosedebedeusarparaproduccin,yaquenoestaprobadotanintensivamentecomootros servidoresweb.

VistasyURLconfs
TuprimerapginahechaconDjango:HolaMundo!
UnavezqueyatenemosinstaladoDjangopodemosempezarajugar.Comoprimerapgina vamoshacerelpopular "Holamundo!" Vamosaverunejemplosencillodecomohacerunhola sinunframework:

1. Creasunarchivodetextoplanoquecontenga"Holamundo!" 2. Guardaselarchivoconelnombreh o l a . h t m l 3. Finalmente,losubesatuservidorwebylisto.


Enesteprocesohemosidentificado2piezasclavesparaeldesarrollodepginas.La primeraeselcontenidodelarchivoenestecaso"Holamundo"ylaURL (http://www.example.com/hola.htmlotalvezhttp://www.example.com/files/hola.htmlsilo pusisteenunsubdirectorio).ConDjango,tambindebesdeespecificarestas2cosas,pero deunamaneradiferente.Elcontenidodeunarchivoesrenderizadoporunafuncinllamada vista,ylaURLesespecificadaporunURLconf.Primerovamosaescribirlafuncin"hola".

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,

comolohicisteanteriormentecorriendoelcomando(p y t h o n m a n a g e . p y r u n s e r v e r ).Silo dejastecorriendoestabien,noesnecesarioqueloreinicies,elservidorautomticamente detectacambiosentucdigoyrecargalonecesario,entoncesnonecesitasreiniciarel servidorparavercambios.Elservidorestacorriendoenladireccinhttp://127.0.0.1:8000/, entoncesabretunavegadorwebfavoritoyentraahttp://127.0.0.1:8000/hello/.Entonces debesdevereltexto"Holamundo"lasalidadetuvista h e l l o . Felicidades!HashechotuprimerapaginawebconDjango.

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

diferente? Paraaveriguarlo,tratadecorrerelservidordedesarrollodedjangoyvisitaralgunaURL quenotengasenelURLconf,porejemplohttp://127.0.0.1:8000/goodbye/o http://127.0.0.1:8000/hello/subdirectory/,oinclusohttp://127.0.0.1:8000/.Entoncesdebes depoderverelmensajePagenotfound(paginanoencontrada,verlasiguienteFigura). DjangomuestraestemensajeporquelaURLqueestastratandodeaccedernoestadefinida enelURLconf.

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

especificodedjango.Comoestasaprendiendopython,nosotrosqueremosqueseascapaz deusartuconocimientoenotrosproyectosqueusenpythonperoquenonecesariamente usendjango.) Parahacerquenuestravistadespliegelafechayhoraactual,lounicoquenecesitamos haceresenganchar d a t e t i m e . d a t e t i m e . n o w ( ) enlavistayregresarunobjeto H t t p R e s p o n s e . Aquestacomoquedara:

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.

Despuesdeaadirnuestrocdigoa v i e w s . p y ,aadirelURLpatterna u r l s . p y paradecirlea djangoquURLdeberademanejarestavista.Algocomo / t i m e / tendramssentido:

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

asociadasdifusamente),entoncesloscambioshechosaunapiezadesoftwaretieneun efectopocoonulosobrelaotrapiezadesoftware. LasURLconfsdedjangosonunbuenejemplodeesteprincipioenlaprctica.Enuna aplicacinwebhechacondjango,lasdefinicionesdelasURLsylasvistasonllamadas looselycoupled(difusamenteasociadas)esoes,ladesicindepodercambiarlaURLyla vistaindistintamenteyqueningunadelas2partesseveaafectadaporlaotra.


Porejemplo,consideremosnuestravistac u r r e n t _ d a t e t i m e .SinosotrosqueremoscambiarlaURLpara laaplicacindigamos,moverlade/ t i m e / a/ c u r r e n t t i m e / nosotrospodemoshacerunrpido cambioenelURLconf,sintenernosquepreocuparacercadelavista.Similarmente,sinosotros quisieramoscambiarlavistaalterandosulgicadealgnmodonosotrospodramoshaceresosin tenerquealterarlaURLalacualestsujeta.

Adems,sinosotrosqueremosexponerlafechaactualendiferentesURLs,nosotros podemoshacerestofcilmenteeditandoelURLconf,sintenerquetocarnadadelcdigode lavista.Esesteejemplo,nuestravista c u r r e n t _ d a t e t i m e estadisponibleendosURLs.Esun ejemploartificial,peroestatcnicapuedevolversebastantetil.

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:

u r l p a t t e r n s = p a t t e r n s ( ' ' , # . . . ( r ' ^ t i m e / p l u s / \ d + / $ ' , h o u r s _ a h e a d ) , # . . . ) (Nosotrosestamosusando # . . . paraimplicarquepuedenhaberotrosURLpatternsque nosotrosquitamosdeesteejemploporcuestionesdesimplicidad.)

EstenuevoURLpattervaacoincidircualquierURLcomo / t i m e / p l u s / 2 / , / t i m e / p l u s / 2 5 / o incluso / t i m e / p l u s / 1 0 0 0 0 0 0 0 0 0 0 0 / .Pensadolobien,vamosalimitareldesplazamiento maximopermitidoa99horas.Estosignificaquequeremospermitirsolounoodosdgitos yennuestraexpresinregularestosetraduciracomo \ d { 1 , 2 } . ( r ' ^ t i m e / p l u s / \ d { 1 , 2 } / $ ' , h o u r s _ a h e a d ) ,

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:

( r ' ^ t i m e / p l u s / ( \ d { 1 , 2 } ) / $ ' , h o u r s _ a h e a d ) , Siestasfamiliarizadoconexpresionesregulares,entoncestesentirascomoencasa Nosotrosestamosparntesispara capturar losdatosquecoincidaneneltexto. ElURLconf,incluyendolas2vistasprevias,quedaraas: 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 , h o u r s _ a h e a d u r l p a t t e r n s = p a t t e r n s ( ' ' , ( r ' ^ h e l l o / $ ' , h e l l o ) , ( r ' ^ t i m e / $ ' , c u r r e n t _ d a t e t i m e ) , ( r ' ^ t i m e / p l u s / ( \ d { 1 , 2 } ) / $ ' , h o u r s _ a h e a d ) , ) Unavezhechoesto,vamosaescribirnuestravista h o u r s _ a h e a d .

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

c u r r e n t _ d a t e t i m e .Unapequeadiferenciaenestalneacomparadaconlosanteriores stringformat(formateosdecadenas)quehemoshecho,esqueahorahaydos simbolos % s enelstringyunatupladevaloresainsertar ( o f f s e t , d t ) . Finalmente,regresamosunobjetoHttpResponseconelHTML.

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 )

Finalmente,esobvioquemuchadeestainformacinessencibleexponetodaslastripas detucdigoydelaconfiguracindedjangoyseratontomostrarestainformacinen Internet.Unapersonamaliciosapuedeintentarusaringenierainversaentuaplicacinweb parahacercosassucias.Poresarazn,lapginadeerrordedjangosolosemuestra cuandolaaplicacinestaenmododebug(depuracin).Vamosaensearteacomo desactivaren"Djangoenproduccin".Porahora,solosabesquecadaproyectodjangoesta enmododebugautomaticamentecuandoloempiezas.(Tesuenafamiliar?lapginade error"Pagenotfound",descritaaliniciodeestecaptulo,trabajadelamismamanera.)

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

formatobasadoentexto. Comencemosconunaplantilladeejemplo.LasiguienteplantillaDjangodescribeunapginaHTMLque agradeceaunapersonaalcompletarunaordenconunaempresa.Pienseenellocomounmodelode carta:

< 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

Filtronovlido Argumentosnovlidosparafiltrosvlidos Sintaxisdeplantillanovlido Etiquetassincerrar(paraetiquetasquerequierenetiquetasdecierre)

Interpretandoplantillas
UnavezobtienesunobjetoTemplate,puedespasarledatosindicandouncontexto.Uncontextoes simplementeunconjuntodenombresdevariablesenlaplantillaysusvaloresasociados.Unaplantilla lasutilizaparallenarsusvariablesyevaluarsusetiquetas. UncontextoesrepresentadoenDjangoporlaclaseContext,queresideenelmdulodjango.template. Suconstructortomaunargumentoopcional:undiccionariodeclavesasociadasavalores.Ejecuteel mtodorender()delobjetoTemplateconelcontextoparallenarlaplantilla:

>>>fromdjango.templateimportContext,Template >>>t=Template('Mynameis{{name}}.') >>>c=Context({'name':'Stephane'}) >>>t.render(c) u'MynameisStephane.'


Unaspectoquedebemosdestacaraquesqueelvaloradevolverdet.render(c)esunobjetoUnicode noesunacadenanormaldepython.Lopuedesconfirmarporlauenfrentedelacadena.Djangoutiliza losobjetosUnicodeenlugardecadenasnormalesentodoelframework.Sientiendeslasrepercusiones deello,sagradecidoporlosdetallessofisticadosqueDjangohaceeneltrasfondoparaquefuncione.Si noentiendeslasrepercusiones,notepreocupesporahora,slosepaqueelsoportedeDjangopara Unicodehacequesearelativamenteindolorosoelsoportedetusaplicacionesconunampliavariedadde conjuntosdecaracteresmsalldelosbsicosAZdelconfunjodecaracteresASCII. Diccionariosycontextos Undiccionarioenpythonesunacorrespondenciaentreclavesconocidasyvaloresdelasvariables.Un contextoessimilaraundiccionario,perouncontextoproporcionafuncionalidadesadicionales,como seexplicaenelcaptuloPlantillasavanzadas. Losnombresdevariablesdebencomenzarconunaletra(AZoaz)ypuedecontenerletras,dgitos, guiones,ypuntos.(Lospuntossonuncasoespecial,enunmomentollegaremos.)Losnombresde variablessedistinguenentreminsculasymaysculas.Heaquunejemplodelacompilaciny representacindeunaplantilla,utilizandounaplantillasimilaraladelcomienzodeestecaptulo. >>>fromdjango.templateimportTemplate,Context >>>raw_template="""<p>Dear{{person_name}},</p> ... ...<p>Thanksforplacinganorderfrom{{company}}.It'sscheduledto ...shipon{{ship_date|date:"Fj,Y"}}.</p> ... ...{%ifordered_warranty%} ...<p>Yourwarrantyinformationwillbeincludedinthepackaging.</p> ...{%else%} ...<p>Youdidn'torderawarranty,soyou'reonyourownwhen

...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:

>>>fromdjango.templateimportTemplate,Context >>>t=Template('Hello,{{name}}') >>>printt.render(Context({'name':'John'})) Hello,John >>>printt.render(Context({'name':'Julie'})) Hello,Julie >>>printt.render(Context({'name':'Pat'})) Hello,Pat


Siemprequequierasprocesarmltiplescontextosutilizandolamismaplantillacomoenelejemplo,es mseficientecrearunobjetoTemplateunavez,yluegoinvocarmltiplesvecesrender():

#Maluso fornamein('John','Julie','Pat'): t=Template('Hello,{{name}}') printt.render(Context({'name':name})) #Buenuso t=Template('Hello,{{name}}') fornamein('John','Julie','Pat'): printt.render(Context({'name':name}))


ElparseodeplantillasenDjangoesbastanterpido.Eneltrasfondo,lamayoradelparsingseproducea travsdeunasimpleexpresinregular.Esteestamarcadoporunagrandiferenciaconlosmotoresde plantillasbasadoenXML,queincurrenenelexcesodeparsingXMLytiendeserpormagnitudmslento queelsistemadeplantilladeDjango.

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 >>>person={'name':'Sally','age':'43'} >>>t=Template('{{person.name}}is{{person.age}}yearsold.')

>>>c=Context({'person':person}) >>>t.render(c) u'Sallyis43yearsold.'


Delmismomodo,elpuntopermiteelaccesoalosatributosdeunobjeto.Porejemplo,elobjeto datetime.datecontienelosatributosyear,month,yday,conelpuntopuedesaccederestosatributosen laplantilladeDjango:

>>>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:

>>>fromdjango.templateimportTemplate,Context >>>classPerson(object): ...def__init__(self,first_name,last_name): ...self.first_name,self.last_name=first_name,last_name >>>t=Template('Hello,{{person.first_name}}{{person.last_name }}.') >>>c=Context({'person':Person('John','Smith')}) >>>t.render(c) u'Hello,JohnSmith.'


Lospuntostambinpuedenaccederamtodosenlosobjetos.Porejemplo,enpythoncadastringtiene losmtodosupper()eisdigit(),ypuedesinvocarlosenlasplantillasdeDjangoutilizandolamisma sintaxisdepunto:

>>>fromdjango.templateimportTemplate,Context >>>t=Template('{{var}}{{var.upper}}{{var.isdigit}}') >>>t.render(Context({'var':'hello'})) u'helloHELLOFalse'

>>>t.render(Context({'var':'123'})) u'123123True'
Notequenoseincluyelosparntesisenlainvocacindelosmtodos.Adems,noesposiblepasar argumentosalosmtodossolopuedesinvocarmtodosquenorequierenargumentos.(Luego explicarmosestafilosofaenestecaptulo.) Finalmente,lospuntostambinseutilizanparaaccesarlosndicesdelaslistas,porejemplo:

>>>fromdjango.templateimportTemplate,Context >>>t=Template('Item2is{{items.2}}.') >>>c=Context({'items':['apples','bananas','carrots']}) >>>t.render(c) u'Item2iscarrots.'


Losndicesnegativosnoestanpermitidos.Porejemplo,lavariabledeplantilla{{items.1}}causara unerrorTemplateSyntaxError. Laslistasdepython Unrecordatorio.Laslistasdepythoncomienzaporelndice0. Labsquedadelpuntopuederesumirseas:cuandoelsistemadeplantillaencuentraunpuntoenel nombredelavariable,esteintentarlossiguientespasos,enesteorden: 1. Bsquedaendiccionario(ejemplo,foo[bar]) 2. Bsquedaporatributo(ejemplo,foo.bar) 3. Invocacindemtodo(ejemplo,foo.bar()) 4. Bsquedaporndice(ejemplo,foo[2]) Elsistemautilizaelprimertipodebusquedaquefuncione.Esuncortocircuitologstico.Elpuntose puedeanidarenmltiplesnivelesdeprofundidad.Elsiguienteejemploutiliza{{person.name.upper}}, quesetraduceaunabsquedaenundiccionarioyluegounallamadaalmtodoupper():

>>>fromdjango.templateimportTemplate,Context >>>person={'name':'Sally','age':'43'} >>>t=Template('{{person.name.upper}}is{{person.age}}years old.') >>>c=Context({'person':person}) >>>t.render(c) u'SALLYis43yearsold.'


Comportamientodelosmtodos
Lasinvocacionesdemtodossonunpocomscomplejasquelosdemspatronesdebsquedas.Heaqu algunascosasatenerencuenta: Sidurantelabsquedadeunmtodo,elmtodoproduceunaexcepcin,laexcepcinse propagaramenosquelaexcepcintengaelatributosilent_variable_failurecuyovaloresTrue.

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.

defdelete(self): #Deletetheaccount delete.alters_data=True


Elsistemadeplantillasnoejecutarcualquiermtodomarcadodeestaforma.Continuandocon elejemploanterior,siunaplantillaincluye{{account.delete}}yelmtdodelete()tieneel atributoalters_data=True,entonceselmtododelete()noserinvocadocuandolaplantillase analiza.Ensulugar,seproducirunerrorsilenciosamente.

Cmosemanejanlasvariablesnovlidas?
Pordefecto,siunavariablenoexiste,elsistemadeplantillalopresentacomounstringvacio,fallando silenciosamente.Porejemplo:

>>>fromdjango.templateimportTemplate,Context >>>t=Template('Yournameis{{name}}.') >>>t.render(Context())

u'Yournameis.' >>>t.render(Context({'var':'hello'})) u'Yournameis.' >>>t.render(Context({'NAME':'hello'})) u'Yournameis.' >>>t.render(Context({'Name':'hello'})) u'Yournameis.'


Elsistemafallasilenciosamenteenlugardelevantarunaexcepcin,yaqueestdiseadaparaser resistenteaunerrorhumano.Enestecaso,todaslasbsquedasfallarnporquelosnombresdelas variablessonincorrectosonocoincidenconlasmaysculasyminsculas.Enelmundoreal,es inaceptableparaunsitiowebquesevuelvainaccesibledebidoapequeoserroressintcticos.

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:

{%iftoday_is_weekend%} <p>Welcometotheweekend!</p> {%endif%}


Laetiqueta{%else%}esopcional:

{%iftoday_is_weekend%} <p>Welcometotheweekend!</p> {%else%} <p>Getbacktowork.</p> {%endif%}

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_listandnotcoach_list%} Therearesomeathletesandabsolutelynocoaches. {%endif%}


Laetiqueta{%if%}nopermiteclusulasandyordentrodelamismaetiqueta,yaqueelorden logsticoseraambiguo.Porejemplo,estonoesvlido:

{%ifathlete_listandcoach_listorcheerleader_list%}
Elusodelosparntesisparacontrolarelordendelasoperacionesnoesadimisible.Sivesquenecesitas parntesis,serecomiendarealizarlaoperacindelaplantillaypasarelresultadocomounavariable dedicadaalaplantilla.Obien,simplementepuedesanidarlaetiqueta{%if%}as:

{%ifathlete_list%} {%ifcoach_listorcheerleader_list%} Wehaveathletes,andeithercoachesorcheerleaders! {%endif%} {%endif%}


Mltiplesusosdelosmismosoperadoreslgicosestnbien,peronopuedescombinardiferentes operadores.Porejemplo,losiguienteesvlido:

{%ifathlete_listorcoach_listorparent_listorteacher_list%}
Tampocoexistelaetiqueta{%elif%}.Puedeslograrlomismoanidandolaetiqueta{%if%}.

{%ifathlete_list%} <p>Herearetheathletes:{{athlete_list}}.</p> {%else%} <p>Noathletesareavailable.</p> {%ifcoach_list%} <p>Herearethecoaches:{{coach_list}}.</p> {%endif%} {%endif%}


Asegresedecerrarcadaetiqueta{%if%}conun{%endif%}.Delocontrario,Djangolanzarun errorTemplateSyntaxError.

for
Laetiqueta{%for%}permiteiterarsobrecadaelementodeunasecuencia.Aligualquelasentencia fordepython,lasintaxisesforXinY,dondeYeslasecuenciaarecorreryXeselnombredelavariable autilizarenunpuntodeterminadodelbucle.Cadavezqueseatraviesaelciclo,elsistemadeplantilla procesartodoentre{%for%}y{%endfor%}. Porejemplo,podrasutilizarlosiguienteparamostrarunalistadeatletasdadalavariableathlete_list:

<ul>

{%forathleteinathlete_list%} <li>{{athlete.name}}</li> {%endfor%} </ul>


Siagregasreversedalaetiqueta,serecorrelalistaenordeninverso:

{%forathleteinathlete_listreversed%} ... {%endfor%}


Tambinesposibleanidarlaetiqueta{%for%}:

{%forathleteinathlete_list%} <h1>{{athlete.name}}</h1> <ul> {%forsportinathlete.sports_played%} <li>{{sport}}</li> {%endfor%} </ul> {%endfor%}


Unpatrncomnescomprobareltamaodeunalistaantesderecorrersobreeste,ymostraruntexto especialsiestvaca:

{%ifathlete_list%} {%forathleteinathlete_list%} <p>{{athlete.name}}</p> {%endfor%} {%else%} <p>Therearenoathletes.Onlycomputerprogrammers.</p> {%endif%}


Debidoaqueestepatrnestancomn,laetiquetaforadmitelaclusulaopcional{%empty%}que lepermitedefinirquemostrarsilalistaestvaca.Esteejemploesequivalentealanterior:

{%forathleteinathlete_list%} <p>{{athlete.name}}</p> {%empty%} <p>Therearenoathletes.Onlycomputerprogrammers.</p> {%endfor%}


Nohaysoporteparadeteneruncicloantesqueelbuclesecomplete.Siquiereslograresto,cambiael valordelavariableaiterarparaqueslorecorraporlosvaloresquedeseasiterar.Delmismomodo,no haysoporteparalasentenciacontinuequeleinstruyealbucleirinmediatamentealprximociclo. (VerseccinFilosofasylimitcionesmsadelanteenestecaptuloparaentenderelrazonamientoenla

decisindeestediseo.) Dentrodecadabucle{%for%},obtienesaccesoaunavariabledeplantillallamadaforloop.Esta variablecontienevariosatributosqueleproveeinformacinsobreelprogresodelbucle: forloop.countersiempreseestableceaunenterorepresentandoelnmerodevecesqueseha entradoalbucle.Lavariableesindexadaenbaseauno,demodoqueenelprimerciclo, forloop.counteresestablecidoconvalor1.Heaquunejemplo:

{%foritemintodo_list%} <p>{{forloop.counter}}:{{item}}</p> {%endfor%}


forloop.counter0escomoforloop.counter,exceptoqueestbasadoenndicecero.Suvalores establecidoalvalor0laprimeravezquerecorreelbuble. forloop.revcountersiempreesestablecidoaunenterorepresentandoelnmerodeelementos restanteenelbucle.Enelprimerciclodelbucle,forloop.revcounterseestablecealnmerototal deelementosdelasecuenciaqueestamosrecorriendo.Enelltimociclodelbucle, forloop.revcounteresestablecidoalvalor1. forloop.revcounter0escomoforloop.revcounter,exceptoqueestbasadoenndicecero.La primeravezqueentraalbucle,forloop.revcounter0esestablecidoalnmerototaldeelementos delasecuenciamenosuno(total1).Enelltimociclodelbucle,lavariableseestablecea0. forloop.firstesunvalorBooleanestablecidoaTruesiestaeslaprimeravezqueserecorreel bucle.Esteesconvenienteparasituacionesespeciales:

{%forobjectinobjects%} {%ifforloop.first%}<liclass="first">{%else%}<li>{%endif%} {{object}} </li> {%endfor%}


forloop.lastesunvalorBooleanestablecidoaTruesiesteeselltimociclodelbucle.Unuso comndeesteesparaponerelcaracterpipe(|)entreunalistadeenlaces:

{%forlinkinlinks%}{{link}}{%ifnotforloop.last%}|{%endif %}{%endfor%}
Elcdigodeplantillaanteriormostraraalgocomolosiguiente:

Link1|Link2|Link3|Link4
Otrousocomnesponerunacomaentreunalistadepalabras:

Favoriteplaces: {%forpinplaces%}{{p}}{%ifnotforloop.last%},{%endif%}{% endfor%}


Encasodebuclesanidados,forloop.parentloopesunareferenciaalobjetoforlooppadredelbucle actual.Heaquunejemplo:

{%forcountryincountries%} <table>

{%forcityincountry.city_list%} <tr> <td>Country#{{forloop.parentloop.counter}}</td> <td>City#{{forloop.counter}}</td> <td>{{city}}</td> </tr> {%endfor%} </table> {%endfor%}


Lavariableforloopestaslodisponbiledentrodelosbucles.Despusqueelparserdeplantillahaya llegadoa{%endfor%},forloopdesaparece. Contextoylavariableforloop Dentrodelbloque{%for%},lasvariablesexistentessonrelocalizadosparaevitarsobrescribirla variableforloop.Djangoexponedichocontextoenelobjetoforloop.parentloop.Generalmenteno tienesquepreocuparseporesto,perosiproveesalaplantillaunavariablellamadaforloop(aunquele desaconsejamossuuso),serrenombradoforloop.parentloopmientrasestdentrodelbloque{%for %}.

ifequal/ifnotequal
ElsistemadeplantilladeDjango,deliberadamente,noesunlenguajedeprogramacincompletoypor tantonotepermiteejecutararbitrariamentecdigopython.(Mssobreestasideasenlaseccin Filosofasylimitaciones.)Entodocaso,esbastantecomnelrequisitodecomparardosvaloresdentro delaplantillaymostraralgosisoniguales.Djangoproporcionalaetiqueta{%ifequal%}paraeste propsito. Laetiqueta{%ifequal%}comparadosvaloresymuestratodoentre{%ifequal%}y{%endifequal %}silosvaloressoniguales.Esteejemplocomparalasvariablesuserycurrentuser:

{%ifequalusercurrentuser%} <h1>Welcome!</h1> {%endifequal%}


Losargumentospuedenserstringenelcdigo(hardcoded),concomillassimplesodobles,demodoque losiguienteesvlido:

{%ifequalsection'sitenews'%} <h1>SiteNews</h1> {%endifequal%} {%ifequalsection"community"%} <h1>Community</h1> {%endifequal%}


Aligualque{%if%},laetiqueta{%ifequal%}soportalaetiquetaopcional{%else%}.

{%ifequalsection'sitenews'%} <h1>SiteNews</h1> {%else%} <h1>NoNewsHere</h1> {%endifequal%}


Solamentevariablesdeplantilla,string,enterosynmerosdecimalessonpermitidoscomoargumentos a{%ifequal%}.Estossonejemplosvlidos:

{%ifequalvariable1%} {%ifequalvariable1.23%} {%ifequalvariable'foo'%} {%ifequalvariable"foo"%}


Otrostiposdevariables,talescomodiccionarios,listasoBooleans,nopuedenserhardcodeden{% ifequal%}.Estossonejemplosnovlidos.

{%ifequalvariableTrue%} {%ifequalvariable[1,2,3]%} {%ifequalvariable{'key':'value'}%}


SinecesitascomprobarsialgoesTrueoFalse,utilizalaetiqueta{%if%}enlugarde{%ifequal%}.

Comentarios
JustocomoenHTMLopython,ellenguajedeplantilladeDjangopermitecomentarios.Paradesignarun comentario,utilizalaetiqueta{##}:

{#Thisisacomment#}
Elcomentarionoserimpresocuandolaplantillaseinterpreta.Loscomentariosconestasintaxisno puedenabarcarmltipleslneas.Estalimitacinmejoraelrendimientoalprocesarlaplantilla.Enla siguienteplantilla,elresultadoseverexactamenteigualcomoenlaplantilla(enotraspalabras,la etiquetadecomentarionoseprocesacomouncomentario):

Thisisa{#thisisnot acomment#} test.


Siquieresusarcomentariosdemltipleslneas,utilizalaetiqueta{%comment%}comoelejemplo:

{%comment%} Thisisa multilinecomment. {%endcomment%}

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

importdatetime defcurrent_datetime(request): now=datetime.datetime.now() html="<html><body>Itisnow%s.</body></html>"%now returnHttpResponse(html)


CambiemosestavistautilizandoelsistemadeplantilladeDjango.Enprincipio,podraspensarhaceralgo comoesto:

fromdjango.templateimportTemplate,Context fromdjango.httpimportHttpResponse importdatetime defcurrent_datetime(request): now=datetime.datetime.now() t=Template("<html><body>Itisnow{{current_date }}.</body></html>") html=t.render(Context({'current_date':now})) returnHttpResponse(html)


Claro,ahseutilizaelsistemadeplantilla,peronoresuelvelosproblemasquesesealanenla introduccindeestecaptulo.Esdecir,laplantillaestincrustradaenelcdigopython,porloquela verdaderaseparacindedatosypresentacinannoselogra.Vamosaarreglaresoubicandolaplantilla enunarchivoseparado,queestavistacargar. Podrasconsiderarguardarlaplantillaenalgnlugardetusistemadearchivoyutilizaslas funcionalidadesintegradasdepythonparaabriryleerelcontenidodelaplantilla.Heaqucomopodra lucirelcdigo,asumiendoquelaplantillafuealmacenadaen /home/djangouser/templates/mytemplate.html:

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:

Nomanejalasituacinenqueelarchivonoseencuentre.Sielarchivomytemplate.htmlno existeonoeslegible,lainvocacinacall()levantaralaexcepcinIOError. Lalocalizacindelaplantillaestescritadirectamente(hardcoded)enelcdigo.Sifuerasa utilizarestatcnicaparatodaslasvistas,estarasduplicandolaubicacindelaplantilla.Sin olvidarqueimplicamuchaescritura! Incluyeunagrancantidaddecdigorepetitivoaburrido.Tienescosasmejoresquehacerque realizarllamadasaopen(),fp.read(),yfp.close()cadavezquecargasunaplantilla. Pararesolverestosproblemas,vamosausarlastcnicastemplateloadingytemplatedirectories.

Cargandoplantilla
DjangoproporcionaunapotenteyconvenienteAPIparacargarplantillasdelsistemadearchivos,conel objetivodeeliminarlaredundanciatantoalcargarplantillascomoenlaplantillaensmisma.Conelfin deutilizarestaAPI,primeronecesitarsindicarleaDjangodndeestnalmacenadoslasplantillas.El lugarparahacerestoesenelarchivodeconfiguracioneselarchivosettings.pyquehemos mencionadoenelcaptuloanterior,cuandohablamossobreROOT_URLCONF.Siestassiguiendolos ejercicios,abreelarchivosettings.pyylocalizalaconfiguracinTEMPLATE_DIRS.Pordefecto,esuna tuplavaca,probablementeconalgunoscomentariosautogenerados:

TEMPLATE_DIRS=( #Putstringshere,like"/home/html/django_templates"or "C:/www/django/templates". #Alwaysuseforwardslashes,evenonWindows. #Don'tforgettouseabsolutepaths,notrelativepaths. )


EstaconfiguracinleindicaalmecanismodelaAPIparacargarplantillasenDjangodndelocalizarlas plantillas.ElijeundirectorioenelquedeseasalmacenarlasplantillasyagregaloaTEMPLATE_DIRS,as:

TEMPLATE_DIRS=( '/home/django/mysite/templates', )
Hayalgunascosasatenerencuenta: Sepuedeindicarcualquierdirectorioquedesees,siempreycuandoeldirectorioylasplantillas enellasseanlegibleporlacuentadeusuarioenlaqueelservidorwebseejecuta.Sinopuedes pensarporunlugarapropiadoparaubicarlasplantillas,lerecomendamoscreareldirectorio templatesdentrodelproyectoesdecir,dentrodeldirectoriomysitequesecreenelcaptulo Iniciando. SiTEMPLATE_DIRScontieneunslodirectorio,noolvideslacomaalfinaldelstring!Larazn deestoesporquepythonrequiereunacomadentrodeunatupladeunsloelementopara eliminarlaambigedadconunaexpresinenparntesis.Setratadeunerrorcomnenlos novatos.

#Mal!Faltalacomaalfinal. TEMPLATE_DIRS=( '/home/django/mysite/templates' )

#Bien.Lacomaestpresente. TEMPLATE_DIRS=( '/home/django/mysite/templates', )


SiestsenWindows,incluyelaletradelaunidadyutilizalabarradiagonal(forwardslash)en lugardelabarradiagonalinversa(backslash),comoelejemplo:

TEMPLATE_DIRS=( 'C:/www/django/templates', )
Lomssimpleesutilizarrutasabsolutasesdecir,rutasdedirectoriosquecomienzanenla razdelsistemadearchivos.Sinembargo,siquieresserunpocomsflexibleydesacoplado, puedestomarventajadelfactorqueelarchivodeconfiguracindeDjangoessimplemente cdigopythonyconstruirdinmicamenteelcontenidodeTEMPLATE_DIRS.Porejemplo:

importos.path TEMPLATE_DIRS=( os.path.join(os.path.dirname(__file__),'templates').replace('\\','/'), )


Esteejemploutilizalavariablemgica__file__depython,queautomaticamentesuvalores establecidoalnombredearchivodelmduloenqueelcdigopythonreside.Esteobtieneel nombredeldirectorioquecontieneasettings.py(os.path.dirname),luegolounificacon templatesdeformamultiplataforma(os.path.join),yfinalmenteseaseguraqueseutilice forwardslashesenlugardebackslashes(encasodelsistemaWindows). Mientrasestamoseneltemadecdigopythondinmicoenelarchivodeconfiguraciones,hay quesealarqueesmuyimportanteevitarerroresenlaconfiguracin.Siintroducesunerror sintctico,ounerrorenejecuccin(runtimeerror),esmuyprobablequeelsitiowebmanejado porDjangocolapse. UnavezajustadoelTEMPLATE_DIRS,elprximopasoescambiarelcdigodelavistaparaqueutilicelas funcionalidadesdecargarplantillasdeDjangoenlugardeexplicitamenteescribirlarutaalcdigo. Volviendoanuestravistacurrent_datetime,vamosacambiarlo:

fromdjango.template.loaderimportget_template fromdjango.templateimportContext fromdjango.httpimportHttpResponse importdatetime defcurrent_datetime(request): now=datetime.datetime.now() t=get_template('current_datetime.html') html=t.render(Context({'current_date':now}))

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.

EstapginadeerroressimilaralaqueexplicamosenelcaptuloVistasyURLconfs,conunapieza adicionaldeinformacindepurada:laseccinTemplateloaderpostmortem.Estaseccinledicecual plantillaDjangointentcargar,juntoconelmotivodecadaintentofallidoesdecir,Filedoesnot exist(Elarchivonoexiste).Estainformacinesvaliosacuandoeststratandodepurarloserroresal cargarplantillas. Continuando,creaelarchivocurrent_datetime.htmldentrodetudirectoriodeplantillasutilizandoel siguientecdigo:

<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():

fromdjango.shortcutsimportrender_to_response importdatetime defcurrent_datetime(request): now=datetime.datetime.now() returnrender_to_response('current_datetime.html',{'current_date': now})


Whatadifference!Letsstepthroughthecodechanges: Wenolongerhavetoimportget_template,Template,Context,orHttpResponse.Instead,we importdjango.shortcuts.render_to_response.Theimportdatetimeremains. Withinthecurrent_datetimefunction,westillcalculatenow,butthetemplateloading,context creation,templaterendering,andHttpResponsecreationarealltakencareofbythe render_to_response()call.Becauserender_to_response()returnsanHttpResponseobject,wecan simplyreturnthatvalueintheview. Thefirstargumenttorender_to_response()isthenameofthetemplatetouse.Thesecondargument, ifgiven,shouldbeadictionarytouseincreatingaContextforthattemplate.Ifyoudontprovidea secondargument,render_to_response()willuseanemptydictionary.

The locals() Trick


Considerourlatestincarnationofcurrent_datetime:

defcurrent_datetime(request): now=datetime.datetime.now() returnrender_to_response('current_datetime.html',{'current_date': now})


Manytimes,asinthisexample,youllfindyourselfcalculatingsomevalues,storingtheminvariables (e.g.,nowintheprecedingcode),andsendingthosevariablestothetemplate.Particularlylazy programmersshouldnotethatitsslightlyredundanttohavetogivenamesfortemporaryvariablesand givenamesforthetemplatevariables.Notonlyisitredundant,butalsoitsextratyping. Soifyoureoneofthoselazyprogrammersandyoulikekeepingcodeparticularlyconcise,youcantake advantageofabuiltinPythonfunctioncalledlocals().Itreturnsadictionarymappingalllocalvariable namestotheirvalues,wherelocalmeansallvariablesthathavebeendefinedwithinthecurrent scope.Thus,theprecedingviewcouldberewrittenlikeso:

defcurrent_datetime(request): current_date=datetime.datetime.now() returnrender_to_response('current_datetime.html',locals())


Here,insteadofmanuallyspecifyingthecontextdictionaryasbefore,wepassthevalueoflocals(), whichwillincludeallvariablesdefinedatthatpointinthefunctionsexecution.Asaconsequence,weve renamedthenowvariabletocurrent_date,becausethatsthevariablenamethatthetemplateexpects. Inthisexample,locals()doesntofferahugeimprovement,butthistechniquecansaveyousometyping ifyouhaveseveraltemplatevariablestodefineorifyourelazy. Onethingtowatchoutforwhenusinglocals()isthatitincludeseverylocalvariable,whichmay comprisemorevariablesthanyouactuallywantyourtemplatetohaveaccessto.Intheprevious example,locals()willalsoincluderequest.Whetherthismatterstoyoudependsonyourapplicationand yourlevelofperfectionism.

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.

Note Windowsusers,besuretouseforwardslashesratherthanbackslashes.get_template()assumesa Unixstylefilenamedesignation.

The include Template Tag


Nowthatwevecoveredthetemplateloadingmechanism,wecanintroduceabuiltintemplatetagthat takesadvantageofit:{%include%}.Thistagallowsyoutoincludethecontentsofanothertemplate. Theargumenttothetagshouldbethenameofthetemplatetoinclude,andthetemplatenamecanbe eitheravariableorahardcoded(quoted)string,ineithersingleordoublequotes.Anytimeyouhave thesamecodeinmultipletemplates,considerusingan{%include%}toremovetheduplication. Thesetwoexamplesincludethecontentsofthetemplatenav.html.Theexamplesareequivalentand illustratethateithersingleordoublequotesareallowed:

{%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

things: IfDEBUGissettoTrue,youllseetheTemplateDoesNotExistexceptiononaDjangoerrorpage. IfDEBUGissettoFalse,thetagwillfailsilently,displayingnothingintheplaceofthetag.

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>Futuretime</title> </head> <body> <h1>Myhelpfultimestampsite</h1> <p>In{{hour_offset}}hour(s),itwillbe{{next_time}}.</p>

<hr> <p>Thanksforvisitingmysite.</p> </body> </html>


Clearly,wevejustduplicatedalotofHTML.Imagineifwehadamoretypicalsite,includinganavigation bar,afewstylesheets,perhapssomeJavaScriptwedendupputtingallsortsofredundantHTMLinto eachtemplate. Theserversideincludesolutiontothisproblemistofactoroutthecommonbitsinbothtemplatesand savetheminseparatetemplatesnippets,whicharethenincludedineachtemplate.Perhapsyoudstore thetopbitofthetemplateinafilecalledheader.html:

<!DOCTYPEHTMLPUBLIC"//W3C//DTDHTML4.01//EN"> <htmllang="en"> <head>


Andperhapsyoudstorethebottombitinafilecalledfooter.html:

<hr> <p>Thanksforvisitingmysite.</p> </body> </html>


Withanincludebasedstrategy,headersandfootersareeasy.Itsthemiddlegroundthatsmessy.In thisexample,bothpagesfeatureatitle<h1>Myhelpfultimestampsite</h1>butthattitlecant fitintoheader.htmlbecausethe<title>onbothpagesisdifferent.Ifweincludedthe<h1>inthe header,wedhavetoincludethe<title>,whichwouldntallowustocustomizeitperpage.Seewhere thisisgoing? Djangostemplateinheritancesystemsolvestheseproblems.Youcanthinkofitasaninsideout versionofserversideincludes.Insteadofdefiningthesnippetsthatarecommon ,youdefinethe snippetsthataredifferent. Thefirststepistodefineabasetemplateaskeletonofyourpagethatchildtemplateswilllaterfillin. Heresabasetemplateforourongoingexample:

<!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:

{%extends"base.html"%} {%blocktitle%}Thecurrenttime{%endblock%} {%blockcontent%} <p>Itisnow{{current_date}}.</p> {%endblock%}


Whilewereatit,letscreateatemplateforthehours_aheadviewfromChapter3.(Ifyourefollowing alongwithcode,wellleaveituptoyoutochangehours_aheadtousethetemplatesysteminsteadof hardcodedHTML.)Hereswhatthatcouldlooklike:

{%extends"base.html"%} {%blocktitle%}Futuretime{%endblock%} {%blockcontent%} <p>In{{hour_offset}}hour(s),itwillbe{{next_time}}.</p> {%endblock%}


Isntthisbeautiful?Eachtemplatecontainsonlythecodethatsuniquetothattemplate.No redundancyneeded.Ifyouneedtomakeasitewidedesignchange,justmakethechangeto base.html,andalloftheothertemplateswillimmediatelyreflectthechange. Hereshowitworks.Whenyouloadthetemplatecurrent_datetime.html,thetemplateengineseesthe {%extends%}tag,notingthatthistemplateisachildtemplate.Theengineimmediatelyloadsthe parenttemplateinthiscase,base.html. Atthatpoint,thetemplateenginenoticesthethree{%block%}tagsinbase.htmlandreplacesthose blockswiththecontentsofthechildtemplate.So,thetitlewevedefinedin{%blocktitle%}willbe used,aswillthe{%blockcontent%}. Notethatsincethechildtemplatedoesntdefinethefooterblock,thetemplatesystemusesthevalue fromtheparenttemplateinstead.Contentwithina{%block%}taginaparenttemplateisalways usedasafallback. Inheritancedoesntaffectthetemplatecontext.Inotherwords,anytemplateintheinheritancetree willhaveaccesstoeveryoneofyourtemplatevariablesfromthecontext. Youcanuseasmanylevelsofinheritanceasneeded.Onecommonwayofusinginheritanceisthe

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

funcionalidad:LacapadebasededatosdeDjango. Nota:AunquenoesestrictamentenecesarioconocerteorabsicadebasesdedatosrelacionalesySQL parausarlacapadebasededatosdeDjango,esmuyrecomendble.Unaintroduccinaesosconceptos estfueradelalcancedeestelibro,perocontinaleyendosieresnuevoenbasesdedatos. Probablementeserscapzdeseguiryentenderlosconceptosenfuncindelcontexto.

La manera Tonta de hacer consultas a la base de datos en las vistas


AscomoenelCaptulo3vimoslamaneratontadegenerarunasalidaenunavista(hardcodeandoel textodirectamentedentrodelavista),hayunamaneratontaderecuperardatosdesdeunabasede datosenunavista.Essimple:solousaunalibreraexistenteenPythonparaejecutarunaconsultaSQL yhazalgoconlosresultados. Enesteejemplodevista,usamoslalibreraMySQLdb(disponibleen http://www.djangoproject.com/r/pythonmysql/)paraconectarseaunabasededatosMySQL,recuperar algunosregistros,yalimentarconellosuntemplateparamostrarunapginaWeb:

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

defbook_list(request): books=Book.objects.order_by('name') returnrender_to_response('book_list.html',{'books':books})

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.

También podría gustarte