tutorial de django girls
TRANSCRIPT
0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
TabladecontenidoIntroducción
¿CómofuncionaInternet?
Introducciónalalíneadecomandos
InstalacióndePython
Editordecódigo
IntroducciónaPython
¿QuéesDjango?
InstalacióndeDjango
ComenzarunproyectoenDjango
ModelosenDjango
AdministradordeDjango
¡Desplegar!
Djangourls
VistasdeDjango-¡Eshoradecrear!
IntroducciónaHTML
ORMdeDjango(Querysets)
Datosdinámicosenplantillas
PlantillasdeDjango
CSS-Hazlobonito
Extenderplantillas
Amplíatuaplicación
FormulariosenDjango
Dominio
¿Quésigue?
DjangoGirlsTutorial
2
TutorialdeDjangoGirls
EstetrabajoestábajolalicenciainternacionalCreativeCommonsAttribution-ShareAlike4.0.Paraverunacopiadeestalicencia,visitaelsiguienteenlacehttp://creativecommons.org/licenses/by-sa/4.0/
TranslationThistutorialhasbeentranslatedfromEnglishintoSpanishbyawonderfulgroupofvolunteers.SpecialthanksgoestoVictoriaMartinezdelaCruz,KevinMorales,JoshuaAranda,SilviaFrias,Leticia,AndreaGonzalez,AdrianManjarres,RodrigoCaicedo,MariaChavez,MarceloNicolasManso,RosaDurante,Moises,IsraelMartinezVargas,JuanCarlos_,N0890Dy,IvanYivoff,KhaterineCastellano,ErickNavarro,cyncyncyn,ZeroSoul13,ErickAguayo,ErnestoRico-Schmidt,MiguelLozano,osueboy,dynarroandGeraldinaGarciaAlvarez.
Introducción¿Algunavezhassentidoqueelmundoestácadavezmáscercanoalatecnologíaydeciertomodotehasquedadoatrás?¿Algunaveztehaspreguntadocómocrearunsitiowebperonuncahastenidolasuficientemotivaciónparaempezar?¿Haspensadoalgunavezqueelmundodelsoftwareesdemasiadocomplicadoparaticomoparaintentarhaceralgoportucuenta?
Bueno,¡tenemosbuenasnoticiasparati!Programarnoestandifícilcomoaparentayqueremosmostrartecuándivertidopuedellegaraser.
Estetutorialnoteconvertiráenprogramadormágicamente.Siquieresserbuenaenesto,necesitarásmesesoinclusosañosdeaprendizajeypráctica.Peroqueremosmostrartequeprogramarocrearsitioswebnoestancomplicadocomoparece.Intentaremosexplicarpequeñasparteslomejorquepodamos,deformaquenotesientasintimidadaporlatecnología.
¡Esperamospoderhacerteamarlatecnologíatantocomonosotraslohacemos!
¿Quéaprenderásconestetutorial?
DjangoGirlsTutorial
3Introducción
Cuandotermineseltutorial,tendrásunaaplicaciónwebsimpleyfuncional:tupropioblog.Temostraremoscomopublicarlaonline,¡asíotrospodránvertutrabajo!
Tendrá(másomenos)éstaapariencia:
Siestássiguiendoestetutorialportucuentaynotienesanadiequeteayudeencasodesurgiralgúnproblema,tenemosunchatparati: .¡Hemospedidoanuestrostutoresyparticipantesanterioresqueesténahídevezencuandoparaayudaraotrosconeltutorial!¡Notemasdejartuspreguntasallí!
Bien,empecemosporelprincipio...
SobrenosotrosycómocontribuirEstetutoriallomantieneDjangoGirls.Siencuentrasalgúnerroroquieresactualizareltutorial,porfavorsiguelaguíadecómocontribuir.
DjangoGirlsTutorial
4Introducción
¿Tegustaríaayudarnosatraducireltutorialaotrosidiomas?Actualmente,lastraduccionessellevanacabosobrelaplataformacrowdin.comen:
https://crowdin.com/project/django-girls-tutorial
Situidiomanoestalistadoencrowdin,porfavorabreunnuevoproblemainformandoelidiomaasípodemosagregarlo.
DjangoGirlsTutorial
5Introducción
¿CómofuncionaInternet?Estecapituloestáinspiradoporlacharla"HowtheInternetworks"deJessicaMcKellar(http://web.mit.edu/jesstess/www/).
ApostamosqueutilizasInternettodoslosdías.Pero,¿sabesloquepasacuandoescribesunadireccióncomohttp://djangogirls.orgentunavegadorypresionas'Enter'?
Loprimeroquetienesqueentenderesqueunsitiowebessólounmontóndearchivosguardadosenundiscoduro.Aligualquetuspelículas,músicaofotos.Sinembargo,lossitioswebposeenunapeculiaridad:ellosincluyenuncódigodecomputadorasllamadoHTML.
Sinoestásfamiliarizadaconlaprogramación,puedeserdifícildecaptarHTMLalprincipio,perotusnavegadoresweb(comoChrome,Safari,Firefox,etc.)loaman.Losnavegadoreswebestándiseñadosparaentenderestecódigo,seguirsusinstruccionesymostrartodosesosarchivosdeloscualestusitiowebestáhechodelamaneraexactacomotuquieresquesemuestren.
Comocualquierotroarchivo,tenemosqueguardarlosarchivosHTMLenalgúnlugardeundiscoduro.ParaInternet,usamosunascomputadorasespecialesypoderosasllamadasservidores.Ellasnotienenunapantalla,mouseoteclado,debidoaquesupropósitoesalmacenardatosyservirlos.Poresarazónsonllamadosservidores--porqueellossirvenlosdatos.
Ok,quizástepreguntescómoluceInternet,¿cierto?
¡Tehemoshechounaimagen!Lucealgoasí:
DjangoGirlsTutorial
6¿CómofuncionaInternet?
Pareceunlío,¿no?Enrealidadesunareddemáquinasconectadas(losmencionadosservidores).¡Cientosdemilesdemáquinas!¡Muchos,muchoskilómetrosdecablesalrededordelmundo!PuedesvisitarelsitiowebSubmarineCableMap(http://submarinecablemap.com/)dondesemuestranlasconexionesdecablessubmarinosalrededordelmundoyverlocomplicadaqueeslared.Aquíhayunacapturadepantalladelapáginaweb:
DjangoGirlsTutorial
7¿CómofuncionaInternet?
Esfascinante,¿no?Pero,obviamente,noesposibleteneruncableentrecadamáquinaconectadaaInternet.Asíque,parallegaraunamáquina(porejemplolaquealojaahttp://djangogirls.org)tenemosquepasarunasolicitudatravésdemuchasmáquinasdiferentes.
Separeceaesto:
DjangoGirlsTutorial
8¿CómofuncionaInternet?
Imaginaquecuandoescribeshttp://djangogirls.org,estasenviandounacartaquedice:"QueridosDjangoGirls,megustaríaversusitiowebdjangogrils.org.Porfavor,envíenmelo!"
Tucartavahacialaoficinadecorreomáscercana.Luegovaaotraunpocomáscercanadesudestinatario,luegoaotrayaotrahastaqueesentregadaensudestino.Loúnicacosadiferenteesquesituenvíascartas(paquetesdedatos)confrecuenciaalmismolugar,cadacartapuedepasarporoficinasdecorreos(routers)totalmentediferentes,dependiendodecómosedistribuyenencadaoficina.
DjangoGirlsTutorial
9¿CómofuncionaInternet?
Sí,estansimplecomoeso.Enviarmensajesyesperaralgunarespuesta.Porsupuesto,envezdepapelylapicerausasbytesdedatos,¡perolaideaeslamisma!
Enlugardedireccionesconelnombredelacalle,ciudad,códigopostalynombredelpaís,utilizamosdireccionesIP.TucomputadorapideprimeroelDNS(DomainNameSystem-enespañolSistemadeNombresdeDominio)paratraducirdjangogirls.orgaunadirecciónIP.Funcionacomolosviejosdirectoriostelefónicosdondepuedesbuscarelnombredelapersonaquesedeseascontactaryestenosmuestrasunúmerodeteléfonoydirección.
Cuandoenvíasunacarta,éstanecesitatenerciertascaracterísticasparaserentregadacorrectamente:unadirección,sello,etc.Tambiénutilizasunlenguajequeelreceptorpuedaentender,¿cierto?Lomismosucedeconlospaquetesdedatosqueenvíasparaverunsitioweb:utilizasunprotocolollamadoHTTP(HypertextTransferProtocol-enespañolProtocolodeTransferenciadeHipertexto).
Asíque,básicamente,cuandotienesunsitiowebnecesitastenerunservidor(lamáquina)dondevive.Elservidorestáesperandocualquiersolicitudentrante(cartasquepidenalservidorqueenvíetusitioweb)yésterespondeenviandotusitioweb(enotracarta).
PuestoqueesteesuntutorialdeDjango,segurotepreguntarásquéesloquehaceDjango.Bueno,cuandoenvíasunarespuesta,nosiemprequieresenviarlomismoatodoelmundo.Esmuchomejorsituscartassonpersonalizadas,especialmenteparalapersonaqueacabadeescribir,¿cierto?Djangonosayudaconlacreacióndeestascartaspersonalizadas:).
DjangoGirlsTutorial
10¿CómofuncionaInternet?
Bastadecharlas,¡pongamosmanosalaobra!
DjangoGirlsTutorial
11¿CómofuncionaInternet?
IntroducciónalainterfazdelíneadecomandosEsemocionante,¿verdad?Vasaescribirtuprimeralíneadecódigoenpocosminutos:)
Permítenospresentarteatuprimernuevoamigo:¡lalíneadecomandos!
Lossiguientespasostemostraráncómousaraquellaventananegraquetodosloshackersusan.Puedeparecerunpocoaterradoralprincipioperoessolounmensajeenpantallaqueesperaaqueledesórdenes.
¿Quéeslalíneadecomandos?Laventana,quegeneralmenteesllamadalíneadecomandosointerfazdelíneadecomandos,esunaaplicaciónbasadaentextoparaver,manejarymanipulararchivosentucomputadora(comoporejemploelExploradordeWindowsoFinderenMac,perosinlainterfazgráfica).Otrosnombresparalalíneadecomandosson:cmd,CLI,símbolodelsistema,consolaoterminal.
AbrirlainterfazdelíneadecomandosLoprimeroquedebemoshacerparaempezaraexperimentarconnuestrainterfazdelineadecomandosesabrirla.
Windows
IralmenúInicio→Todoslosprogramas→Accesorios→CommandPrompt
MacOSX
Aplicaciones→Servicios→Terminal
Linux
EstáprobablementeenAplicaciones→Accesorios→Terminal,peroesodependedetudistribución.Sinoloencuentras,Googlealo:)
DjangoGirlsTutorial
12Introducciónalalíneadecomandos
PromptAhoradeberíasverunaventanablancaonegraqueestáesperandotusórdenes.
SiestásenMacoLinux,probablementeverás$,así:
$
EnWindows,esunsignoasí>,comoeste:
>
Cadacomandoseráprecedidoporestesignoyunespacio,peronotienesqueescribirlo.Tucomputadoraloharáporti:)
Sólounapequeñanota:entucaso,talvezhayalgocomoC:\Users\ola>oOlas-MacBook-Air:~ola$antesdelpromptyesoes100%correcto.Enestetutoriallosimplificaremoslomásposible.
Tuprimercomando(¡YAY!)Vamosaempezarconalgosimple.Escribeestecomando:
$whoami
o
>whoami
YluegooprimelateclaEnter.Esteeselresultado:
$whoamiolasitarska
Comopuedesver,lacomputadorasólotepresentótunombredeusuario.Bien,¿eh?:)
Tratadeescribircadacomando,nocopiesypegues.¡Teacordarásmásdeestamanera!
Básicos
DjangoGirlsTutorial
13Introducciónalalíneadecomandos
Cadasistemaoperativotieneunconjuntodiferentedecomandosparalalíneadecomandos,asíqueasegúratedeseguirlasinstruccionesparatusistemaoperativo.Vamosaintentarlo,¿deacuerdo?
Directorioactual
Seríabuenosaberdóndeestamosahora,¿cierto?Vamosaver.EscribeestecomandoyoprimeEnter:
$pwd
/Users/olasitarska
SiestásenWindows:
>cd
C:\Users\olasitarska
Probablementeverásalgosimilarentumáquina.Unavezqueabreslalíneadecomandosgeneralmenteempiezaseneldirectoriohomedetuusuario.
Nota:'pwd'significa'printworkingdirectory'-enespañol,'mostrardirectoriodetrabajo'.
Listadearchivosydirectorios
¿Quéhayaquí?Seríabuenosaber.Veamos:
$ls
Applications
Desktop
Downloads
Music
...
Windows:
>dir
DirectoryofC:\Users\olasitarska
05/08/201407:28PM<DIR>Applications
05/08/201407:28PM<DIR>Desktop
05/08/201407:28PM<DIR>Downloads
05/08/201407:28PM<DIR>Music
...
DjangoGirlsTutorial
14Introducciónalalíneadecomandos
Cambiaeldirectorioactual
¿Quizáspodemosiranuestroescritorio?
$cdDesktop
Windows:
>cdDesktop
Compruebasirealmentehacambiado:
$pwd
/Users/olasitarska/Desktop
Windows:
>cd
C:\Users\olasitarska\Desktop
¡Aquíestá!
Protip:siescribescdDyluegooprimestabenelteclado,lalíneadecomandosautomáticamentecompletaráelrestodelnombreparaquepuedasnavegarmásrápido.Sihaymásdeunacarpetaqueempiececon"D",presionaelbotóntabdosvecesparaobtenerunalistadeopciones.
Creardirectorio
¿QuétalsicreamosundirectoriodeDjangoGirlsentuescritorio?Puedeshacerlodeestamanera:
$mkdirdjangogirls
Windows:
>mkdirdjangogirls
DjangoGirlsTutorial
15Introducciónalalíneadecomandos
Estepequeñocomandocrearáunacarpetaconelnombredjangogirlsentuescritorio.¡Puedescomprobarsiestáallíbuscandoentuescritoriooejecutandoelcomandols/dir!Inténtalo:)
Protip:Sinoquieresescribirunayotravezlosmismoscomandos,pruebaoprimiendolaflechaarribayflechaabajodetutecladoparaverrecientescomandosutilizados.
¡Ejercicios!
Unpequeñoretoparati:eneldirectorioreciéncreadodjangogirlscreaundirectoriollamadotest.Utilizaloscomandoscdymkdir.
Solución:
$cddjangogirls
$mkdirtest
$ls
Windows:
>cddjangogirls
>mkdirtest
>dir
08/05/201419:28<DIR>test
¡Felicitaciones!:)
Limpiar
Noqueremosdejarundesorden,asíquevamosaeliminartodoloquehicimoshastaestemomento.
Enprimerlugar,tenemosquevolveralescritorio:
$cd..
Windows:
DjangoGirlsTutorial
16Introducciónalalíneadecomandos
>cd..
cd..cambiaráeldirectorioactualaldirectoriopadre(quesignificaeldirectorioquecontieneeldirectorioactual).
Revisadóndeestás:
$pwd
/Users/olasitarska/Desktop
Windows:
>cd
C:\Users\olasitarska\Desktop
Ahoraeshoradeeliminareldirectoriodjangogirls.
Atención:Eliminararchivosutilizandodel,rmdirormhacequenopuedanrecuperarse,loquesignificaquelosarchivosborradosdesapareceránparasiempreDebessermuycuidadosaconestecomando.
$rm-rdjangogirls
Windows:
>rmdir/sdjangogirls
djangogirls,¿Estásseguro<Y/N>?Y
Hecho!Asegurémonosqueenverdadfueronborrados,vamosaver:
$ls
Windows:
>dir
Salida
¡Estoestodoporahora!Ahorapuedescerrarlalíneadecomandossinproblemas.Vamosahacerloalestilohacker,¿bien?:)
DjangoGirlsTutorial
17Introducciónalalíneadecomandos
$exit
Windows:
>exit
Genial,¿no?:)
ÍndiceAquíhayunalistadealgunoscomandosútiles:
Comando(Windows)
Comando(MacOS/Linux) Descripción Ejemplo
exit exit Cierralaventana exit
cd cd Cambiaeldirectorio cdtest
dir ls Listadirectorios/archivos dir
copy cp Copiadearchivos copyc:\test\test.txtc:\windows\test.txt
move mv Muevearchivos movec:\test\test.txtc:\windows\test.txt
mkdir mkdir Creaunnuevodirectorio mkdirtestdirectory
del rm Eliminaarchivos/directorios delc:\test\test.txt
Estossonsoloalgunosdeloscomandosquepuedesejecutarenlalíneadecomandos.Novasausarnadamásqueesosporahora.
Sitienescuriosidad,ss64.comcontieneunareferenciacompletadecomandosparatodoslossistemasoperativos.
¿Lista?¡VamosasumergirnosenPython!
DjangoGirlsTutorial
18Introducciónalalíneadecomandos
VamosaempezarconPython¡Porfinestamosaquí!
Peroprimero,déjenosdecirtequéesPython.Pythonesunlenguajedeprogramaciónmuypopularquepuedeutilizarseparalacreacióndesitiosweb,juegos,softwareacadémico,gráficosymucho,muchomás.
Pythonseoriginóenladécadade1980ysuobjetivoprincipalesserlegibleporlossereshumanos(¡nosóloparalasmáquinas!),poresoparecemuchomássimplequeotroslenguajesdeprogramación.Estohacequeseamásfácildeaprender,peronotepreocupes,¡Pythonestambiénmuypoderoso!
InstalacióndePythonEstesubcapítulosebasaenuntutorialdeGeekGirlsCarrots(http://django.carrots.pl/)
DjangoestáescritoenPython.NecesitamosPythonparacualquiercosaenDjango.¡Vamosaempezarconlainstalación!QueremosqueinstalesPython3.4,asíquesitienesalgunaversiónanterior,deberásactualizarla.
Windows
PuedesdescargarPythonparaWindowsdesdeelsitiowebhttps://www.python.org/downloads/release/python-343/.Despuésdedescargarelarchivo*.msi,debesejecutarlo(hazdobleclickenelarchivo)ysiguelasinstrucciones.Esimportanterecordarlaruta(eldirectorio)dondesehainstaladoPython.¡Seránecesariomásadelante!
Algoparatenerencuenta:enlasegundapantalladelasistentedeinstalación,llamada"Customize",asegúratedeirhaciaabajoyelegirlaopción"Addpython.exetothePath",comoen
DjangoGirlsTutorial
19InstalacióndePython
Linux
EsmuyposiblequeyatengasPythoninstalado.Paraverificarqueyalotienesinstalado(yquéversiónes),abreunaconsolaytipeaelsiguientecomando:
$python3--version
Python3.4.2
SinotienesPythoninstaladoosiquieresunaversióndiferente,puedesinstalarlocomosigue:
Ubuntu
Tipeaestecomandoentuconsola:
sudoapt-getinstallpython3.4
Fedora
Usaestecomandoentuconsola:
DjangoGirlsTutorial
20InstalacióndePython
sudoyuminstallpython3.4
OSX
Debesiralsitiowebhttps://www.python.org/downloads/release/python-342/ydescargarelinstaladordePython:
descargaelarchivoDMGMacOSX64-bit/32-bitinstaller,hazdobleclickparaabrirlo,dobleclickenPython.mpkgparaejecutaralinstalador.
VerificaquelainstalaciónfueexitosaabriendolaTerminalyejecutandoelcomandopython3:
$python3--version
Python3.4.2
Sitienesalgunadudaosialgosaliómalynosabescómoresolverlo-¡pideayudaatututor!Algunasveceslascosasnosalentanfácilmenteyesmejorpedirayudaaalguienconmásexperiencia.
DjangoGirlsTutorial
21InstalacióndePython
EditordecódigoEstásapuntodeescribirtuprimeralíneadecódigo,asíque¡eshoradedescargaruneditordecódigo!
Haymuchoseditoresdiferentes,cuálusardependemuchodelapreferenciapersonal.LamayoríadeprogramadoresdePythonusanIDEs(EntornosdeDesarrolloIntegrados)complejosperomuypoderosos,comoPyCharm.Sinembargo,comoprincipiante,esoesprobablementemenosconveniente;nuestrasrecomendacionessonigualdepoderosasperomuchomassimples.
Nuestrassugerenciasestánlistadasabajo,perosiéntetelibredepreguntarleatututorcuálessonsuspreferencias-asíserámásfácilobtenersuayuda.
GeditGeditesuneditordecódigoabierto,gratis,disponibleparatodoslossistemasoperativos.
Descárgaloaquí
SublimeText2SublimeTextesuneditormuypopularconunperiododepruebagratis.Esfácildeinstalaryestádisponibleparatodoslossistemasoperativos.
Descárgaloaquí
AtomAtomesuneditordecódigomuynuevocreadoporGitHub.Esgratis,decódigoabierto,fácildeinstalaryfácildeusar.EstádisponibleparaWindows,OSXyLinux.
Descárgaloaquí
¿Porquéestamosinstalandouneditordecódigo?
DjangoGirlsTutorial
22Editordecódigo
Puedesestarpreguntándoteporquéestamosinstalandouneditorespecial,enlugardeusaruneditorconvencionalcomoWordoNotepad.
Enprimerlugar,elcódigotienequesertextoplanoyelproblemadelasaplicacionescomoWordoTexteditesqueenrealidadnoproducentextoplano.Loquegeneranestextoenriquecido(contipografíasyformato),usandoformatospropioscomortf.
Lasegundarazónesqueloseditoresdecódigosonherramientasespecializadasy,comotales,tienencaracterísticasmuyútiles,comoresaltarlasintáxisdelcódigocondiferentescoloresdeacuerdoasusignificadoocerrarcomillasportiautomáticamente.
Veremostodoestoenacciónmásadelante.Enbreveempezarásapensarentufieleditordecódigocomounadetusherramientasfavoritas:)
DjangoGirlsTutorial
23Editordecódigo
IntroducciónaPythonPartedeestecapítulosebasaentutorialesporGeekGirlsCarrots(http://django.carrots.pl/).
¡Vamosaescribiralgodecódigo!
PythonpromptParaempezarajugarconPython,tenemosqueabrirunalíneadecomandosennuestracomputadora.Yasabescómohacerlo,loaprendisteenelcapítulodeIntroducciónalalíneadecomandos.
Unavezqueestéslisto,siguelassiguientesinstrucciones.
QueremosabrirunaconsoladePython,asíqueescribepython3ypulsaEnter.
$python3
Python3.4.2(...)
Type"copyright","credits"or"license"formoreinformation.
>>>
TuprimercomandoenPython!DespuésdeejecutarelcomandodePython,elcursorcambiaa>>>.ParanosotrosestosignificaqueporahorasólopodemosutilizarcomandosenellenguajePython.Notienesqueescribirel>>>-Pythonloharáporti.
SideseassalirdelaconsoladePythonencualquiermomento,simplementeescribeexit()ousaelatajoCtrl+ZparaWindowsyCtrl+DparaMac/Linux.Luegonoverásmás>>>.
PeroahoranoqueremossalirdelaconsoladePython.Queremosaprendermássobreella.Vamosaempezarconalgomuysimple.Porejemplo,tratadeescribiralgodematemáticas,como2+3ypulsaEnter.
>>>2+3
5
DjangoGirlsTutorial
24IntroducciónaPython
¡Bien!¿Vescomosaliólarespuesta?¡Pythonsabematemáticas!Podríasintentarotroscomandoscomo:-4*5-5-1-40/2
Diviérteteconestoporunmomentoyluegovuelveaquí:).
Comopuedesver,Pythonesunagrancalculadora.Siteestáspreguntandoquémáspuedehacer...
Strings¿Ytunombre?Escribatunombredepilaenfrasescomoésta:
>>>"Ola"
'Ola'
¡Hascreadotuprimerstring!Esunasecuenciadecaracteresquepuedeserprocesadaporunacomputadora.Elstring(oenespañol,cadena)debecomenzaryterminarconelmismocarácter.Estopuedesercomillassimples(')odobles(")-ellasledicenaPythonqueloqueestadentroesunacadena.
Lascadenaspuedenserconcatenadas.Pruebaesto:
>>>"Hola"+"Ola"
'HolaOla'
Tambiénpuedesmultiplicarlascadenasconunnúmero:
>>>"Ola"*3
'OlaOlaOla'
Sinecesitasponerunapóstrofedentrodetucadena,tienesdosmanerasdehacerlo.
Usandocomillasdobles:
>>>"Runnin'downthehill"
"Runnin'downthehill"
oescapandoelapóstrofeconunabarrainvertida(``):
>>>'Runnin\'downthehill'
"Runnin'downthehill"
DjangoGirlsTutorial
25IntroducciónaPython
Bien,¿eh?Paravertunombreenletrasmayúsculas,simplementeescribe:
>>>"Ola".upper()
'OLA'
¡Usastelafunciónupperentucadena!Unafunción(comoupper())esunconjuntodeinstruccionesquePythontienequerealizarsobreunobjetodeterminado("Ola")unavezquesellama.
Siquisierassaberelnúmerodeletrasquecontienetunombre,tambiénexisteunafunciónparaesto.
>>>len("Ola")
3
Tepreguntarásporquéavecessellamaalasfuncionesconun.alfinaldeunacadena(como"Ola".upper())yavecessellamaaunafunciónycolocaslacadenaentreparéntesis.Bueno,enalgunoscasoslasfuncionespertenecenaobjetos,comoupper(),quesólopuedeserutilizadosobrecadenas(upper()esunafuncióndelosobjetosstring).Enestecaso,llamamosmétodoaestafunción.Otraveces,lasfuncionesnopertenecenaningúnobjetoespecíficoypuedenserusadosendiferentesobjetos,comolen().Estaeslarazóndeporquéestamospasando"Ola"comounparámetroalafunciónlen.
Resumen
Ok,suficientesobrelascadenas.Hastaahorahasaprendidosobre:
laterminal-teclearcomandos(código)dentrodelaterminaldePythonresultaenrespuestasdePythonnúmerosystrings-enPythonlosnúmerossonusadosparamatemáticasystringsparaobjetosdetextooperadores-como+y*,combinavaloresparaproducirunonuevofunciones-comoupper()ylen(),realizanopcionessobrelosobjetos.
Estossonlosconocimientosbásicosquepuedesaprenderdecualquierlenguajedeprogramación.¿Listaparaalgounpocomásdifícil?¡Apostamosqueloestás!
Errores
DjangoGirlsTutorial
26IntroducciónaPython
Intentemosconalgonuevo.¿Podríamosobtenerlalongituddeunnúmerodelamismamaneraqueobtuvimoslalongituddenuestronombre?Teclealen(304023)ypresionaEnter:
>>>len(304023)
Traceback(mostrecentcalllast):
File"<stdin>",line1,in<module>
TypeError:objectoftype'int'hasnolen()
¡Obtuvimosnuestroprimererror!Dicequelosobjetosdetipo"int"(númerosenteros)notienenningunalongitud.¿Quépodemoshacerahora?Quizáspodemosescribirelnumerocomounstring.Losstringstienenlongitud,¿cierto?
>>>len(str(304023))
6
¡Funcionó!Utilizamoslafunciónstrdentrodelafunciónlen.str()conviertetodoastrings.
LafunciónstrconviertecosasenstringsLafunciónintconviertecosasenintegers
Importante:podemosconvertirnúmerosentexto,peronopodemosnecesariamenteconvertirtextoennúmeros-¿quéseríaint('hello')?
VariablesUnconceptoimportanteenprogramaciónsonlasvariables.Unavariablenoesmásqueunnombreparaalgunacosaparaquepuedasusarlamástarde.Losprogramadoresusanestasvariablesparaalmacenardatos,hacersucódigomáslegibleyasínotenerqueseguirrecordandoquehacecadacosa.
Supongamosquequeremoscrearunanuevavariablellamadaname:
>>>name="Ola"
¿Ves?¡Esfácil!Essimplemente:nameequivaleaOla.
Comotehasdadocuenta,elprogramanoregresaalgocomolohaciaantes.Entonces,¿Cómosabemosquelavariableexisterealmente?SimplementeintroducenameypulsaEnter:
DjangoGirlsTutorial
27IntroducciónaPython
>>>name
'Ola'
¡Súper!Tuprimervariable:).Siemprepodráscambiaraloqueserefiere:
>>>name="Sonja"
>>>name
'Sonja'
Puedesusarladentrodefuncionestambién:
>>>len(name)
5
Increíble,¿verdad?Porsupuesto,lasvariablespuedensercualquiercosa,¡tambiénnúmeros!Pruebaesto:
>>>a=4
>>>b=6
>>>a*b
24
Pero¿quépasasiusamoselnombreequivocado?¿Puedesadivinarquépasaría?¡Vamosaprobar!
>>>city="Tokyo"
>>>ctiy
Traceback(mostrecentcalllast):
File"<stdin>",line1,in<module>
NameError:name'ctiy'isnotdefined
¡Unerror!Comopuedesver,PythontienediferentestiposdeerroresyestesellamaNameError.Pythontedaráesteerrorsiintentasutilizarunavariablequenohasidodefinidaaún.Simásadelanteteencuentrasconesteerror,verificatucódigoparaversinohasescritomalunavariable.
Juegaconestoporunratoymiraquepuedeshacer!
LafunciónprintIntentaesto:
DjangoGirlsTutorial
28IntroducciónaPython
>>>name='Maria'
>>>name
'Maria'
>>>print(name)
Maria
Cuandosóloescribesname,elintérpretedePythonrespondeconlarepresentacióndelstringdelavariable'name',quesonlasletrasM-a-r-i-a,rodeadasdecomillassimples''.Cuandodicesprint(name),Pythonvaa"imprimir"elcontenidodelavariablealapantalla,sinlascomillas,queesmejor.
Comoveremosdespués,print()tambiénesútilcuandoqueremosimprimircosasdesdeadentrodelasfunciones,obiencuandoqueremosimprimircosasenmúltipleslíneas.
ListasAdemásdestringeintegers,Pythontienetodaclasedediferentestiposdeobjetos.Ahoravamosaintroducirunollamadolist.Laslistassonexactamenteloquepiensasqueson:sonobjetosquesonlistasdeotrosobjetos:)
Anímateycreaunalista:
>>>[]
[]
Sí,estalistaestávacía.Noesmuyútil,¿verdad?Vamosacrearunalistadenúmerosdelotería.Noqueremosrepetirtodoeltiempo,asíquelospondremosenunavariabletambién:
>>>lottery=[3,42,12,19,30,59]
Muybien,¡tenemosunalista!¿Quépodemoshacerconella?Vamosavercuántosnúmerosdeloteríahayenlalista.¿Tienesalgunaideadequéfuncióndeberíasusarparaeso?¡Yasabesesto!
>>>len(lottery)
6
¡Sí!len()puededarteelnúmerodeobjetosenunalista.Útil,¿verdad?Talvezlaordenemosahora:
DjangoGirlsTutorial
29IntroducciónaPython
>>>lottery.sort()
Estonodevuelvenada,sólocambióelordenenquelosnúmerosaparecenenlalista.Vamosaimprimirlalistaotravezyverquepasó:
>>>print(lottery)
[3,12,19,30,42,59]
Comopuedesver,losnúmerosentulistaahoraestánordenadosdemenoramayor.¡Felicidades!
¿Tegustaríainvertireseorden?¡Vamosahacerlo!
>>>lottery.reverse()
>>>print(lottery)
[59,42,30,19,12,3]
Fácil,¿no?Siquieresañadiralgoatulista,puedeshacerloescribiendoestecomando:
>>>lottery.append(199)
>>>print(lottery)
[59,42,30,19,12,3,199]
Sideseasmostrarsóloelprimernúmero,puedeshacerlomedianteelusodeindexes(enespañol,índices).Uníndiceeselnúmeroquetedicedóndeenunalistaapareceunítem.Lacomputadorainicialacuentaen0,asíqueelprimerobjetoentulistaestáenelíndice0,elsiguientees1,yasísucesivamente.Intentaesto:
>>>print(lottery[0])
59
>>>print(lottery[1])
42
Comopuedesver,puedesaccederadiferentesobjetosentulistautilizandoelnombredelalistayelíndicedelobjetodentrodecorchetes.
Paradiversiónadicional,pruebaalgunosotrosíndices:6,7,1000,-1,-6ó-1000.Aversisepuedespredecirelresultadoantesdeintentarelcomando.¿Tienensentidolosresultados?
PuedesencontrarunalistadetodoslosmétodosdisponiblesparalistasenestecapítulodeladocumentacióndePython:https://docs.python.org/3/tutorial/datastructures.html
DjangoGirlsTutorial
30IntroducciónaPython
DiccionariosUndiccionarioessimilaraunalista,peroaccedesavaloresusandounaclaveenvezdeuníndice.Unaclavepuedesercualquiercadenaonúmero.Lasintaxisparadefinirundiccionariovacíoes:
>>>{}
{}
Estodemuestraqueacabasdecrearundiccionariovacío.¡Hurra!
Ahora,trataescribiendoelsiguientecomando(intentareemplazandoconpropiainformación):
>>>participant={'name':'Ola','country':'Poland','favorite_numbers':[7,42,92]}
Conestecomando,acabasdecrearunavariableparticipantcontresparesclave-valor:
Laclavenameapuntaalvalor'Ola'(unobjetostring),countryapuntaa'Poland'(otrostring),yfavorite_numbersapuntaa[7,42,92](unalistcontresnúmerosenella).
Puedesverificarelcontenidodeclavesindividualesconestasintaxis:
>>>print(participant['name'])
Ola
Loves,essimilaraunalista.Perononecesitasrecordarelíndice-sóloelnombre.
¿QuépasasilepedimosaPythonelvalordeunaclavequenoexiste?¿Puedesadivinar?¡Pruébaloyverás!
>>>participant['age']
Traceback(mostrecentcalllast):
File"<stdin>",line1,in<module>
KeyError:'age'
¡Mira,otroerror!EsteesunKeyError.Pythonteayudaytedicequelallave'age'noexisteenestediccionario.
¿Cuándoutilizarundiccionarioounalista?Bueno,esoesunbuenpuntoparareflexionar.Sólotenunasoluciónenmenteantesdemirarlarespuestaenlasiguientelínea.
DjangoGirlsTutorial
31IntroducciónaPython
¿Sólonecesitasunasecuenciaordenadadeelementos?Usaunalista.¿Necesitasasociarvaloresconclaves,asípuedesbuscarloseficientemente(usandolasclaves)másadelante?Utilizaundiccionario.
Losdiccionarios,comolaslistas,sonmutables,loquesignificaquepuedensercambiadosdespuésdesercreados.Puedesagregarnuevosparesclave/valoreneldiccionariodespuésdequehasidocreado,porejemplo:
>>>participant['favorite_language']='Python'
Comoenlaslistas,elmétodolen()enlosdiccionarios,devuelveelnúmerodeparesclave-valoreneldiccionario.Adelante,escribeelcomando:
>>>len(participant)
4
Esperotengasentidohastaahora.:)¿Listaparamásdiversiónconlosdiccionarios?Saltaalasiguientelíneaparaalgunascosassorprendentes.
Puedesutilizarelcomandodelparaborrarunelementoeneldiccionario.Porejemplo,sideseaseliminarlaentradacorrespondientealaclave'favorite_numbers',sólotienesqueescribirelsiguientecomando:
>>>delparticipant['favorite_numbers']
>>>participant
{'country':'Poland','favorite_language':'Python','name':'Ola'}
Comopuedesverenlasalida,elpardeclave-valorcorrespondientealaclave'favorite_numbers'hasidoeliminado.
Ademásdeesto,tambiénpuedescambiarunvalorasociadoaunaclaveyacreadaeneldiccionario.Teclea:
>>>participant['country']='Germany'
>>>participant
{'country':'Germany','favorite_language':'Python','name':'Ola'}
Comopuedesver,elvalordelaclave'country'hasidomodificadode'Poland'a'Germany'.:)¿Emocionante?¡Hurra!Hasaprendidootracosaasombrosa.
Resumen
DjangoGirlsTutorial
32IntroducciónaPython
¡Genial!Sabesmuchosobreprogramaciónahora.Enestaúltimaparteaprendistesobre:
errors-ahorasabescómoleeryentenderloserroresqueaparecensiPythonnoentiendeuncomandoquelehasdadovariables-nombresparalosobjetosquetepermitencodificarmásfácilmenteyhacerelcódigomáslegiblelists-listasdeobjetosalmacenadosenunordendeterminadodictionaries-objetosalmacenadoscomoparesclave-valor
¿Emocionadaporlasiguienteparte?:)
ComparacosasUnagranpartedelaprogramaciónincluyecompararcosas.¿Quéeslomásfácilparacomparar?Números,porsupuesto.Vamosavercómofunciona:
>>>5>2
True
>>>3<1
False
>>>5>2*2
True
>>>1==1
True
>>>5!=2
True
LedimosaPythonalgunosnúmerosparacomparar.Comopuedesver,Pythonnosólopuedecompararnúmeros,sinoquetambiénpuedecompararresultadosdemétodo.Bien,¿eh?
¿Tepreguntasporquépusimosdossignosigual==alladodelotroparacompararsilosnúmerossoniguales?Utilizamosunsolo=paraasignarvaloresalasvariables.Siempre,siempreesnecesarioponerdos==Sideseascomprobarquelascosassonigualesentresí.Tambiénpodemosafirmarquelascosasnosonigualesaotras.Paraeso,utilizamoselsímbolo!=,comomostramosenelejemploanterior.
DadostareasmásaPython:
>>>6>=12/2
True
>>>3<=2
False
DjangoGirlsTutorial
33IntroducciónaPython
>y<sonfáciles,pero¿quéessignifica>=y<=?Seleenasí:
x>ysignifica:xesmayorqueyx<ysignifica:xesmenorqueyx<=ysignifica:xesmenoroigualqueyx>=ysignifica:xesmayoroigualquey
¡Genial!¿Quiereshacerunomas?Intentaesto:
>>>6>2and2<3
True
>>>3>2and2<1
False
>>>3>2or2<1
True
PuedesdarleaPythontodoslosnúmerosparacompararquequieras,ysiempretedaráunarespuesta.Muyinteligente,¿verdad?
and-siutilizaseloperadorand,ambascomparacionesdebenserTrueparaqueelresultadodetodoelcomandoseaTrueor-siutilizaseloperadoror,sólounadelascomparacionestienequeserTrueparaqueelresultadodetodoelcomandoseaTrue
¿Hasoídolaexpresión"compararmanzanasconnaranjas"?VamosaprobarelequivalenteenPython:
>>>1>'django'
Traceback(mostrecentcalllast):
File"<stdin>",line1,in<module>
TypeError:unorderabletypes:int()>str()
Aquíverásquealigualqueenlaexpresión,Pythonnoescapazdecompararunnúmero(int)yunstring(str).Encambio,muestraunTypeErrorynosdicequelosdostiposnosepuedencomparados.
BooleanPorcierto,acabasdeaprenderacercadeunnuevotipodeobjetoenPython.SellamaunBoolean--yesprobablementeeltipomássimplequeexiste.
HaysólodosobjetosBoolean:-True-False
DjangoGirlsTutorial
34IntroducciónaPython
PeroparaquePythonentiendaesto,esnecesarioquesiempreloescribascomoTrue(primeraletramayúscula,conelrestodelaletrasminúsculas).true,TRUE,tRUEnofuncionarán--sóloTrueescorrecto.(LomismoaplicaaFalsetambién,porsupuesto.)
Losvaloresbooleanospuedenservariables,también.Veelsiguienteejemplo:
>>>a=True
>>>a
True
Tambiénpuedeshacerlodeestamanera:
>>>a=2>5
>>>a
False
Practicaydiviérteteconlosbooleanosejecutandolossiguientescomandos:
TrueandTrue
FalseandTrue
Trueor1==1
1!=2
¡Felicidades!Losbooleanossonunadelasfuncionesmásgenialesenprogramaciónyacabasdeaprendercómousarlos.
¡Guárdalo!HastaahorahemosestadoescribiendonuestrocódigoPythonenelintérprete,locualnoslimitaaunalíneadecódigoalavez.Normalmentelosprogramassonguardadosenarchivosysonejecutadosporelintérpreteocompiladordenuestrolenguajedeprogramación.Hastaahora,hemosestadocorriendonuestrosprogramasdeaunalíneaporvezenelintérpretedePython.Necesitaremosmásdeunalíneadecódigoparalassiguientestareas,entoncesnecesitaremoshacerrápidamenteloquesigue:
SalirdelintérpretedePythonAbrireleditordetextodenuestraelecciónGuardaralgodecódigoenunnuevoarchivodePython¡Ejecutarlo!
ParasalirdelintérpretedePythonquehemosestadousando,simplementeescribelafunciónexit():
DjangoGirlsTutorial
35IntroducciónaPython
>>>exit()
$
Estotellevarádevueltaalalíneadecomandos.
Anteriormente,elegimosuneditordecódigoenlaseccióndeEditordecódigo.Tendremosqueabrireleditorahorayescribiralgodecódigoenunarchivonuevo:
print('Hello,Djangogirls!')
NotaDeberíasnotarunadelascosasmásgenialesdeloseditoresdecódigo:¡loscolores!EnlaconsoladePython,todoeradelmismocolor,peroahorapuedesverquelafunciónprintesdeuncolordiferentedelstringqueestáadentrodeella.Esosedenomina"resaltadodesintaxis",yesunagranayudacuandoestásprogramando.Prestaatenciónaloscolores,yobtendrásunapistacuandoteolvidesdecerrarunstringocometesunerroralescribirunapalabraclave(comoeldefenunafunción,queveremosabajo).Estaesunadelasrazonesporlascualesusaruneditordecódigo:)
Obviamente,ahoraeresunadesarrolladoraPythonmuyexperimentada,asíquesiéntetelibredeescribiralgodelcódigoquehasaprendidohoy.
Ahoratenemosqueguardarelarchivoyasignarleunnombredescriptivo.Vamosallamaralarchivopython_intro.pyyguardarloentuescritorio.Podemosnombrarelarchivodecualquiermaneraquequeramos,loimportanteaquíesasegurarsequeelarchivofinalicecon.py,estoleindicaanuestracomputadoraqueesteesunarchivoejecutabledePythonyquePythonpuedecorrerlo.
Conelarchivoguardado,¡eshoradeejecutarlo!Utilizandolashabilidadesquehasaprendidoenlaseccióndelíneadecomandos,utilizalaterminalparacambiarlosdirectorioseiralescritorio.
EnunaMac,elcomandoseveráalgocomoesto:
cd/Users/<your_name>/Desktop
EnLinux,vaaserasí(lapalabra"Desktop"puedeestartraducidaatuidioma):
cd/home/<your_name>/Desktop
YenWindows,seráasí:
DjangoGirlsTutorial
36IntroducciónaPython
cdC:\Users\<your_name>\Desktop
Sitequedasatascada,sólopideayuda.
yluegousaPythonparaejecutarelcódigoenelarchivocomosigue:
$python3python_intro.py
Hello,Djangogirls!
¡Muybien!EjecutastetuprimerprogramadePythondesdeunarchivo.¿Nosesienteincreíble?
Ahorapuedesmoverteaunaherramientaesencialenlaprogramación:
If...elif...elseUnmontóndecosasenelcódigosólosonejecutadascuandosecumplenlascondicionesdadas.PoresoPythontienealgollamadosentenciasif.
Reemplazaelcódigoentuarchivopython_intro.pyporesto:
if3>2:
Siloguardáramosyloejecutáramos,veríamosunerrorcomoeste:
$python3python_intro.py
File"python_intro.py",line2
^
SyntaxError:unexpectedEOFwhileparsing
Pythonesperaqueledemosmásinstruccionesquesesuponeseránejecutadassilacondición3>2resultaserverdadera(oTrueenestecaso).IntentemoshacerquePythonimprima"Itworks!".Cambiatucódigoenelarchivopython_intro.pyparaqueseveacomoesto:
if3>2:
print('Itworks!')
¿Observascómohemosindentadolasiguientelíneadecódigocon4espacios?TenemosquehacerestoparaquePythonsepaquécódigoejecutarsilacomparaciónresultaverdadera.Puedesponerunespacio,perocasitodoslosprogramadoresPythonhacen4
DjangoGirlsTutorial
37IntroducciónaPython
espaciosparahacerqueelcódigoseamáslegible.Unsolotabtambiéncontarácomo4espacios.
Guárdaloyejecútalodenuevo:
$python3python_intro.py
Itworks!
¿Quépasasilacondiciónnoesverdadera?
Enejemplosanteriores,elcódigofueejecutadosólocuandolascondicioneseranciertas.PeroPythontambiéntienedeclaracioneselifyelse:
if5>2:
print('5isindeedgreaterthan2')
else:
print('5isnotgreaterthan2')
Alejecutarestoseimprimirá:
$python3python_intro.py
5isindeedgreaterthan2
Si2fueraunnúmeromayorque5,entonceselsegundocomandoseríaejecutado.Fácil,¿verdad?Vamosavercómofuncionaelif:
name='Sonja'
ifname=='Ola':
print('HeyOla!')
elifname=='Sonja':
print('HeySonja!')
else:
print('Heyanonymous!')
yalejecutarlo:
$python3python_intro.py
HeySonja!
¿Vesloquepasóahí?
Resumen
DjangoGirlsTutorial
38IntroducciónaPython
Enlosúltimostresejerciciosaprendisteacercade:
Compararcosas-enPythonpuedescompararcosashaciendousode>,>=,==,<=,<ydelosoperatoresandyorBoolean-untipodeobjetoquesólopuedetenerunodedosvalores:TrueoFalseGuardararchivos-cómoalmacenarcódigoenarchivosasípuedesejecutarprogramasmásgrandesif...elif...else-sentenciasquetepermitenejecutarcódigosólocuandosecumplenciertascondiciones
¡Eshoradeleerlaúltimapartedeestecapítulo!
¡Tuspropiasfunciones!¿Recuerdaslasfuncionescomolen()quepuedesejecutarenPython?Bien,buenasnoticias,¡ahoraaprenderáscómoescribirtuspropiasfunciones!
UnafunciónesunasecuenciadeinstruccionesquePythondebeejecutar.CadafunciónenPythoncomienzaconlapalabraclavedef,seleasignaunnombreypuedeteneralgunosparámetros.Vamosaempezarconalgofácil.Reemplazaelcódigoenpython_intro.pyconlosiguiente:
defhi():
print('Hithere!')
print('Howareyou?')
hi()
Bien,¡nuestraprimerafunciónestálista!
Tepreguntarásporquéhemosescritoelnombredelafunciónenlaparteinferiordelarchivo.EstoesporquePythonleeelarchivoyloejecutadesdearribahaciaabajo.Asíqueparapoderutilizarnuestrafunción,tenemosquereescribirsunombreenlaparteinferior.
Ejecutemosestoyveamosquésucede:
$python3python_intro.py
Hithere!
Howareyou?
¡Esofuefácil!Vamosaconstruirnuestraprimerafunciónconparámetros.Utilizaremoselejemploanterior-unafunciónquedice'Hi'alapersonaqueejecutaelprograma-conunnombre:
DjangoGirlsTutorial
39IntroducciónaPython
defhi(name):
Comopuedesver,ahoradimosanuestrafunciónunparámetroquellamamosname:
defhi(name):
ifname=='Ola':
print('HiOla!')
elifname=='Sonja':
print('HiSonja!')
else:
print('Hianonymous!')
hi()
Comopuedesnotar,tuvimosqueponerdosindentacionesantesdelafunciónprintporqueifnecesitasaberloquedeberíaocurrircuandosecumplelacondición.Vamosavercómofunciona:
$python3python_intro.py
Traceback(mostrecentcalllast):
File"python_intro.py",line10,in<module>
hi()
TypeError:hi()missing1requiredpositionalargument:'name'
Oops,unerror.Porsuerte,Pythonnosdaunmensajedeerrorbastanteútil.Nosdicequelafunciónhi()(laquedefinimos)tieneunargumentorequerido(llamadoname)yquesenosolvidópasarloalllamaralafunción.Vamosaarreglarloenlaparteinferiordelarchivo:
hi("Ola")
yloejecutamosotravez:
$python3python_intro.py
HiOla!
¿Ysicambiamoselnombre?
hi("Sonja")
ylocorremos:
DjangoGirlsTutorial
40IntroducciónaPython
$python3python_intro.py
HiSonja!
Ahora,¿quécreesquepasarásiescribesotronombreallí?(NoOlaoSonja).Pruébaloyverássitienesrazón.Estodeberíaimprimir:
Hianonymous!
Estoesincreíble,¿verdad?Deestaformanotienesquerepetirtodocadavezquedeseascambiarelnombredelapersonaalaquelafuncióndeberíasaludar.Yesoesexactamenteporquénecesitamosfunciones-¡paranorepetirtucódigo!
Vamosahaceralgomásinteligente-haymásdedosnombres,yescribirunacondiciónparacadaunoseríadifícil,¿no?
defhi(name):
print('Hi'+name+'!')
hi("Rachel")
Ahoravamosallamaralcódigo:
$python3python_intro.py
HiRachel!
¡Felicidades!Acabasdeaprendercómoescribirfunciones:)
BuclesEstayaeslaúltimaparte.¿Esofuerápido,verdad?:)
Comohemosmencionado,losprogramadoressonperezosos,nolesgustarepetircosas.Laprogramaciónintentaautomatizarlascosas,asíquenoqueremossaludaracadapersonaporsunombremanualmente,¿verdad?Esahídondelosbuclessevuelvenmuyútiles.
¿Todavíarecuerdaslaslistas?Hagamosunalistadelaschicas:
girls=['Rachel','Monica','Phoebe','Ola','You']
Queremossaludaratodasellasporsunombre.Tenemoslafunciónhiquehaceeso,asíquevamosausarlaenunbucle:
DjangoGirlsTutorial
41IntroducciónaPython
fornameingirls:
Lasentenciaforsecomportademanerasimilaralasentenciaif,elcódigoquesiguecontinuacióndebeestarindentadousandocuatroespacios.
Aquíestáelcódigocompletoqueestaráenelarchivo:
defhi(name):
print('Hi'+name+'!')
girls=['Rachel','Monica','Phoebe','Ola','You']
fornameingirls:
hi(name)
print('Nextgirl')
ycuandoloejecutamos:
$python3python_intro.py
HiRachel!
Nextgirl
HiMonica!
Nextgirl
HiPhoebe!
Nextgirl
HiOla!
Nextgirl
HiYou!
Nextgirl
Comopuedesver,todoloqueponesconunaindentacióndentrodeunasentenciaforserárepetidoparacadaelementodelalistagirls.
Tambiénpuedesusarelforennúmerosusandolafunciónrange:
foriinrange(1,6):
print(i)
Loqueimprimirá:
1
2
3
4
5
DjangoGirlsTutorial
42IntroducciónaPython
rangeesunafunciónquecreaunalistadenúmerosenserie(estosnúmerossonproporcionadosporticomoparámetros).
TenencuentaqueelsegundodeestosdosnúmerosnoseráincluidoenlalistaqueretornaráPython(esdecir,range(1,6)cuentadesde1a5,peronoincluyeelnúmero6).
ResumenEsoestodo.¡Eresgenial!Estonofuetanfácilrealmente,asíquedeberíassentirteorgullosadetimisma.¡Estamosmuyorgullososdequehayasllegadohastaaquí!
Talvezquierashaceralgodistintoporunmomento-estirarte,caminarunpoco,descansartusojos-antesdepasaralsiguientecapítulo.:)
DjangoGirlsTutorial
43IntroducciónaPython
¿QuéesDjango?Django(gdh/ˈdʒæŋɡoʊ/jang-goh)esunframeworkparaaplicacioneswebgratuitoyopensource,escritoenPython.EsunWEBframework-unconjuntodecomponentesqueteayudanadesarrollarsitioswebmásfácilyrápidamente.
Verás,cuandoestásconstruyendounsitioweb,frecuentementenecesitasunconjuntodecomponentessimilares:unamanerademanejarlaautenticacióndeusuarios(registrarse,iniciarsesión,cerrarsesión),unpaneldeadministraciónparatusitioweb,formularios,unaformadesubirarchivos,etc.
Porsuerteparati,hacetiempovariaspersonasnotaronquelosdesarrolladoreswebenfrentanproblemassimilarescuandoconstruyenunsitionuevo,poresojuntaroncabezasycrearonframeworks(Djangoesunodeellos)queteofrecencomponenteslistosparausarse.
Losframeworksexistenparaahorrartetenerquereinventarlaruedayayudarteaaliviarlacargacuandoconstruyesunsitio.
¿Porquénecesitasunframework?ParaentenderparaqueesDjango,necesitamosmirarmasdecercaalosservidores.Loprimeroesqueelservidornecesitasaberquequieresquetesirvaunapáginaweb.
Imaginaunbuzón(puerto)elcualesmonitoreadoporcartasentrantes(peticiones).Estoesrealizadoporunservidorweb.Elservidorwebleelacarta,yenvíaunarespuestaconunapáginaweb.Perocuandoquieresenviaralgo,tienesqueteneralgúncontenido.YDjangoesalgoqueteayudaacrearelcontenido.
¿Quésucedecuandoalguiensolicitaunapáginawebdetuservidor?CuandollegaunapeticiónaunservidorwebespasadoaDjangoqueintentaaveriguarloquerealmenteessolicitado.Tomaprimerounadireccióndepáginawebytratadeaveriguarquéhacer.EstaparteesrealizadaporurlresolverdeDjango(tengaencuentaqueladireccióndeunsitiowebesllamadaURL-UniformResourceLocator-asíqueelnombre
DjangoGirlsTutorial
44¿QuéesDjango?
urlresolvertienesentido).Estenoesmuyinteligente-tomaunalistadepatronesytratadeigualarlaURL.DjangocompruebalospatronesdearribahaciaabajoysialgosecoincideentoncesDjangolepasalasolicitudalafunciónasociada(quesellamavista).
Imaginaauncarterollevandounacarta.Ellaestácaminandoporlacalleycompruebacadanúmerodecasaconelqueestáenlacarta.Sicoincide,elladejalacartaallí.Asíescomofuncionaelurlresolver!
Enlafuncióndevistasehacentodaslascosasinteresantes:podemosmiraraunabasededatosparabuscaralgunainformación.¿Talvezelusuariopidiócambiaralgoenlosdatos?Comounacartadiciendo"Porfavorcambialadescripcióndemitrabajo."Lavistapuedecomprobarsitenespermitidohacereso,entoncesactualizarladescripcióndeltrabajoparaustedydevolverleunmensaje:"¡hecho!".EntonceslavistageneraunarespuestayDjangopuedeenviarlaalnavegadordelusuario.
Porsupuesto,ladescripciónanteriorsesimplificaunpoco,perononecesitassabertodaslascosastécnicasaun.Tenerunaideageneralessuficiente.
Asíqueenlugardemeternosdemasiadoenlosdetalles,simplementecomenzaremoscreandoalgoconDjangoyaprenderemostodaslaspiezasimportantesenelcamino!
DjangoGirlsTutorial
45¿QuéesDjango?
InstalacióndeDjangoPartedeestecapituloestabasadoenlostutorialesdeGeekGirlsCarrots(http://django.carrots.pl/).
Partedeestecapítulosebasaeneldjango-marcadortutorialbajolicenciadeCreativeCommonsAttribution-ShareAlike4.0internacional.Eltutorialdedjango-marcadortienederechosdeautordeMarkusZapke-Gündemannetal.
EntornovirtualAntesdeinstalarDjango,instalaremosunaherramientaextremadamenteútilqueayudaráamantenertuentornodedesarrolloordenadoensucomputadora.Esposibleomitirestepaso,peroesmuyrecomendablenohacerlo-¡comenzarconlamejorconfiguraciónposibleayudaraaevitarmuchosproblemasenelfuturo!
Asíque,vamosacrearunentornovirtual(tambiénllamadounvirtualenv).AislarálaconfiguraciónPython/Djangoenbasedecadaproyecto,loquesignificaquecualquiercambioquerealiceenunsitiowebnoafectaráaotrosquetambiénestésdesarrollando.Genial,¿no?
Todoloquenecesitashaceresencontrarundirectorioenelquedeseescrearelvirtualenv;tudirectoriohome,porejemplo.EnWindowspuedeversecomoC:\Users\Name(dondenombreeselnombredetuusuario).
Paraestetutorialusaremosunnuevodirectoriodjangogirlsentudirectoriohome:
mkdirdjangogirls
cddjangogirls
Haremosunvirtualenvllamadomyvenv.Elcomandogeneralestaráenelformato:
python3-mvenvmyvenv
Windows
Paracrearunnuevovirtualenv,debesabrirlaconsola(teloindicamosunoscuantoscapítulosantes,¿recuerdas?)yejecutaC:\Python34\python-mvenvmyvenv.Severáasí:
DjangoGirlsTutorial
46InstalacióndeDjango
C:\Users\Name\djangogirls>C:\Python34\python-mvenvmyvenv
endondeC:\Python34\pythoneseldirectorioenelqueinstalastePythonpreviamenteymyvenveselnombredetuvirtualenv.Puedesutilizarcualquierotronombre,peroasegúratedeusarminúsculasynodejarespacios,acentosocaracteresespeciales.Tambiénesunabuenaideamantenerelnombrecorto.¡Vasareferirteaélmucho!
LinuxyOSX
CrearunvirtualenvenLinuxyOSXestansimplecomoejecutarpython3-mvenvmyvenv.Severáasí:
~/djangogirls$python3-mvenvmyvenv
myvenveselnombredetuvirtualenv.Puedesusarcualquierotronombre,peromanténelusodeminúsculasynoincluyasespacios.Tambiénesunabuenaideamantenerelnombrecorto.¡Vasareferirteaélmucho!
Nota:Actualmente,iniciarelentornovirtualenUbuntu14.04deestamaneraproduceelsiguienteerror:
Error:Command'['/home/eddie/Slask/tmp/venv/bin/python3','-Im','ensurepip','--upgrade','--default-pip']'returnednon-zeroexitstatus1
Paraevitaresto,utilizadirectamenteelcomandovirtualenv.
~/djangogirls$sudoapt-getinstallpython-virtualenv
~/djangogirls$virtualenv--python=python3.4myvenv
TrabajarconvirtualenvEstecomandoanteriorcrearáundirectoriollamadomyvenv(ocualquiernombrequehayasescogido)quecontienenuestroentornovirtual(básicamenteunmontóndearchivosycarpetas).Todoloquequeremoshacerahoraesiniciarloejecutando:
C:\Users\Name\djangogirls>myvenv\Scripts\activate
enWindows,o:
DjangoGirlsTutorial
47InstalacióndeDjango
~/djangogirls$sourcemyvenv/bin/activate
enOSXyLinux.
¡Recuerdareemplazarmyvenvcontunombredevirtualenvquehayaselegido!
Nota:aveceslafuentepodríanoestardisponible.Enesoscasostratadehacerloesto:
~/djangogirls$.myvenv/bin/activate
Sabrásquetienesvirtualenviniciadocuandoveasquepareceestemensajeenlaconsola:
(myvenv)C:\Users\Name\djangogirls>
o:
(myvenv)~/djangogirls$
¡Notaqueelprefijo(myvenv)aparece!
Cuandotrabajesenunentornovirtual,pythonautomáticamentesereferiráalaversióncorrecta,demodoquepuedesutilizarpythonenvezdepython3.
Tenemostodaslasdependenciasimportantesensulugar.¡FinalmentepodemosinstalarDjango!
InstalarDjangoAhoraquetienestuvirtualenviniciado,puedesinstalarDjangousandopip.Enlaconsola,ejecutapipinstalldjango==1.8(fíjatequeutilizamosundoblesignoigual:==).
(myvenv)~$pipinstalldjango==1.8
Downloading/unpackingdjango==1.8
Installingcollectedpackages:django
Successfullyinstalleddjango
Cleaningup...
EnWindows
DjangoGirlsTutorial
48InstalacióndeDjango
SiobtienesunerroralejecutarpipenWindowscompruebasilarutadetuproyectocontieneespacios,acentosocaracteresespeciales(porejemplo,C:\Users\UserName\djangogirls).Silotiene,porfavorconsideramoverlaaotrolugarsinespacios,acentosocaracteresespeciales(sugerencia:C:\djangogirls).Despuésdehacerloejecutanuevamenteelcomandoanterior.
enLinux
SiobtienesunerroralcorrerpipenUbuntu12.04ejecutapython-mpipinstall-U-force-resintallpipparaarreglarlainstalacióndepipenelvirtualenv.
Esoestodo!Ahoraestáslisto(porfin)paracrearunaaplicaciónDjango!
DjangoGirlsTutorial
49InstalacióndeDjango
¡TuprimerproyectoenDjango!PartedeestecapituloestabasadoenlostutorialesdeGeekGirlsCarrots(http://django.carrots.pl/).
Partedeestecapítulosebasaeneldjango-marcadortutorialbajolicenciadeCreativeCommonsAttribution-ShareAlike4.0internacional.Eltutorialdedjango-marcadortienederechosdeautordeMarkusZapke-Gündemannetal.
Vamosacrearunsimpleblog!
ElprimerpasoparacrearloesparainiciarunnuevoproyectoenDjango.Básicamente,estosignificaquepodráscorreralgunosscriptsproporcionadosporDjangoquecrearánelesqueletodeunproyectoparanosotros:unmontóndedirectoriosyarchivosquevamosautilizarmásadelante.
LosnombresdealgunosarchivosydirectoriossonmuyimportantesparaDjango.Nodeberíasrenombrarlosarchivosqueestamosapuntodecrear.Moverlosaunlugardiferentetampocoesunabuenaidea.Djangotienequemantenerunaciertaestructuraparasercapazdeencontrarcosasimportantes.
Recuerdacorrertodoenelvirtualenv.Sinovesunprefijo(myvenv)entuconsolanecesitasactivartuvirtualenv.ExplicamoscómohaceresoenelcapítulodeInstalacióndeDjangoenlasecciónTrabajandoconvirtualenv.Puedeshacerloescribiendoelsiguientecomando:myvenv\Scripts\activateenWindowsomyvenv/bin/activateenMacOS/Linux.
NotaControladosvecesqueincluisteelpunto(.)alfinaldelcomando,esimportanteporqueledicealscriptqueinstaleDjangoeneldirectorioactual.
Enlaconsoladebesejecutar(recuerdanoescribir(myvenv)~/djangogirls$,¿ok?):
(myvenv)~/djangogirls$django-adminstartprojectmysite.
EnWindows:
(myvenv)C:\Users\Name\djangogirls>django-admin.pystartprojectmysite.
django-admin.pyesunscriptquecrearálosarchivosydirectoriosparati.Ahoradeberíastenerunaestructuradedirectoriosparecidaaesto:
DjangoGirlsTutorial
50ComenzarunproyectoenDjango
djangogirls
├───manage.py
└───mysite
settings.py
urls.py
wsgi.py
__init__.py
manage.pyesunscriptqueayudaconlaadministracióndelsitio.Conellopodremosiniciarunservidorwebennuestroordenadorsinnecesidaddeinstalarnadamás,entreotrascosas.
Elarchivosettings.pycontienelaconfiguracióndetusitioweb.
¿Recuerdascuandohablamosdeuncarteroquedebíacomprobardondeentregarunacarta?Elarchivourls.pycontieneunalistadelospatronesutilizadosporurlresolver.
Ignoremoslosotrosarchivosporahora-noloscambiaremos.¡Loúnicoquedebesrecordaresnoborrarlosporaccidente!
CambiandolaconfiguraciónVamosahaceralgunoscambiosenmysite/settings.py.Abreelarchivousandoeleditordecódigoquehasinstaladoanteriormente.
Seríabuenotenerelhorariocorrectoennuestrositioweb.VealalistadehusoshorariosdeWikipediaycopiatuzonahoraria(TZ).(porejemplo,Europe/Berlin)
Ensettings.py,encuentralalíneaquecontieneTIME_ZONEymodifícalaparaelegirtupropiazonahoraria:
TIME_ZONE='Europe/Berlin'
Modificando"Europe/Berlin"comocorresponda
Tambiénnecesitaremosagregarunarutaparalosarchivosestáticos(aprenderemostodosobrelosarchivosestáticosyCSSmástardeenestetutorial).Vehaciaabajohastaelfinaldelarchivo,yjustopordebajodelaentradaSTATIC_URL,agregaunanuevallamadaSTATIC_ROOT:
STATIC_URL='/static/'
STATIC_ROOT=os.path.join(BASE_DIR,'static')
DjangoGirlsTutorial
51ComenzarunproyectoenDjango
ConfigurarunabasededatosHayunagranvariedaddeopcionesdebasesdedatosparaalmacenarlosdatosdetusitio.Utilizaremoselquevienepordefecto,sqlite3.
Estoyaestáconfiguradoenestapartedetuarchivomysite/settings.py:
DATABASES={
'default':{
'ENGINE':'django.db.backends.sqlite3',
'NAME':os.path.join(BASE_DIR,'db.sqlite3'),
}
}
Paracrearunabasededatosparanuestroblog,ejecutemoslosiguienteenlaconsola:pythonmanage.pymigrate(necesitamosestareneldirectoriodedjangogirlsquecontieneelarchivomanage.py).Siesovabien,deberíasveralgoasí:
(myvenv)~/djangogirls$pythonmanage.pymigrate
Operationstoperform:
Applyallmigrations:admin,contenttypes,auth,sessions
Runningmigrations:
Applyingcontenttypes.0001_initial...OK
Applyingauth.0001_initial...OK
Applyingadmin.0001_initial...OK
Applyingsessions.0001_initial...OK
¡Ylisto!¡Eshoradeiniciarelservidorwebyversinuestrositiowebestáfuncionando!
Debesestareneldirectorioquecontieneelarchivomanage.py(enlacarpetadjangogirls).Enlaconsola,podemosiniciarelservidorwebejecutandopythonmanage.pyrunserver:
(myvenv)~/djangogirls$pythonmanage.pyrunserver
Ahoratodoloquedebeshacerescontrolarquetusitioestécorriendo-abretunavegador(Firefox,Chrome,Safari,InternetExploreroelqueutilices)eingresaladirección:
http://127.0.0.1:8000/
Elservidorwebseapropiarádetuconsolahastaqueloterminesmanualmente:paratipearmáscomandosoabresunanuevaterminal(ynoteolvidesdeactivartuvirtualenvallítambién),ofrenaelservidorwebyendoalaconsolaenlaqueestácorriendoypresionando
DjangoGirlsTutorial
52ComenzarunproyectoenDjango
Ctrl+C-lasteclasControlyCjuntas(enWindows,deberáspresionarCtrl+Break).
¡Felicitaciones!¡Hascreadotuprimersitiowebylohasejecutadousandounservidorweb!¿Noesgenial?
¿Listaparaelpróximopaso?¡Esmomentodecrearalgodecontenido!
DjangoGirlsTutorial
53ComenzarunproyectoenDjango
ModelosenDjangoLoquequeremoscrearahoraesalgoquevaaalmacenartodoslospostsennuestroblog.Peroparapoderhacerlotenemosquehablarunpocodeacercadealgollamadoobjetos.
ObjetosHayunconceptoenelmundodelaprogramaciónllamadoprogramaciónorientadaaobjetos.Laideaesqueenlugardeescribirtodocomounaaburridasecuenciadeinstruccionesdeprogramaciónpodemosmodelarcosasydefinircómointeractúanconlasdemás.
Entonces¿Quéesunobjeto?Esunconjuntodepropiedadesyacciones.Suenararo,perotedaremosunejemplo.
SiqueremosunmodelarungatocrearemosunobjetoGatoquetienealgunaspropiedades,comosonporejemplocolor,edad,estadodeánimo(esdecir,bueno,malo,sueño;)),dueño(queesunobjetoPersonao,talvez,enelcasodequeelgatoseacallejero,estapropiedadestarávacía).
YluegoelGatotienealgunasacciones:ronronear,rasguñaroalimentarse(enlacualdaremosalgatoalgunosComidaDeGato,quepodríaserunobjetoindependienteconpropiedades,comoporejemplo,sabor).
Gato
---------
color
edad
humor
dueño
ronronear()
rasguñar()
alimentarse(comida_de_gato)
ComidaDeGato
----------
sabor
Básicamentesetratadedescribircosasrealesenelcódigoconpropiedades(llamadaspropiedadesdelobjeto)ylasacciones(llamadasmétodos).
Yahora,¿cómomodelamoslospostsenelblog?Queremosconstruirunblog,¿no?
DjangoGirlsTutorial
54ModelosenDjango
Tenemosprimeroqueresponderalgunaspreguntas:¿Quéesunpostdeunblog?¿Quécaracterísticasdebetener?
Bueno,seguroquenuestrospostsnecesitanuntextoconsucontenidoyuntítulo,¿cierto?Tambiénseríabuenosaberquiénloescribió,asíquenecesitamosunautor.Porúltimo,queremossabercuándoelpostfuecreadoypublicado.
Post
--------
title
text
author
created_date
published_date
¿Quétipodecosaspodríahacerseconunaentradadelblog?Seríabuenoteneralgúnmétodoquepubliquelaentrada,¿no?
Asíquevamosanecesitarelmétodopublicar.
Puestoqueyasabemosloquequeremoslograr,¡podemosempezaramoderlarloenDjango!
ModeloenDjangoSabiendoquéesunobjeto,podemoscrearunmodeloenDjangoparanuestrospostsenelblog.
UnmodeloenDjangoesuntipoespecialdeobjetoqueseguardaenlabasededatos.Unabasededatosesunacoleccióndedatos.Allíesellugarenelcualalmacenaráslainformaciónsobreusuarios,postsdelblog,etc.UtilizaremosunabasededatosSQLiteparaalmacenarnuestrosdatos.EsteeseladaptadordebasededatospredeterminadaenDjango--serásuficienteparanosotrosporahora.
Piensaenelmodeloenlabasededatoscomounahojadecálculoconcolumnas(campos)yfilas(datos).
Creandounaaplicación
Paramantenertodoenorden,crearemosunaaplicaciónseparadadentrodenuestroproyecto.Esmuybuenotenertodoorganizadodesdeelprincipio.Paracrearunaaplicación,necesitamosejecutarelsiguientecomandoenlaconsola(dentrodelacarpetadedjangogirlsdondeestáelarchivomanage.py):
DjangoGirlsTutorial
55ModelosenDjango
(myvenv)~/djangogirls$pythonmanage.pystartappblog
Vasnotarquesecreaunnuevodirectoriollamadoblogycontieneunaseriedearchivos.Nuestrosdirectoriosyarchivosennuestroproyectodeberíanparecerseaesto:
djangogirls
├──mysite
|__init__.py
|settings.py
|urls.py
|wsgi.py
├──manage.py
└──blog
├──migrations
|__init__.py
├──__init__.py
├──admin.py
├──models.py
├──tests.py
└──views.py
DespuésdecrearunaaplicacióntambiénnecesitamosdecirleaDjangoquedebeutilizarla.Lohacemosenelarchivomysite/settings.py.TenemosqueencontrarINSTALLED_APPSyañadirunalíneaquecontiene'blog',justoporencimade).Elproductofinaldebeteneresteaspecto:
INSTALLED_APPS=(
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'blog',
)
CreandoelModeloPost
Enelarchivoblog/models.pydefinimostodoslosobjetosllamadosModels-esteesunlugarenelcualdefiniremosnuestromodelopost.
Vamosabrirblog/models.py,quitamostodoyescribimosuncódigocomoeste:
DjangoGirlsTutorial
56ModelosenDjango
fromdjango.dbimportmodels
fromdjango.utilsimporttimezone
classPost(models.Model):
author=models.ForeignKey('auth.User')
title=models.CharField(max_length=200)
text=models.TextField()
created_date=models.DateTimeField(
default=timezone.now)
published_date=models.DateTimeField(
blank=True,null=True)
defpublish(self):
self.published_date=timezone.now()
self.save()
def__str__(self):
returnself.title
Vuelveaverificarqueusastedosguionesbajos(_)encadaladodelstr.EstosseutilizanconfrecuenciaenPythonyavecestambiénlosllamamos"dunder"(diminutivoeninglésde"double-underscore").
Daunpocodemiedo,¿verdad?Peronotepreocupes,¡vamosaexplicarquésignificanestaslíneas!
Todaslaslíneasquecomienzanconfromoimportsonlíneasparaañadiralgodeotrosarchivos.Asíqueenvezdecopiarypegarlasmismascosasencadaarchivo,podemosincluiralgunaspartesconfrom...import....
classPost(models.Model):-estalíneadefinenuestromodelo(esunobjeto).
classesunapalabraclavequeindicaqueestamosdefiniendounobjeto.Posteselnombredenuestromodelo.Podemosdarleunnombrediferente(perodebemosevitarespaciosenblancoycaracteresespeciales).Unaclasesiemprecomienzaconsuprimeraletraenmayúscula.models.ModelsignificaquePostesunmodelodeDjango,asíDjangosabequedebeguardarloenlabasededatos.
Ahoradefinimoslaspropiedadesquehablábamos:title,text,created_date,published_dateyauthor.Parahaceresotenemosquedefiniruntipodecampo(¿estexto?¿unnúmero?¿unafecha?¿unarelaciónconotroobjeto-esdecir,unusuario?).
models.CharField-estoescomodefinesuntextoconunnúmerolimitadodecaracteres.models.TextField-estoesparatextoslargossinunlímite.Seráidealparael
DjangoGirlsTutorial
57ModelosenDjango
contenidodeunpost,¿verdad?models.DateTimeField-estoesfechayhora.modelos.ForeignKey-esteesunvínculoconotromodelo.
Novamosaexplicarcadapedacitodecódigo,yaquenostomaríademasiadotiempo.DebesecharunvistazoaladocumentacióndeDjangosiquieressabermássobreloscamposdelosModelosycómodefinircosasdiferentesalasdescritasanteriormente(https://docs.djangoproject.com/en/1.8/ref/models/fields/#field-types).
¿Yquésobredefpublish(self):?Esexactamentenuestrométodopublishquemencionamosanteriormente.defsignificaquesetratadeunafunciónométodo.publisheselnombredelmétodo.Puedescambiarlo,siquieres.Lareglaesqueusamosminúsculasyguionesbajosenlugardeespacios(esdecir,siquierestenerunmétodoquecalculeelpreciomedio,estepodríallamarsecalculate_average_price).
Losmétodosmuyamenudodevuelvenalgo.Hayunejemplodeestoenelmétodo__str__.Enesteescenario,cuandollamamosa__str__()obtendremosuntexto(string)conuntítulodePost.
Sialgotodavíanoestáclarosobremodelos,¡nodudesenpreguntaratututor!Sabemosqueesmuycomplicado,sobretodocuandoestásentendiendoquéfuncionesyobjetossonmientrassiguesestedocumento.Consuerte,¡todotieneunpocomássentidoparatiahora!
Creartablasparalosmodelosentubasededatos
Elúltimopasoesañadirnuestronuevomodeloanuestrabasededatos.PrimerotenemosquehacerqueDjangosepaquetenemosalgunoscambiosennuestromodelo(acabamosdecrearlo),escribepythonmanage.pymakemigrationsblog.Severáasí:
(myvenv)~/djangogirls$pythonmanage.pymakemigrationsblog
Migrationsfor'blog':
0001_initial.py:
-CreatemodelPost
Djangoprepararáunarchivodemigraciónquetenemosqueaplicarahoraanuestrabasededatosescribiendopythonmanage.pymigrateblog.Elresultadodebeser:
(myvenv)~/djangogirls$pythonmanage.pymigrateblog
Operationstoperform:
Applyallmigrations:blog
Runningmigrations:
Applyingblog.0001_initial...OK
DjangoGirlsTutorial
58ModelosenDjango
¡Hurra!NuestromodelodePostestáahoraennuestrabasededatos.Seríabuenoverlo,¿no?¡DirígetealsiguientecapítuloparavercómolucetuPost!
DjangoGirlsTutorial
59ModelosenDjango
AdministradordeDjangoParaagregar,editaryborrarlospostsquehemosmodelado,utilizaremoseladministradordeDjango.
Vamosaabrirelarchivoblog/admin.pyyreemplazarsucontenidoconesto:
fromdjango.contribimportadmin
from.modelsimportPost
admin.site.register(Post)
Comopuedesver,importamos(incluimos)elmodeloPostdefinidoenelcapítuloanterior.Parahacernuestromodelovisibleenlapáginadeladministrador,tenemosqueregistrarelmodeloconadmin.site.register(Post).
Ok,eshoradevertumodeloPost.Recuerdaejecutarpythonmanage.pyrunserverenlaconsolaparacorrerelservidorweb.Vealnavegadorytipealadirecciónhttp://127.0.0.1:8000/admin/.Verásunapáginadeingresocomolaquesigue:
Parapoderingresardeberáscrearunsuperusuario-unusuarioquetienecontrolsobretodoloquehayenelsitio.Vuelvehaciaatrásatulíneadecomandosytipeapythonmanage.pycreatesuperuser,presionaenterytipeatunombredeusuario(enminúsculas,sinespacios),direccióndeemailycontraseñacuandoseanrequeridos.Notepreocupesquenopuedes
DjangoGirlsTutorial
60AdministradordeDjango
vertucontraseñamientraslatipeas-asíescomodebeser.Simplementetipéalaypresiona'Enter'paracontinuar.Lasalidadeestecomandodeberíaverseasí(nombredeusuarioyemaildeberíanserlostuyos):
(myvenv)~/djangogirls$pythonmanage.pycreatesuperuser
Username:admin
Emailaddress:[email protected]
Password:
Password(again):
Superusercreatedsuccessfully.
Vuelveatunavegadoreingresaconlascredencialesdesuperusuarioqueelegiste,ahoradeberíaspoderverelpaneldeadministracióndeDjango.
VeaPostsyexperimentaunpococonesto.Agregacincooseispostsdelblog.Notepreocupesporelcontenido-puedessimplementecopiarypegartextodeestetutorialenelcontenidodetuspostsparaahorrartiempo:).
Asegúratedequeporlomenosdosotresposts(peronotodas)tienenlafechadepublicación.Seráútilluego.
DjangoGirlsTutorial
61AdministradordeDjango
SiquieressabermássobreeladministradordeDjango,puedesvisitarladocumentacióndeDjango:https://docs.djangoproject.com/en/1.8/ref/contrib/admin/
Esteprobablementeseaunbuenmomentoparatomaruncafé(oté)oalgoparacomeryre-energizarte.CreastetuprimermodelodeDjango-¡merecesunpequeñorecreo!
DjangoGirlsTutorial
62AdministradordeDjango
¡Despliega!Nota:Elsiguientecapítulopuedeseravecesunpocodifícildesuperar.Sepersistenteyacábalo.Eldespliegueesunaparteimportantedelprocesoeneldesarrolloweb.Estecapítuloestásituadoenelmediodeltutorialparaquetututorpuedaayudarteaponertusitiowebenlínea,loquepuedeserunprocesoalgomáscomplicado.Estosignificaquepodrásacabareltutorialportucuentasiseteacabaeltiempo.
Hastaahoratusitiowebestabadisponiblesóloentuordenador,¡ahoraaprenderáscómodesplegarlo!EldespliegueeselprocesodepublicartuaplicaciónenInternetparaquelagentepuedaaccederyvertuaplicación:).
Comoyahasaprendido,unsitiowebtienequeestarenunservidor.Haymuchosproveedores,perousaremosunoquetieneunprocesodedesplieguerelativamentesimple:PythonAnywhere.PythonAnywhereesgratisparapequeñasaplicacionesquenotienendemasiadosvisitantes,definitivamentesuficienteparaestecaso.
ElotroservicioexternoquevamosautilizaresGitHub,unserviciodealojamientodecódigo.Hayotrasopcionesporahí,perohoyendíacasitodoslosprogramadorestienenunacuentadeGitHub,¡yahoratútambiénlavasatener!
UsaremosGitHubcomopasointermedioparatransportarnuestrocódigodesdeyhastaPythonAnywhere.
GitGitesun"sistemadecontroldeversiones"usadopormuchosprogramadores-esunsistemaqueregistraloscambiosenlosarchivosatravésdeltiempodeformatalquepuedasaccederaversionesespecíficascuandolodesees.Esmuysimilaralaopciónde"registrarcambios"enMicrosoftWord,peromuchomáspoderoso.
InstalarGit
Windows
PuedesdescargarGitdegit-scm.com.Puedeshacerclicen"Next"paratodoslospasosexceptoenuno;enelquintopasotitulado"AdjustingyourPATHenvironment",elije"RunGitandassociatedUnixtoolsfromtheWindowscommand-line"(laúltimaopción).Apartede
DjangoGirlsTutorial
63¡Desplegar!
eso,losvalorespordefectofuncionaránbien."CheckoutWindows-style,commitUnix-stylelineendings"tambiénestábien.
MacOS
DescargaGitdegit-scm.comysiguelasinstrucciones.
Linux
Sinolotienesyainstalado,gitdeberíaestardisponibleatravésdeladministradordepaquetes,pruebacon:
sudoapt-getinstallgit
#o
sudoyuminstallgit
IniciarnuestrorepositorioGitGitrastrealoscambiosrealizadosaungrupodeterminadodeficherosenloquellamamosunrepositoriodecódigo(o"repo"paraabreviar).Iniciemosunoparanuestroproyecto.Abrelaconsolayejecutalossiguientescomandoseneldirectoriodedjangogirls:
Nota:Compruebaeldirectoriodetrabajoactualconelcomandopwd(OSX/Linux)ocd(Windows)antesdeinicializarelrepositorio.Deberíasestarenlacarpetadjangogirls.
$gitinit
InitializedemptyGitrepositoryin~/djangogirls/.git/
$gitconfiguser.name"Tunombre"
$gitconfiguser.emailtú@ejemplo.com
Inicializarelrepositoriogitesalgoquesólonecesitamoshacerunavezporproyecto(ynotendrásquevolveraponertuusuarioycorreoelectróniconuncamás)
Gitllevaráunregistrodeloscambiosrealizadosentodoslosficherosycarpetasenestedirectorio,perohayalgunosficherosquequeremosqueignore.Estolohacemoscreandounficherollamado.gitignoreeneldirectoriobase.Abretueditorycreaunnuevoficheroconelsiguientecontenido:
DjangoGirlsTutorial
64¡Desplegar!
*.pyc
__pycache__
myvenv
db.sqlite3
.DS_Store
Yguárdalocomo.gitignoreenlaprimeracarpeta"djangogirls".
Nota:¡Elpuntoalprincipiodelnombredelficheroesimportante!Sitienesdificultadesparacrearlo(alosMacnolesgustaquecreesficherosqueempiezanporpuntodesdeFinder,porejemplo),usalaopción"Guardarcomo"entueditor,esonofalla.
Esbuenaideautilizarelcomandogitstatusantesdegitaddocuandonoestésseguradeloquevaahacer,paraevitarcualquiersorpresa(porejemplo,añadirohacercommitdeficherosnodeseados).Elcomandogitstatusdevuelveinformaciónsobrelosficherossinseguimiento(untracked),modificados,preparados(staged),elestadodelaramaymuchomás.Lasalidadeberíasersimilara:
$gitstatus
Onbranchmaster
Initialcommit
Untrackedfiles:
(use"gitadd<file>..."toincludeinwhatwillbecommitted)
.gitignore
blog/
manage.py
mysite/
nothingaddedtocommitbutuntrackedfilespresent(use"gitadd"totrack)
Yfinalmenteguardamosnuestroscambios.Vealaconsolayejecutaestoscomandos:
$gitadd-A.
$gitcommit-m"MiappDjangoGirls,primercommit"
[...]
13fileschanged,200insertions(+)
createmode100644.gitignore
[...]
createmode100644mysite/wsgi.py
EnviarnuestrocódigoaGitHub
DjangoGirlsTutorial
65¡Desplegar!
VisitaGitHub.comyregistraunanuevacuentadeusuariogratuita.Luego,creaunnuevorepositorioconelnombre"my-first-blog".Dejadesmarcadalaopción"InitialisewithaREADME",dejalaopción.gitignoreenblanco(lohemoshechoamano)ydejalalicenciacomo"None".
NotaElnombremy-first-blogesimportante.Podríaselegirotracosa,perovaaaparecermuchasvecesenlasinstruccionesquesiguenytendríasquesustituirlocadavez.Probablementeseamássencilloquedarteconelnombremy-first-blog.
EnlapróximapantallaveráslaURLparaclonarturepositorio.Eligelaversión"HTTPS",cópialayenunmomentolapegaremosenlaconsola:
DjangoGirlsTutorial
66¡Desplegar!
AhoratenemosqueconectarelrepositorioGitdetuordenadorconelqueestáenGitHub.
$gitremoteaddoriginhttps://github.com/<your-github-username>/my-first-blog.git
$gitpush-uoriginmaster
EscribetunombredeusuarioycontraseñadeGitHubydeberíasveralgoasí:
Usernamefor'https://github.com':hjwp
Passwordfor'https://[email protected]':
Countingobjects:6,done.
Writingobjects:100%(6/6),200bytes|0bytes/s,done.
Total3(delta0),reused0(delta0)
Tohttps://github.com/hjwp/my-first-blog.git
*[newbranch]master->master
Branchmastersetuptotrackremotebranchmasterfromorigin.
TucódigoestáahoraenGitHub.¡Veymíralo!Verásqueestáenbuenacompañía;Django,elTutorialdeDjangoGirlsymuchosotrosgrandesproyectosdecódigoabiertotambiénalojansucódigoenGitHub:)
ConfigurarnuestroblogenPythonAnywhereEshoraderegistrarunacuentagratuitadetipo"Beginner"enPythonAnywhere.
www.pythonanywhere.com
Nota:CuandoelijastunombredeusuariotenencuentaquelaURLdetublogtendrálaformanombredeusuario.pythonanywhere.com,asíqueobienelijetupropioapodoobienunnombrequedescribasobrequétratatublog.
BajarnuestrocódigoenPythonAnywhereCuandotehayasregistradoenPythonAnywhereserásredirigidaatupaneldecontrolopágina"Consoles".Elijelaopciónparainiciarunaconsola"Bash",queeslaversiónPythonAnywheredeunaconsola,comolaquetienesentuPC
Nota:PythonAnywhereestábasadoenLinux,porloquesiestásenWindowslaconsolaseráunpocodistintaalaquetienesentuordenador.
DjangoGirlsTutorial
67¡Desplegar!
DescarguemosnuestrocódigodesdeGitHubaPythonAnywheremediantelacreacióndeun"clon"delrepositorio.EscribelosiguienteenlaconsoladePythonAnywhere:
$gitclonehttps://github.com/<tu-usuario-github>/my-first-blog.git
EstovaadescargarunacopiadetucódigoenPythonAnywhere.Compruébaloescribiendo:
$treemy-first-blog
my-first-blog/
├──blog
│├──__init__.py
│├──admin.py
│├──migrations
││├──0001_initial.py
││└──__init__.py
│├──models.py
│├──tests.py
│└──views.py
├──manage.py
└──mysite
├──__init__.py
├──settings.py
├──urls.py
└──wsgi.py
CrearunvirtualenvenPythonAnywhere
Talycomohicisteentupropioordenador,puedescrearunvirtualenvenPythonAnywhere.EnlaconsolaBash,escribe:
20:20~$cdmy-first-blog
20:20~$virtualenv--python=python3.4myvenv
Runningvirtualenvwithinterpreter/usr/bin/python3.4
[...]
Installingsetuptools,pip...done.
20:20~$sourcemyvenv/bin/activate
(mvenv)20:20~$pipinstalldjangowhitenoise
Collectingdjango
[...]
Successfullyinstalleddjango-1.8whitenoise-1.0.6
Recopilarficherosestáticos
DjangoGirlsTutorial
68¡Desplegar!
¿Teestabaspreguntandoquéesesode"whitenoise"?Esunaherramientaparaservirlosllamados"ficherosestáticos".Losficherosestáticosfuncionandedistintaformaenlosservidoresencomparaciónconcómolohacenennuestropropioordenadorynecesitamosunaherramientacomo"whitenoise"paraservirlos.
Aprenderemosunpocomássobrelosficherosestáticosmásadelante,cuandoeditemoselCSSdenuestrositio.
Porahorasólonecesitamosejecutarenelservidoruncomandoadicionalllamado"collectstatic".LediceaDjangoquerecopiletodoslosficherosestáticosquenecesitaenelservidor.Porelmomento,principalmentesonlosficherosestáticosquehacenqueelpaneldeadministraciónestébonito.
20:20~$pythonmanage.pycollectstatic
Youhaverequestedtocollectstaticfilesatthedestination
locationasspecifiedinyoursettings:
/home/edith/my-first-blog/static
Thiswilloverwriteexistingfiles!
Areyousureyouwanttodothis?
Type'yes'tocontinue,or'no'tocancel:yes
Escribe"yes",¡yahíva!¿Noteencantahacerquelascomputadorasimprimanpáginasypáginasdetextoimposibledeentender?Siemprehagoruiditosparaacompañarlo.Brp,brpbrp...
Copying'/home/edith/.virtualenvs/mvenv/lib/python3.4/site-packages/django/contrib/admin/static/admin/js/actions.min.js'
Copying'/home/edith/.virtualenvs/mvenv/lib/python3.4/site-packages/django/contrib/admin/static/admin/js/inlines.min.js'
[...]
Copying'/home/edith/.virtualenvs/mvenv/lib/python3.4/site-packages/django/contrib/admin/static/admin/css/changelists.css'
Copying'/home/edith/.virtualenvs/mvenv/lib/python3.4/site-packages/django/contrib/admin/static/admin/css/base.css'
62staticfilescopiedto'/home/edith/my-first-blog/static'.
CrearlabasededatosenPythonAnywhere
Aquíhayotracosaqueesdiferenteentretuordenadoryelservidor:ésteutilizaunabasededatosdiferente.Porlotanto,lascuentasdeusuarioylasentradaspuedenserdiferentesenelservidoryentuordenador.
Asíqueinicializamoslabasededatosenelservidorigualquelohicimosennuestroordenador,conmigrateycreatesuperuser:
DjangoGirlsTutorial
69¡Desplegar!
(mvenv)20:20~$pythonmanage.pymigrate
Operationstoperform:
[...]
Applyingsessions.0001_initial...OK
(mvenv)20:20~$pythonmanage.pycreatesuperuser
PublicarnuestroblogcomounaaplicaciónwebAhoraquenuestrocódigoestáenPythonAnywhere,elvirtualenvestálisto,losficherosestáticoshansidorecopiladosylabasededatosestáinicializada,estamoslistasparapublicarlacomounaaplicaciónweb.
HazclicenellogodePythonAnywhereparavolveralpanelprincipal,hazclicenlapestañaWebypinchaenAddanewwebapp.
Enlaventanadediálogo,despuésdeconfirmarelnombrededominio,elijemanualconfiguration(configuraciónmanual)(NBlaopción"Django"no).Luego,elijePython3.4yhazclicen"Next"paraterminarconelasistente.
Notaasegúratedeelegirlaopciónde"Manualconfiguration",nolade"Django".SomosdemasiadobuenasparalaconfiguraciónpordefectodeDjangodePythonAnywhere;-)
Configurarelvirtualenv
SerásredirigidaalapantalladeconfiguracióndePythonAnywhereparatuaplicaciónweb,alaquedeberásaccedercadavezquequierashacercambiosenlaaplicacióndelservidor.
DjangoGirlsTutorial
70¡Desplegar!
Enlasección"Virtualenv",hazcliceneltextorojoquedice"Enterthepathtoavirtualenv"(Introducelarutaaunvirtualenv)yescribe:/home/<-tu-usuario->/my-first-blog/myvenv/
Nota:sustituyetupropionombredeusuariocomocorresponda.Sicometesunerror,PythonAnywheretemostraráunapequeñaadvertencia.
ConfigurarelficheroWSGI
Djangofuncionautilizandoel"protocoloWSGI",unestándarparaservirsitioswebusandoPython,quePythonAnywheresoporta.LaformadeconfigurarPythonAnywhereparaquereconozcanuestroblogDjangoeseditarunficherodeconfiguraciónWSGI.
Hazclicenelenlace"WSGIconfigurationfile"(enlasección"Code"enlapartedearribadelapágina;sellamaráalgoparecidoa/var/www/<tu-usuario>_pythonanywhere_com_wsgi.py)yteredirigiráaleditor.
Eliminatodoelcontenidoactualyreemplázaloconalgocomoesto:
DjangoGirlsTutorial
71¡Desplegar!
importos
importsys
path='/home/<tu-usuario>/my-first-blog'#aquíutilizatupropiousuario
ifpathnotinsys.path:
sys.path.append(path)
os.environ['DJANGO_SETTINGS_MODULE']='mysite.settings'
fromdjango.core.wsgiimportget_wsgi_application
fromwhitenoise.djangoimportDjangoWhiteNoise
application=DjangoWhiteNoise(get_wsgi_application())
Notanoolvidessustituirtupropionombredeusuariodondedice<tu-usuario>
EsteficheroseencargadedecirleaPythonAnywheredóndevivenuestraaplicaciónwebycómosellamaelficherodeconfiguracióndeDjango.Tambiénconfiguralaherramientaparaficherosestáticos"whitenoise".
DaleaSaveyvuelvealapestañaWeb.
¡Todolisto!DalealbotónverdegrandequediceReloadypodrásvertuaplicación.Verásunenlaceaellaenlapartedearribadelapágina.
ConsejosdedepuraciónSiapareceunerrorcuandointentasvisitartusitio,elprimerlugarquedeberásrevisarparaobtenerinformacióndedepuracióneselerrorlog;encontrarásunenlaceaélenlapestañaWebdePythonAnywhere.Miraaversihayalgúnmensajedeerrorahí.Losmásrecientesestánalfinal.Losproblemasmáscomunesincluyen
olvidaralgunodelospasosquehicimosenlaconsola:crearelvirtualenv,activarlo,instalarDjangoenél,ejecutarcollectstatic,inicializarlabasededatoscometerunerrorenlarutadelvirtualenvenlapestañaWeb;suelehaberunmensajitodeerrordecolorrojo,sihayalgúnproblemacometerunerrorenelficherodeconfiguraciónWSGI;¿haspuestobienlarutaalacarpetamy-first-blog?
¡Tututorestáahíparaayudar!
¡Estásenvivo!
DjangoGirlsTutorial
72¡Desplegar!
Lapáginapordefectodetusitiodeberíadecir"WelcometoDjango",igualqueentuPClocal.Intentaañadir/admin/alfinaldelaURLyteredirigiráalpaneldeadministración.Ingresacontunombredeusuarioycontraseñayverásquepuedesañadirnuevasentradasenelservidor.
DateunaGRANpalmadaenlaespalda;losdesplieguesenelservidorsonunadelaspartesmáscomplejasdeldesarrollowebymuchasvecesalagentelecuestavariosdíastenerlofuncionando.Perotútienestusitioenvivo,enInternetdeverdad,¡asícomosuena!
DjangoGirlsTutorial
73¡Desplegar!
DjangourlsVamosaconstruirnuestraprimerapáginaweb--¡unapáginadeinicioparatublog!Peroprimero,vamosaaprenderunpocosobreDjangourls.
¿QuéesunaURL?UnaURLessimplementeunadirecciónweb,puedesverunaURLcadavezquevisitascualquiersitioweb-esvisibleenlabarradedireccionesdetunavegador(¡Sí!127.0.0.1:8000esunaURL.Yhttp://djangogirls.comestambiénunaURL):
CadapáginaenInternetnecesitasupropiaURL.DeestamaneratuaplicaciónsabeloquedebemostraraunusuarioqueabreunaURL.EnDjangoseusaalgollamadoURLconf(configuracióndeURL),unconjuntodepatronesqueDjangointentaráhacercoincidirconladirecciónURLrecibidaparaencontrarlavistacorrecta.
¿CómofuncionanlasURLsenDjango?Vamosaabrirelarchivomysite/urls.pyyvercómoes:
fromdjango.conf.urlsimportinclude,url
fromdjango.contribimportadmin
urlpatterns=[
#Examples:
#url(r'^$','mysite.views.home',name='home'),
#url(r'^blog/',include('blog.urls')),
url(r'^admin/',include(admin.site.urls)),
]
Comopuedesver,Djangoyapusoalgoaquíparanosotros.
DjangoGirlsTutorial
74Djangourls
Laslíneasquecomienzancon#soncomentarios-significaqueesaslíneasnoseránejecutadasporPython.Muyútil,¿verdad?
YaestáaquílaURLdeadmin,quevisitasteenelcapítuloanterior:
url(r'^admin/',include(admin.site.urls)),
EstosignificaqueparacadaURLqueempiezaconadmin/Djangoencontrarásucorrespondienteview.EnestecasoestamosincluyendoenunasolalíneamuchasURLsdeadmin,asínoestátodocomprimidoenestepequeñoarchivo-esmáslimpioylegible.
Regex¿TepreguntascómoDjangocoincidelasdireccionesURLconlasvistas?Bueno,estaparteesdifícil.Djangoutilizaregex--expresionesregulares.Regextienemuchas(¡unmontón!)denormasqueformanunpatróndebúsqueda.Dadoquelasexpresionesregularessonuntemaavanzado,noentraremosendetallessobresufuncionamiento.
Siteinteresaentendercómocreamosesospatrones,aquíhayunejemplodelproceso-solamentenecesitaremosunsubconjuntodereglaslimitadoparaexpresarelpatrónqueestamosbuscando:
^denotaelprincipiodeltexto
$denotaelfinaldeltexto
\drepresentaundígito
+indicaqueelítemanteriordeberíaserrepetido<strong>porlomenos</strong>unavez
()paraencerrarunapartedelpatrón
CualquierotracosaenladefinicióndelURLserátomadaliteralmente.
Ahoraimaginaquetienesunsitiowebconunadireccióncomoesta:http://www.mysite.com/post/12345/,donde12345eselnúmerodepost.
Escribirvistasseparadasparatodoslosnúmerosdepostseríarealmentemolesto.ConlasexpresionesregularespodemoscrearunpatrónquecoincidirálaURLyextraeráelnúmeroparanosotras: ̂ post/(\d+)/$.Analicemosestaexpresiónparteporparteparaentenderquéesloqueestamoshaciendoaquí:
^post/leestádiciendoaDjangoquetomecualquiercosaquetengapost/alprincipiodelURL(justoantesde ̂ )(\d+)significaquehabráunnúmero(deunoomásdígitos)yquequeremosqueesenúmeroseacapturadoyextraído
DjangoGirlsTutorial
75Djangourls
/lediceaDjangoqueotrocaracter/deberíaveniracontinuación$indicaelfinaldelURL,loquesignificaquesólocadenasfinalizandocon/coincidiránconestepatrón
¡TuprimerURLdeDjango!¡EshoradecrearnuestroprimerURL!Queremosque'http://127.0.0.1:8000/'sealapáginadeiniciodenuestroblogyquemuestreunalistadeposts.
Tambiénqueremosmantenerelarchivomysite/urls.pylimpio,asíqueimportaremosURLsdenuestroblogalarchivomysite/urls.pyprincipal.
Eliminalaslíneascomentadas(líneascomenzandocon#)yagregaunalíneaqueimportaráblog.urlsenelurlprincipal('').
Tuarchivomysite/urls.pydeberíaversecomoeste:
fromdjango.conf.urlsimportinclude,url
fromdjango.contribimportadmin
urlpatterns=[
url(r'^admin/',include(admin.site.urls)),
url(r'',include('blog.urls')),
]
Djangoahoraredirigirátodoloquevayahacia'http://127.0.0.1:8000/'ablog.urlsybuscarámásinstruccionesallí.
CuandoescribesexpresionesregularesenPythonacostúmbrateaponerralprincipiodelacadena-estoessolamenteunapistaparaquePythonentiendaquelacadenacontenerácaracteresespecialesquenosonparaserinterpretadosporPythonsinoquesonpartedelaexpresiónregular.
blog.urlsCreaunnuevoarchivovacíoblog/urls.py.¡Muybien!Agregaestasprimerasdoslíneas:
fromdjango.conf.urlsimportinclude,url
from.importviews
AquísoloestamosimportandolosmétodosdeDjangoytodasnuestrasviewsdelblog(todavíanotenemosninguna,peroloharemosenunminuto)
DjangoGirlsTutorial
76Djangourls
Luegodeesto,podemosagregarnuestroprimerpatrónURL:
urlpatterns=[
url(r'^$',views.post_list),
]
Comopuedesver,ahoraestamosasignandounaviewllamadapost_listalURL ̂ $.Estaexpresiónregularcoincidirácon ̂ (uninicio)seguidode$(unfinal)-porlotanto,sólounacadenavacíacoincidirá.Yestoescorrecto,yaqueenlosURLresolversdeDjango'http://127.0.0.1:8000/'noespartedelURL.EstepatrónmostraráaDjangoqueviews.post_listesellugarcorrectoalqueirsialguieningresaatusitiowebconladirección'http://127.0.0.1:8000/'.
¿Todobien?Abrehttp://127.0.0.1:8000/entunavegadorparaverelresultado.
Nohaymásun"Itworks",¿verdad?Notepreocupes,essolamenteunapáginadeerror,¡nadaquenosasuste!Dehecho,sonbastanteútiles:
Puedesleerquenohayningúnatributo'post_list'.¿post_listterecuerdaalgo?¡Asíescomollamamosanuestravista!Estosignificaquetodoestáensulugar,sóloquenocreamosnuestraviewtodavía.Notepreocupes,yallegaremosaeso.
SiquieressabermássobreDjangoURLconfs,miraladocumentaciónoficial:https://docs.djangoproject.com/en/1.8/topics/http/urls/
DjangoGirlsTutorial
77Djangourls
VistasdeDjango-¡Eshoradecrear!Eshoradedeshacersedelerrorquehemoscreadoenelcapítuloanterior:)
UnaViewesunlugardondeponemosla"lógica"denuestraaplicación.Sesolicitaráinformacióndelmodelquecreasteanteriormenteysepasaráaunaviewquecrearásenelpróximocapítulo.LasvistassonsólométodosdePythonquesonunpocomáscomplicadosqueloquehicimosenelcapítulodeIntroducciónaPython.
LasVistassecolocanenelarchivoviews.py.Agregaremosnuestrasviewsalarchivoblog/views.py.
blog/views.pyBien,vamosabrirestearchivoyverloquecontiene:
fromdjango.shortcutsimportrender
#Createyourviewshere.
Nodemasiadascosasaquítodavía.Laviewmássimplepuedesercomoesto:
defpost_list(request):
returnrender(request,'blog/post_list.html',{})
Comopuedesver,hemoscreadounmétodo(def)llamadopost_listquetomaunrequestyhaceunreturndeunmétodorenderquerenderizará(construirá)nuestraplantillablog/post_list.html.
Guardaelarchivo,dirígeteahttp://127.0.0.1:8000/yveamosloquetenemosahora.
¡Otroerror!Leamosloqueestápasandoahora:
DjangoGirlsTutorial
78VistasdeDjango-¡Eshoradecrear!
Esteesunofácil:TemplateDoesNotExist.¡Vamosaarreglaresteerrorcreandounaplantillaenelsiguientecapítulo!
AprendemásacercadelasviewsdeDjangoleyendoladocumentaciónoficial:https://docs.djangoproject.com/en/1.8/topics/http/views/
DjangoGirlsTutorial
79VistasdeDjango-¡Eshoradecrear!
IntroducciónaHTMLTeestaráspreguntando,¿quéesunaplantilla?
Unaplantillaesunarchivoquepodemosreutilizarparapresentarinformacióndiferentedeformaconsistente-porejemplo,sepodríautilizarunaplantillaparaayudarteaescribirunacarta,porqueaunquecadacartapuedecontenerunmensajedistintoydirigirseaunapersonadiferente,compartiránelmismoformato.
ElformatodeunaplantilladeDjangosedescribeenunlenguajellamadoHTML(queeselcódigoHTMLquemencionamosenelprimercapítuloCómofuncionaInternet).
¿QuéesHTML?HTMLesunsimplecódigoqueesinterpretadoportunavegadorweb-comoChrome,FirefoxoSafari-paramostrarunapáginawebalusuario.
HTMLsignificaHyperTextMarkupLanguage-enespañol,LenguajedeMarcasdeHyperTexto.HyperTextsignificaqueesuntipodetextoquesoportahipervínculosentrepáginas.Markupsignificaquehemostomadoundocumentoylohemosmarcadoconcódigoparadecirleaalgo(enestecaso,unnavegador)cómointerpretarlapágina.ElcódigoHTMLestáconstruidoconetiquetas,cadaunacomenzandocon<yterminandocon>.Estasetiquetasdemarcadosonelementos.
¡Tuprimeraplantilla!Crearunaplantillasignificacrearunarchivodeplantilla.Todoesunarchivo,¿verdad?Probablementehayasnotadoestoya.
Lasplantillasseguardaneneldirectoriodeblog/templates/blog.Asíqueprimerocreaundirectoriollamadotemplatesdentrodetudirectorioblog.Luegocreaotrodirectoriollamadoblogdentrodetudirectoriodetemplates:
blog
└───templates
└───blog
DjangoGirlsTutorial
80IntroducciónaHTML
(Talveztepreguntesporquénecesitamosdosdirectoriosllamadosblog-comodescubrirásmásadelante,estoessimplementeunaútilconvencióndenomenclaturaquehacelavidamásfácilcuandolascosasempiezanacomplicarsemás.)
Yahoracreaunarchivopost_list.html(déjaloenblancoporahora)dentrodelacarpetablog/templates/blog.
Miracómosevesusitiowebahora:http://127.0.0.1:8000/
SitodavíatienesunerrorTemplateDoesNotExists,intentareiniciarelservidor.Vealalíneadecomandos,deténelservidorpulsandoCtrl+C(teclasControlyCjuntas)ycomienzadenuevomediantelaejecucióndelcomandopythonmanage.pyrunserver.
¡Ningúnerrormás!Felicidades:)Sinembargo,porahora,tusitiowebnoestápublicandonadaexceptounapáginaenblanco,porquelaplantillatambiénestávacía.Tenemosquearreglarlo.
Añadelosiguienteatuarchivodeplantilla:
<html>
<p>Hithere!</p>
<p>Itworks!</p>
</html>
¿Cómoluceahoratusitioweb?Hazclickparaver:http://127.0.0.1:8000/
¡Funcionó!Buentrabajo:)
Laetiquetamásbásica,<html>,essiempreelprincipiodecualquierpáginaweby</html>essiempreelfinal.Comopuedesver,todoelcontenidodelapáginawebvadesdeelprincipiodelaetiqueta<html>yhastalaetiquetadecierre</html><p>esunaetiquetaparaloselementosdepárrafo;</p>cierracadapárrafo
Cabeza&cuerpoCadapáginaHTMLtambiénsedivideendoselementos:headybody.
headesunelementoquecontieneinformaciónsobreeldocumentoquenosemuestraenlapantalla.
bodyesunelementoquecontienetodoloquesemuestracomopartedelapáginaweb.
DjangoGirlsTutorial
81IntroducciónaHTML
Usamos<head>paradecirleelnavegadoracercadelaconfiguracióndelapáginay<body>paradecirloquerealmenteestáenlapágina.
Porejemplo,puedesponerleuntítuloalapáginawebdentrodela<head>,así:
<html>
<head>
<title>Ola'sblog</title>
</head>
<body>
<p>Hithere!</p>
<p>Itworks!</p>
</body>
</html>
Guardaelarchivoyactualizatupágina.
¿Observascómoelnavegadorhacomprendidoque"Ola'sblog"eseltítulodetupágina?Hainterpretado<title>Ola'sblog</title>ycolocóeltextoenlabarradetítulodetunavegador(tambiénseutilizaráparamarcadoresyasísucesivamente).
Probablementetambiénhayasnotadoquecadaetiquetadeaperturacoincideconunaetiquetadecierre,conun/,yqueloselementossonanidados(esdecir,nopuedescerrarunaetiquetaparticularhastaquetodoslosqueestabanensuinteriorsehayancerradotambién).
Escomoponercosasencajas.Tienesunacajagrande,<html></html>;ensuinteriorhay<body></body>,yquecontienelascajasaúnmáspequeñas:<p></p>.
Tienesqueseguirestasreglasdeetiquetasdecierreydeanidacióndeelementos-sinolohaces,elnavegadorpuedenosercapazdeinterpretarloscorrectamenteytupáginasemostraráincorrectamente.
Personalizatuplantilla¡Ahorapuedesdivertirteunpocoytratardepersonalizartuplantilla!Aquíhayalgunasetiquetasútilesparaeso:
<h1>Untítulo</h1>-paratutítulomásimportante<h2>Unsubtítulo</h2>-paraeltítulodelsiguientenivel<h3>Unsubsubtítulo</h3>-...yasíhasta<h6><em>texto</em>-poneencursivatutexto<strong>texto</strong>-poneennegritatutexto
DjangoGirlsTutorial
82IntroducciónaHTML
<br/>-unsaltodelínea(nopuedescolocarnadadentrodebr)<ahref="http://djangogirls.org">link</a>-creaunvínculo<ul><li>primerelemento</li><li>segundoelemento</li></ul>-creaunalista,¡igualqueesta!<div></div>-defineunaseccióndelapágina
Aquíhayunejemplodeunaplantillacompleta:
<html>
<head>
<title>DjangoGirlsblog</title>
</head>
<body>
<div>
<h1><ahref="">DjangoGirlsBlog</a></h1>
</div>
<div>
<p>published:14.06.2014,12:14</p>
<h2><ahref="">Myfirstpost</a></h2>
<p>Aeneaneuleoquam.Pellentesqueornaresemlaciniaquamvenenatisvestibulum.Donecidelitnonmiportagravidaategetmetus.Fuscedapibus,tellusaccursuscommodo,tortormauriscondimentumnibh,utfermentummassajustositametrisus.
</div>
<div>
<p>published:14.06.2014,12:14</p>
<h2><ahref="">Mysecondpost</a></h2>
<p>Aeneaneuleoquam.Pellentesqueornaresemlaciniaquamvenenatisvestibulum.Donecidelitnonmiportagravidaategetmetus.Fuscedapibus,tellusaccursuscommodo,tortormauriscondimentumnibh,utf.
</div>
</body>
</html>
Aquíhemoscreadotresseccionesdiv.
Elprimerelementodivcontieneeltítulodenuestroblog-esunencabezadoyunenlaceOtrosdoselementosdivcontienennuestrospostsconlafechadepublicación,h2conuntítuloqueesclickeableydosp(párrafo)detexto,unoparalafechayunoparanuestropost.
Nosdaesteefecto:
¡Yaaay!Perohastaelmomento,nuestraplantillasólomuestraexactamentelamismainformación-considerandoqueanteshablábamosdeplantillascomopermitiéndonosmostrarinformacióndiferenteenelmismoformato.
DjangoGirlsTutorial
83IntroducciónaHTML
LoquequeremosrealmenteesmostrarpostsrealesañadidosennuestrapáginadeadministracióndeDjango-yahíesadondevamosacontinuación.
Unacosamás:¡despliega!SeríabuenovertodoestodisponibleenInternet,¿no?HagamosotrodespliegueenPythonAnywhere:
HazuncommitysubetucódigoaGitHub
Enprimerlugar,veamosquéarchivoshancambiadodesdequehicimoseldespliegueporúltimavez:
$gitstatus
Asegúratedequeestáseneldirectoriodjangogirlsyvamosadecirleagitqueincluyatodosloscambiosdentrodeestedirectorio:
$gitadd-A.
Nota-A(abreviaturade"all")significaquegittambiénreconocerásihaseliminadoarchivos(pordefecto,sóloreconocearchivosnuevos/modificados).Tambiénrecuerda(delcapítulo3)que.significaeldirectorioactual.
Antesdequesubamostodoslosarchivos,vamosaverquéesloquegitsubirá(todoslosarchivosquegitcargarádeberíanaparecerenverde):
$gitstatus
Yacasiestamos,ahoraestiempodedecirlequeguardeestecambioensuhistorial.Vamosadarleun"mensajedecommit"dondedescribimosloquehemoscambiado.Puedesescribircualquiercosaquetegustaríaenestaetapa,peroesútilescribiralgodescriptivoparaquepuedesrecordarloquehashechoenelfuturo.
$gitcommit-m"CambieelHTMLparalapágina."
NotaAsegúratedeusarcomillasdoblesalrededordelmensajedecommit.
Unavezquehicimosesto,subimos(push)nuestroscambiosaPythonAnywhere:
DjangoGirlsTutorial
84IntroducciónaHTML
gitpush
DescargatunuevocódigoaPythonAnywhereyactualizatuaplicaciónweb
AbrelapáginadeconsolasdePythonAnywhereyveatuconsolaBash(ocomienzaunanueva).Luego,ejecuta:
$cd~/my-first-blog$gitpull[...]
Ymiracómotucódigosedescarga.Siquierescomprobarqueyahaterminado,puedesiralapestañaFilesyvertucódigoenPythonAnywhere.
Finalmente,dirígetealapestañaWebyseleccionaReloadentuaplicaciónweb.
¡Tuactualizacióndeberíaestarenlínea!Actualizatusitiowebenelnavegador.Ahoradeberíaspodervertuscambios:)
DjangoGirlsTutorial
85IntroducciónaHTML
ORMdeDjangoyQuerySetsEnestecapítuloaprenderáscómoDjangoseconectaalabasededatosyalmacenalosdatosenella.¡Vamosasumergirnos!
¿QuéesunQuerySet?UnQuerySetes,enesencia,unalistadeobjetosdeunmodelodeterminado.UnQuerySettepermiteleerlosdatosdebasededatos,filtrarlosyordenarlos.
Esmásfácildeaprenderconejemplos.Vamosaintentarlo,¿deacuerdo?
DjangoshellAbrelaconsolayescribeestecomando:
(myvenv)~/djangogirls$pythonmanage.pyshell
Elresultadodeberíaser:
(InteractiveConsole)
>>>
AhoraestásenlaconsolainteractivadeDjango.EscomolaconsoladePython,peroconuntoquedemagiaDjango:).PuedesutilizartodosloscomandosPythonaquítambién,porsupuesto.
Vertodoslosobjetos
Vamosamostrartodosnuestrospostsprimero.Puedeshacerloconelsiguientecomando:
>>>Post.objects.all()
Traceback(mostrecentcalllast):
File"<console>",line1,in<module>
NameError:name'Post'isnotdefined
¡Uy!Aparecióunerror.NosdicequenohayningúnobjetoPost.Estoescorrecto,¡nosolvidamosdeimportarloprimero!
DjangoGirlsTutorial
86ORMdeDjango(Querysets)
>>>fromblog.modelsimportPost
Estoessimple:importamoselmodeloPostdeblog.models.Vamosaintentarmostrartodoslospostsnuevamente:
>>>Post.objects.all()
[<Post:myposttitle>,<Post:anotherposttitle>]
Estaesunalistadelaspostscreadasanteriormente.HemoscreadoestospostsusandolainterfazdeladministradordeDjango.Sinembargo,ahoraqueremoscrearnuevospostsusandoPython,¿cómolohacemos?
Crearobjetos
EstaeslaformadecrearunnuevoobjetoPostenlabasededatos:
>>>Post.objects.create(author=me,title='Sampletitle',text='Test')
Perohayuningredientefaltante:me.NecesitamospasarunainstanciadelmodeloUsercomoautor.¿Cómohacemoseso?
PrimeroimportemoselmodeloUser:
>>>fromdjango.contrib.auth.modelsimportUser
¿Quéusuariostenemosennuestrabasededatos?Veamos:
>>>User.objects.all()
[<User:ola>]
Esteeselsuperusuarioquecreamosanteriormente,Vamosaobtenerunainstanciadeeseusuarioahora:
me=User.objects.get(username='ola')
Comopuedesver,hicimosungetdeunUserconelusernamequeseaiguala'ola'.¡Genial!Acuérdatedeponertunombredeusuarioparaobtenertuusuario.
Ahorafinalmentepodemoscrearnuestroprimerpost:
DjangoGirlsTutorial
87ORMdeDjango(Querysets)
>>>Post.objects.create(author=me,title='Sampletitle',text='Test')
¡Hurra!¿Quieresprobarsifuncionó?
>>>Post.objects.all()
[<Post:Sampletitle>]
Agregamásposts
Ahorapuedesdivertirteunpocoyañadirmáspostsparavercómofunciona.Añade2ó3másyavanzaalasiguienteparte.
Filtrarobjetos
UnaparteimportantedelosQuerySetseslahabilidadparafiltrarlos.DigamosquequeremosencontrartodoslospostscuyoautoreselUserola.UsaremosfilterenvezdeallenPost.objects.all().Enlosparéntesisestableceremosquécondiciónoconducionesdebencumplirseporunpostdelblogparaterminarennuestroqueryset.Ennuestrocasoseríaauthoresigualame.LaformadeescribirloenDjangoes:author=me.Ahoranuestrobloquedecódigosevecomoesto:
>>>Post.objects.filter(author=me)
[<Post:Sampletitle>,<Post:Postnumber2>,<Post:My3rdpost!>,<Post:4thtitleofpost>]
¿Otalvezquerramosvertodoslospostsquecontenganlapalabra'title'enelcampotitle?
>>>Post.objects.filter(title__contains='title')
[<Post:Sampletitle>,<Post:4thtitleofpost>]
NotaHaydosguionesbajos(_)entretitleycontains.DjangoORMutilizaestasintaxisparasepararlosnombresdeloscampos("title")yoperacionesofiltros("contains").Sisóloutilizasunguiónbajo,obtendrásunerrorcomo"FieldError:Cannotresolvekeywordtitle_contains".
Tambiénpuedesobtenerunalistadetodoslospostspublicados.Lohacemosfiltrandolospostsquetienenelcampopublished_dateenelpasado:
fromdjango.utilsimporttimezonePost.objects.filter(published_date__lte=timezone.now())[]
DjangoGirlsTutorial
88ORMdeDjango(Querysets)
Desafortunadamente,ningunodenuestrospostshansidopublicadostodavía.¡Vamosacambiaresto!Primeroobténunainstanciadeunpostquequerramospublicar:
>>>post=Post.objects.get(id=1)
¡Luegoutilizaelmétodopublishparapublicarlo!
>>>post.publish()
Ahoraintentaobtenerlalistadepostspublicadosnuevamente(presionalateclaconlaflechahaciaarriba3vecesypresionaEnter):
>>>Post.objects.filter(published_date__lte=timezone.now())
[<Post:Sampletitle>]
Ordenandoobjetos
LosQuerySetstambiéntepermitenordenarlalistadeobjetos.Intentemosordenarlosporelcampocreated_date:
>>>Post.objects.order_by('created_date')
[<Post:Sampletitle>,<Post:Postnumber2>,<Post:My3rdpost!>,<Post:4thtitleofpost>]
Tambiénpodemosinvertirelordenamientoagregando-alprincipio:
>>>Post.objects.order_by('-created_date')
[<Post:4thtitleofpost>,<Post:My3rdpost!>,<Post:Postnumber2>,<Post:Sampletitle>]
¡Genial!¡Ahoraestáslistaparalasiguienteparte!Paracerrarlaconsola,tipea:
>>>exit()
$
DjangoGirlsTutorial
89ORMdeDjango(Querysets)
QuerysetsdeDjangoTenemosdiferentespiezasensulugar:elmodeloPostestádefinidoenmodels.py,tenemosapost_listenviews.pyylaplantillaagregada.¿PerocómoharemosrealmenteparaquenuestrospostsaparezcanennuestraplantillaHTML?Porqueesoesloquequeremoshacer:tomaralgúncontenido(modelosguardadosenlabasededatos)ymostrarloadecuadamenteennuestraplantilla,¿no?
Estoesexactamenteloquelasviewssesuponequehacen:conectarmodelosconplantillas.Ennuestraviewpost_listnecesitaremostomarlosmodelosquedeseamosmostrarypasarlosaunaplantilla.Asíquebásicamenteenunaviewdecidimosqué(modelo)semostraráenunaplantilla.
Muybien,ahora¿cómolohacemos?
Necesitamosabrirnuestroarchivoblog/views.py.Hastaahoralaviewpost_listseveasí:
fromdjango.shortcutsimportrender
defpost_list(request):
returnrender(request,'blog/post_list.html',{})
¿Recuerdascuandohablamosdeincluircódigoendiferentesarchivos?Ahoratenemosqueincluirelmodeloquedefinimosenelarchivomodels.py.Agregaremoslalíneafrom.modelsimportPostdelasiguienteforma:
fromdjango.shortcutsimportrender
from.modelsimportPost
Elpuntodespuésdefromindicaeldirectorioactualolaaplicaciónactual.Comoviews.pyymodels.pyestánenelmismodirectorio,simplementeusamos.yelnombredelarchivo(sin.py).Ahoraimportamoselnombredelmodelo(Post).
¿Peroahoraquésigue?ParatomarpublicacionesrealesdelmodeloPost,necesitamosalgollamadoQuerySet(conjuntodeconsultas).
QuerySet
DjangoGirlsTutorial
90Datosdinámicosenplantillas
YadebesestarfamiliarizadaconlaformaenquefuncionanlosQuerySets.HablamosdeellosenelcapítuloDjangoORM(QuerySets).
Entoncesahoranosinteresaobtenerunalistadeentradasdelblogquehansidopublicadasyordenadasporpublished_date(fechadepublicación),¿no?¡YahicimosesoenelcapítuloQuerySets!
Post.objects.filter(published_date__lte=timezone.now()).order_by('published_date')
Ahorapondremosestebloquedecódigoenelarchivoblog/views.py,agregándoloalafuncióndefpost_list(request):
fromdjango.shortcutsimportrender
fromdjango.utilsimporttimezone
from.modelsimportPost
defpost_list(request):
posts=Post.objects.filter(published_date__lte=timezone.now()).order_by('published_date'
returnrender(request,'blog/post_list.html',{})
ObservaquecreamosunavariableennuestroQuerySet:posts.TómalacomoelnombredenuestroQuerySet.DeaquíenadelantevamosareferirnosalQuerySetconesenombre.
LaúltimaparteespasarelQuerySetpostsalaplantilla(veremoscómomostrarlaenelsiguientecapítulo).
Enlafunciónrenderyatenemoselparámetrorequest(todoloquerecibimosdelusuarioviaInternet)yelarchivo'blog/post_list.html'comoplantilla.Elúltimoparámetro,queseveasí:{}esuncampoenelquepodemosagregaralgunascosasparaquelaplantillalasuse.Necesitamosnombrarlos(losseguiremosllamando'posts'porahora:)).Sedeberíaverasí:{'posts':posts}.Observaquelapartequevaantesde:estáentrecomillas''.
Finalmentenuestroarchivoblog/views.pydeberíaverseasí:
fromdjango.shortcutsimportrender
fromdjango.utilsimporttimezone
from.modelsimportPost
defpost_list(request):
posts=Post.objects.filter(published_date__lte=timezone.now()).order_by('published_date'
returnrender(request,'blog/post_list.html',{'posts':posts})
DjangoGirlsTutorial
91Datosdinámicosenplantillas
¡Terminamos!AhoraregresemosanuestraplantillaymostremosesteQuerySet.
SiquieresleerunpocomásacercadeQuerySetsenDjango,puedesdarleunvistazoa:https://docs.djangoproject.com/en/1.8/ref/models/querysets/
DjangoGirlsTutorial
92Datosdinámicosenplantillas
PlantillasdeDjango¡Eshorademostraralgunosdatos!Djangonosproveelasútilestemplatetagsparaello.
¿Quésonlastemplatetags?Verás,enHTMLnopuedesrealmenteponercódigoPython,porquelosnavegadoresnoloentienden.EllossólosabenHTML.SabemosqueHTMLesalgoestático,mientrasquePythonesmuchomásdinámico.
DjangotemplatetagsnospermitentransferircosasdePythoncomocosasenHTML,asíquetupuedesconstruirsitioswebdinámicosmásrápidoyfácil.
MostrarlaplantillapostlistEnelcapítuloanteriordimosanuestraplantillaunalistadepostsenlavariableposts.AhoralomostraremosenHTML.
ParaimprimirunavariableenunaplantilladeDjango,utilizamosllavesdoblesconelnombredelavariabledentro,así:
{{posts}}
Pruebaestoentuplantillablog/templates/blog/post_list.html(reemplazaelsegundoyeltercerpardeetiquetas<div></div>conlalínea{{posts}}),guardaelarchivoyactualizalapáginaparaverlosresultados:
Comopuedesver,todoloqueobtenemosesesto:
DjangoGirlsTutorial
93PlantillasdeDjango
[<Post:Misegundopost>,<Post:Miprimerpost>]
EstosignificaqueDjangoloentiendecomounalistadeobjetos.¿RecuerdasdeIntroducciónaPythoncómopodemosmostrarlistas?Sí,¡conlosciclosfor!EnunaplantilladeDjango,lohacesdeestamanera:
{%forpostinposts%}
{{post}}
{%endfor%}
Pruebaestoentuplantilla.
¡Funciona!PeroqueremosquesemuestrencomolospostsestáticosquecreamosanteriormenteenelcapítulodeIntroducciónaHTML.PuedesmezclarHTMLytemplatetags.Nuestrobodyseveráasí:
<div>
<h1><ahref="/">DjangoGirlsBlog</a></h1>
</div>
{%forpostinposts%}
<div>
<p>published:{{post.published_date}}</p>
<h1><ahref="">{{post.title}}</a></h1>
<p>{{post.text|linebreaks}}</p>
</div>
{%endfor%}
Todoloqueponesentre{%for%}y{%endfor%}serepetiráparacadaobjetoenlalista.Actualizatupágina:
DjangoGirlsTutorial
94PlantillasdeDjango
¿Hasnotadoqueutilizamosunanotacióndiferenteestavez{{post.title}}o{{post.text}}?EstamosaccediendoadatosencadaunodeloscamposdefinidosennuestromodeloPost.Tambiénel|linebreaksestádirigiendoeltextodelospostsatravésdeunfiltroparaconvertirsaltosdelíneaenpárrafos.
UnacosamásSeríabuenoversitusitiowebseguiráfuncionandoenlaInternetpública,¿verdad?IntentemosdesplegándolaenPythonAnywherenuevamente.Aquítedejamosunayudamemoria...
Primero,subetucódigoaGitHub
$gitstatus[...]$gitadd-A.$gitstatus[...]$gitcommit-m"Addedviewstocreate/editblogpostinsidethesite."[...]$gitpush
Luego,identifícateenPythonAnywhereyveatuconsolaBash(oempiezaunanueva),yejecuta:
$cdmy-first-blog$gitpull[...]
Finalmente,vealapestañaWebypresionaReloadentuaplicaciónweb.¡Tuactualizacióndeberíapoderverse!
DjangoGirlsTutorial
95PlantillasdeDjango
¡Felicidades!Ahorasigueadelante,tratadeagregarunnuevopostusandoelpaneldeadministradordeDjango(¡recuerdaañadirpublished_date!)yluegoactualizatupáginaparaversiaparecetunuevopost.
¿Funcionacomounencanto?¡Estamosorgullosos!Aléjatedetucomputadoraporunrato,tehasganadoundescanso.:)
DjangoGirlsTutorial
96PlantillasdeDjango
CSS-¡Hazlobonito!Nuestroblogtodavíasevebastantefeo,¿verdad?¡Eshoradehacerlobonito!VamosausarCSSparaeso.
¿QuéesCSS?CSS(CascadingStyleSheets,quesignifica'hojasdeestiloencascada')esunlenguajeutilizadoparadescribirelaspectoyelformatodeunsitiowebescritoenlenguajedemarcado(comoHTML).Trátalocomomaquillajeparanuestrapáginaweb;).
Peronoqueremosempezardecerootravez,¿verdad?Unavezmás,usaremosalgoqueyahasidorealizadoporprogramadoresypublicadoenInternetdeformagratuita.Yasabes,reinventarlaruedanoesdivertido.
¡VamosausarBootstrap!BootstrapesunodelosframeworksHTMLyCSSmáspopularesparadesarrollarwebsbonitas:http://getbootstrap.com/
LoescribieronprogramadoresquetrabajabanparaTwitteryahoralodesarrollanvoluntariosdetodoelmundo.
InstalarBootstrapParainstalarBootstraptienesqueañadirestoal<head>detufichero.html(blog/templates/blog/post_list.html):
<linkrel="stylesheet"href="//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css"
<linkrel="stylesheet"href="//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap-theme.min.css"
Estonoañadeningúnficheroatuproyecto.SimplementeapuntaaficherosqueexistenenInternet.Adelante,abretusitiowebyactualizalapágina.¡Aquíestá!
DjangoGirlsTutorial
97CSS-Hazlobonito
¡Sevemuchomejor!
FicherosestáticosenDjangoFinalmentenosvamosafijarenestascosasquehemosestadollamandoficherosestáticos.LosficherosestáticossontodostusCSSeimágenes;ficherosquenosondinámicos,porloquesucontenidonodependedelcontextodelapeticiónyseránigualesparatodoslosusuarios.
DóndeponerlosficherosestáticosparaDjango
Comohasvistocuandohemosejecutadocollectstaticenelservidor,Djangoyasabedóndeencontrarlosficherosestáticosparalaaplicación"admin".Ahoranecesitamosañadiralgunosficherosestáticosparanuestrapropiaaplicación,blog.
Estoloconseguimoscreandounacarpetallamadastaticdentrodelaaplicaciónblog:
djangogirls
├──blog
│├──migrations
│└──static
└──mysite
Djangoencontraráautomáticamentecualquiercarpetaquesellame"static"dentrodelascarpetasdetusaplicacionesypodráutilizarsucontenidocomoficherosestáticos.
¡TuprimerficheroCSS!
DjangoGirlsTutorial
98CSS-Hazlobonito
CreemosunficheroCSSahora,paraañadirtupropioestiloatupáginaweb.Crearunnuevodirectoriollamadocssdentrodetudirectoriostatic.Despuéscreaunnuevoficherollamadoblog.cssdentrodeestedirectoriocss.¿Lista?
djangogirls
└───blog
└───static
└───css
└───blog.css
¡EshoradeescribiralgodeCSS!Abreelficheroblog/static/css/blog.cssentueditordecódigo.
NovamosaentrarmuchoenlapersonalizaciónyelaprendizajedeCSSaquíporqueesbastantefácilylopuedesaprenderportucuentadespuésdeestetaller.RecomendamosenormementehacerestecursodeHTMLyCSSenCodecademyparaaprendertodoloquenecesitassabersobrecómohacertussitioswebmásbonitosconCSS.
Perovamosahacerunpocoalmenos.¿Talvezpodríamoscambiarelcolordenuestrotítulo?Losordenadoresutilizancódigosespecialesparaentenderloscolores.Empiezancon#ylessiguen6letras(A-F)ynúmeros(0-9).Puedesencontrarcódigosdecolor,porejemplo,aquí:http://www.colorpicker.com/.Tambiénpuedesutilizarcolorespredefinidosutilizandosunombreeninglés,comoredygreen.
Entuficheroblog/static/css/blog.cssdeberíasañadirelsiguientecódigo:
h1a{
color:#FCA205;
}
h1aesunselectorCSS.Quieredecirqueestamosaplicandonuestrosestilosacualquierelementoaqueseencuentredentrodeunelementoh1(porejemplocuandotenemosencódigoalgocomo:<h1><ahref="">enlace</a></h1>).Enestecasoleestamosdiciendoquecambieelcolora#FCA205,queesnaranja.Porsupuesto,¡puedesponertupropiocoloraquí!
EnunficheroCSSdefinimoslosestilosparaloselementosdelficheroHTML.Loselementosseidentificanporelnombredelelemento(esdecir,a,h1,body),elatributoclass(clase)oelatributoid(identificador).Classeidsonnombresqueleasignastúmismaalelemento.Lasclasesdefinengruposdeelementosylosidsapuntanaelementosespecíficos.Porejemplo,lasiguienteetiquetasepuedeidentificarconCSSusandoelnombrea,laclaseexternal_linkoelidlink_to_wiki_page:
DjangoGirlsTutorial
99CSS-Hazlobonito
<ahref="http://en.wikipedia.org/wiki/Django"class="external_link"id="link_to_wiki_page"
PuedesleermássobreselectoresdeCSSenw3schools.
TambiénnecesitamosdecirleanuestraplantillaHTMLquehemosañadidoCSS.Abreelficheroblog/templates/blog/post_list.htmlyañadeestalíneajustoalprincipio:
{%loadstaticfiles%}
Aquísóloestamoscargandoficherosestáticos:).Luego,entreel<head>y</head>,despuésdelosenlacesalosficherosCSSdeBootstrap(elnavegadorleelosficherosenelordenenqueestán,asíquenuestroficheropodríasobrescribirpartesdelcódigodeBootstrap),añadelasiguientelínea:
<linkrel="stylesheet"href="{%static'css/blog.css'%}">
LeacabamosdedeciranuestraplantilladóndeseencuentranuestroficheroCSS.
Ahoratuficherodeberíateneresteaspecto:
{%loadstaticfiles%}
<html>
<head>
<title>DjangoGirlsblog</title>
<linkrel="stylesheet"href="//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css"
<linkrel="stylesheet"href="//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap-theme.min.css"
<linkrel="stylesheet"href="{%static'css/blog.css'%}">
</head>
<body>
<div>
<h1><ahref="/">DjangoGirlsBlog</a></h1>
</div>
{%forpostinposts%}
<div>
<p>published:{{post.published_date}}</p>
<h1><ahref="">{{post.title}}</a></h1>
<p>{{post.text|linebreaks}}</p>
</div>
{%endfor%}
</body>
</html>
Deacuerdo,¡guardaelficheroyactualizaelsitio!
DjangoGirlsTutorial
100CSS-Hazlobonito
¡Buentrabajo!¿Quizánosgustaríadarleunpocodeaireanuestrositiowebyaumentartambiénelmargenenelladoizquierdo?¡Vamosaintentarlo!
body{
padding-left:15px;
}
AñadeestoatuCSS,guardaelficheroy¡miracómofunciona!
¿Quizápodríamospersonalizarlatipografíadeltítulo?Pegaestoenlasección<head>delficheroblog/templates/blog/post_list.html:
<linkhref="http://fonts.googleapis.com/css?family=Lobster&subset=latin,latin-ext"rel
DjangoGirlsTutorial
101CSS-Hazlobonito
EstalíneavaaimportarunatipografíallamadaLobsterdeGoogleFonts(https://www.google.com/fonts).
Ahoraañadelalíneafont-family:'Lobster';enelficheroCSSblog/static/css/blog.cssdentrodelbloquededeclaraciónh1a(elcódigoentrellaves{y})yactualizalapágina:
h1a{
color:#FCA205;
font-family:'Lobster';
}
¡Genial!
Comosemencionóanteriormente,CSStieneunconceptodeclasesquebásicamentepermitenombrarunapartedelcódigoHTMLyaplicarestilossóloaestaparte,sinafectaraotras.Esmuyútilsitienesdosdivsquehacenalgomuydiferente(comoelencabezadoylaentrada)ynoquieresquetenganelmismoaspecto.
¡Adelante!NombraalgunaspartesdelcódigoHTML.Añadeunaclasellamadapage-headeraldivquecontieneelencabezado,así:
<divclass="page-header">
<h1><ahref="/">DjangoGirlsBlog</a></h1>
</div>
Yahoraañadelaclasepostaldivquecontieneunaentradadelblog.
DjangoGirlsTutorial
102CSS-Hazlobonito
<divclass="post">
<p>published:{{post.published_date}}</p>
<h1><ahref="">{{post.title}}</a></h1>
<p>{{post.text|linebreaks}}</p>
</div>
Ahoraañadiremosbloquesdedeclaraciónadiferentesselectores.Losselectoresquecomienzancon.hacenreferenciaalasclases.HaymuchostutorialesyexplicacionessobreCSSenlawebqueteayudaránaentenderelsiguientecódigo.Porahora,simplementecopiaypegaestebloquedecódigoentuficheroblog/static/css/blog.css:
DjangoGirlsTutorial
103CSS-Hazlobonito
.page-header{
background-color:#ff9400;
margin-top:0;
padding:20px20px20px40px;
}
.page-headerh1,.page-headerh1a,.page-headerh1a:visited,.page-headerh1a:active{
color:#ffffff;
font-size:36pt;
text-decoration:none;
}
.content{
margin-left:40px;
}
h1,h2,h3,h4{
font-family:'Lobster',cursive;
}
.date{
float:right;
color:#828282;
}
.save{
float:right;
}
.post-formtextarea,.post-forminput{
width:100%;
}
.top-menu,.top-menu:hover,.top-menu:visited{
color:#ffffff;
float:right;
font-size:26pt;
margin-right:20px;
}
.post{
margin-bottom:70px;
}
.posth1a,.posth1a:visited{
color:#000000;
}
LuegorodeaelcódigoHTMLquemuestralasentradasconlasdeclaracionesdeclases.Sustituyeesto:
DjangoGirlsTutorial
104CSS-Hazlobonito
{%forpostinposts%}
<divclass="post">
<p>published:{{post.published_date}}</p>
<h1><ahref="">{{post.title}}</a></h1>
<p>{{post.text|linebreaks}}</p>
</div>
{%endfor%}
enblog/templates/blog/post_list.htmlporesto:
<divclass="contentcontainer">
<divclass="row">
<divclass="col-md-8">
{%forpostinposts%}
<divclass="post">
<divclass="date">
{{post.published_date}}
</div>
<h1><ahref="">{{post.title}}</a></h1>
<p>{{post.text|linebreaks}}</p>
</div>
{%endfor%}
</div>
</div>
</div>
Guardalosficherosyactualizatusitio.
¡Bien!Seveincreíble,¿verdad?Enrealidadelcódigoqueacabamosdepegarnoestandifícildeentenderydeberíassercapazdeentenderlamayoríasóloconleerlo.
NotengasmiedodejugarunpococonesteCSSeintentarcambiaralgunascosas.Sirompesalgo,notepreocupes,¡siemprepuedesdeshacerlo!
DjangoGirlsTutorial
105CSS-Hazlobonito
Decualquierforma,tevolvemosarecomendarquehagaselcursodeHTMLyCSSdeCodeacademycomounatareapost-tallerparaqueaprendastodoloquenecesitassaberparahacertussitioswebmásbonitosconCSS.
¡¿Listaparaelsiguientecapítulo?!:)
DjangoGirlsTutorial
106CSS-Hazlobonito
ExtendiendoPlantillasOtracosabuenaqueDjangotieneparatíeslaextensióndeplantillas.¿Quésignificaesto?SignificaquepuedesusarlasmismaspartesdetuHTMLparadiferentespáginasdetusitioweb.
Deestaformanotienesquerepetirelcódigoencadaunodelosarchivoscuandoquieresusarunamismainformaciónounmismoesquema.Ysiquierescambiaralgo,nonecesitashacerloencadaplantilla.
CreandounaplantillabaseUnaplantillabaseeslaplantillamásbásicaqueextiendesencadapáginadetusitioweb.
Vamosacrearunarchivobase.htmlenblog/templates/blog/:
blog
└───templates
└───blog
base.html
post_list.html
Luegoábreloycopiatodoloquehayenpost_list.htmlalarchivobase.html,delasiguientemanera:
DjangoGirlsTutorial
107Extenderplantillas
{%loadstaticfiles%}
<html>
<head>
<title>DjangoGirlsblog</title>
<linkrel="stylesheet"href="//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css"
<linkrel="stylesheet"href="//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap-theme.min.css"
<linkhref='//fonts.googleapis.com/css?family=Lobster&subset=latin,latin-ext'
<linkrel="stylesheet"href="{%static'css/blog.css'%}">
</head>
<body>
<divclass="page-header">
<h1><ahref="/">DjangoGirlsBlog</a></h1>
</div>
<divclass="contentcontainer">
<divclass="row">
<divclass="col-md-8">
{%forpostinposts%}
<divclass="post">
<divclass="date">
{{post.published_date}}
</div>
<h1><ahref="">{{post.title}}</a></h1>
<p>{{post.text|linebreaks}}</p>
</div>
{%endfor%}
</div>
</div>
</div>
</body>
</html>
Luego,enbase.htmlreemplazaporcompletotu<body>(todoloquehayaentre<body>and</body>)conesto:
<body>
<divclass="page-header">
<h1><ahref="/">DjangoGirlsBlog</a></h1>
</div>
<divclass="contentcontainer">
<divclass="row">
<divclass="col-md-8">
{%blockcontent%}
{%endblock%}
</div>
</div>
</div>
</body>
DjangoGirlsTutorial
108Extenderplantillas
Básicamenteremplazamostodoentre{%forpostinposts%}{%endfor%}con:
{%blockcontent%}
{%endblock%}
¿Quésignificaesto?Acabasdecrearunblock,unatemplatetagquetepermiteinsertarHTMLenestebloqueenotrasplantillasqueextiendanabase.html.Temostraremoscomohacerestoenunmomento.
Ahoraguárdaloyabretuarchivoblog/templates/blog/post_list.htmldenuevo.Eliminatodoloquenoestédentrodelbodyyluegoeliminatambién<divclass="page-header"></div>,deformaquetuarchivoseveráasi:
{%forpostinposts%}
<divclass="post">
<divclass="date">
{{post.published_date}}
</div>
<h1><ahref="">{{post.title}}</a></h1>
<p>{{post.text|linebreaks}}</p>
</div>
{%endfor%}
Yahoraagregaestalíneaaliniciodelarchivo:
{%extends'blog/base.html'%}
Significaqueahoraestamosextendiendodelaplantillabase.htmlenpost_list.html.Sólonosfaltaunacosa:ponertodo(exceptolalíneaqueacabamosdeagregar)entre{%blockcontent%}y{%endblockcontent%}.Comoesto:
{%extends'blog/base.html'%}
{%blockcontent%}
{%forpostinposts%}
<divclass="post">
<divclass="date">
{{post.published_date}}
</div>
<h1><ahref="">{{post.title}}</a></h1>
<p>{{post.text|linebreaks}}</p>
</div>
{%endfor%}
{%endblockcontent%}
DjangoGirlsTutorial
109Extenderplantillas
¡Esoestodo!Verificaquetusitiowebaúnfuncioneapropiadamente:)
SitienesunerrorTemplateDoesNotExistsquedigaquenohayunarchivoblog/base.htmlytienesrunserverejecutándoseenlaconsola,intentapararlo(presionandoCtrl+C-lasteclasControlyCjuntas)yreinicialoejecutandoelcomandopythonmanage.pyrunserver.
DjangoGirlsTutorial
110Extenderplantillas
AmplíatuaplicaciónYahemoscompletadotodoslospasosnecesariosparalacreacióndenuestrositioweb:sabemoscómoescribirunmodel,url,viewytemplate.Tambiénsabemoscómohacerquenuestrositiowebsevealindo.
¡Horadepracticar!
Loprimeroquenecesitamosennuestrobloges,obviamente,unapáginaparamostrarunpost,¿cierto?
YatenemosunmodeloPost,asíquenonecesitamosañadirnadaamodels.py.
CreaunenlaceenlaplantillaVamosaempezarañadiendounenlacedentrodelarchivoblog/templates/blog/post_list.html.Hastaelmomentodeberíaverseasí:
{%extends'blog/base.html'%}
{%blockcontent%}
{%forpostinposts%}
<divclass="post">
<divclass="date">
{{post.published_date}}
</div>
<h1><ahref="">{{post.title}}</a></h1>
<p>{{post.text|linebreaks}}</p>
</div>
{%endfor%}
{%endblockcontent%}
Queremostenerunenlaceaunapáginadedetallesobreeltítulodelpost.Vamosacambiar<h1><ahref="">{{post.title}}</a></h1>dentrodelenlace:
<h1><ahref="{%url'blog.views.post_detail'pk=post.pk%}">{{post.title}}</a></h1>
Eshoradeexplicarelmisterioso{%url'blog.views.post_detail'pk=post.pk%}.Comoprobablementesospeches,lanotación{%%}significaqueestamosutilizandoDjangotemplatetags.¡EstavezvamosautilizarunoquevaacrearunadirecciónURLparanosotros!
DjangoGirlsTutorial
111Amplíatuaplicación
blog.views.post_detailesunarutahaciapost_detailviewquequeremoscrear.Porfavornota:blogeselnombredenuestraaplicación(elblogdedirectorio),viewseselnombredelarchivoviews.pyypost_detaileselnombredelaview.
Ahoracuandovayamosa:http://127.0.0.1:8000/tendremosunerror(comoeradeesperar,yaquenotenemosunadirecciónURLounaviewparapost_detail).Severáasí:
VamosacrearunaURLenurls.pyparanuestroviewpost_detail!
URL:http://127.0.0.1:8000/post/1/
QueremoscrearunaURLqueapunteaDjangoaunaviewdenominadapost_detail,quemostraráunaentradadelblog.Agregalalíneaurl(r'^post/(?P<pk>[0-9]+)/$',views.post_detail),alarchivoblog/urls.py.Deberíateneresteaspecto:
```fromdjango.conf.urlsimportinclude,urlfrom.importviews
urlpatterns=[
url(r'^$',views.post_list),
url(r'^post/(?P<pk>[0-9]+)/$',views.post_detail),
]
DjangoGirlsTutorial
112Amplíatuaplicación
Esedaunpocodemiedo,peronotepreocupes-loexplicaremosparati:comienzacon`^`otravez,"elprincipio".`post/`sólosignificaquedespuésdelcomienzo,ladirecciónURLdebecontenerlapalabra**post**y**/**.Hastaahora,bien.`(?P<pk>[0-9]+)`-estaparteesmáscomplicada.SignificaqueDjangollevarátodoloquecoloquesaquíylotransferiráaunavistacomounavariablellamada`pk`.`[0-9]`tambiénnosdicequesólopuedeserunnúmero,nounaletra(tododeberíaestarentre0y9).`+`significaquetienequehaberunoomásdígitos.Entoncesalgocomo`http://127.0.0.1:8000/post//`noesválido,pero`1234567890/post/http://127.0.0.1:8000/`esperfectamenteaceptable!-`/`-entoncesnecesitamos**/**denuevo-`$`-¡"elfinal"!
Esosignificaquesientrasen`http://127.0.0.1:8000/post/5/`entunavegador,Djangoentenderáqueestásbuscandouna*view*denominada`post_detail`ytransferirálainformaciónde`pk`queesiguala`5`aesa*view*.
`pk`eslaabreviaciónde`primarykey`.EstenombreseutilizaamenudoenproyectosdeDjango.Peropuedesnombrartusvariablescomoteguste(recuerda:¡minúsculasy`_`enlugardeespaciosenblanco!).Porejemploenlugarde`(?.¿P<pk>[0-9]+)`podríamostenerlavariable`post_id`,asíqueestoloveríascomo:`(?P<post_id>[0-9]+)`.
¡Bien!¡Actualizalapágina:http://127.0.0.1:8000/¡Boom!¡Sinembargovemosotroerror!Comoeradeesperarse.
![AttributeError][2]
[2]:images/attribute_error2.png
¿Teacuerdasdelpróximopaso?Porsupuesto:¡agregarunaview!
##post_detailview
Estaveznuestra*view*tomaráunparámetroadicional`pk`.¿Nuestra*view*necesitarecibirla,cierto?Entoncesdefiniremosnuestrafuncióncomo`defpost_detail(request,pk):`.Tenencuentaquetenemosqueusarexactamenteelmismonombrequeespecificamosenlasurls(`pk`).¡Omitirestavariableesincorrectoyresultaráenunerror!
Ahora,queremossólounpostdelblog.Paraellopodemosusarquerysetscomoeste:
Post.objects.get(pk=pk)
Peroestecódigotieneunproblema.Sinohayningún`Post`con`llaveprimaria`(`pk`)tendremosunerrormuyfeo.
![DoesNotExisterror][3]
[3]:images/does_not_exist2.png
¡Noqueremoseso!Pero,porsupuesto,Djangovieneconalgoqueseencargarádeeseproblemapornosotros:`get_object_or_404`.Encasodequenohayaningún`Post`coneldado`pk`semostraráunamásagradablepágina(`PageNotFound404`).
![Pagenotfound][4]
[4]:images/404_2.png
Labuenanoticiaesquepuedescreartupropiapágina`PageNotFound`ydiseñarlacomodesees.Peroporahoranoestanimportante,asíqueloomitiremos.
¡Eshoradeagregaruna*view*anuestroarchivo`views.py`!
Deberíamosabrir`blog/views.py`yagregarelsiguientecódigo:
fromdjango.shortcutsimportrender,get_object_or_404
Cercadeotraslíneas`from`.Yenelfinaldelarchivoañadimosnuestra*view*:
```defpost_detail(request,pk):
post=get_object_or_404(Post,pk=pk)
returnrender(request,'blog/post_detail.html',{'post':post})
DjangoGirlsTutorial
113Amplíatuaplicación
Sí.Eshoradeactualizarlapágina:http://127.0.0.1:8000/
¡Funcionó!Pero¿quépasacuandohacesclickenunenlaceeneltítulodelpost?
¡Ohno!¡Otroerror!Peroyasabemoscómolidiarconeso,¿no?¡Tenemosqueañadirunaplantilla!
Crearemosunarchivoenblog/templates/blogllamadopost_detail.html.
Severáasí:
{%extends'blog/base.html'%}
{%blockcontent%}
<divclass="post">
{%ifpost.published_date%}
<divclass="date">
{{post.published_date}}
</div>
{%endif%}
<h1>{{post.title}}</h1>
<p>{{post.text|linebreaks}}</p>
</div>
{%endblock%}
Unavezmásestamosextendiendobase.html.Enelbloquecontentqueremosmostrarlafechadepublicación(siexiste),títuloytextodenuestrosposts.Perodeberíamosdiscutiralgunascosasimportantes,¿cierto?
{%if...%}...{%endif%}esuntemplatetagquepodemosusarcuandoquerramosveralgo(¿recuerdasif...else...</code>delcapítulodeIntroducciónaPython?).Enesteescenarioqueremoscomprobarsielcampopublished_datedeunpostnoestávacío.
Bien,podemosactualizarnuestrapáginayversiPageNotFoundsehaido.
¡Yay!¡Funciona!
Unacosamás:¡Tiempodeimplementación!SeríabuenoverificarquetusitiowebaúnfuncionaráenPythonAnywhere,¿cierto?Intentemosdesplegardenuevo.
DjangoGirlsTutorial
114Amplíatuaplicación
$gitstatus
$gitadd-A.
$gitstatus
$gitcommit-m"Addedviewstocreate/editblogpostinsidethesite."
$gitpush
Luego,enunaconsolaBashdePythonAnywhere
$cdmy-first-blog$gitpull[...]
Finalmente,vealapestañaWebyhazclickenReload.
¡Yesodeberíasertodo!Felicidades:)
DjangoGirlsTutorial
115Amplíatuaplicación
FormulariosenDjangoLoúltimoqueharemosennuestrowebsiteescrearunapartadoparaagregaryeditarpostsenelblog.Djangoadminestábien,peroesbastantedifícildepersonalizaryhacerlobonito.Conformstendremosunpoderabsolutosobrenuestrainterfaz-podemoshacercasicualquiercosaquepodamosimaginar!
LobuenodeDjangoformsesquepodemosdefinirlodesdeceroocreandounModelFormyseguardaráelresultadodelformularioenelmodelo.
Estoesexactamenteloquequeremoshacer:crearemosunformularioparanuestromodeloPost.
ComocadaparteimportantedeDjango,formstienensupropioarchivo:forms.py.
Tenemosquecrearunarchivoconestenombreeneldirectorioblog.
blog
└──forms.py
Ok,vamosabrirloyvamosaescribirelsiguientecódigo:
fromdjangoimportforms
from.modelsimportPost
classPostForm(forms.ModelForm):
classMeta:
model=Post
fields=('title','text',)
PrimeronecesitamosimportarDjangoforms(fromdjangoimportforms)y,obviamente,nuestromodeloPost(from.modelsimportPost).
PostForm,comoprobablementesospechas,eselnombredelformulario.NecesitamosdecirleaDjangoqueesteformularioesunModelForm(asíDjangoharáalgodemagiaparanosotros)-forms.ModelFormesresponsabledeello.
Acontinuación,tenemosclassMeta,dondeledecimosaDjangoquémodelodebeutilizarparacrearesteformulario(model=Post).
DjangoGirlsTutorial
116FormulariosenDjango
Finalmente,podemosdecirquecampo(s)queremosennuestroformulario.Enesteescenariosóloqueremostitleytext-authorserálapersonaquesehaautenticado(¡tú!)ycreated_datesedefiniráautomáticamentecuandocreemosunpost(esdecirenelcódigo),¿si?
¡Yesoestodo!Todoloquenecesitamoshacerahoraesusarelformularioenunaviewymostrarlaenunaplantilla.
Unavezmásvamosacrear:unenlacealapágina,unadirecciónURL,unavistayunaplantilla.
EnlaceaunapáginaconelformularioEshoradeabrirblog/templates/blog/base.html.Vamosaañadirunenlaceendivllamadopage-header:
<ahref="{%url'blog.views.post_new'%}"class="top-menu"><spanclass="glyphiconglyphicon-plus"
Tenencuentaquequeremosllamaranuestranuevavistapost_new.
Despuésdeagregarlalínea,tuarchivohtmldeberíateneresteaspecto:
DjangoGirlsTutorial
117FormulariosenDjango
{%loadstaticfiles%}
<html>
<head>
<title>DjangoGirlsblog</title>
<linkrel="stylesheet"href="//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css"
<linkrel="stylesheet"href="//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap-theme.min.css"
<linkhref='//fonts.googleapis.com/css?family=Lobster&subset=latin,latin-ext'
<linkrel="stylesheet"href="{%static'css/blog.css'%}">
</head>
<body>
<divclass="page-header">
<ahref="{%url'blog.views.post_new'%}"class="top-menu"><spanclass="glyphiconglyphicon-plus"
<h1><ahref="/">DjangoGirlsBlog</a></h1>
</div>
<divclass="contentcontainer">
<divclass="row">
<divclass="col-md-8">
{%blockcontent%}
{%endblock%}
</div>
</div>
</div>
</body>
</html>
Luegodeguardaryactualizarlapáginahttp://127.0.0.1:8000obviamenteverásunerrorNoReverseMatchfamiliar,¿verdad?
URLAbrimosblog/urls.pyyañadimosunalínea:
url(r'^post/new/$',views.post_new,name='post_new'),
Yelcódigofinaltendráesteaspecto:
fromdjango.conf.urlsimportinclude,url
from.importviews
urlpatterns=[
url(r'^$',views.post_list),
url(r'^post/(?P<pk>[0-9]+)/$',views.post_detail),
url(r'^post/new/$',views.post_new,name='post_new'),
]
DjangoGirlsTutorial
118FormulariosenDjango
Despuésdeactualizarelsitio,veremosunAttributeError,puestoquenotenemoslavistapost_newimplementada.Vamosaañadirlaahora.
Vistapost_newEselmomentodeabrirelarchivoblog/views.pyyagregarlassiguienteslíneasalrestodelasfilasfrom:
from.formsimportPostForm
ynuestravista:
defpost_new(request):
form=PostForm()
returnrender(request,'blog/post_edit.html',{'form':form})
ParacrearunnuevoformularioPost,tenemosquellamaraPostForm()ypasarloalaplantilla.Volveremosaestavistapero,porahora,vamosacrearrápidamenteunaplantillaparaelformulario.
PlantillaTenemosquecrearunarchivopost_edit.htmleneldirectorioblog/templates/blog.Parahacerqueunformulariofuncionenecesitamosvariascosas:
tenemosquemostrarelformulario.Podemoshacerlo,porejemplo,conunsimple``.lalíneaanteriortienequeestardentrodeunaetiquetadeformularioHTML:<formmethod="POST">...</form>
necesitamosunbotónGuardar.LohacemosconunbotónHTML:<buttontype='submit'>Save</button>
yfinalmentejustodespuésdelaaperturade<form...>necesitamosagregar{%csrf_token%}.¡Estoesmuyimportanteyaquehacequetusformulariosseanseguros!Djangosequejarásiteolvidasdeestapartecuandointenteguardarelformulario.
DjangoGirlsTutorial
119FormulariosenDjango
Bueno,vamosavercómoquedaráelHTMLenpost_edit.html:
{%extends'blog/base.html'%}
{%blockcontent%}
<h1>Newpost</h1>
<formmethod="POST"class="post-form">{%csrf_token%}
{{form.as_p}}
<buttontype="submit"class="savebtnbtn-default">Save</button>
</form>
{%endblock%}
¡Eshoradeactualizar!¡Si!¡Tuformulariosemuestra!
DjangoGirlsTutorial
120FormulariosenDjango
Pero,¡unmomento!Siescribesalgoenloscampostítleytextytratasdeguardarloscambios-¿quépasará?
¡Nada!Unavezmásestamosenlamismapáginayeltextosehaido...noseañadeningúnpostnuevo.Entonces,¿quéhaidomal?
Larespuestaes:nada.Tenemosquetrabajarunpocomásennuestravista.
GuardarelformularioAbreblog/views.pyunavezmás.Actualmente,loquetenemosenlavistapost_newes:
defpost_new(request):
form=PostForm()
returnrender(request,'blog/post_edit.html',{'form':form})
Cuandoenviamoselformulariosomosredirigidosalamismavista,peroestaveztenemosalgunosdatosadicionalesenrequest,másespecíficamenteenrequest.POST(elnombrenotienenadaqueverconunpostdelblog,serefiereaqueestamos"publicando"-eninglés,posting-datos).¿RecuerdasqueenelarchivoHTMLladefiniciónde<form>tenía
DjangoGirlsTutorial
121FormulariosenDjango
lavariablemethod="POST"?Todosloscamposdelformularioestanahoraenrequest.POST.NodeberíasrenombrarlavariablePOST(elúniconombrequetambiénesválidoparalavariablemethodesGET,peronotenemostiempoparaexplicarcuálesladiferencia).
Ennuestraviewtenemosdosposiblessituacionesacontemplar.Primero:cuandoaccedemosalapáginaporprimeravezyqueremosunformularioenblanco.Segundo:cuandovolvemosalaviewconlosdatosdelformularioqueacabamosdeescribir.Asíquetenemosqueañadirunacondición(utilizaremosifparaeso).
ifrequest.method=="POST":
[...]
else:
form=PostForm()
Eshoradellenarlospuntos[...].SielmethodesPOSTqueremosconstruirelPostFormconlosdatosdelformulario,¿no?Loharemoscon:
form=PostForm(request.POST)
Fácil!Losiguienteesverificarsielformularioescorrecto(todosloscamposnecesariosestándefinidosynohayvaloresincorrectos).Lohacemosconform.is_valid().
Comprobamosqueelformularioesválidoy,siesasí,¡lopodemossalvar!
ifform.is_valid():
post=form.save(commit=False)
post.author=request.user
post.save()
Básicamente,tenemosquehacerdoscosasaquí:guardamoselformularioconform.saveyañadimosunautor(yaquenohabíaningúncampodeauthorenelPostFormyestecampoesobligatorio).commit=FalsesignificaquenoqueremosguardarelmodeloPosttodavía-queremosañadirelautorprimero.Lamayoríadelasvecesutilizarásform.save(),sincommit=False,peroenestecaso,tenemosquehacerlo.post.save()conservaráloscambios(añadiendoaautor)ysecrearáunanuevopostenelblog.
Porúltimo,seríagenialsipodemosinmediatamenteiralapáginapost_detaildelnuevopostdeblog,¿no?Parahacerlonecesitamosimportaralgomás:
fromdjango.shortcutsimportredirect
DjangoGirlsTutorial
122FormulariosenDjango
Agrégaloalprincipiodelarchivo.Yahorapodemosdecir:véalapáginapost_detaildelpostreciéncreado.
returnredirect('blog.views.post_detail',pk=post.pk)
blog.views.post_detaileselnombredelavistaalaquequeremosir.¿Recuerdasqueestaviewrequiereunavariablepk?Parapasarloalasvistasutilizamospk=post.pk,dondeposteselpostreciéncreado.
Bien,hablamosmucho,peroprobablementequeremosvercomoseveahoralavista,¿verdad?
defpost_new(request):
ifrequest.method=="POST":
form=PostForm(request.POST)
ifform.is_valid():
post=form.save(commit=False)
post.author=request.user
post.save()
returnredirect('blog.views.post_detail',pk=post.pk)
else:
form=PostForm()
returnrender(request,'blog/post_edit.html',{'form':form})
Vamosaversifunciona.Vealapáginahttp://127.0.0.1:8000/post/new/,añadeuntitleyuntext,guardalo...¡yvoilà!Seañadeelnuevopostalblogysenosredirigealapáginadepost_detail.
Probablementehasvistoquenohemosdefinidolafechadepublicación.VamosaintroducirunbotónpublicarenDjangoGirlsTutorial:Extensions.
¡Esoesgenial!
ValidacióndeformulariosAhora,vamosaenseñartequétanbuenoesDjangoforms.Unpostdelblogdebetenerloscampostitleytext.EnnuestromodeloPostnodijimos(adiferenciadepublished_date)queestoscampossonrequeridos,asíqueDjango,pordefecto,esperaqueesténdefinidos.
Tratadeguardarelformulariosintitleytext.¡Adivinaquépasará!
DjangoGirlsTutorial
123FormulariosenDjango
Djangoseencargadevalidarquetodosloscamposenelformularioesténcorrectos.¿Noesgenial?
ComorecientementehemosutilizadolainterfazdeadministradordeDjango,elsistemapiensaqueestamosconectadas.Hayalgunassituacionesquepodríanllevarnosadesconectarnos(cerrandoelnavegador,reiniciandolabasededatos,etc.).Siestásrecibiendoerroresalcrearunpostqueindicanlafaltadeiniciodesesióndeusuario,dirígetealapáginadeadministraciónhttp://127.0.0.1:8000/admineiniciasesiónnuevamente.Estoresolveráelproblematemporalmente.HayunarreglopermanenteesperándoteenelcapítuloTarea:¡Añadirseguridadatusitioweb!despuésdeltutorialprincipal.
DjangoGirlsTutorial
124FormulariosenDjango
EditarformularioAhorasabemoscómoagregarunnuevoformulario.Pero,¿quépasasiqueremoseditarunoexistente?Esmuysimilaraloqueacabamosdehacer.Vamosacrearalgunascosasimportantesrápidamente(sinoentiendesalgo,pregúntaleatututororevisalocapítulosanteriores,sontemasqueyahemoscubierto).
Abreelarchivoblog/templates/blog/post_detail.htmlyañadeestalínea:
<aclass="btnbtn-default"href="{%url'post_edit'pk=post.pk%}"><spanclass="glyphiconglyphicon-pencil"></span></a>
paraquelaplantillaquede:
{%extends'blog/base.html'%}
{%blockcontent%}
<divclass="date">
{%ifpost.published_date%}
{{post.published_date}}
{%endif%}
<aclass="btnbtn-default"href="{%url'post_edit'pk=post.pk%}"><spanclass="glyphiconglyphicon-pencil"
</div>
<h1>{{post.title}}</h1>
<p>{{post.text|linebreaks}}</p>
{%endblock%}
Enelarchivoblog/urls.pyañadimosestalínea:
url(r'^post/(?P<pk>[0-9]+)/edit/$',views.post_edit,name='post_edit'),
Vamosareusarlaplantillablog/templates/blog/post_edit.html,asíqueloúltimoquenosfaltaesunaview.
Abramoselarchivoblog/views.pyyañadamosalfinalestalínea:
DjangoGirlsTutorial
125FormulariosenDjango
defpost_edit(request,pk):
post=get_object_or_404(Post,pk=pk)
ifrequest.method=="POST":
form=PostForm(request.POST,instance=post)
ifform.is_valid():
post=form.save(commit=False)
post.author=request.user
post.save()
returnredirect('blog.views.post_detail',pk=post.pk)
else:
form=PostForm(instance=post)
returnrender(request,'blog/post_edit.html',{'form':form})
Estosevecasiexactamenteigualanuestraviewpost_new,¿no?Peronodeltodo.Primero:pasamosunparámetroextrapkdelosurls.Luego:obtenemoselmodeloPostquequeremoseditarconget_object_or_404(Post,pk=pk)ydespués,alcrearelformulariopasamosestepostcomounainstanciatantoalguardarelformulario:
form=PostForm(request.POST,instance=post)
comoalabrirunformularioconestepostparaeditarlo:
form=PostForm(instance=post)
Ok,¡vamosaprobarsifunciona!Dirígetealapáginapost_detail.Debehaberahíunbotónparaeditarenlaesquinasuperiorderecha:
DjangoGirlsTutorial
126FormulariosenDjango
Aldarclickahí,debesverelformularioconnuestropostdelblog:
¡Siéntetelibredecambiareltítulooeltextoyguardaloscambios!
¡Felicitaciones!¡Tuaplicaciónestácadavezmáscompleta!
SinecesitasmásinformaciónsobrelosformulariosdeDjango,debesleerladocumentación:https://docs.djangoproject.com/en/1.8/topics/forms/
Unacosamás:¡Tiempodeimplementación!VeamossitodoestofuncionaenPythonAnywhere.¡Tiempodehacerotrodespliegue!
Primero,hazuncommitcontunuevocódigoysúbeloaGitHub
$gitstatus$gitadd-A.$gitstatus$gitcommit-m"Addedviewstocreate/editblogpostinsidethesite."$gitpush
Luego,enunaconsolaBashdePythonAnywhere
$cdmy-first-blog$gitpull[...]
Finalmente,vealapestañaWebyhazclickenReload.
DjangoGirlsTutorial
127FormulariosenDjango
¡Yesodeberíasertodo!Felicidades:)
DjangoGirlsTutorial
128FormulariosenDjango
DominioPythonAnywheretehadadoundominiogratuito,perotalveznoquierastener".pythonanywhere.com"alfinaldelaURLdetublog.Quizásquieraquetublogvivaen"www.infinite-kitten-pictures.org"o"www.3d-printed-steam-engine-parts.com"o"www.antique-buttons.com"o"www.mutant-unicornz.net",oloquequierasquesea.
AquíhablaremosbrevementesobrecómoobtenerundominioyveremoscómovincularloatuaplicaciónwebenPythonAnywhere.Sinembargo,deberíassaberquelamayoríadelosdominiossonpagos,yPythonAnywheretecobraráunvaloradicionalparausartupropionombrededominio--noesdemasiadodineroentotal,peroesprobablementealgoquequierashacersólosiestásmuycomprometidaconlacausa.
¿Donderegistrarundominio?Undominiotípicocuestaalrededorde15dólaresestadounidensesanuales.Hayopcionesmásbaratasymáscaras,dependiendodelproveedor.Hayunagrancantidaddeempresasalasquepuedescomprarundominio:unasimplebúsquedaengoogledarácientosdeopciones.
NuestraopciónfavoritaesIwantmyname.Ellossepromocionancomounaopción"indoloraparaelmanejodedominios"yrealmenteloson.
Tambiénpuedesobtenerdominiosgratuitos.dot.tkesunlugarparaobteneruno,perodeberíamosadvertirtequelosdominiosgratuitosavecessesientenalgo"baratos"--situsitiovaaserunsitioparaunnegocioprofesional,seguramentequierasconsiderarcomprarundominio"apropiado"quetermineen.com.
CómoapuntartudominioaPythonAnywhereSielegistelaopcióndeiwantmyname.com,hazclickenDomainsenelmenúyelijetunuevodominio.LuegoencuentraelvínculoamanageDNSrecords:
Ahoranecesitasencontraresteformulario:
DjangoGirlsTutorial
129Dominio
Ycompletarloconlossiguientesdetalles:-Hostname:www-Type:CNAME-Value:tudominiodePythonAnywhere(porejemplo,djangogirls.pythonanywhere.com)-TTL:60
Enlaparteinferior,hazclickenelbotón"Agregar"yguardaloscambios.
NotaSiutilizasteunproveedordedominiosdiferente,lainterfazexactaparaencontrartusconfiguracionesdeDNS/CNAMEserádiferente,perotuobjetivoeselmismo:configurarunCNAMEqueapunteatunuevodominioenyourusername.pythonanywhere.com.
Puedetomarunosminutosparatudominioparaempezarafuncionar,¡sépaciente!
ConfiguraeldominioatravésdelaaplicaciónwebenPythonAnywhereTambiénnecesitarásdecirleaPythonAnywherequequieresusartudominiopersonalizado.
VealapáginaPythonAnywhereAccountsyhazunaactualizacióndeltipodecuenta.Laopciónmáseconómica(elplan"Hacker")estábienparaempezar.Siemprepuedeselegirunplanconmayoresprestacionesdespuéscuandotevuelvassuper-famosaytengasmillonesdevisitas.
Luego,vealapestañaWebyanotaunpardecosas:
CopialarutaatuvirtualenvyponlaenalgúnlugarseguroAbretuarchivodeconfiguraciónWSGI,copiaelcontenido,ypégaloenalgúnlugarseguro
Luego,hazclickenDeletedetuviejaaplicaciónweb.Notepreocupes,estonoeliminarátucódigo,solamentecambiaráeldominioyourusername.pythonanywhere.com.Luego,creaunanuevaaplicaciónwebysigueestospasos:
IngresatunombrededominioElije"configuraciónmanual"ElijePython3.4¡Ylisto!
Cuandoseasredirigidaalapestañaweb.
PegalarutaalvirtualenvqueguardasteanteriormenteAbretunuevoarchivodeconfiguraciónWSGIypegaelcontenidodetuviejoarchivodeconfiguración
DjangoGirlsTutorial
130Dominio
Hazclickenactualizar,¡deberíasverquetusitioestáenlíneaenelnuevodominio!
Siteencuentrasconalgúnproblema,hazclickenelvínculo"Sendfeedback"enelsitiodePythonAnywhere,yunodesusamigablesadministradorestecontactaráparaayudarteenbreve.
DjangoGirlsTutorial
131Dominio
¿Quésigue?¡Datemuchasfelicitaciones!¡Eresincreíble!.¡Estamosorgullosos!<3
¿Quéhacerahora?
Tomaundescansoyrelájate.Acabasdehaceralgorealmentegrande.
Despuésdeeso,asegúratede:
SeguiraDjangoGirlsenFacebookoTwitterparaestaraldía
¿Mepuedesrecomendarrecursosadicionales?
¡Sí!Enprimerlugar,sigueadelanteypruebanuestrolibrollamadoDjangoGirlsTutorial:Extensiones.
Másadelante,puedesintentarlosrecursoslistadosacontinuación.¡Estántodosmuyrecomendados!
Django'sofficialtutorialNewCodertutorialsCodeAcademyPythoncourseCodeAcademyHTML&CSScourseDjangoCarrotstutorialLearnPythonTheHardWaybookGettingStartedWithDjangovideolessonsTwoScoopsofDjango:BestPracticesforDjangobook
DjangoGirlsTutorial
132¿Quésigue?