Tutorial de Django Girls

advertisement
DjangoGirlsTutorial
Tabladecontenido
Introducción
0
¿CómofuncionaInternet?
1
Introducciónalalíneadecomandos
2
InstalacióndePython
3
Editordecódigo
4
IntroducciónaPython
5
¿QuéesDjango?
6
InstalacióndeDjango
7
ComenzarunproyectoenDjango
8
ModelosenDjango
9
AdministradordeDjango
10
¡Desplegar!
11
Djangourls
12
VistasdeDjango-¡Eshoradecrear!
13
IntroducciónaHTML
14
ORMdeDjango(Querysets)
15
Datosdinámicosenplantillas
16
PlantillasdeDjango
17
CSS-Hazlobonito
18
Extenderplantillas
19
Amplíatuaplicación
20
FormulariosenDjango
21
Dominio
22
¿Quésigue?
23
2
DjangoGirlsTutorial
TutorialdeDjangoGirls
EstetrabajoestábajolalicenciainternacionalCreativeCommonsAttributionShareAlike4.0.Paraverunacopiadeestalicencia,visitaelsiguienteenlace
http://creativecommons.org/licenses/by-sa/4.0/
Translation
ThistutorialhasbeentranslatedfromEnglishintoSpanishbyawonderfulgroupof
volunteers.SpecialthanksgoestoVictoriaMartinezdelaCruz,KevinMorales,Joshua
Aranda,SilviaFrias,Leticia,AndreaGonzalez,AdrianManjarres,RodrigoCaicedo,Maria
Chavez,MarceloNicolasManso,RosaDurante,Moises,IsraelMartinezVargas,
JuanCarlos_,N0890Dy,IvanYivoff,KhaterineCastellano,ErickNavarro,cyncyncyn,
ZeroSoul13,ErickAguayo,ErnestoRico-Schmidt,MiguelLozano,osueboy,dynarroand
GeraldinaGarciaAlvarez.
Introducción
¿Algunavezhassentidoqueelmundoestácadavezmáscercanoalatecnologíayde
ciertomodotehasquedadoatrás?¿Algunaveztehaspreguntadocómocrearunsitioweb
peronuncahastenidolasuficientemotivaciónparaempezar?¿Haspensadoalgunavez
queelmundodelsoftwareesdemasiadocomplicadoparaticomoparaintentarhaceralgo
portucuenta?
Bueno,¡tenemosbuenasnoticiasparati!Programarnoestandifícilcomoaparentay
queremosmostrartecuándivertidopuedellegaraser.
Estetutorialnoteconvertiráenprogramadormágicamente.Siquieresserbuenaenesto,
necesitarásmesesoinclusosañosdeaprendizajeypráctica.Peroqueremosmostrarteque
programarocrearsitioswebnoestancomplicadocomoparece.Intentaremosexplicar
pequeñasparteslomejorquepodamos,deformaquenotesientasintimidadaporla
tecnología.
¡Esperamospoderhacerteamarlatecnologíatantocomonosotraslohacemos!
¿Quéaprenderásconestetutorial?
Introducción
3
DjangoGirlsTutorial
Cuandotermineseltutorial,tendrásunaaplicaciónwebsimpleyfuncional:tupropioblog.
Temostraremoscomopublicarlaonline,¡asíotrospodránvertutrabajo!
Tendrá(másomenos)éstaapariencia:
Siestássiguiendoestetutorialportucuentaynotienesanadiequeteayudeencaso
desurgiralgúnproblema,tenemosunchatparati:
.¡Hemos
pedidoanuestrostutoresyparticipantesanterioresqueesténahídevezencuando
paraayudaraotrosconeltutorial!¡Notemasdejartuspreguntasallí!
Bien,empecemosporelprincipio...
Sobrenosotrosycómocontribuir
EstetutoriallomantieneDjangoGirls.Siencuentrasalgúnerroroquieresactualizarel
tutorial,porfavorsiguelaguíadecómocontribuir.
Introducción
4
DjangoGirlsTutorial
¿Tegustaríaayudarnosatraducireltutoriala
otrosidiomas?
Actualmente,lastraduccionessellevanacabosobrelaplataformacrowdin.comen:
https://crowdin.com/project/django-girls-tutorial
Situidiomanoestalistadoencrowdin,porfavorabreunnuevoproblemainformandoel
idiomaasípodemosagregarlo.
Introducción
5
DjangoGirlsTutorial
¿CómofuncionaInternet?
Estecapituloestáinspiradoporlacharla"HowtheInternetworks"deJessicaMcKellar
(http://web.mit.edu/jesstess/www/).
ApostamosqueutilizasInternettodoslosdías.Pero,¿sabesloquepasacuandoescribes
unadireccióncomohttp://djangogirls.orgentunavegadorypresionas'Enter'?
Loprimeroquetienesqueentenderesqueunsitiowebessólounmontóndearchivos
guardadosenundiscoduro.Aligualquetuspelículas,músicaofotos.Sinembargo,los
sitioswebposeenunapeculiaridad:ellosincluyenuncódigodecomputadorasllamado
HTML.
Sinoestásfamiliarizadaconlaprogramación,puedeserdifícildecaptarHTMLalprincipio,
perotusnavegadoresweb(comoChrome,Safari,Firefox,etc.)loaman.Losnavegadores
webestándiseñadosparaentenderestecódigo,seguirsusinstruccionesymostrartodos
esosarchivosdeloscualestusitiowebestáhechodelamaneraexactacomotuquieres
quesemuestren.
Comocualquierotroarchivo,tenemosqueguardarlosarchivosHTMLenalgúnlugardeun
discoduro.ParaInternet,usamosunascomputadorasespecialesypoderosasllamadas
servidores.Ellasnotienenunapantalla,mouseoteclado,debidoaquesupropósitoes
almacenardatosyservirlos.Poresarazónsonllamadosservidores--porqueellossirven
losdatos.
Ok,quizástepreguntescómoluceInternet,¿cierto?
¡Tehemoshechounaimagen!Lucealgoasí:
¿CómofuncionaInternet?
6
DjangoGirlsTutorial
Pareceunlío,¿no?Enrealidadesunareddemáquinasconectadas(losmencionados
servidores).¡Cientosdemilesdemáquinas!¡Muchos,muchoskilómetrosdecables
alrededordelmundo!PuedesvisitarelsitiowebSubmarineCableMap
(http://submarinecablemap.com/)dondesemuestranlasconexionesdecablessubmarinos
alrededordelmundoyverlocomplicadaqueeslared.Aquíhayunacapturadepantallade
lapáginaweb:
¿CómofuncionaInternet?
7
DjangoGirlsTutorial
Esfascinante,¿no?Pero,obviamente,noesposibleteneruncableentrecadamáquina
conectadaaInternet.Asíque,parallegaraunamáquina(porejemplolaquealojaa
http://djangogirls.org)tenemosquepasarunasolicitudatravésdemuchasmáquinas
diferentes.
Separeceaesto:
¿CómofuncionaInternet?
8
DjangoGirlsTutorial
Imaginaquecuandoescribeshttp://djangogirls.org,estasenviandounacartaquedice:
"QueridosDjangoGirls,megustaríaversusitiowebdjangogrils.org.Porfavor,envíenmelo!"
Tucartavahacialaoficinadecorreomáscercana.Luegovaaotraunpocomáscercana
desudestinatario,luegoaotrayaotrahastaqueesentregadaensudestino.Loúnica
cosadiferenteesquesituenvíascartas(paquetesdedatos)confrecuenciaalmismolugar,
cadacartapuedepasarporoficinasdecorreos(routers)totalmentediferentes,dependiendo
decómosedistribuyenencadaoficina.
¿CómofuncionaInternet?
9
DjangoGirlsTutorial
Sí,estansimplecomoeso.Enviarmensajesyesperaralgunarespuesta.Porsupuesto,en
vezdepapelylapicerausasbytesdedatos,¡perolaideaeslamisma!
Enlugardedireccionesconelnombredelacalle,ciudad,códigopostalynombredelpaís,
utilizamosdireccionesIP.TucomputadorapideprimeroelDNS(DomainNameSystem-en
españolSistemadeNombresdeDominio)paratraducirdjangogirls.orgaunadirecciónIP.
Funcionacomolosviejosdirectoriostelefónicosdondepuedesbuscarelnombredela
personaquesedeseascontactaryestenosmuestrasunúmerodeteléfonoydirección.
Cuandoenvíasunacarta,éstanecesitatenerciertascaracterísticasparaserentregada
correctamente:unadirección,sello,etc.Tambiénutilizasunlenguajequeelreceptorpueda
entender,¿cierto?Lomismosucedeconlospaquetesdedatosqueenvíasparaverunsitio
web:utilizasunprotocolollamadoHTTP(HypertextTransferProtocol-enespañolProtocolo
deTransferenciadeHipertexto).
Asíque,básicamente,cuandotienesunsitiowebnecesitastenerunservidor(lamáquina)
dondevive.Elservidorestáesperandocualquiersolicitudentrante(cartasquepidenal
servidorqueenvíetusitioweb)yésterespondeenviandotusitioweb(enotracarta).
PuestoqueesteesuntutorialdeDjango,segurotepreguntarásquéesloquehaceDjango.
Bueno,cuandoenvíasunarespuesta,nosiemprequieresenviarlomismoatodoelmundo.
Esmuchomejorsituscartassonpersonalizadas,especialmenteparalapersonaqueacaba
deescribir,¿cierto?Djangonosayudaconlacreacióndeestascartaspersonalizadas:).
¿CómofuncionaInternet?
10
DjangoGirlsTutorial
Bastadecharlas,¡pongamosmanosalaobra!
¿CómofuncionaInternet?
11
DjangoGirlsTutorial
Introducciónalainterfazdelíneade
comandos
Esemocionante,¿verdad?Vasaescribirtuprimeralíneadecódigoenpocosminutos:)
Permítenospresentarteatuprimernuevoamigo:¡lalíneadecomandos!
Lossiguientespasostemostraráncómousaraquellaventananegraquetodosloshackers
usan.Puedeparecerunpocoaterradoralprincipioperoessolounmensajeenpantallaque
esperaaqueledesórdenes.
¿Quéeslalíneadecomandos?
Laventana,quegeneralmenteesllamadalíneadecomandosointerfazdelíneade
comandos,esunaaplicaciónbasadaentextoparaver,manejarymanipulararchivosentu
computadora(comoporejemploelExploradordeWindowsoFinderenMac,perosinla
interfazgráfica).Otrosnombresparalalíneadecomandosson:cmd,CLI,símbolodel
sistema,consolaoterminal.
Abrirlainterfazdelíneadecomandos
Loprimeroquedebemoshacerparaempezaraexperimentarconnuestrainterfazdelinea
decomandosesabrirla.
Windows
IralmenúInicio→Todoslosprogramas→Accesorios→CommandPrompt
MacOSX
Aplicaciones→Servicios→Terminal
Linux
EstáprobablementeenAplicaciones→Accesorios→Terminal,peroesodependedetu
distribución.Sinoloencuentras,Googlealo:)
Introducciónalalíneadecomandos
12
DjangoGirlsTutorial
Prompt
Ahoradeberíasverunaventanablancaonegraqueestáesperandotusórdenes.
SiestásenMacoLinux,probablementeverás $,así:
$
EnWindows,esunsignoasí >,comoeste:
>
Cadacomandoseráprecedidoporestesignoyunespacio,peronotienesqueescribirlo.Tu
computadoraloharáporti:)
Sólounapequeñanota:entucaso,talvezhayalgocomo C:\Users\ola>o OlasMacBook-Air:~ola$antesdelpromptyesoes100%correcto.Enestetutoriallo
simplificaremoslomásposible.
Tuprimercomando(¡YAY!)
Vamosaempezarconalgosimple.Escribeestecomando:
$whoami
o
>whoami
YluegooprimelateclaEnter.Esteeselresultado:
$whoamiolasitarska
Comopuedesver,lacomputadorasólotepresentótunombredeusuario.Bien,¿eh?:)
Tratadeescribircadacomando,nocopiesypegues.¡Teacordarásmásdeesta
manera!
Básicos
Introducciónalalíneadecomandos
13
DjangoGirlsTutorial
Cadasistemaoperativotieneunconjuntodiferentedecomandosparalalíneade
comandos,asíqueasegúratedeseguirlasinstruccionesparatusistemaoperativo.Vamos
aintentarlo,¿deacuerdo?
Directorioactual
Seríabuenosaberdóndeestamosahora,¿cierto?Vamosaver.Escribeestecomandoy
oprimeEnter:
$pwd
/Users/olasitarska
SiestásenWindows:
>cd
C:\Users\olasitarska
Probablementeverásalgosimilarentumáquina.Unavezqueabreslalíneadecomandos
generalmenteempiezaseneldirectoriohomedetuusuario.
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
...
Introducciónalalíneadecomandos
14
DjangoGirlsTutorial
Cambiaeldirectorioactual
¿Quizáspodemosiranuestroescritorio?
$cdDesktop
Windows:
>cdDesktop
Compruebasirealmentehacambiado:
$pwd
/Users/olasitarska/Desktop
Windows:
>cd
C:\Users\olasitarska\Desktop
¡Aquíestá!
Protip:siescribes cdDyluegooprimes tabenelteclado,lalíneadecomandos
automáticamentecompletaráelrestodelnombreparaquepuedasnavegarmás
rápido.Sihaymásdeunacarpetaqueempiececon"D",presionaelbotón tabdos
vecesparaobtenerunalistadeopciones.
Creardirectorio
¿QuétalsicreamosundirectoriodeDjangoGirlsentuescritorio?Puedeshacerlodeesta
manera:
$mkdirdjangogirls
Windows:
>mkdirdjangogirls
Introducciónalalíneadecomandos
15
DjangoGirlsTutorial
Estepequeñocomandocrearáunacarpetaconelnombre djangogirlsentuescritorio.
¡Puedescomprobarsiestáallíbuscandoentuescritoriooejecutandoelcomando ls/dir!
Inténtalo:)
Protip:Sinoquieresescribirunayotravezlosmismoscomandos,pruebaoprimiendo
la flechaarribay flechaabajodetutecladoparaverrecientescomandos
utilizados.
¡Ejercicios!
Unpequeñoretoparati:eneldirectorioreciéncreado djangogirlscreaundirectorio
llamado test.Utilizaloscomandos cdy mkdir.
Solución:
$cddjangogirls
$mkdirtest
$ls
Windows:
>cddjangogirls
>mkdirtest
>dir
08/05/201419:28<DIR>test
¡Felicitaciones!:)
Limpiar
Noqueremosdejarundesorden,asíquevamosaeliminartodoloquehicimoshastaeste
momento.
Enprimerlugar,tenemosquevolveralescritorio:
$cd..
Windows:
Introducciónalalíneadecomandos
16
DjangoGirlsTutorial
>cd..
cd ..cambiaráeldirectorioactualaldirectoriopadre(quesignificaeldirectorioque
contieneeldirectorioactual).
Revisadóndeestás:
$pwd
/Users/olasitarska/Desktop
Windows:
>cd
C:\Users\olasitarska\Desktop
Ahoraeshoradeeliminareldirectorio djangogirls.
Atención:Eliminararchivosutilizando del, rmdiro rmhacequenopuedan
recuperarse,loquesignificaquelosarchivosborradosdesapareceránparasiempre
Debessermuycuidadosaconestecomando.
$rm-rdjangogirls
Windows:
>rmdir/sdjangogirls
djangogirls,¿Estásseguro<Y/N>?Y
Hecho!Asegurémonosqueenverdadfueronborrados,vamosaver:
$ls
Windows:
>dir
Salida
¡Estoestodoporahora!Ahorapuedescerrarlalíneadecomandossinproblemas.Vamosa
hacerloalestilohacker,¿bien?:)
Introducciónalalíneadecomandos
17
DjangoGirlsTutorial
$exit
Windows:
>exit
Genial,¿no?:)
Índice
Aquíhayunalistadealgunoscomandosútiles:
Comando
(Windows)
Comando(Mac
OS/Linux)
Descripción
Ejemplo
exit
exit
Cierralaventana
exit
cd
cd
Cambiael
directorio
cdtest
dir
ls
Lista
directorios/archivos
dir
copy
cp
Copiadearchivos
copyc:\test\test.txt
c:\windows\test.txt
move
mv
Muevearchivos
movec:\test\test.txt
c:\windows\test.txt
mkdir
mkdir
Creaunnuevo
directorio
mkdirtestdirectory
del
rm
Elimina
archivos/directorios
delc:\test\test.txt
Estossonsoloalgunosdeloscomandosquepuedesejecutarenlalíneadecomandos.No
vasausarnadamásqueesosporahora.
Sitienescuriosidad,ss64.comcontieneunareferenciacompletadecomandosparatodos
lossistemasoperativos.
¿Lista?
¡VamosasumergirnosenPython!
Introducciónalalíneadecomandos
18
DjangoGirlsTutorial
VamosaempezarconPython
¡Porfinestamosaquí!
Peroprimero,déjenosdecirtequéesPython.Pythonesunlenguajedeprogramaciónmuy
popularquepuedeutilizarseparalacreacióndesitiosweb,juegos,softwareacadémico,
gráficosymucho,muchomás.
Pythonseoriginóenladécadade1980ysuobjetivoprincipalesserlegibleporlosseres
humanos(¡nosóloparalasmáquinas!),poresoparecemuchomássimplequeotros
lenguajesdeprogramación.Estohacequeseamásfácildeaprender,peronote
preocupes,¡Pythonestambiénmuypoderoso!
InstalacióndePython
EstesubcapítulosebasaenuntutorialdeGeekGirlsCarrots(http://django.carrots.pl/)
DjangoestáescritoenPython.NecesitamosPythonparacualquiercosaenDjango.¡Vamos
aempezarconlainstalación!QueremosqueinstalesPython3.4,asíquesitienesalguna
versiónanterior,deberásactualizarla.
Windows
PuedesdescargarPythonparaWindowsdesdeelsitioweb
https://www.python.org/downloads/release/python-343/.Despuésdedescargarelarchivo
*.msi,debesejecutarlo(hazdobleclickenelarchivo)ysiguelasinstrucciones.Es
importanterecordarlaruta(eldirectorio)dondesehainstaladoPython.¡Seránecesario
másadelante!
Algoparatenerencuenta:enlasegundapantalladelasistentedeinstalación,llamada
"Customize",asegúratedeirhaciaabajoyelegirlaopción"Addpython.exetothePath",
comoen
InstalacióndePython
19
DjangoGirlsTutorial
Linux
EsmuyposiblequeyatengasPythoninstalado.Paraverificarqueyalotienesinstalado(y
quéversiónes),abreunaconsolaytipeaelsiguientecomando:
$python3--version
Python3.4.2
SinotienesPythoninstaladoosiquieresunaversióndiferente,puedesinstalarlocomo
sigue:
Ubuntu
Tipeaestecomandoentuconsola:
sudoapt-getinstallpython3.4
Fedora
Usaestecomandoentuconsola:
InstalacióndePython
20
DjangoGirlsTutorial
sudoyuminstallpython3.4
OSX
Debesiralsitiowebhttps://www.python.org/downloads/release/python-342/ydescargarel
instaladordePython:
descargaelarchivoDMGMacOSX64-bit/32-bitinstaller,
hazdobleclickparaabrirlo,
dobleclickenPython.mpkgparaejecutaralinstalador.
VerificaquelainstalaciónfueexitosaabriendolaTerminalyejecutandoelcomando
python3:
$python3--version
Python3.4.2
Sitienesalgunadudaosialgosaliómalynosabescómoresolverlo-¡pideayudaatututor!
Algunasveceslascosasnosalentanfácilmenteyesmejorpedirayudaaalguienconmás
experiencia.
InstalacióndePython
21
DjangoGirlsTutorial
Editordecódigo
Estásapuntodeescribirtuprimeralíneadecódigo,asíque¡eshoradedescargaruneditor
decódigo!
Haymuchoseditoresdiferentes,cuálusardependemuchodelapreferenciapersonal.La
mayoríadeprogramadoresdePythonusanIDEs(EntornosdeDesarrolloIntegrados)
complejosperomuypoderosos,comoPyCharm.Sinembargo,comoprincipiante,esoes
probablementemenosconveniente;nuestrasrecomendacionessonigualdepoderosas
peromuchomassimples.
Nuestrassugerenciasestánlistadasabajo,perosiéntetelibredepreguntarleatututor
cuálessonsuspreferencias-asíserámásfácilobtenersuayuda.
Gedit
Geditesuneditordecódigoabierto,gratis,disponibleparatodoslossistemasoperativos.
Descárgaloaquí
SublimeText2
SublimeTextesuneditormuypopularconunperiododepruebagratis.Esfácildeinstalary
estádisponibleparatodoslossistemasoperativos.
Descárgaloaquí
Atom
AtomesuneditordecódigomuynuevocreadoporGitHub.Esgratis,decódigoabierto,
fácildeinstalaryfácildeusar.EstádisponibleparaWindows,OSXyLinux.
Descárgaloaquí
¿Porquéestamosinstalandouneditorde
código?
Editordecódigo
22
DjangoGirlsTutorial
Puedesestarpreguntándoteporquéestamosinstalandouneditorespecial,enlugarde
usaruneditorconvencionalcomoWordoNotepad.
Enprimerlugar,elcódigotienequesertextoplanoyelproblemadelasaplicacionescomo
WordoTexteditesqueenrealidadnoproducentextoplano.Loquegeneranestexto
enriquecido(contipografíasyformato),usandoformatospropioscomortf.
Lasegundarazónesqueloseditoresdecódigosonherramientasespecializadasy,como
tales,tienencaracterísticasmuyútiles,comoresaltarlasintáxisdelcódigocondiferentes
coloresdeacuerdoasusignificadoocerrarcomillasportiautomáticamente.
Veremostodoestoenacciónmásadelante.Enbreveempezarásapensarentufieleditor
decódigocomounadetusherramientasfavoritas:)
Editordecódigo
23
DjangoGirlsTutorial
IntroducciónaPython
PartedeestecapítulosebasaentutorialesporGeekGirlsCarrots
(http://django.carrots.pl/).
¡Vamosaescribiralgodecódigo!
Pythonprompt
ParaempezarajugarconPython,tenemosqueabrirunalíneadecomandosennuestra
computadora.Yasabescómohacerlo,loaprendisteenelcapítulodeIntroducciónalalínea
decomandos.
Unavezqueestéslisto,siguelassiguientesinstrucciones.
QueremosabrirunaconsoladePython,asíqueescribe python3ypulsaEnter.
$python3
Python3.4.2(...)
Type"copyright","credits"or"license"formoreinformation.
>>>
TuprimercomandoenPython!
DespuésdeejecutarelcomandodePython,elcursorcambiaa >>>.Paranosotrosesto
significaqueporahorasólopodemosutilizarcomandosenellenguajePython.Notienes
queescribirel >>>-Pythonloharáporti.
SideseassalirdelaconsoladePythonencualquiermomento,simplementeescribe
exit()ousaelatajo Ctrl+ZparaWindowsy Ctrl+DparaMac/Linux.Luegono
verásmás >>>.
PeroahoranoqueremossalirdelaconsoladePython.Queremosaprendermássobreella.
Vamosaempezarconalgomuysimple.Porejemplo,tratadeescribiralgodematemáticas,
como 2+3ypulsaEnter.
>>>2+3
5
IntroducciónaPython
24
DjangoGirlsTutorial
¡Bien!¿Vescomosaliólarespuesta?¡Pythonsabematemáticas!Podríasintentarotros
comandoscomo:- 4*5- 5-1- 40/2
Diviérteteconestoporunmomentoyluegovuelveaquí:).
Comopuedesver,Pythonesunagrancalculadora.Siteestáspreguntandoquémáspuede
hacer...
Strings
¿Ytunombre?Escribatunombredepilaenfrasescomoésta:
>>>"Ola"
'Ola'
¡Hascreadotuprimerstring!Esunasecuenciadecaracteresquepuedeserprocesadapor
unacomputadora.Elstring(oenespañol,cadena)debecomenzaryterminarconelmismo
carácter.Estopuedesercomillassimples( ')odobles( ")-ellasledicenaPythonquelo
queestadentroesunacadena.
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"
IntroducciónaPython
25
DjangoGirlsTutorial
Bien,¿eh?Paravertunombreenletrasmayúsculas,simplementeescribe:
>>>"Ola".upper()
'OLA'
¡Usastelafunción upperentucadena!Unafunción(como upper())esunconjuntode
instruccionesquePythontienequerealizarsobreunobjetodeterminado( "Ola")unavez
quesellama.
Siquisierassaberelnúmerodeletrasquecontienetunombre,tambiénexisteunafunción
paraesto.
>>>len("Ola")
3
Tepreguntarásporquéavecessellamaalasfuncionesconun .alfinaldeunacadena
(como "Ola".upper())yavecessellamaaunafunciónycolocaslacadenaentre
paréntesis.Bueno,enalgunoscasoslasfuncionespertenecenaobjetos,como upper(),
quesólopuedeserutilizadosobrecadenas(upper()esunafuncióndelosobjetosstring).
Enestecaso,llamamosmétodoaestafunción.Otraveces,lasfuncionesnopertenecena
ningúnobjetoespecíficoypuedenserusadosendiferentesobjetos,como len().Estaes
larazóndeporquéestamospasando "Ola"comounparámetroalafunción len.
Resumen
Ok,suficientesobrelascadenas.Hastaahorahasaprendidosobre:
laterminal-teclearcomandos(código)dentrodelaterminaldePythonresultaen
respuestasdePython
númerosystrings-enPythonlosnúmerossonusadosparamatemáticasystrings
paraobjetosdetexto
operadores-como+y*,combinavaloresparaproducirunonuevo
funciones-comoupper()ylen(),realizanopcionessobrelosobjetos.
Estossonlosconocimientosbásicosquepuedesaprenderdecualquierlenguajede
programación.¿Listaparaalgounpocomásdifícil?¡Apostamosqueloestás!
Errores
IntroducciónaPython
26
DjangoGirlsTutorial
Intentemosconalgonuevo.¿Podríamosobtenerlalongituddeunnúmerodelamisma
maneraqueobtuvimoslalongituddenuestronombre?Teclea len(304023)ypresiona
Enter:
>>>len(304023)
Traceback(mostrecentcalllast):
File"<stdin>",line1,in<module>
TypeError:objectoftype'int'hasnolen()
¡Obtuvimosnuestroprimererror!Dicequelosobjetosdetipo"int"(númerosenteros)no
tienenningunalongitud.¿Quépodemoshacerahora?Quizáspodemosescribirelnumero
comounstring.Losstringstienenlongitud,¿cierto?
>>>len(str(304023))
6
¡Funcionó!Utilizamoslafunción strdentrodelafunción len. str()conviertetodoa
strings.
Lafunción strconviertecosasenstrings
Lafunción intconviertecosasenintegers
Importante:podemosconvertirnúmerosentexto,peronopodemosnecesariamente
convertirtextoennúmeros-¿quésería int('hello')?
Variables
Unconceptoimportanteenprogramaciónsonlasvariables.Unavariablenoesmásqueun
nombreparaalgunacosaparaquepuedasusarlamástarde.Losprogramadoresusan
estasvariablesparaalmacenardatos,hacersucódigomáslegibleyasínotenerqueseguir
recordandoquehacecadacosa.
Supongamosquequeremoscrearunanuevavariablellamada name:
>>>name="Ola"
¿Ves?¡Esfácil!Essimplemente:nameequivaleaOla.
Comotehasdadocuenta,elprogramanoregresaalgocomolohaciaantes.Entonces,
¿Cómosabemosquelavariableexisterealmente?Simplementeintroduce nameypulsa
Enter:
IntroducciónaPython
27
DjangoGirlsTutorial
>>>name
'Ola'
¡Súper!Tuprimervariable:).Siemprepodráscambiaraloqueserefiere:
>>>name="Sonja"
>>>name
'Sonja'
Puedesusarladentrodefuncionestambién:
>>>len(name)
5
Increíble,¿verdad?Porsupuesto,lasvariablespuedensercualquiercosa,¡también
números!Pruebaesto:
>>>a=4
>>>b=6
>>>a*b
24
Pero¿quépasasiusamoselnombreequivocado?¿Puedesadivinarquépasaría?¡Vamos
aprobar!
>>>city="Tokyo"
>>>ctiy
Traceback(mostrecentcalllast):
File"<stdin>",line1,in<module>
NameError:name'ctiy'isnotdefined
¡Unerror!Comopuedesver,Pythontienediferentestiposdeerroresyestesellama
NameError.Pythontedaráesteerrorsiintentasutilizarunavariablequenohasido
definidaaún.Simásadelanteteencuentrasconesteerror,verificatucódigoparaversino
hasescritomalunavariable.
Juegaconestoporunratoymiraquepuedeshacer!
Lafunciónprint
Intentaesto:
IntroducciónaPython
28
DjangoGirlsTutorial
>>>name='Maria'
>>>name
'Maria'
>>>print(name)
Maria
Cuandosóloescribes name,elintérpretedePythonrespondeconlarepresentacióndel
stringdelavariable'name',quesonlasletrasM-a-r-i-a,rodeadasdecomillassimples''.
Cuandodices print(name),Pythonvaa"imprimir"elcontenidodelavariablealapantalla,
sinlascomillas,queesmejor.
Comoveremosdespués, print()tambiénesútilcuandoqueremosimprimircosasdesde
adentrodelasfunciones,obiencuandoqueremosimprimircosasenmúltipleslíneas.
Listas
Ademásdestringeintegers,Pythontienetodaclasedediferentestiposdeobjetos.Ahora
vamosaintroducirunollamadolist.Laslistassonexactamenteloquepiensasqueson:son
objetosquesonlistasdeotrosobjetos:)
Anímateycreaunalista:
>>>[]
[]
Sí,estalistaestávacía.Noesmuyútil,¿verdad?Vamosacrearunalistadenúmerosde
lotería.Noqueremosrepetirtodoeltiempo,asíquelospondremosenunavariabletambién:
>>>lottery=[3,42,12,19,30,59]
Muybien,¡tenemosunalista!¿Quépodemoshacerconella?Vamosavercuántos
númerosdeloteríahayenlalista.¿Tienesalgunaideadequéfuncióndeberíasusarpara
eso?¡Yasabesesto!
>>>len(lottery)
6
¡Sí! len()puededarteelnúmerodeobjetosenunalista.Útil,¿verdad?Talvezla
ordenemosahora:
IntroducciónaPython
29
DjangoGirlsTutorial
>>>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(en
españ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,puedesaccederadiferentesobjetosentulistautilizandoelnombredela
listayelíndicedelobjetodentrodecorchetes.
Paradiversiónadicional,pruebaalgunosotrosíndices:6,7,1000,-1,-6ó-1000.Aversise
puedespredecirelresultadoantesdeintentarelcomando.¿Tienensentidolosresultados?
Puedesencontrarunalistadetodoslosmétodosdisponiblesparalistasenestecapítulode
ladocumentacióndePython:https://docs.python.org/3/tutorial/datastructures.html
IntroducciónaPython
30
DjangoGirlsTutorial
Diccionarios
Undiccionarioessimilaraunalista,peroaccedesavaloresusandounaclaveenvezdeun
índice.Unaclavepuedesercualquiercadenaonúmero.Lasintaxisparadefinirun
diccionariovacíoes:
>>>{}
{}
Estodemuestraqueacabasdecrearundiccionariovacío.¡Hurra!
Ahora,trataescribiendoelsiguientecomando(intentareemplazandoconpropia
información):
>>>participant={'name':'Ola','country':'Poland','favorite_numbers':[7,42,92]}
Conestecomando,acabasdecrearunavariable participantcontresparesclave-valor:
Laclave nameapuntaalvalor 'Ola'(unobjeto string),
countryapuntaa 'Poland'(otro string),
y favorite_numbersapuntaa [7,42,92](una listcontresnú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'no
existeenestediccionario.
¿Cuándoutilizarundiccionarioounalista?Bueno,esoesunbuenpuntoparareflexionar.
Sólotenunasoluciónenmenteantesdemirarlarespuestaenlasiguientelínea.
IntroducciónaPython
31
DjangoGirlsTutorial
¿Sólonecesitasunasecuenciaordenadadeelementos?Usaunalista.
¿Necesitasasociarvaloresconclaves,asípuedesbuscarloseficientemente(usando
lasclaves)másadelante?Utilizaundiccionario.
Losdiccionarios,comolaslistas,sonmutables,loquesignificaquepuedensercambiados
despuésdesercreados.Puedesagregarnuevosparesclave/valoreneldiccionario
despuésdequehasidocreado,porejemplo:
>>>participant['favorite_language']='Python'
Comoenlaslistas,elmétodo len()enlosdiccionarios,devuelveelnúmerodepares
clave-valoreneldiccionario.Adelante,escribeelcomando:
>>>len(participant)
4
Esperotengasentidohastaahora.:)¿Listaparamásdiversiónconlosdiccionarios?Saltaa
lasiguientelíneaparaalgunascosassorprendentes.
Puedesutilizarelcomando delparaborrarunelementoeneldiccionario.Porejemplo,si
deseaseliminarlaentradacorrespondientealaclave 'favorite_numbers',sólotienesque
escribirelsiguientecomando:
>>>delparticipant['favorite_numbers']
>>>participant
{'country':'Poland','favorite_language':'Python','name':'Ola'}
Comopuedesverenlasalida,elpardeclave-valorcorrespondientealaclave
'favorite_numbers'hasidoeliminado.
Ademásdeesto,tambiénpuedescambiarunvalorasociadoaunaclaveyacreadaenel
diccionario.Teclea:
>>>participant['country']='Germany'
>>>participant
{'country':'Germany','favorite_language':'Python','name':'Ola'}
Comopuedesver,elvalordelaclave 'country'hasidomodificadode 'Poland'a
'Germany'.:)¿Emocionante?¡Hurra!Hasaprendidootracosaasombrosa.
Resumen
IntroducciónaPython
32
DjangoGirlsTutorial
¡Genial!Sabesmuchosobreprogramaciónahora.Enestaúltimaparteaprendistesobre:
errors-ahorasabescómoleeryentenderloserroresqueaparecensiPythonno
entiendeuncomandoquelehasdado
variables-nombresparalosobjetosquetepermitencodificarmásfácilmenteyhacer
elcódigomáslegible
lists-listasdeobjetosalmacenadosenunordendeterminado
dictionaries-objetosalmacenadoscomoparesclave-valor
¿Emocionadaporlasiguienteparte?:)
Comparacosas
Unagranpartedelaprogramaciónincluyecompararcosas.¿Quéeslomásfácilpara
comparar?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ólo
puedecompararnúmeros,sinoquetambiénpuedecompararresultadosdemétodo.Bien,
¿eh?
¿Tepreguntasporquépusimosdossignosigual ==alladodelotroparacompararsilos
númerossoniguales?Utilizamosunsolo =paraasignarvaloresalasvariables.Siempre,
siempreesnecesarioponerdos ==Sideseascomprobarquelascosassonigualesentre
sí.Tambiénpodemosafirmarquelascosasnosonigualesaotras.Paraeso,utilizamosel
símbolo !=,comomostramosenelejemploanterior.
DadostareasmásaPython:
>>>6>=12/2
True
>>>3<=2
False
IntroducciónaPython
33
DjangoGirlsTutorial
>y <sonfáciles,pero¿quéessignifica >=y <=?Seleenasí:
x >ysignifica:xesmayorquey
x <ysignifica:xesmenorquey
x <=ysignifica:xesmenoroigualquey
x >=ysignifica:xesmayoroigualquey
¡Genial!¿Quiereshacerunomas?Intentaesto:
>>>6>2and2<3
True
>>>3>2and2<1
False
>>>3>2or2<1
True
PuedesdarleaPythontodoslosnúmerosparacompararquequieras,ysiempretedará
unarespuesta.Muyinteligente,¿verdad?
and-siutilizaseloperador and,ambascomparacionesdebenserTrueparaqueel
resultadodetodoelcomandoseaTrue
or-siutilizaseloperador or,sólounadelascomparacionestienequeserTruepara
queelresultadodetodoelcomandoseaTrue
¿Hasoídolaexpresión"compararmanzanasconnaranjas"?Vamosaprobarelequivalente
enPython:
>>>1>'django'
Traceback(mostrecentcalllast):
File"<stdin>",line1,in<module>
TypeError:unorderabletypes:int()>str()
Aquíverásquealigualqueenlaexpresión,Pythonnoescapazdecompararunnúmero
( int)yunstring( str).Encambio,muestraunTypeErrorynosdicequelosdostiposno
sepuedencomparados.
Boolean
Porcierto,acabasdeaprenderacercadeunnuevotipodeobjetoenPython.Sellamaun
Boolean--yesprobablementeeltipomássimplequeexiste.
HaysólodosobjetosBoolean:-True-False
IntroducciónaPython
34
DjangoGirlsTutorial
PeroparaquePythonentiendaesto,esnecesarioquesiempreloescribascomoTrue
(primeraletramayúscula,conelrestodelaletrasminúsculas).true,TRUE,tRUEno
funcionará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óny
acabasdeaprendercómousarlos.
¡Guárdalo!
HastaahorahemosestadoescribiendonuestrocódigoPythonenelintérprete,locualnos
limitaaunalíneadecódigoalavez.Normalmentelosprogramassonguardadosen
archivosysonejecutadosporelintérpreteocompiladordenuestrolenguajede
programación.Hastaahora,hemosestadocorriendonuestrosprogramasdeaunalíneapor
vezenelintérpretedePython.Necesitaremosmásdeunalíneadecódigoparalas
siguientestareas,entoncesnecesitaremoshacerrápidamenteloquesigue:
SalirdelintérpretedePython
Abrireleditordetextodenuestraelección
GuardaralgodecódigoenunnuevoarchivodePython
¡Ejecutarlo!
ParasalirdelintérpretedePythonquehemosestadousando,simplementeescribela
funciónexit():
IntroducciónaPython
35
DjangoGirlsTutorial
>>>exit()
$
Estotellevarádevueltaalalíneadecomandos.
Anteriormente,elegimosuneditordecódigoenlaseccióndeEditordecódigo.Tendremos
queabrireleditorahorayescribiralgodecódigoenunarchivonuevo:
print('Hello,Djangogirls!')
NotaDeberíasnotarunadelascosasmásgenialesdeloseditoresdecódigo:¡los
colores!EnlaconsoladePython,todoeradelmismocolor,peroahorapuedesverque
lafunción printesdeuncolordiferentedelstringqueestáadentrodeella.Esose
denomina"resaltadodesintaxis",yesunagranayudacuandoestásprogramando.
Prestaatenciónaloscolores,yobtendrásunapistacuandoteolvidesdecerrarun
stringocometesunerroralescribirunapalabraclave(comoel defenunafunción,
queveremosabajo).Estaesunadelasrazonesporlascualesusaruneditorde
código:)
Obviamente,ahoraeresunadesarrolladoraPythonmuyexperimentada,asíquesiéntete
libredeescribiralgodelcódigoquehasaprendidohoy.
Ahoratenemosqueguardarelarchivoyasignarleunnombredescriptivo.Vamosallamaral
archivopython_intro.pyyguardarloentuescritorio.Podemosnombrarelarchivode
cualquiermaneraquequeramos,loimportanteaquíesasegurarsequeelarchivofinalice
con.py,estoleindicaanuestracomputadoraqueesteesunarchivoejecutablede
PythonyquePythonpuedecorrerlo.
Conelarchivoguardado,¡eshoradeejecutarlo!Utilizandolashabilidadesquehas
aprendidoenlaseccióndelíneadecomandos,utilizalaterminalparacambiarlos
directorioseiralescritorio.
EnunaMac,elcomandoseveráalgocomoesto:
cd/Users/<your_name>/Desktop
EnLinux,vaaserasí(lapalabra"Desktop"puedeestartraducidaatuidioma):
cd/home/<your_name>/Desktop
YenWindows,seráasí:
IntroducciónaPython
36
DjangoGirlsTutorial
cdC:\Users\<your_name>\Desktop
Sitequedasatascada,sólopideayuda.
yluegousaPythonparaejecutarelcódigoenelarchivocomosigue:
$python3python_intro.py
Hello,Djangogirls!
¡Muybien!EjecutastetuprimerprogramadePythondesdeunarchivo.¿Nosesiente
increíble?
Ahorapuedesmoverteaunaherramientaesencialenlaprogramación:
If...elif...else
Unmontóndecosasenelcódigosólosonejecutadascuandosecumplenlascondiciones
dadas.PoresoPythontienealgollamadosentenciasif.
Reemplazaelcódigoentuarchivopython_intro.pyporesto:
if3>2:
Siloguardáramosyloejecutáramos,veríamosunerrorcomoeste:
$python3python_intro.py
File"python_intro.py",line2
^
SyntaxError:unexpectedEOFwhileparsing
Pythonesperaqueledemosmásinstruccionesquesesuponeseránejecutadassila
condición 3>2resultaserverdadera(o Trueenestecaso).Intentemoshacerque
Pythonimprima"Itworks!".Cambiatucódigoenelarchivopython_intro.pyparaquese
veacomoesto:
if3>2:
print('Itworks!')
¿Observascómohemosindentadolasiguientelíneadecódigocon4espacios?Tenemos
quehacerestoparaquePythonsepaquécódigoejecutarsilacomparaciónresulta
verdadera.Puedesponerunespacio,perocasitodoslosprogramadoresPythonhacen4
IntroducciónaPython
37
DjangoGirlsTutorial
espaciosparahacerqueelcódigoseamáslegible.Unsolotabtambiéncontarácomo4
espacios.
Guárdaloyejecútalodenuevo:
$python3python_intro.py
Itworks!
¿Quépasasilacondiciónnoesverdadera?
Enejemplosanteriores,elcódigofueejecutadosólocuandolascondicioneseranciertas.
PeroPythontambiéntienedeclaraciones elify else:
if5>2:
print('5isindeedgreaterthan2')
else:
print('5isnotgreaterthan2')
Alejecutarestoseimprimirá:
$python3python_intro.py
5isindeedgreaterthan2
Si2fueraunnúmeromayorque5,entonceselsegundocomandoseríaejecutado.Fácil,
¿verdad?Vamosavercómofunciona elif:
name='Sonja'
ifname=='Ola':
print('HeyOla!')
elifname=='Sonja':
print('HeySonja!')
else:
print('Heyanonymous!')
yalejecutarlo:
$python3python_intro.py
HeySonja!
¿Vesloquepasóahí?
Resumen
IntroducciónaPython
38
DjangoGirlsTutorial
Enlosúltimostresejerciciosaprendisteacercade:
Compararcosas-enPythonpuedescompararcosashaciendousode >, >=, ==,
<=, <ydelosoperatores andy or
Boolean-untipodeobjetoquesólopuedetenerunodedosvalores: Trueo False
Guardararchivos-cómoalmacenarcódigoenarchivosasípuedesejecutar
programasmásgrandes
if...elif...else-sentenciasquetepermitenejecutarcódigosólocuandosecumplen
ciertascondiciones
¡Eshoradeleerlaúltimapartedeestecapítulo!
¡Tuspropiasfunciones!
¿Recuerdaslasfuncionescomo len()quepuedesejecutarenPython?Bien,buenas
noticias,¡ahoraaprenderáscómoescribirtuspropiasfunciones!
UnafunciónesunasecuenciadeinstruccionesquePythondebeejecutar.Cadafunciónen
Pythoncomienzaconlapalabraclave def,seleasignaunnombreypuedeteneralgunos
parámetros.Vamosaempezarconalgofácil.Reemplazaelcódigoenpython_intro.pycon
losiguiente:
defhi():
print('Hithere!')
print('Howareyou?')
hi()
Bien,¡nuestraprimerafunciónestálista!
Tepreguntarásporquéhemosescritoelnombredelafunciónenlaparteinferiordel
archivo.EstoesporquePythonleeelarchivoyloejecutadesdearribahaciaabajo.Asíque
parapoderutilizarnuestrafunción,tenemosquereescribirsunombreenlaparteinferior.
Ejecutemosestoyveamosquésucede:
$python3python_intro.py
Hithere!
Howareyou?
¡Esofuefácil!Vamosaconstruirnuestraprimerafunciónconparámetros.Utilizaremosel
ejemploanterior-unafunciónquedice'Hi'alapersonaqueejecutaelprograma-conun
nombre:
IntroducciónaPython
39
DjangoGirlsTutorial
defhi(name):
Comopuedesver,ahoradimosanuestrafunciónunparámetroquellamamos name:
defhi(name):
ifname=='Ola':
print('HiOla!')
elifname=='Sonja':
print('HiSonja!')
else:
print('Hianonymous!')
hi()
Comopuedesnotar,tuvimosqueponerdosindentacionesantesdelafunción print
porque ifnecesitasaberloquedeberíaocurrircuandosecumplelacondición.Vamosa
vercómofunciona:
$python3python_intro.py
Traceback(mostrecentcalllast):
File"python_intro.py",line10,in<module>
hi()
TypeError:hi()missing1requiredpositionalargument:'name'
Oops,unerror.Porsuerte,Pythonnosdaunmensajedeerrorbastanteútil.Nosdicequela
función hi()(laquedefinimos)tieneunargumentorequerido(llamado name)yquese
nosolvidópasarloalllamaralafunción.Vamosaarreglarloenlaparteinferiordelarchivo:
hi("Ola")
yloejecutamosotravez:
$python3python_intro.py
HiOla!
¿Ysicambiamoselnombre?
hi("Sonja")
ylocorremos:
IntroducciónaPython
40
DjangoGirlsTutorial
$python3python_intro.py
HiSonja!
Ahora,¿quécreesquepasarásiescribesotronombreallí?(NoOlaoSonja).Pruébaloy
verássitienesrazón.Estodeberíaimprimir:
Hianonymous!
Estoesincreíble,¿verdad?Deestaformanotienesquerepetirtodocadavezquedeseas
cambiarelnombredelapersonaalaquelafuncióndeberíasaludar.Yesoesexactamente
porquénecesitamosfunciones-¡paranorepetirtucódigo!
Vamosahaceralgomásinteligente-haymásdedosnombres,yescribirunacondición
paracadaunoseríadifícil,¿no?
defhi(name):
print('Hi'+name+'!')
hi("Rachel")
Ahoravamosallamaralcódigo:
$python3python_intro.py
HiRachel!
¡Felicidades!Acabasdeaprendercómoescribirfunciones:)
Bucles
Estayaeslaúltimaparte.¿Esofuerápido,verdad?:)
Comohemosmencionado,losprogramadoressonperezosos,nolesgustarepetircosas.La
programaciónintentaautomatizarlascosas,asíquenoqueremossaludaracadapersona
porsunombremanualmente,¿verdad?Esahídondelosbuclessevuelvenmuyútiles.
¿Todavíarecuerdaslaslistas?Hagamosunalistadelaschicas:
girls=['Rachel','Monica','Phoebe','Ola','You']
Queremossaludaratodasellasporsunombre.Tenemoslafunción hiquehaceeso,así
quevamosausarlaenunbucle:
IntroducciónaPython
41
DjangoGirlsTutorial
fornameingirls:
Lasentenciaforsecomportademanerasimilaralasentenciaif,elcódigoquesigue
continuació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óndentrodeunasentencia for
serárepetidoparacadaelementodelalista girls.
Tambiénpuedesusarel forennúmerosusandolafunción range:
foriinrange(1,6):
print(i)
Loqueimprimirá:
1
2
3
4
5
IntroducciónaPython
42
DjangoGirlsTutorial
rangeesunafunciónquecreaunalistadenúmerosenserie(estosnúmerosson
proporcionadosporticomoparámetros).
Tenencuentaqueelsegundodeestosdosnúmerosnoseráincluidoenlalistaque
retornaráPython(esdecir, range(1,6)cuentadesde1a5,peronoincluyeelnúmero6).
Resumen
Esoestodo.¡Eresgenial!Estonofuetanfácilrealmente,asíquedeberíassentirte
orgullosadetimisma.¡Estamosmuyorgullososdequehayasllegadohastaaquí!
Talvezquierashaceralgodistintoporunmomento-estirarte,caminarunpoco,descansar
tusojos-antesdepasaralsiguientecapítulo.:)
IntroducciónaPython
43
DjangoGirlsTutorial
¿QuéesDjango?
Django(gdh/ˈdʒæŋɡoʊ/jang-goh)esunframeworkparaaplicacioneswebgratuitoyopen
source,escritoenPython.EsunWEBframework-unconjuntodecomponentesquete
ayudanadesarrollarsitioswebmásfácilyrápidamente.
Verás,cuandoestásconstruyendounsitioweb,frecuentementenecesitasunconjuntode
componentessimilares:unamanerademanejarlaautenticacióndeusuarios(registrarse,
iniciarsesión,cerrarsesión),unpaneldeadministraciónparatusitioweb,formularios,una
formadesubirarchivos,etc.
Porsuerteparati,hacetiempovariaspersonasnotaronquelosdesarrolladoresweb
enfrentanproblemassimilarescuandoconstruyenunsitionuevo,poresojuntaroncabezas
ycrearonframeworks(Djangoesunodeellos)queteofrecencomponenteslistospara
usarse.
Losframeworksexistenparaahorrartetenerquereinventarlaruedayayudarteaaliviarla
cargacuandoconstruyesunsitio.
¿Porquénecesitasunframework?
ParaentenderparaqueesDjango,necesitamosmirarmasdecercaalosservidores.Lo
primeroesqueelservidornecesitasaberquequieresquetesirvaunapáginaweb.
Imaginaunbuzón(puerto)elcualesmonitoreadoporcartasentrantes(peticiones).Estoes
realizadoporunservidorweb.Elservidorwebleelacarta,yenvíaunarespuestaconuna
páginaweb.Perocuandoquieresenviaralgo,tienesqueteneralgúncontenido.YDjango
esalgoqueteayudaacrearelcontenido.
¿Quésucedecuandoalguiensolicitauna
páginawebdetuservidor?
CuandollegaunapeticiónaunservidorwebespasadoaDjangoqueintentaaveriguarlo
querealmenteessolicitado.Tomaprimerounadireccióndepáginawebytratadeaveriguar
quéhacer.EstaparteesrealizadaporurlresolverdeDjango(tengaencuentaquela
direccióndeunsitiowebesllamadaURL-UniformResourceLocator-asíqueelnombre
¿QuéesDjango?
44
DjangoGirlsTutorial
urlresolvertienesentido).Estenoesmuyinteligente-tomaunalistadepatronesytratade
igualarlaURL.Djangocompruebalospatronesdearribahaciaabajoysialgosecoincide
entoncesDjangolepasalasolicitudalafunciónasociada(quesellamavista).
Imaginaauncarterollevandounacarta.Ellaestácaminandoporlacalleycompruebacada
númerodecasaconelqueestáenlacarta.Sicoincide,elladejalacartaallí.Asíescomo
funcionaelurlresolver!
Enlafuncióndevistasehacentodaslascosasinteresantes:podemosmiraraunabasede
datosparabuscaralgunainformación.¿Talvezelusuariopidiócambiaralgoenlosdatos?
Comounacartadiciendo"Porfavorcambialadescripcióndemitrabajo."Lavistapuede
comprobarsitenespermitidohacereso,entoncesactualizarladescripcióndeltrabajopara
ustedydevolverleunmensaje:"¡hecho!".EntonceslavistageneraunarespuestayDjango
puedeenviarlaalnavegadordelusuario.
Porsupuesto,ladescripciónanteriorsesimplificaunpoco,perononecesitassabertodas
lascosastécnicasaun.Tenerunaideageneralessuficiente.
Asíqueenlugardemeternosdemasiadoenlosdetalles,simplementecomenzaremos
creandoalgoconDjangoyaprenderemostodaslaspiezasimportantesenelcamino!
¿QuéesDjango?
45
DjangoGirlsTutorial
InstalacióndeDjango
PartedeestecapituloestabasadoenlostutorialesdeGeekGirlsCarrots
(http://django.carrots.pl/).
Partedeestecapítulosebasaeneldjango-marcadortutorialbajolicenciadeCreative
CommonsAttribution-ShareAlike4.0internacional.Eltutorialdedjango-marcadortiene
derechosdeautordeMarkusZapke-Gündemannetal.
Entornovirtual
AntesdeinstalarDjango,instalaremosunaherramientaextremadamenteútilqueayudaráa
mantenertuentornodedesarrolloordenadoensucomputadora.Esposibleomitireste
paso,peroesmuyrecomendablenohacerlo-¡comenzarconlamejorconfiguraciónposible
ayudaraaevitarmuchosproblemasenelfuturo!
Asíque,vamosacrearunentornovirtual(tambiénllamadounvirtualenv).Aislarála
configuraciónPython/Djangoenbasedecadaproyecto,loquesignificaquecualquier
cambioquerealiceenunsitiowebnoafectaráaotrosquetambiénestésdesarrollando.
Genial,¿no?
Todoloquenecesitashaceresencontrarundirectorioenelquedeseescrearel
virtualenv;tudirectoriohome,porejemplo.EnWindowspuedeversecomo
C:\Users\Name(donde nombreeselnombredetuusuario).
Paraestetutorialusaremosunnuevodirectorio djangogirlsentudirectoriohome:
mkdirdjangogirls
cddjangogirls
Haremosunvirtualenvllamado myvenv.Elcomandogeneralestaráenelformato:
python3-mvenvmyvenv
Windows
Paracrearunnuevo virtualenv,debesabrirlaconsola(teloindicamosunoscuantos
capítulosantes,¿recuerdas?)yejecuta C:\Python34\python-mvenvmyvenv.Severáasí:
InstalacióndeDjango
46
DjangoGirlsTutorial
C:\Users\Name\djangogirls>C:\Python34\python-mvenvmyvenv
endonde C:\Python34\pythoneseldirectorioenelqueinstalastePythonpreviamentey
myvenveselnombredetu virtualenv.Puedesutilizarcualquierotronombre,pero
asegúratedeusarminúsculasynodejarespacios,acentosocaracteresespeciales.
Tambiénesunabuenaideamantenerelnombrecorto.¡Vasareferirteaélmucho!
LinuxyOSX
Crearun virtualenvenLinuxyOSXestansimplecomoejecutar python3-mvenv
myvenv.Severáasí:
~/djangogirls$python3-mvenvmyvenv
myvenveselnombredetu virtualenv.Puedesusarcualquierotronombre,peromantén
elusodeminúsculasynoincluyasespacios.Tambiénesunabuenaideamantenerel
nombrecorto.¡Vasareferirteaélmucho!
Nota:Actualmente,iniciarelentornovirtualenUbuntu14.04deestamaneraproduce
elsiguienteerror:
Error:Command'['/home/eddie/Slask/tmp/venv/bin/python3','-Im','ensurepip','--upgrade','--defa
Paraevitaresto,utilizadirectamenteelcomando virtualenv.
~/djangogirls$sudoapt-getinstallpython-virtualenv
~/djangogirls$virtualenv--python=python3.4myvenv
Trabajarconvirtualenv
Estecomandoanteriorcrearáundirectoriollamado myvenv(ocualquiernombrequehayas
escogido)quecontienenuestroentornovirtual(básicamenteunmontóndearchivosy
carpetas).Todoloquequeremoshacerahoraesiniciarloejecutando:
C:\Users\Name\djangogirls>myvenv\Scripts\activate
enWindows,o:
InstalacióndeDjango
47
DjangoGirlsTutorial
~/djangogirls$sourcemyvenv/bin/activate
enOSXyLinux.
¡Recuerdareemplazar myvenvcontunombrede virtualenvquehayaselegido!
Nota:avecesla fuentepodríanoestardisponible.Enesoscasostratadehacerlo
esto:
~/djangogirls$.myvenv/bin/activate
Sabrásquetienes virtualenviniciadocuandoveasquepareceestemensajeenla
consola:
(myvenv)C:\Users\Name\djangogirls>
o:
(myvenv)~/djangogirls$
¡Notaqueelprefijo (myvenv)aparece!
Cuandotrabajesenunentornovirtual, pythonautomáticamentesereferiráalaversión
correcta,demodoquepuedesutilizar pythonenvezde python3.
Tenemostodaslasdependenciasimportantesensulugar.¡Finalmentepodemosinstalar
Django!
InstalarDjango
Ahoraquetienestu virtualenviniciado,puedesinstalarDjangousando pip.Enla
consola,ejecuta pipinstalldjango==1.8(fíjatequeutilizamosundoblesignoigual: ==).
(myvenv)~$pipinstalldjango==1.8
Downloading/unpackingdjango==1.8
Installingcollectedpackages:django
Successfullyinstalleddjango
Cleaningup...
EnWindows
InstalacióndeDjango
48
DjangoGirlsTutorial
SiobtienesunerroralejecutarpipenWindowscompruebasilarutadetuproyecto
contieneespacios,acentosocaracteresespeciales(porejemplo, C:\Users\User
Name\djangogirls).Silotiene,porfavorconsideramoverlaaotrolugarsinespacios,
acentosocaracteresespeciales(sugerencia: C:\djangogirls).Despuésdehacerlo
ejecutanuevamenteelcomandoanterior.
enLinux
SiobtienesunerroralcorrerpipenUbuntu12.04ejecuta python-mpipinstall-Uforce-resintallpipparaarreglarlainstalacióndepipenelvirtualenv.
Esoestodo!Ahoraestáslisto(porfin)paracrearunaaplicaciónDjango!
InstalacióndeDjango
49
DjangoGirlsTutorial
¡TuprimerproyectoenDjango!
PartedeestecapituloestabasadoenlostutorialesdeGeekGirlsCarrots
(http://django.carrots.pl/).
Partedeestecapítulosebasaeneldjango-marcadortutorialbajolicenciadeCreative
CommonsAttribution-ShareAlike4.0internacional.Eltutorialdedjango-marcadortiene
derechosdeautordeMarkusZapke-Gündemannetal.
Vamosacrearunsimpleblog!
ElprimerpasoparacrearloesparainiciarunnuevoproyectoenDjango.Básicamente,esto
significaquepodráscorreralgunosscriptsproporcionadosporDjangoquecrearánel
esqueletodeunproyectoparanosotros:unmontóndedirectoriosyarchivosquevamosa
utilizarmásadelante.
LosnombresdealgunosarchivosydirectoriossonmuyimportantesparaDjango.No
deberíasrenombrarlosarchivosqueestamosapuntodecrear.Moverlosaunlugar
diferentetampocoesunabuenaidea.Djangotienequemantenerunaciertaestructurapara
sercapazdeencontrarcosasimportantes.
Recuerdacorrertodoenelvirtualenv.Sinovesunprefijo (myvenv)entuconsola
necesitasactivartuvirtualenv.Explicamoscómohaceresoenelcapítulode
InstalacióndeDjangoenlasecciónTrabajandoconvirtualenv.Puedeshacerlo
escribiendoelsiguientecomando: myvenv\Scripts\activateenWindowso
myvenv/bin/activateenMacOS/Linux.
NotaControladosvecesqueincluisteelpunto( .)alfinaldelcomando,esimportante
porqueledicealscriptqueinstaleDjangoeneldirectorioactual.
Enlaconsoladebesejecutar(recuerdanoescribir (myvenv)~/djangogirls$,¿ok?):
(myvenv)~/djangogirls$django-adminstartprojectmysite.
EnWindows:
(myvenv)C:\Users\Name\djangogirls>django-admin.pystartprojectmysite.
django-admin.pyesunscriptquecrearálosarchivosydirectoriosparati.Ahoradeberías
tenerunaestructuradedirectoriosparecidaaesto:
ComenzarunproyectoenDjango
50
DjangoGirlsTutorial
djangogirls
├───manage.py
└───mysite
settings.py
urls.py
wsgi.py
__init__.py
manage.pyesunscriptqueayudaconlaadministracióndelsitio.Conellopodremosiniciar
unservidorwebennuestroordenadorsinnecesidaddeinstalarnadamás,entreotras
cosas.
Elarchivo settings.pycontienelaconfiguracióndetusitioweb.
¿Recuerdascuandohablamosdeuncarteroquedebíacomprobardondeentregaruna
carta?Elarchivo urls.pycontieneunalistadelospatronesutilizadospor urlresolver.
Ignoremoslosotrosarchivosporahora-noloscambiaremos.¡Loúnicoquedebesrecordar
esnoborrarlosporaccidente!
Cambiandolaconfiguración
Vamosahaceralgunoscambiosen mysite/settings.py.Abreelarchivousandoeleditor
decódigoquehasinstaladoanteriormente.
Seríabuenotenerelhorariocorrectoennuestrositioweb.Vealalistadehusoshorariosde
Wikipediaycopiatuzonahoraria(TZ).(porejemplo, Europe/Berlin)
Ensettings.py,encuentralalíneaquecontiene TIME_ZONEymodifícalaparaelegirtupropia
zonahoraria:
TIME_ZONE='Europe/Berlin'
Modificando"Europe/Berlin"comocorresponda
Tambiénnecesitaremosagregarunarutaparalosarchivosestáticos(aprenderemostodo
sobrelosarchivosestáticosyCSSmástardeenestetutorial).Vehaciaabajohastaelfinal
delarchivo,yjustopordebajodelaentrada STATIC_URL,agregaunanuevallamada
STATIC_ROOT:
STATIC_URL='/static/'
STATIC_ROOT=os.path.join(BASE_DIR,'static')
ComenzarunproyectoenDjango
51
DjangoGirlsTutorial
Configurarunabasededatos
Hayunagranvariedaddeopcionesdebasesdedatosparaalmacenarlosdatosdetusitio.
Utilizaremoselquevienepordefecto, sqlite3.
Estoyaestáconfiguradoenestapartedetuarchivo mysite/settings.py:
DATABASES={
'default':{
'ENGINE':'django.db.backends.sqlite3',
'NAME':os.path.join(BASE_DIR,'db.sqlite3'),
}
}
Paracrearunabasededatosparanuestroblog,ejecutemoslosiguienteenlaconsola:
pythonmanage.pymigrate(necesitamosestareneldirectoriode djangogirlsquecontiene
elarchivo manage.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!
Debesestareneldirectorioquecontieneelarchivo manage.py(enlacarpeta
djangogirls).Enlaconsola,podemosiniciarelservidorwebejecutando pythonmanage.py
runserver:
(myvenv)~/djangogirls$pythonmanage.pyrunserver
Ahoratodoloquedebeshacerescontrolarquetusitioestécorriendo-abretunavegador
(Firefox,Chrome,Safari,InternetExploreroelqueutilices)eingresaladirección:
http://127.0.0.1:8000/
Elservidorwebseapropiarádetuconsolahastaqueloterminesmanualmente:paratipear
máscomandosoabresunanuevaterminal(ynoteolvidesdeactivartuvirtualenvallí
también),ofrenaelservidorwebyendoalaconsolaenlaqueestácorriendoypresionando
ComenzarunproyectoenDjango
52
DjangoGirlsTutorial
Ctrl+C-lasteclasControlyCjuntas(enWindows,deberáspresionarCtrl+Break).
¡Felicitaciones!¡Hascreadotuprimersitiowebylohasejecutadousandounservidorweb!
¿Noesgenial?
¿Listaparaelpróximopaso?¡Esmomentodecrearalgodecontenido!
ComenzarunproyectoenDjango
53
DjangoGirlsTutorial
ModelosenDjango
Loquequeremoscrearahoraesalgoquevaaalmacenartodoslospostsennuestroblog.
Peroparapoderhacerlotenemosquehablarunpocodeacercadealgollamado objetos.
Objetos
Hayunconceptoenelmundodelaprogramaciónllamado programaciónorientadaa
objetos.Laideaesqueenlugardeescribirtodocomounaaburridasecuenciade
instruccionesdeprogramaciónpodemosmodelarcosasydefinircómointeractúanconlas
demás.
Entonces¿Quéesunobjeto?Esunconjuntodepropiedadesyacciones.Suenararo,pero
tedaremosunejemplo.
Siqueremosunmodelarungatocrearemosunobjeto Gatoquetienealgunas
propiedades,comosonporejemplo color, edad, estadodeánimo(esdecir,bueno,malo,
sueño;)), dueño(queesunobjeto Personao,talvez,enelcasodequeelgatosea
callejero,estapropiedadestarávacía).
Yluegoel Gatotienealgunasacciones: ronronear, rasguñaro alimentarse(enlacual
daremosalgatoalgunos ComidaDeGato,quepodríaserunobjetoindependientecon
propiedades,comoporejemplo, sabor).
Gato
--------color
edad
humor
dueño
ronronear()
rasguñar()
alimentarse(comida_de_gato)
ComidaDeGato
---------sabor
Básicamentesetratadedescribircosasrealesenelcódigoconpropiedades(llamadas
propiedadesdelobjeto)ylasacciones(llamadas métodos).
Yahora,¿cómomodelamoslospostsenelblog?Queremosconstruirunblog,¿no?
ModelosenDjango
54
DjangoGirlsTutorial
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ún
métodoquepubliquelaentrada,¿no?
Asíquevamosanecesitarelmétodo publicar.
Puestoqueyasabemosloquequeremoslograr,¡podemosempezaramoderlarloen
Django!
ModeloenDjango
Sabiendoquéesunobjeto,podemoscrearunmodeloenDjangoparanuestrospostsenel
blog.
UnmodeloenDjangoesuntipoespecialdeobjetoqueseguardaenla basededatos.
Unabasededatosesunacoleccióndedatos.Allíesellugarenelcualalmacenarásla
informaciónsobreusuarios,postsdelblog,etc.UtilizaremosunabasededatosSQLitepara
almacenarnuestrosdatos.Esteeseladaptadordebasededatospredeterminadaen
Django--serásuficienteparanosotrosporahora.
Piensaenelmodeloenlabasededatoscomounahojadecálculoconcolumnas(campos)
yfilas(datos).
Creandounaaplicación
Paramantenertodoenorden,crearemosunaaplicaciónseparadadentrodenuestro
proyecto.Esmuybuenotenertodoorganizadodesdeelprincipio.Paracrearuna
aplicación,necesitamosejecutarelsiguientecomandoenlaconsola(dentrodelacarpeta
de djangogirlsdondeestáelarchivo manage.py):
ModelosenDjango
55
DjangoGirlsTutorial
(myvenv)~/djangogirls$pythonmanage.pystartappblog
Vasnotarquesecreaunnuevodirectoriollamado blogycontieneunaseriedearchivos.
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.
Lohacemosenelarchivo mysite/settings.py.Tenemosqueencontrar INSTALLED_APPSy
añadirunalíneaquecontiene 'blog',justoporencimade ).Elproductofinaldebetener
esteaspecto:
INSTALLED_APPS=(
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'blog',
)
CreandoelModeloPost
Enelarchivo blog/models.pydefinimostodoslosobjetosllamados Models-esteesun
lugarenelcualdefiniremosnuestromodelopost.
Vamosabrir blog/models.py,quitamostodoyescribimosuncódigocomoeste:
ModelosenDjango
56
DjangoGirlsTutorial
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( _)encadaladodel str.Estosse
utilizanconfrecuenciaenPythonyavecestambiénlosllamamos"dunder"(diminutivo
eninglésde"double-underscore").
Daunpocodemiedo,¿verdad?Peronotepreocupes,¡vamosaexplicarquésignifican
estaslíneas!
Todaslaslíneasquecomienzancon fromo importsonlíneasparaañadiralgodeotros
archivos.Asíqueenvezdecopiarypegarlasmismascosasencadaarchivo,podemos
incluiralgunaspartescon from...import....
classPost(models.Model):-estalíneadefinenuestromodelo(esun objeto).
classesunapalabraclavequeindicaqueestamosdefiniendounobjeto.
Posteselnombredenuestromodelo.Podemosdarleunnombrediferente(pero
debemosevitarespaciosenblancoycaracteresespeciales).Unaclasesiempre
comienzaconsuprimeraletraenmayúscula.
models.ModelsignificaquePostesunmodelodeDjango,asíDjangosabequedebe
guardarloenlabasededatos.
Ahoradefinimoslaspropiedadesquehablábamos: title, text, created_date,
published_datey author.Parahaceresotenemosquedefiniruntipodecampo(¿es
texto?¿unnúmero?¿unafecha?¿unarelaciónconotroobjeto-esdecir,unusuario?).
models.CharField-estoescomodefinesuntextoconunnúmerolimitadode
caracteres.
models.TextField-estoesparatextoslargossinunlímite.Seráidealparael
ModelosenDjango
57
DjangoGirlsTutorial
contenidodeunpost,¿verdad?
models.DateTimeField-estoesfechayhora.
modelos.ForeignKey-esteesunvínculoconotromodelo.
Novamosaexplicarcadapedacitodecódigo,yaquenostomaríademasiadotiempo.
DebesecharunvistazoaladocumentacióndeDjangosiquieressabermássobrelos
camposdelosModelosycómodefinircosasdiferentesalasdescritasanteriormente
(https://docs.djangoproject.com/en/1.8/ref/models/fields/#field-types).
¿Yquésobre defpublish(self):?Esexactamentenuestrométodo publishque
mencionamosanteriormente. defsignificaquesetratadeunafunciónométodo. publish
eselnombredelmétodo.Puedescambiarlo,siquieres.Lareglaesqueusamosminúsculas
yguionesbajosenlugardeespacios(esdecir,siquierestenerunmétodoquecalculeel
preciomedio,estepodríallamarse calculate_average_price).
Losmétodosmuyamenudo devuelvenalgo.Hayunejemplodeestoenelmétodo
__str__.Enesteescenario,cuandollamamosa __str__()obtendremosuntexto(string)
conuntítulodePost.
Sialgotodavíanoestáclarosobremodelos,¡nodudesenpreguntaratututor!Sabemos
queesmuycomplicado,sobretodocuandoestásentendiendoquéfuncionesyobjetosson
mientrassiguesestedocumento.Consuerte,¡todotieneunpocomássentidoparatiahora!
Creartablasparalosmodelosentubasededatos
Elúltimopasoesañadirnuestronuevomodeloanuestrabasededatos.Primerotenemos
quehacerqueDjangosepaquetenemosalgunoscambiosennuestromodelo(acabamos
decrearlo),escribe pythonmanage.pymakemigrationsblog.Severáasí:
(myvenv)~/djangogirls$pythonmanage.pymakemigrationsblog
Migrationsfor'blog':
0001_initial.py:
-CreatemodelPost
Djangoprepararáunarchivodemigraciónquetenemosqueaplicarahoraanuestrabase
dedatosescribiendo pythonmanage.pymigrateblog.Elresultadodebeser:
(myvenv)~/djangogirls$pythonmanage.pymigrateblog
Operationstoperform:
Applyallmigrations:blog
Runningmigrations:
Applyingblog.0001_initial...OK
ModelosenDjango
58
DjangoGirlsTutorial
¡Hurra!NuestromodelodePostestáahoraennuestrabasededatos.Seríabuenoverlo,
¿no?¡DirígetealsiguientecapítuloparavercómolucetuPost!
ModelosenDjango
59
DjangoGirlsTutorial
AdministradordeDjango
Paraagregar,editaryborrarlospostsquehemosmodelado,utilizaremoseladministrador
deDjango.
Vamosaabrirelarchivo blog/admin.pyyreemplazarsucontenidoconesto:
fromdjango.contribimportadmin
from.modelsimportPost
admin.site.register(Post)
Comopuedesver,importamos(incluimos)elmodeloPostdefinidoenelcapítuloanterior.
Parahacernuestromodelovisibleenlapáginadeladministrador,tenemosqueregistrarel
modelocon admin.site.register(Post).
Ok,eshoradevertumodeloPost.Recuerdaejecutar pythonmanage.pyrunserverenla
consolaparacorrerelservidorweb.Vealnavegadorytipealadirección
http://127.0.0.1:8000/admin/.Verásunapáginadeingresocomolaquesigue:
Parapoderingresardeberáscrearunsuperusuario-unusuarioquetienecontrolsobretodo
loquehayenelsitio.Vuelvehaciaatrásatulíneadecomandosytipea pythonmanage.py
createsuperuser,presionaenterytipeatunombredeusuario(enminúsculas,sinespacios),
direccióndeemailycontraseñacuandoseanrequeridos.Notepreocupesquenopuedes
AdministradordeDjango
60
DjangoGirlsTutorial
vertucontraseñamientraslatipeas-asíescomodebeser.Simplementetipéalaypresiona
'Enter'paracontinuar.Lasalidadeestecomandodeberíaverseasí(nombredeusuarioy
emaildeberíanserlostuyos):
(myvenv)~/djangogirls$pythonmanage.pycreatesuperuser
Username:admin
Emailaddress:admin@admin.com
Password:
Password(again):
Superusercreatedsuccessfully.
Vuelveatunavegadoreingresaconlascredencialesdesuperusuarioqueelegiste,ahora
deberíaspoderverelpaneldeadministracióndeDjango.
VeaPostsyexperimentaunpococonesto.Agregacincooseispostsdelblog.Note
preocupesporelcontenido-puedessimplementecopiarypegartextodeestetutorialenel
contenidodetuspostsparaahorrartiempo:).
Asegúratedequeporlomenosdosotresposts(peronotodas)tienenlafechade
publicación.Seráútilluego.
AdministradordeDjango
61
DjangoGirlsTutorial
SiquieressabermássobreeladministradordeDjango,puedesvisitarladocumentaciónde
Django:https://docs.djangoproject.com/en/1.8/ref/contrib/admin/
Esteprobablementeseaunbuenmomentoparatomaruncafé(oté)oalgoparacomery
re-energizarte.CreastetuprimermodelodeDjango-¡merecesunpequeñorecreo!
AdministradordeDjango
62
DjangoGirlsTutorial
¡Despliega!
Nota:Elsiguientecapítulopuedeseravecesunpocodifícildesuperar.Sepersistente
yacábalo.Eldespliegueesunaparteimportantedelprocesoeneldesarrolloweb.
Estecapítuloestásituadoenelmediodeltutorialparaquetututorpuedaayudartea
ponertusitiowebenlínea,loquepuedeserunprocesoalgomáscomplicado.Esto
significaquepodrásacabareltutorialportucuentasiseteacabaeltiempo.
Hastaahoratusitiowebestabadisponiblesóloentuordenador,¡ahoraaprenderáscómo
desplegarlo!EldespliegueeselprocesodepublicartuaplicaciónenInternetparaquela
gentepuedaaccederyvertuaplicación:).
Comoyahasaprendido,unsitiowebtienequeestarenunservidor.Haymuchos
proveedores,perousaremosunoquetieneunprocesodedesplieguerelativamentesimple:
PythonAnywhere.PythonAnywhereesgratisparapequeñasaplicacionesquenotienen
demasiadosvisitantes,definitivamentesuficienteparaestecaso.
ElotroservicioexternoquevamosautilizaresGitHub,unserviciodealojamientode
código.Hayotrasopcionesporahí,perohoyendíacasitodoslosprogramadorestienen
unacuentadeGitHub,¡yahoratútambiénlavasatener!
UsaremosGitHubcomopasointermedioparatransportarnuestrocódigodesdeyhasta
PythonAnywhere.
Git
Gitesun"sistemadecontroldeversiones"usadopormuchosprogramadores-esun
sistemaqueregistraloscambiosenlosarchivosatravésdeltiempodeformatalque
puedasaccederaversionesespecíficascuandolodesees.Esmuysimilaralaopciónde
"registrarcambios"enMicrosoftWord,peromuchomáspoderoso.
InstalarGit
Windows
PuedesdescargarGitdegit-scm.com.Puedeshacerclicen"Next"paratodoslospasos
exceptoenuno;enelquintopasotitulado"AdjustingyourPATHenvironment",elije"RunGit
andassociatedUnixtoolsfromtheWindowscommand-line"(laúltimaopción).Apartede
¡Desplegar!
63
DjangoGirlsTutorial
eso,losvalorespordefectofuncionaránbien."CheckoutWindows-style,commitUnix-style
lineendings"tambiénestábien.
MacOS
DescargaGitdegit-scm.comysiguelasinstrucciones.
Linux
Sinolotienesyainstalado,gitdeberíaestardisponibleatravésdeladministradorde
paquetes,pruebacon:
sudoapt-getinstallgit
#o
sudoyuminstallgit
IniciarnuestrorepositorioGit
Gitrastrealoscambiosrealizadosaungrupodeterminadodeficherosenloquellamamos
unrepositoriodecódigo(o"repo"paraabreviar).Iniciemosunoparanuestroproyecto.Abre
laconsolayejecutalossiguientescomandoseneldirectoriode djangogirls:
Nota:Compruebaeldirectoriodetrabajoactualconelcomando pwd(OSX/Linux)o
cd(Windows)antesdeinicializarelrepositorio.Deberíasestarenlacarpeta
djangogirls.
$gitinit
InitializedemptyGitrepositoryin~/djangogirls/.git/
$gitconfiguser.name"Tunombre"
$gitconfiguser.emailtú@ejemplo.com
Inicializarelrepositoriogitesalgoquesólonecesitamoshacerunavezporproyecto(yno
tendrásquevolveraponertuusuarioycorreoelectróniconuncamás)
Gitllevaráunregistrodeloscambiosrealizadosentodoslosficherosycarpetaseneste
directorio,perohayalgunosficherosquequeremosqueignore.Estolohacemoscreando
unficherollamado .gitignoreeneldirectoriobase.Abretueditorycreaunnuevofichero
conelsiguientecontenido:
¡Desplegar!
64
DjangoGirlsTutorial
*.pyc
__pycache__
myvenv
db.sqlite3
.DS_Store
Yguárdalocomo .gitignoreenlaprimeracarpeta"djangogirls".
Nota:¡Elpuntoalprincipiodelnombredelficheroesimportante!Sitienesdificultades
paracrearlo(alosMacnolesgustaquecreesficherosqueempiezanporpuntodesde
Finder,porejemplo),usalaopción"Guardarcomo"entueditor,esonofalla.
Esbuenaideautilizarelcomando gitstatusantesde gitaddocuandonoestéssegura
deloquevaahacer,paraevitarcualquiersorpresa(porejemplo,añadirohacercommitde
ficherosnodeseados).Elcomando gitstatusdevuelveinformaciónsobrelosficherossin
seguimiento(untracked),modificados,preparados(staged),elestadodelaramaymucho
má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
¡Desplegar!
65
DjangoGirlsTutorial
VisitaGitHub.comyregistraunanuevacuentadeusuariogratuita.Luego,creaunnuevo
repositorioconelnombre"my-first-blog".Dejadesmarcadalaopción"Initialisewitha
README",dejalaopción.gitignoreenblanco(lohemoshechoamano)ydejalalicencia
como"None".
NotaElnombre my-first-blogesimportante.Podríaselegirotracosa,perovaa
aparecermuchasvecesenlasinstruccionesquesiguenytendríasquesustituirlocada
vez.Probablementeseamássencilloquedarteconelnombre my-first-blog.
EnlapróximapantallaveráslaURLparaclonarturepositorio.Eligelaversión"HTTPS",
cópialayenunmomentolapegaremosenlaconsola:
¡Desplegar!
66
DjangoGirlsTutorial
AhoratenemosqueconectarelrepositorioGitdetuordenadorconelqueestáenGitHub.
$gitremoteaddoriginhttps://github.com/<your-github-username>/my-first-blog.git
$gitpush-uoriginmaster
EscribetunombredeusuarioycontraseñadeGitHubydeberíasveralgoasí:
Usernamefor'https://github.com':hjwp
Passwordfor'https://hjwp@github.com':
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én
alojansucódigoenGitHub:)
Configurarnuestroblogen
PythonAnywhere
Eshoraderegistrarunacuentagratuitadetipo"Beginner"enPythonAnywhere.
www.pythonanywhere.com
Nota:CuandoelijastunombredeusuariotenencuentaquelaURLdetublogtendrá
laforma nombredeusuario.pythonanywhere.com,asíqueobienelijetupropioapodoo
bienunnombrequedescribasobrequétratatublog.
BajarnuestrocódigoenPythonAnywhere
CuandotehayasregistradoenPythonAnywhereserásredirigidaatupaneldecontrolo
página"Consoles".Elijelaopciónparainiciarunaconsola"Bash",queeslaversión
PythonAnywheredeunaconsola,comolaquetienesentuPC
Nota:PythonAnywhereestábasadoenLinux,porloquesiestásenWindowsla
consolaseráunpocodistintaalaquetienesentuordenador.
¡Desplegar!
67
DjangoGirlsTutorial
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
¡Desplegar!
68
DjangoGirlsTutorial
¿Teestabaspreguntandoquéesesode"whitenoise"?Esunaherramientaparaservirlos
llamados"ficherosestáticos".Losficherosestáticosfuncionandedistintaformaenlos
servidoresencomparaciónconcómolohacenennuestropropioordenadorynecesitamos
unaherramientacomo"whitenoise"paraservirlos.
Aprenderemosunpocomássobrelosficherosestáticosmásadelante,cuandoeditemosel
CSSdenuestrositio.
Porahorasólonecesitamosejecutarenelservidoruncomandoadicionalllamado
"collectstatic".LediceaDjangoquerecopiletodoslosficherosestáticosquenecesitaenel
servidor.Porelmomento,principalmentesonlosficherosestáticosquehacenqueelpanel
deadministració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áginasy
páginasdetextoimposibledeentender?Siemprehagoruiditosparaacompañarlo.Brp,brp
brp...
Copying'/home/edith/.virtualenvs/mvenv/lib/python3.4/site-packages/django/contrib/admin/static/admin
Copying'/home/edith/.virtualenvs/mvenv/lib/python3.4/site-packages/django/contrib/admin/static/admin
[...]
Copying'/home/edith/.virtualenvs/mvenv/lib/python3.4/site-packages/django/contrib/admin/static/admin
Copying'/home/edith/.virtualenvs/mvenv/lib/python3.4/site-packages/django/contrib/admin/static/admin
62staticfilescopiedto'/home/edith/my-first-blog/static'.
CrearlabasededatosenPythonAnywhere
Aquíhayotracosaqueesdiferenteentretuordenadoryelservidor:ésteutilizaunabase
dedatosdiferente.Porlotanto,lascuentasdeusuarioylasentradaspuedenserdiferentes
enelservidoryentuordenador.
Asíqueinicializamoslabasededatosenelservidorigualquelohicimosennuestro
ordenador,con migratey createsuperuser:
¡Desplegar!
69
DjangoGirlsTutorial
(mvenv)20:20~$pythonmanage.pymigrate
Operationstoperform:
[...]
Applyingsessions.0001_initial...OK
(mvenv)20:20~$pythonmanage.pycreatesuperuser
Publicarnuestroblogcomounaaplicación
web
AhoraquenuestrocódigoestáenPythonAnywhere,elvirtualenvestálisto,losficheros
estáticoshansidorecopiladosylabasededatosestáinicializada,estamoslistaspara
publicarlacomounaaplicaciónweb.
HazclicenellogodePythonAnywhereparavolveralpanelprincipal,hazclicenlapestaña
WebypinchaenAddanewwebapp.
Enlaventanadediálogo,despuésdeconfirmarelnombrededominio,elijemanual
configuration(configuraciónmanual)(NBlaopción"Django"no).Luego,elijePython3.4y
hazclicen"Next"paraterminarconelasistente.
Notaasegúratedeelegirlaopciónde"Manualconfiguration",nolade"Django".
SomosdemasiadobuenasparalaconfiguraciónpordefectodeDjangode
PythonAnywhere;-)
Configurarelvirtualenv
SerásredirigidaalapantalladeconfiguracióndePythonAnywhereparatuaplicaciónweb,a
laquedeberásaccedercadavezquequierashacercambiosenlaaplicacióndelservidor.
¡Desplegar!
70
DjangoGirlsTutorial
Enlasección"Virtualenv",hazcliceneltextorojoquedice"Enterthepathtoavirtualenv"
(Introducelarutaaunvirtualenv)yescribe: /home/<-tu-usuario->/my-first-blog/myvenv/
Nota:sustituyetupropionombredeusuariocomocorresponda.Sicometesunerror,
PythonAnywheretemostraráunapequeñaadvertencia.
ConfigurarelficheroWSGI
Djangofuncionautilizandoel"protocoloWSGI",unestándarparaservirsitioswebusando
Python,quePythonAnywheresoporta.LaformadeconfigurarPythonAnywhereparaque
reconozcanuestroblogDjangoeseditarunficherodeconfiguraciónWSGI.
Hazclicenelenlace"WSGIconfigurationfile"(enlasección"Code"enlapartedearribade
lapágina;sellamaráalgoparecidoa /var/www/<tu-usuario>_pythonanywhere_com_wsgi.py)y
teredirigiráaleditor.
Eliminatodoelcontenidoactualyreemplázaloconalgocomoesto:
¡Desplegar!
71
DjangoGirlsTutorial
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ónweby
cómosellamaelficherodeconfiguracióndeDjango.Tambiénconfiguralaherramientapara
ficherosestáticos"whitenoise".
DaleaSaveyvuelvealapestañaWeb.
¡Todolisto!DalealbotónverdegrandequediceReloadypodrásvertuaplicación.Verásun
enlaceaellaenlapartedearribadelapágina.
Consejosdedepuración
Siapareceunerrorcuandointentasvisitartusitio,elprimerlugarquedeberásrevisarpara
obtenerinformacióndedepuracióneselerrorlog;encontrarásunenlaceaélenlapestaña
WebdePythonAnywhere.Miraaversihayalgúnmensajedeerrorahí.Losmásrecientes
estánalfinal.Losproblemasmáscomunesincluyen
olvidaralgunodelospasosquehicimosenlaconsola:crearelvirtualenv,activarlo,
instalarDjangoenél,ejecutarcollectstatic,inicializarlabasededatos
cometerunerrorenlarutadelvirtualenvenlapestañaWeb;suelehaberunmensajito
deerrordecolorrojo,sihayalgúnproblema
cometerunerrorenelficherodeconfiguraciónWSGI;¿haspuestobienlarutaala
carpetamy-first-blog?
¡Tututorestáahíparaayudar!
¡Estásenvivo!
¡Desplegar!
72
DjangoGirlsTutorial
Lapáginapordefectodetusitiodeberíadecir"WelcometoDjango",igualqueentuPC
local.Intentaañadir /admin/alfinaldelaURLyteredirigiráalpaneldeadministración.
Ingresacontunombredeusuarioycontraseñayverásquepuedesañadirnuevasentradas
enelservidor.
DateunaGRANpalmadaenlaespalda;losdesplieguesenelservidorsonunadelas
partesmáscomplejasdeldesarrollowebymuchasvecesalagentelecuestavariosdías
tenerlofuncionando.Perotútienestusitioenvivo,enInternetdeverdad,¡asícomosuena!
¡Desplegar!
73
DjangoGirlsTutorial
Djangourls
Vamosaconstruirnuestraprimerapáginaweb--¡unapáginadeinicioparatublog!Pero
primero,vamosaaprenderunpocosobreDjangourls.
¿QuéesunaURL?
UnaURLessimplementeunadirecciónweb,puedesverunaURLcadavezquevisitas
cualquiersitioweb-esvisibleenlabarradedireccionesdetunavegador(¡Sí!
127.0.0.1:8000esunaURL.Yhttp://djangogirls.comestambiénunaURL):
CadapáginaenInternetnecesitasupropiaURL.Deestamaneratuaplicaciónsabeloque
debemostraraunusuarioqueabreunaURL.EnDjangoseusaalgollamado URLconf
(configuracióndeURL),unconjuntodepatronesqueDjangointentaráhacercoincidirconla
direcciónURLrecibidaparaencontrarlavistacorrecta.
¿CómofuncionanlasURLsenDjango?
Vamosaabrirelarchivo mysite/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.
Djangourls
74
DjangoGirlsTutorial
Laslíneasquecomienzancon #soncomentarios-significaqueesaslíneasnoserán
ejecutadasporPython.Muyútil,¿verdad?
YaestáaquílaURLdeadmin,quevisitasteenelcapítuloanterior:
url(r'^admin/',include(admin.site.urls)),
EstosignificaqueparacadaURLqueempiezacon admin/Djangoencontrarásu
correspondienteview.EnestecasoestamosincluyendoenunasolalíneamuchasURLsde
admin,asínoestátodocomprimidoenestepequeñoarchivo-esmáslimpioylegible.
Regex
¿TepreguntascómoDjangocoincidelasdireccionesURLconlasvistas?Bueno,estaparte
esdifícil.Djangoutiliza regex--expresionesregulares.Regextienemuchas(¡unmontón!)
denormasqueformanunpatróndebúsqueda.Dadoquelasexpresionesregularessonun
temaavanzado,noentraremosendetallessobresufuncionamiento.
Siteinteresaentendercómocreamosesospatrones,aquíhayunejemplodelprocesosolamentenecesitaremosunsubconjuntodereglaslimitadoparaexpresarelpatrónque
estamosbuscando:
^denotaelprincipiodeltexto
$denotaelfinaldeltexto
\drepresentaundígito
+indicaqueelítemanteriordeberíaserrepetido<strong>porlomenos</strong>unavez
()paraencerrarunapartedelpatrón
CualquierotracosaenladefinicióndelURLserátomadaliteralmente.
Ahoraimaginaquetienesunsitiowebconunadireccióncomoesta:
http://www.mysite.com/post/12345/,donde 12345eselnúmerodepost.
Escribirvistasseparadasparatodoslosnúmerosdepostseríarealmentemolesto.Conlas
expresionesregularespodemoscrearunpatrónquecoincidirálaURLyextraeráelnúmero
paranosotras: ^post/(\d+)/$.Analicemosestaexpresiónparteporparteparaentender
quéesloqueestamoshaciendoaquí:
^post/leestádiciendoaDjangoquetomecualquiercosaquetenga post/alprincipio
delURL(justoantesde ^)
(\d+)significaquehabráunnúmero(deunoomásdígitos)yquequeremosqueese
númeroseacapturadoyextraído
Djangourls
75
DjangoGirlsTutorial
/lediceaDjangoqueotrocaracter /deberíaveniracontinuación
$indicaelfinaldelURL,loquesignificaquesólocadenasfinalizandocon /
coincidiránconestepatrón
¡TuprimerURLdeDjango!
¡EshoradecrearnuestroprimerURL!Queremosque'http://127.0.0.1:8000/'sealapágina
deiniciodenuestroblogyquemuestreunalistadeposts.
Tambiénqueremosmantenerelarchivo mysite/urls.pylimpio,asíqueimportaremosURLs
denuestro blogalarchivo mysite/urls.pyprincipal.
Eliminalaslíneascomentadas(líneascomenzandocon #)yagregaunalíneaque
importará blog.urlsenelurlprincipal( '').
Tuarchivo mysite/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/'a blog.urlsy
buscarámásinstruccionesallí.
CuandoescribesexpresionesregularesenPythonacostúmbrateaponer ralprincipiode
lacadena-estoessolamenteunapistaparaquePythonentiendaquelacadenacontenerá
caracteresespecialesquenosonparaserinterpretadosporPythonsinoquesonpartede
laexpresiónregular.
blog.urls
Creaunnuevoarchivovacío blog/urls.py.¡Muybien!Agregaestasprimerasdoslíneas:
fromdjango.conf.urlsimportinclude,url
from.importviews
AquísoloestamosimportandolosmétodosdeDjangoytodasnuestras viewsdel blog
(todavíanotenemosninguna,peroloharemosenunminuto)
Djangourls
76
DjangoGirlsTutorial
Luegodeesto,podemosagregarnuestroprimerpatrónURL:
urlpatterns=[
url(r'^$',views.post_list),
]
Comopuedesver,ahoraestamosasignandouna viewllamada post_listalURL ^$.
Estaexpresiónregularcoincidirácon ^(uninicio)seguidode $(unfinal)-porlotanto,
sólounacadenavacíacoincidirá.Yestoescorrecto,yaqueenlosURLresolversde
Django'http://127.0.0.1:8000/'noespartedelURL.EstepatrónmostraráaDjangoque
views.post_listesellugarcorrectoalqueirsialguieningresaatusitiowebconla
direcció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íes
comollamamosanuestravista!Estosignificaquetodoestáensulugar,sóloqueno
creamosnuestraviewtodavía.Notepreocupes,yallegaremosaeso.
SiquieressabermássobreDjangoURLconfs,miraladocumentaciónoficial:
https://docs.djangoproject.com/en/1.8/topics/http/urls/
Djangourls
77
DjangoGirlsTutorial
VistasdeDjango-¡Eshoradecrear!
Eshoradedeshacersedelerrorquehemoscreadoenelcapítuloanterior:)
UnaViewesunlugardondeponemosla"lógica"denuestraaplicación.Sesolicitará
informacióndel modelquecreasteanteriormenteysepasaráauna viewquecrearásen
elpróximocapítulo.LasvistassonsólométodosdePythonquesonunpocomás
complicadosqueloquehicimosenelcapítulodeIntroducciónaPython.
LasVistassecolocanenelarchivo views.py.Agregaremosnuestrasviewsalarchivo
blog/views.py.
blog/views.py
Bien,vamosabrirestearchivoyverloquecontiene:
fromdjango.shortcutsimportrender
#Createyourviewshere.
Nodemasiadascosasaquítodavía.Laviewmássimplepuedesercomoesto:
defpost_list(request):
returnrender(request,'blog/post_list.html',{})
Comopuedesver,hemoscreadounmétodo( def)llamado post_listquetomaun
requestyhaceun returndeunmétodo renderquerenderizará(construirá)nuestra
plantilla blog/post_list.html.
Guardaelarchivo,dirígeteahttp://127.0.0.1:8000/yveamosloquetenemosahora.
¡Otroerror!Leamosloqueestápasandoahora:
VistasdeDjango-¡Eshoradecrear!
78
DjangoGirlsTutorial
Esteesunofácil:TemplateDoesNotExist.¡Vamosaarreglaresteerrorcreandounaplantilla
enelsiguientecapítulo!
AprendemásacercadelasviewsdeDjangoleyendoladocumentaciónoficial:
https://docs.djangoproject.com/en/1.8/topics/http/views/
VistasdeDjango-¡Eshoradecrear!
79
DjangoGirlsTutorial
IntroducciónaHTML
Teestaráspreguntando,¿quéesunaplantilla?
Unaplantillaesunarchivoquepodemosreutilizarparapresentarinformacióndiferentede
formaconsistente-porejemplo,sepodríautilizarunaplantillaparaayudarteaescribiruna
carta,porqueaunquecadacartapuedecontenerunmensajedistintoydirigirseauna
personadiferente,compartiránelmismoformato.
ElformatodeunaplantilladeDjangosedescribeenunlenguajellamadoHTML(queesel
códigoHTMLquemencionamosenelprimercapítuloCómofuncionaInternet).
¿QuéesHTML?
HTMLesunsimplecódigoqueesinterpretadoportunavegadorweb-comoChrome,
FirefoxoSafari-paramostrarunapáginawebalusuario.
HTMLsignificaHyperTextMarkupLanguage-enespañol,LenguajedeMarcasde
HyperTexto.HyperTextsignificaqueesuntipodetextoquesoportahipervínculosentre
páginas.Markupsignificaquehemostomadoundocumentoylohemosmarcadocon
códigoparadecirleaalgo(enestecaso,unnavegador)cómointerpretarlapágina.El
códigoHTMLestáconstruidoconetiquetas,cadaunacomenzandocon <yterminando
con >.Estasetiquetasdemarcadosonelementos.
¡Tuprimeraplantilla!
Crearunaplantillasignificacrearunarchivodeplantilla.Todoesunarchivo,¿verdad?
Probablementehayasnotadoestoya.
Lasplantillasseguardaneneldirectoriode blog/templates/blog.Asíqueprimerocreaun
directoriollamado templatesdentrodetudirectorioblog.Luegocreaotrodirectorio
llamado blogdentrodetudirectoriodetemplates:
blog
└───templates
└───blog
IntroducciónaHTML
80
DjangoGirlsTutorial
(Talveztepreguntesporquénecesitamosdosdirectoriosllamados blog-como
descubrirásmásadelante,estoessimplementeunaútilconvencióndenomenclaturaque
hacelavidamásfácilcuandolascosasempiezanacomplicarsemás.)
Yahoracreaunarchivo post_list.html(déjaloenblancoporahora)dentrodelacarpeta
blog/templates/blog.
Miracómosevesusitiowebahora:http://127.0.0.1:8000/
Sitodavíatienesunerror TemplateDoesNotExists,intentareiniciarelservidor.Veala
líneadecomandos,deténelservidorpulsandoCtrl+C(teclasControlyCjuntas)y
comienzadenuevomediantelaejecucióndelcomando pythonmanage.pyrunserver.
¡Ningúnerrormás!Felicidades:)Sinembargo,porahora,tusitiowebnoestápublicando
nadaexceptounapáginaenblanco,porquelaplantillatambiénestávacía.Tenemosque
arreglarlo.
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áginawebva
desdeelprincipiodelaetiqueta <html>yhastalaetiquetadecierre </html>
<p>esunaetiquetaparaloselementosdepárrafo; </p>cierracadapárrafo
Cabeza&cuerpo
CadapáginaHTMLtambiénsedivideendoselementos:headybody.
headesunelementoquecontieneinformaciónsobreeldocumentoquenosemuestra
enlapantalla.
bodyesunelementoquecontienetodoloquesemuestracomopartedelapágina
web.
IntroducciónaHTML
81
DjangoGirlsTutorial
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ítulodetu
navegador(tambiénseutilizaráparamarcadoresyasísucesivamente).
Probablementetambiénhayasnotadoquecadaetiquetadeaperturacoincideconuna
etiquetadecierre,conun /,yqueloselementossonanidados(esdecir,nopuedescerrar
unaetiquetaparticularhastaquetodoslosqueestabanensuinteriorsehayancerrado
también).
Escomoponercosasencajas.Tienesunacajagrande, <html></html>;ensuinteriorhay
<body></body>,yquecontienelascajasaúnmáspequeñas: <p></p>.
Tienesqueseguirestasreglasdeetiquetasdecierreydeanidacióndeelementos-sinolo
haces,elnavegadorpuedenosercapazdeinterpretarloscorrectamenteytupáginase
mostraráincorrectamente.
Personalizatuplantilla
¡Ahorapuedesdivertirteunpocoytratardepersonalizartuplantilla!Aquíhayalgunas
etiquetasú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
IntroducciónaHTML
82
DjangoGirlsTutorial
<br/>-unsaltodelínea(nopuedescolocarnadadentrodebr)
<ahref="http://djangogirls.org">link</a>-creaunvínculo
<ul><li>primerelemento</li><li>segundoelemento</li></ul>-creaunalista,¡igualque
esta!
<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.Don
</div>
<div>
<p>published:14.06.2014,12:14</p>
<h2><ahref="">Mysecondpost</a></h2>
<p>Aeneaneuleoquam.Pellentesqueornaresemlaciniaquamvenenatisvestibulum.Don
</div>
</body>
</html>
Aquíhemoscreadotressecciones div.
Elprimerelemento divcontieneeltítulodenuestroblog-esunencabezadoyun
enlace
Otrosdoselementos divcontienennuestrospostsconlafechadepublicación, h2
conuntítuloqueesclickeableydos p(párrafo)detexto,unoparalafechayunopara
nuestropost.
Nosdaesteefecto:
¡Yaaay!Perohastaelmomento,nuestraplantillasólomuestraexactamentelamisma
información-considerandoqueanteshablábamosdeplantillascomopermitiéndonos
mostrarinformacióndiferenteenelmismoformato.
IntroducciónaHTML
83
DjangoGirlsTutorial
Loquequeremosrealmenteesmostrarpostsrealesañadidosennuestrapáginade
administracióndeDjango-yahíesadondevamosacontinuación.
Unacosamás:¡despliega!
SeríabuenovertodoestodisponibleenInternet,¿no?Hagamosotrodespliegueen
PythonAnywhere:
HazuncommitysubetucódigoaGitHub
Enprimerlugar,veamosquéarchivoshancambiadodesdequehicimoseldesplieguepor
últimavez:
$gitstatus
Asegúratedequeestáseneldirectorio djangogirlsyvamosadecirlea gitqueincluya
todosloscambiosdentrodeestedirectorio:
$gitadd-A.
Nota -A(abreviaturade"all")significaque gittambiénreconocerásihaseliminado
archivos(pordefecto,sóloreconocearchivosnuevos/modificados).Tambiénrecuerda
(delcapítulo3)que .significaeldirectorioactual.
Antesdequesubamostodoslosarchivos,vamosaverquéesloque gitsubirá(todoslos
archivosque gitcargarádeberíanaparecerenverde):
$gitstatus
Yacasiestamos,ahoraestiempodedecirlequeguardeestecambioensuhistorial.Vamos
adarleun"mensajedecommit"dondedescribimosloquehemoscambiado.Puedes
escribircualquiercosaquetegustaríaenestaetapa,peroesútilescribiralgodescriptivo
paraquepuedesrecordarloquehashechoenelfuturo.
$gitcommit-m"CambieelHTMLparalapágina."
NotaAsegúratedeusarcomillasdoblesalrededordelmensajedecommit.
Unavezquehicimosesto,subimos(push)nuestroscambiosaPythonAnywhere:
IntroducciónaHTML
84
DjangoGirlsTutorial
gitpush
DescargatunuevocódigoaPythonAnywhereyactualizatu
aplicaciónweb
AbrelapáginadeconsolasdePythonAnywhereyveatuconsolaBash(ocomienza
unanueva).Luego,ejecuta:
$cd~/my-first-blog$gitpull[...]
Ymiracómotucódigosedescarga.Siquierescomprobarqueyahaterminado,puedesira
lapestañaFilesyvertucódigoenPythonAnywhere.
Finalmente,dirígetealapestañaWebyseleccionaReloadentuaplicaciónweb.
¡Tuactualizacióndeberíaestarenlínea!Actualizatusitiowebenelnavegador.Ahora
deberíaspodervertuscambios:)
IntroducciónaHTML
85
DjangoGirlsTutorial
ORMdeDjangoyQuerySets
EnestecapítuloaprenderáscómoDjangoseconectaalabasededatosyalmacenalos
datosenella.¡Vamosasumergirnos!
¿QuéesunQuerySet?
UnQuerySetes,enesencia,unalistadeobjetosdeunmodelodeterminado.UnQuerySet
tepermiteleerlosdatosdebasededatos,filtrarlosyordenarlos.
Esmásfácildeaprenderconejemplos.Vamosaintentarlo,¿deacuerdo?
Djangoshell
Abrelaconsolayescribeestecomando:
(myvenv)~/djangogirls$pythonmanage.pyshell
Elresultadodeberíaser:
(InteractiveConsole)
>>>
AhoraestásenlaconsolainteractivadeDjango.EscomolaconsoladePython,perocon
untoquedemagiaDjango:).PuedesutilizartodosloscomandosPythonaquítambién,por
supuesto.
Vertodoslosobjetos
Vamosamostrartodosnuestrospostsprimero.Puedeshacerloconelsiguientecomando:
>>>Post.objects.all()
Traceback(mostrecentcalllast):
File"<console>",line1,in<module>
NameError:name'Post'isnotdefined
¡Uy!Aparecióunerror.NosdicequenohayningúnobjetoPost.Estoescorrecto,¡nos
olvidamosdeimportarloprimero!
ORMdeDjango(Querysets)
86
DjangoGirlsTutorial
>>>fromblog.modelsimportPost
Estoessimple:importamoselmodelo Postde blog.models.Vamosaintentarmostrar
todoslospostsnuevamente:
>>>Post.objects.all()
[<Post:myposttitle>,<Post:anotherposttitle>]
Estaesunalistadelaspostscreadasanteriormente.Hemoscreadoestospostsusandola
interfazdeladministradordeDjango.Sinembargo,ahoraqueremoscrearnuevosposts
usandoPython,¿cómolohacemos?
Crearobjetos
EstaeslaformadecrearunnuevoobjetoPostenlabasededatos:
>>>Post.objects.create(author=me,title='Sampletitle',text='Test')
Perohayuningredientefaltante: me.Necesitamospasarunainstanciadelmodelo User
comoautor.¿Cómohacemoseso?
PrimeroimportemoselmodeloUser:
>>>fromdjango.contrib.auth.modelsimportUser
¿Quéusuariostenemosennuestrabasededatos?Veamos:
>>>User.objects.all()
[<User:ola>]
Esteeselsuperusuarioquecreamosanteriormente,Vamosaobtenerunainstanciadeese
usuarioahora:
me=User.objects.get(username='ola')
Comopuedesver,hicimosun getdeun Userconel usernamequeseaiguala'ola'.
¡Genial!Acuérdatedeponertunombredeusuarioparaobtenertuusuario.
Ahorafinalmentepodemoscrearnuestroprimerpost:
ORMdeDjango(Querysets)
87
DjangoGirlsTutorial
>>>Post.objects.create(author=me,title='Sampletitle',text='Test')
¡Hurra!¿Quieresprobarsifuncionó?
>>>Post.objects.all()
[<Post:Sampletitle>]
Agregamásposts
Ahorapuedesdivertirteunpocoyañadirmáspostsparavercómofunciona.Añade2ó3
másyavanzaalasiguienteparte.
Filtrarobjetos
UnaparteimportantedelosQuerySetseslahabilidadparafiltrarlos.Digamosque
queremosencontrartodoslospostscuyoautoreselUserola.Usaremos filterenvezde
allen Post.objects.all().Enlosparéntesisestableceremosquécondicióno
conducionesdebencumplirseporunpostdelblogparaterminarennuestroqueryset.En
nuestrocasosería authoresiguala me.LaformadeescribirloenDjangoes: author=me.
Ahoranuestrobloquedecódigosevecomoesto:
>>>Post.objects.filter(author=me)
[<Post:Sampletitle>,<Post:Postnumber2>,<Post:My3rdpost!>,<Post:4thtitleofpost>]
¿Otalvezquerramosvertodoslospostsquecontenganlapalabra'title'enelcampo
title?
>>>Post.objects.filter(title__contains='title')
[<Post:Sampletitle>,<Post:4thtitleofpost>]
NotaHaydosguionesbajos( _)entre titley contains.DjangoORMutilizaesta
sintaxisparasepararlosnombresdeloscampos("title")yoperacionesofiltros
("contains").Sisóloutilizasunguiónbajo,obtendrásunerrorcomo"FieldError:Cannot
resolvekeywordtitle_contains".
Tambiénpuedesobtenerunalistadetodoslospostspublicados.Lohacemosfiltrandolos
postsquetienenelcampo published_dateenelpasado:
fromdjango.utilsimporttimezone
Post.objects.filter(published_date__lte=timezone.now())[]
ORMdeDjango(Querysets)
88
DjangoGirlsTutorial
Desafortunadamente,ningunodenuestrospostshansidopublicadostodavía.¡Vamosa
cambiaresto!Primeroobténunainstanciadeunpostquequerramospublicar:
>>>post=Post.objects.get(id=1)
¡Luegoutilizaelmétodo publishparapublicarlo!
>>>post.publish()
Ahoraintentaobtenerlalistadepostspublicadosnuevamente(presionalateclaconla
flechahaciaarriba3vecesypresionaEnter):
>>>Post.objects.filter(published_date__lte=timezone.now())
[<Post:Sampletitle>]
Ordenandoobjetos
LosQuerySetstambiéntepermitenordenarlalistadeobjetos.Intentemosordenarlosporel
campo created_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()
$
ORMdeDjango(Querysets)
89
DjangoGirlsTutorial
QuerysetsdeDjango
Tenemosdiferentespiezasensulugar:elmodelo Postestádefinidoen models.py,
tenemosa post_listen views.pyylaplantillaagregada.¿Perocómoharemosrealmente
paraquenuestrospostsaparezcanennuestraplantillaHTML?Porqueesoesloque
queremoshacer:tomaralgúncontenido(modelosguardadosenlabasededatos)y
mostrarloadecuadamenteennuestraplantilla,¿no?
Estoesexactamenteloquelasviewssesuponequehacen:conectarmodeloscon
plantillas.Ennuestraview post_listnecesitaremostomarlosmodelosquedeseamos
mostrarypasarlosaunaplantilla.Asíquebásicamenteenunaviewdecidimosqué
(modelo)semostraráenunaplantilla.
Muybien,ahora¿cómolohacemos?
Necesitamosabrirnuestroarchivo blog/views.py.Hastaahoralaview post_listseve
así:
fromdjango.shortcutsimportrender
defpost_list(request):
returnrender(request,'blog/post_list.html',{})
¿Recuerdascuandohablamosdeincluircódigoendiferentesarchivos?Ahoratenemosque
incluirelmodeloquedefinimosenelarchivo models.py.Agregaremoslalínea from
.modelsimportPostdelasiguienteforma:
fromdjango.shortcutsimportrender
from.modelsimportPost
Elpuntodespuésde fromindicaeldirectorioactualolaaplicaciónactual.Como views.py
y models.pyestánenelmismodirectorio,simplementeusamos .yelnombredelarchivo
(sin .py).Ahoraimportamoselnombredelmodelo( Post).
¿Peroahoraquésigue?Paratomarpublicacionesrealesdelmodelo Post,necesitamos
algollamado QuerySet(conjuntodeconsultas).
QuerySet
Datosdinámicosenplantillas
90
DjangoGirlsTutorial
YadebesestarfamiliarizadaconlaformaenquefuncionanlosQuerySets.Hablamosde
ellosenelcapítuloDjangoORM(QuerySets).
Entoncesahoranosinteresaobtenerunalistadeentradasdelblogquehansidopublicadas
yordenadaspor published_date(fechadepublicación),¿no?¡Yahicimosesoenel
capítuloQuerySets!
Post.objects.filter(published_date__lte=timezone.now()).order_by('published_date')
Ahorapondremosestebloquedecódigoenelarchivo blog/views.py,agregándoloala
función defpost_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ómalacomoelnombre
denuestroQuerySet.DeaquíenadelantevamosareferirnosalQuerySetconesenombre.
LaúltimaparteespasarelQuerySet postsalaplantilla(veremoscómomostrarlaenel
siguientecapítulo).
Enlafunción renderyatenemoselparámetro request(todoloquerecibimosdelusuario
viaInternet)yelarchivo 'blog/post_list.html'comoplantilla.Elúltimoparámetro,quese
veasí: {}esuncampoenelquepodemosagregaralgunascosasparaquelaplantillalas
use.Necesitamosnombrarlos(losseguiremosllamando 'posts'porahora:)).Sedebería
verasí: {'posts':posts}.Observaquelapartequevaantesde :estáentrecomillas
''.
Finalmentenuestroarchivo blog/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})
Datosdinámicosenplantillas
91
DjangoGirlsTutorial
¡Terminamos!AhoraregresemosanuestraplantillaymostremosesteQuerySet.
SiquieresleerunpocomásacercadeQuerySetsenDjango,puedesdarleunvistazoa:
https://docs.djangoproject.com/en/1.8/ref/models/querysets/
Datosdinámicosenplantillas
92
DjangoGirlsTutorial
PlantillasdeDjango
¡Eshorademostraralgunosdatos!Djangonosproveelasútilestemplatetagsparaello.
¿Quésonlastemplatetags?
Verás,enHTMLnopuedesrealmenteponercódigoPython,porquelosnavegadoresnolo
entienden.EllossólosabenHTML.SabemosqueHTMLesalgoestático,mientrasque
Pythonesmuchomásdinámico.
DjangotemplatetagsnospermitentransferircosasdePythoncomocosasenHTML,así
quetupuedesconstruirsitioswebdinámicosmásrápidoyfácil.
Mostrarlaplantillapostlist
Enelcapítuloanteriordimosanuestraplantillaunalistadepostsenlavariable posts.
AhoralomostraremosenHTML.
ParaimprimirunavariableenunaplantilladeDjango,utilizamosllavesdoblesconel
nombredelavariabledentro,así:
{{posts}}
Pruebaestoentuplantilla blog/templates/blog/post_list.html(reemplazaelsegundoyel
tercerpardeetiquetas <div></div>conlalínea {{posts}}),guardaelarchivoy
actualizalapáginaparaverlosresultados:
Comopuedesver,todoloqueobtenemosesesto:
PlantillasdeDjango
93
DjangoGirlsTutorial
[<Post:Misegundopost>,<Post:Miprimerpost>]
EstosignificaqueDjangoloentiendecomounalistadeobjetos.¿Recuerdasde
IntroducciónaPythoncómopodemosmostrarlistas?Sí,¡conlosciclosfor!Enuna
plantilladeDjango,lohacesdeestamanera:
{%forpostinposts%}
{{post}}
{%endfor%}
Pruebaestoentuplantilla.
¡Funciona!Peroqueremosquesemuestrencomolospostsestáticosquecreamos
anteriormenteenelcapítulodeIntroducciónaHTML.PuedesmezclarHTMLytemplate
tags.Nuestro bodyseverá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:
PlantillasdeDjango
94
DjangoGirlsTutorial
¿Hasnotadoqueutilizamosunanotacióndiferenteestavez {{post.title}}o {{
post.text}}?Estamosaccediendoadatosencadaunodeloscamposdefinidosen
nuestromodelo Post.Tambiénel |linebreaksestádirigiendoeltextodelospostsa
travésdeunfiltroparaconvertirsaltosdelíneaenpárrafos.
Unacosamás
SeríabuenoversitusitiowebseguiráfuncionandoenlaInternetpública,¿verdad?
IntentemosdesplegándolaenPythonAnywherenuevamente.Aquítedejamosunayuda
memoria...
Primero,subetucódigoaGitHub
$gitstatus[...]$gitadd-A.$gitstatus[...]$gitcommit-m"Addedviewstocreate/edit
blogpostinsidethesite."[...]$gitpush
Luego,identifícateenPythonAnywhereyveatuconsolaBash(oempiezauna
nueva),yejecuta:
$cdmy-first-blog$gitpull[...]
Finalmente,vealapestañaWebypresionaReloadentuaplicaciónweb.¡Tu
actualizacióndeberíapoderverse!
PlantillasdeDjango
95
DjangoGirlsTutorial
¡Felicidades!Ahorasigueadelante,tratadeagregarunnuevopostusandoelpanelde
administradordeDjango(¡recuerdaañadirpublished_date!)yluegoactualizatupáginapara
versiaparecetunuevopost.
¿Funcionacomounencanto?¡Estamosorgullosos!Aléjatedetucomputadoraporunrato,
tehasganadoundescanso.:)
PlantillasdeDjango
96
DjangoGirlsTutorial
CSS-¡Hazlobonito!
Nuestroblogtodavíasevebastantefeo,¿verdad?¡Eshoradehacerlobonito!Vamosa
usarCSSparaeso.
¿QuéesCSS?
CSS(CascadingStyleSheets,quesignifica'hojasdeestiloencascada')esunlenguaje
utilizadoparadescribirelaspectoyelformatodeunsitiowebescritoenlenguajede
marcado(comoHTML).Trátalocomomaquillajeparanuestrapáginaweb;).
Peronoqueremosempezardecerootravez,¿verdad?Unavezmás,usaremosalgoque
yahasidorealizadoporprogramadoresypublicadoenInternetdeformagratuita.Yasabes,
reinventarlaruedanoesdivertido.
¡VamosausarBootstrap!
BootstrapesunodelosframeworksHTMLyCSSmáspopularesparadesarrollarwebs
bonitas:http://getbootstrap.com/
LoescribieronprogramadoresquetrabajabanparaTwitteryahoralodesarrollanvoluntarios
detodoelmundo.
InstalarBootstrap
ParainstalarBootstraptienesqueañ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.cs
Estonoañadeningúnficheroatuproyecto.Simplementeapuntaaficherosqueexistenen
Internet.Adelante,abretusitiowebyactualizalapágina.¡Aquíestá!
CSS-Hazlobonito
97
DjangoGirlsTutorial
¡Sevemuchomejor!
FicherosestáticosenDjango
Finalmentenosvamosafijarenestascosasquehemosestadollamandoficheros
estáticos.LosficherosestáticossontodostusCSSeimágenes;ficherosquenoson
dinámicos,porloquesucontenidonodependedelcontextodelapeticiónyserániguales
paratodoslosusuarios.
DóndeponerlosficherosestáticosparaDjango
Comohasvistocuandohemosejecutado collectstaticenelservidor,Djangoyasabe
dóndeencontrarlosficherosestáticosparalaaplicación"admin".Ahoranecesitamosañadir
algunosficherosestáticosparanuestrapropiaaplicación, blog.
Estoloconseguimoscreandounacarpetallamada staticdentrodelaaplicaciónblog:
djangogirls
├──blog
│├──migrations
│└──static
└──mysite
Djangoencontraráautomáticamentecualquiercarpetaquesellame"static"dentrodelas
carpetasdetusaplicacionesypodráutilizarsucontenidocomoficherosestáticos.
¡TuprimerficheroCSS!
CSS-Hazlobonito
98
DjangoGirlsTutorial
CreemosunficheroCSSahora,paraañadirtupropioestiloatupáginaweb.Crearun
nuevodirectoriollamado cssdentrodetudirectorio static.Despuéscreaunnuevo
ficherollamado blog.cssdentrodeestedirectorio css.¿Lista?
djangogirls
└───blog
└───static
└───css
└───blog.css
¡EshoradeescribiralgodeCSS!Abreelfichero blog/static/css/blog.cssentueditorde
código.
NovamosaentrarmuchoenlapersonalizaciónyelaprendizajedeCSSaquíporquees
bastantefácilylopuedesaprenderportucuentadespuésdeestetaller.Recomendamos
enormementehacerestecursodeHTMLyCSSenCodecademyparaaprendertodoloque
necesitassabersobrecómohacertussitioswebmásbonitosconCSS.
Perovamosahacerunpocoalmenos.¿Talvezpodríamoscambiarelcolordenuestro
título?Losordenadoresutilizancódigosespecialesparaentenderloscolores.Empiezan
con #ylessiguen6letras(A-F)ynúmeros(0-9).Puedesencontrarcódigosdecolor,por
ejemplo,aquí:http://www.colorpicker.com/.Tambiénpuedesutilizarcolorespredefinidos
utilizandosunombreeninglés,como redy green.
Entufichero blog/static/css/blog.cssdeberíasañadirelsiguientecódigo:
h1a{
color:#FCA205;
}
h1aesunselectorCSS.Quieredecirqueestamosaplicandonuestrosestilosacualquier
elemento aqueseencuentredentrodeunelemento h1(porejemplocuandotenemos
encódigoalgocomo: <h1><ahref="">enlace</a></h1>).Enestecasoleestamosdiciendo
quecambieelcolora #FCA205,queesnaranja.Porsupuesto,¡puedesponertupropio
coloraquí!
EnunficheroCSSdefinimoslosestilosparaloselementosdelficheroHTML.Los
elementosseidentificanporelnombredelelemento(esdecir, a, h1, body),elatributo
class(clase)oelatributo id(identificador).Classeidsonnombresqueleasignastú
mismaalelemento.Lasclasesdefinengruposdeelementosylosidsapuntanaelementos
específicos.Porejemplo,lasiguienteetiquetasepuedeidentificarconCSSusandoel
nombre a,laclase external_linkoelid link_to_wiki_page:
CSS-Hazlobonito
99
DjangoGirlsTutorial
<ahref="http://en.wikipedia.org/wiki/Django"class="external_link"id="link_to_wiki_page"
PuedesleermássobreselectoresdeCSSenw3schools.
TambiénnecesitamosdecirleanuestraplantillaHTMLquehemosañadidoCSS.Abreel
fichero blog/templates/blog/post_list.htmlyañadeestalíneajustoalprincipio:
{%loadstaticfiles%}
Aquísóloestamoscargandoficherosestáticos:).Luego,entreel <head>y </head>,
despuésdelosenlacesalosficherosCSSdeBootstrap(elnavegadorleelosficherosenel
ordenenqueestán,asíquenuestroficheropodríasobrescribirpartesdelcódigode
Bootstrap),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.
<linkrel="stylesheet"href="//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap-them
<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!
CSS-Hazlobonito
100
DjangoGirlsTutorial
¡Buentrabajo!¿Quizánosgustaríadarleunpocodeaireanuestrositiowebyaumentar
tambiénelmargenenelladoizquierdo?¡Vamosaintentarlo!
body{
padding-left:15px;
}
AñadeestoatuCSS,guardaelficheroy¡miracómofunciona!
¿Quizápodríamospersonalizarlatipografíadeltítulo?Pegaestoenlasección <head>del
fichero blog/templates/blog/post_list.html:
<linkhref="http://fonts.googleapis.com/css?family=Lobster&subset=latin,latin-ext"rel
CSS-Hazlobonito
101
DjangoGirlsTutorial
EstalíneavaaimportarunatipografíallamadaLobsterdeGoogleFonts
(https://www.google.com/fonts).
Ahoraañadelalínea font-family:'Lobster';enelficheroCSS blog/static/css/blog.css
dentrodelbloquededeclaración h1a(elcódigoentrellaves {y })yactualizala
página:
h1a{
color:#FCA205;
font-family:'Lobster';
}
¡Genial!
Comosemencionóanteriormente,CSStieneunconceptodeclasesquebásicamente
permitenombrarunapartedelcódigoHTMLyaplicarestilossóloaestaparte,sinafectara
otras.Esmuyútilsitienesdosdivsquehacenalgomuydiferente(comoelencabezadoyla
entrada)ynoquieresquetenganelmismoaspecto.
¡Adelante!NombraalgunaspartesdelcódigoHTML.Añadeunaclasellamada pageheaderal divquecontieneelencabezado,así:
<divclass="page-header">
<h1><ahref="/">DjangoGirlsBlog</a></h1>
</div>
Yahoraañadelaclase postal divquecontieneunaentradadelblog.
CSS-Hazlobonito
102
DjangoGirlsTutorial
<divclass="post">
<p>published:{{post.published_date}}</p>
<h1><ahref="">{{post.title}}</a></h1>
<p>{{post.text|linebreaks}}</p>
</div>
Ahoraañadiremosbloquesdedeclaraciónadiferentesselectores.Losselectoresque
comienzancon .hacenreferenciaalasclases.Haymuchostutorialesyexplicaciones
sobreCSSenlawebqueteayudaránaentenderelsiguientecódigo.Porahora,
simplementecopiaypegaestebloquedecódigoentufichero blog/static/css/blog.css:
CSS-Hazlobonito
103
DjangoGirlsTutorial
.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:
CSS-Hazlobonito
104
DjangoGirlsTutorial
{%forpostinposts%}
<divclass="post">
<p>published:{{post.published_date}}</p>
<h1><ahref="">{{post.title}}</a></h1>
<p>{{post.text|linebreaks}}</p>
</div>
{%endfor%}
en blog/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ódigoqueacabamosdepegarnoestan
difícildeentenderydeberíassercapazdeentenderlamayoríasóloconleerlo.
NotengasmiedodejugarunpococonesteCSSeintentarcambiaralgunascosas.Si
rompesalgo,notepreocupes,¡siemprepuedesdeshacerlo!
CSS-Hazlobonito
105
DjangoGirlsTutorial
Decualquierforma,tevolvemosarecomendarquehagaselcursodeHTMLyCSSde
Codeacademycomounatareapost-tallerparaqueaprendastodoloquenecesitassaber
parahacertussitioswebmásbonitosconCSS.
¡¿Listaparaelsiguientecapítulo?!:)
CSS-Hazlobonito
106
DjangoGirlsTutorial
ExtendiendoPlantillas
OtracosabuenaqueDjangotieneparatíeslaextensióndeplantillas.¿Quésignifica
esto?SignificaquepuedesusarlasmismaspartesdetuHTMLparadiferentespáginasde
tusitioweb.
Deestaformanotienesquerepetirelcódigoencadaunodelosarchivoscuandoquieres
usarunamismainformaciónounmismoesquema.Ysiquierescambiaralgo,nonecesitas
hacerloencadaplantilla.
Creandounaplantillabase
Unaplantillabaseeslaplantillamásbásicaqueextiendesencadapáginadetusitioweb.
Vamosacrearunarchivo base.htmlen blog/templates/blog/:
blog
└───templates
└───blog
base.html
post_list.html
Luegoábreloycopiatodoloquehayen post_list.htmlalarchivo base.html,dela
siguientemanera:
Extenderplantillas
107
DjangoGirlsTutorial
{%loadstaticfiles%}
<html>
<head>
<title>DjangoGirlsblog</title>
<linkrel="stylesheet"href="//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.
<linkrel="stylesheet"href="//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap-them
<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,en base.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>
Extenderplantillas
108
DjangoGirlsTutorial
Básicamenteremplazamostodoentre {%forpostinposts%}{%endfor%}con:
{%blockcontent%}
{%endblock%}
¿Quésignificaesto?Acabasdecrearun block,unatemplatetagquetepermiteinsertar
HTMLenestebloqueenotrasplantillasqueextiendana base.html.Temostraremoscomo
hacerestoenunmomento.
Ahoraguárdaloyabretuarchivo blog/templates/blog/post_list.htmldenuevo.Elimina
todoloquenoesté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'%}
Significaqueahoraestamosextendiendodelaplantilla base.htmlen post_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%}
Extenderplantillas
109
DjangoGirlsTutorial
¡Esoestodo!Verificaquetusitiowebaúnfuncioneapropiadamente:)
Sitienesunerror TemplateDoesNotExistsquedigaquenohayunarchivo
blog/base.htmlytienes runserverejecutándoseenlaconsola,intentapararlo
(presionandoCtrl+C-lasteclasControlyCjuntas)yreinicialoejecutandoelcomando
pythonmanage.pyrunserver.
Extenderplantillas
110
DjangoGirlsTutorial
Amplíatuaplicación
Yahemoscompletadotodoslospasosnecesariosparalacreacióndenuestrositioweb:
sabemoscómoescribirunmodel,url,viewytemplate.Tambiénsabemoscómohacerque
nuestrositiowebsevealindo.
¡Horadepracticar!
Loprimeroquenecesitamosennuestrobloges,obviamente,unapáginaparamostrarun
post,¿cierto?
Yatenemosunmodelo Post,asíquenonecesitamosañadirnadaa models.py.
Creaunenlaceenlaplantilla
Vamosaempezarañadiendounenlacedentrodelarchivo
blog/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%}.Como
probablementesospeches,lanotación {%%}significaqueestamosutilizandoDjango
templatetags.¡EstavezvamosautilizarunoquevaacrearunadirecciónURLpara
nosotros!
Amplíatuaplicación
111
DjangoGirlsTutorial
blog.views.post_detailesunarutahacia post_detailviewquequeremoscrear.Porfavor
nota: blogeselnombredenuestraaplicación(el blogdedirectorio), viewsesel
nombredelarchivo views.pyy post_detaileselnombredelaview.
Ahoracuandovayamosa:http://127.0.0.1:8000/tendremosunerror(comoeradeesperar,
yaquenotenemosunadirecciónURLounaviewpara post_detail).Severáasí:
VamosacrearunaURLen urls.pyparanuestroview post_detail!
URL:http://127.0.0.1:8000/post/1/
QueremoscrearunaURLqueapunteaDjangoaunaviewdenominada post_detail,que
mostraráunaentradadelblog.Agregalalínea url(r'^post/(?P<pk>[0-9]+)/$',
views.post_detail),alarchivo blog/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),
]
Amplíatuaplicación
112
DjangoGirlsTutorial
Esedaunpocodemiedo,peronotepreocupes-loexplicaremosparati:comienzacon`^`otravez,"
Esosignificaquesientrasen`http://127.0.0.1:8000/post/5/`entunavegador,Djangoentenderáque
`pk`eslaabreviaciónde`primarykey`.EstenombreseutilizaamenudoenproyectosdeDjango.Pero
¡Bien!¡Actualizalapágina:http://127.0.0.1:8000/¡Boom!¡Sinembargovemosotroerror!Comoerade
![AttributeError][2]
[2]:images/attribute_error2.png
¿Teacuerdasdelpróximopaso?Porsupuesto:¡agregarunaview!
##post_detailview
Estaveznuestra*view*tomaráunparámetroadicional`pk`.¿Nuestra*view*necesitarecibirla,ciert
Ahora,queremossólounpostdelblog.Paraellopodemosusarquerysetscomoeste:
Post.objects.get(pk=pk)
Peroestecódigotieneunproblema.Sinohayningún`Post`con`llaveprimaria`(`pk`)tendremosun
![DoesNotExisterror][3]
[3]:images/does_not_exist2.png
¡Noqueremoseso!Pero,porsupuesto,Djangovieneconalgoqueseencargarádeeseproblemapornoso
![Pagenotfound][4]
[4]:images/404_2.png
Labuenanoticiaesquepuedescreartupropiapágina`PageNotFound`ydiseñarlacomodesees.Pero
¡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})
Amplíatuaplicación
113
DjangoGirlsTutorial
Sí.Eshoradeactualizarlapágina:http://127.0.0.1:8000/
¡Funcionó!Pero¿quépasacuandohacesclickenunenlaceeneltítulodelpost?
¡Ohno!¡Otroerror!Peroyasabemoscómolidiarconeso,¿no?¡Tenemosqueañadiruna
plantilla!
Crearemosunarchivoen blog/templates/blogllamado post_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ásestamosextendiendo base.html.Enelbloque contentqueremosmostrarla
fechadepublicación(siexiste),títuloytextodenuestrosposts.Perodeberíamosdiscutir
algunascosasimportantes,¿cierto?
{%if...%}...{%endif%}esuntemplatetagquepodemosusarcuandoquerramosver
algo(¿recuerdasif...else...</code>delcapítulodeIntroducciónaPython?).Eneste
escenarioqueremoscomprobarsielcampo published_datedeunpostnoestávacío.
Bien,podemosactualizarnuestrapáginayversi PageNotFoundsehaido.
¡Yay!¡Funciona!
Unacosamás:¡Tiempodeimplementación!
SeríabuenoverificarquetusitiowebaúnfuncionaráenPythonAnywhere,¿cierto?
Intentemosdesplegardenuevo.
Amplíatuaplicación
114
DjangoGirlsTutorial
$gitstatus
$gitadd-A.
$gitstatus
$gitcommit-m"Addedviewstocreate/editblogpostinsidethesite."
$gitpush
Luego,enunaconsolaBashdePythonAnywhere
$cdmy-first-blog$gitpull[...]
Finalmente,vealapestañaWebyhazclickenReload.
¡Yesodeberíasertodo!Felicidades:)
Amplíatuaplicación
115
DjangoGirlsTutorial
FormulariosenDjango
Loúltimoqueharemosennuestrowebsiteescrearunapartadoparaagregaryeditarposts
enelblog.Django adminestábien,peroesbastantedifícildepersonalizaryhacerlo
bonito.Con formstendremosunpoderabsolutosobrenuestrainterfaz-podemoshacer
casicualquiercosaquepodamosimaginar!
LobuenodeDjangoformsesquepodemosdefinirlodesdeceroocreandoun ModelFormy
seguardaráelresultadodelformularioenelmodelo.
Estoesexactamenteloquequeremoshacer:crearemosunformularioparanuestromodelo
Post.
ComocadaparteimportantedeDjango,formstienensupropioarchivo: forms.py.
Tenemosquecrearunarchivoconestenombreeneldirectorio blog.
blog
└──forms.py
Ok,vamosabrirloyvamosaescribirelsiguientecódigo:
fromdjangoimportforms
from.modelsimportPost
classPostForm(forms.ModelForm):
classMeta:
model=Post
fields=('title','text',)
PrimeronecesitamosimportarDjangoforms( fromdjangoimportforms)y,obviamente,
nuestromodelo Post( from.modelsimportPost).
PostForm,comoprobablementesospechas,eselnombredelformulario.Necesitamos
decirleaDjangoqueesteformularioesun ModelForm(asíDjangoharáalgodemagiapara
nosotros)- forms.ModelFormesresponsabledeello.
Acontinuación,tenemos classMeta,dondeledecimosaDjangoquémodelodebeutilizar
paracrearesteformulario( model=Post).
FormulariosenDjango
116
DjangoGirlsTutorial
Finalmente,podemosdecirquecampo(s)queremosennuestroformulario.Eneste
escenariosóloqueremos titley text- authorserálapersonaquesehaautenticado
(¡tú!)y created_datesedefiniráautomáticamentecuandocreemosunpost(esdecirenel
código),¿si?
¡Yesoestodo!Todoloquenecesitamoshacerahoraesusarelformularioenunaviewy
mostrarlaenunaplantilla.
Unavezmásvamosacrear:unenlacealapágina,unadirecciónURL,unavistayuna
plantilla.
Enlaceaunapáginaconelformulario
Eshoradeabrir blog/templates/blog/base.html.Vamosaañadirunenlaceen div
llamado page-header:
<ahref="{%url'blog.views.post_new'%}"class="top-menu"><spanclass="glyphiconglyphicon-plus"
Tenencuentaquequeremosllamaranuestranuevavista post_new.
Despuésdeagregarlalínea,tuarchivohtmldeberíateneresteaspecto:
FormulariosenDjango
117
DjangoGirlsTutorial
{%loadstaticfiles%}
<html>
<head>
<title>DjangoGirlsblog</title>
<linkrel="stylesheet"href="//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.
<linkrel="stylesheet"href="//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap-them
<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="glyphicongly
<h1><ahref="/">DjangoGirlsBlog</a></h1>
</div>
<divclass="contentcontainer">
<divclass="row">
<divclass="col-md-8">
{%blockcontent%}
{%endblock%}
</div>
</div>
</div>
</body>
</html>
Luegodeguardaryactualizarlapágina http://127.0.0.1:8000obviamenteverásunerror
NoReverseMatchfamiliar,¿verdad?
URL
Abrimos blog/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'),
]
FormulariosenDjango
118
DjangoGirlsTutorial
Despuésdeactualizarelsitio,veremosun AttributeError,puestoquenotenemoslavista
post_newimplementada.Vamosaañadirlaahora.
Vistapost_new
Eselmomentodeabrirelarchivo blog/views.pyyagregarlassiguienteslíneasalrestode
lasfilas from:
from.formsimportPostForm
ynuestravista:
defpost_new(request):
form=PostForm()
returnrender(request,'blog/post_edit.html',{'form':form})
Paracrearunnuevoformulario Post,tenemosquellamara PostForm()ypasarloala
plantilla.Volveremosaestavistapero,porahora,vamosacrearrápidamenteunaplantilla
paraelformulario.
Plantilla
Tenemosquecrearunarchivo post_edit.htmleneldirectorio blog/templates/blog.Para
hacerqueunformulariofuncionenecesitamosvariascosas:
tenemosquemostrarelformulario.Podemoshacerlo,porejemplo,conunsimple``.
lalíneaanteriortienequeestardentrodeunaetiquetadeformularioHTML: <form
method="POST">...</form>
necesitamosunbotón Guardar.LohacemosconunbotónHTML: <button
type='submit'>Save</button>
yfinalmentejustodespuésdelaaperturade <form...>necesitamosagregar {%
csrf_token%}.¡Estoesmuyimportanteyaquehacequetusformulariosseanseguros!
Djangosequejarásiteolvidasdeestapartecuandointenteguardarelformulario.
FormulariosenDjango
119
DjangoGirlsTutorial
Bueno,vamosavercómoquedaráelHTMLen post_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!
FormulariosenDjango
120
DjangoGirlsTutorial
Pero,¡unmomento!Siescribesalgoenloscampos títley textytratasdeguardarlos
cambios-¿quépasará?
¡Nada!Unavezmásestamosenlamismapáginayeltextosehaido...noseañadeningún
postnuevo.Entonces,¿quéhaidomal?
Larespuestaes:nada.Tenemosquetrabajarunpocomásennuestravista.
Guardarelformulario
Abre blog/views.pyunavezmás.Actualmente,loquetenemosenlavista post_newes:
defpost_new(request):
form=PostForm()
returnrender(request,'blog/post_edit.html',{'form':form})
Cuandoenviamoselformulariosomosredirigidosalamismavista,peroestaveztenemos
algunosdatosadicionalesen request,másespecíficamenteen request.POST(elnombre
notienenadaqueverconunpostdelblog,serefiereaqueestamos"publicando"-en
inglés,posting-datos).¿RecuerdasqueenelarchivoHTMLladefiniciónde <form>tenía
FormulariosenDjango
121
DjangoGirlsTutorial
lavariable method="POST"?Todosloscamposdelformularioestanahoraen request.POST.
Nodeberíasrenombrarlavariable POST(elúniconombrequetambiénesválidoparala
variable methodes GET,peronotenemostiempoparaexplicarcuálesladiferencia).
Ennuestraviewtenemosdosposiblessituacionesacontemplar.Primero:cuando
accedemosalapáginaporprimeravezyqueremosunformularioenblanco.Segundo:
cuandovolvemosalaviewconlosdatosdelformularioqueacabamosdeescribir.Asíque
tenemosqueañadirunacondición(utilizaremos ifparaeso).
ifrequest.method=="POST":
[...]
else:
form=PostForm()
Eshoradellenarlospuntos [...].Siel methodes POSTqueremosconstruirel
PostFormconlosdatosdelformulario,¿no?Loharemoscon:
form=PostForm(request.POST)
Fácil!Losiguienteesverificarsielformularioescorrecto(todosloscamposnecesarios
estándefinidosynohayvaloresincorrectos).Lohacemoscon form.is_valid().
Comprobamosqueelformularioesválidoy,siesasí,¡lopodemossalvar!
ifform.is_valid():
post=form.save(commit=False)
post.author=request.user
post.save()
Básicamente,tenemosquehacerdoscosasaquí:guardamoselformulariocon form.save
yañadimosunautor(yaquenohabíaningúncampode authorenel PostFormyeste
campoesobligatorio). commit=Falsesignificaquenoqueremosguardarelmodelo Post
todavía-queremosañadirelautorprimero.Lamayoríadelasvecesutilizarás form.save(),
sin commit=False,peroenestecaso,tenemosquehacerlo. post.save()conservarálos
cambios(añadiendoaautor)ysecrearáunanuevopostenelblog.
Porúltimo,seríagenialsipodemosinmediatamenteiralapágina post_detaildelnuevo
postdeblog,¿no?Parahacerlonecesitamosimportaralgomás:
fromdjango.shortcutsimportredirect
FormulariosenDjango
122
DjangoGirlsTutorial
Agrégaloalprincipiodelarchivo.Yahorapodemosdecir:véalapágina post_detaildel
postreciéncreado.
returnredirect('blog.views.post_detail',pk=post.pk)
blog.views.post_detaileselnombredelavistaalaquequeremosir.¿Recuerdasque
estaviewrequiereunavariable pk?Parapasarloalasvistasutilizamos pk=post.pk,
donde posteselpostrecié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ñadeun titley
un text,guardalo...¡yvoilà!Seañadeelnuevopostalblogysenosredirigealapágina
de post_detail.
Probablementehasvistoquenohemosdefinidolafechadepublicación.Vamosaintroducir
unbotónpublicarenDjangoGirlsTutorial:Extensions.
¡Esoesgenial!
Validacióndeformularios
Ahora,vamosaenseñartequétanbuenoesDjangoforms.Unpostdelblogdebetenerlos
campos titley text.Ennuestromodelo Postnodijimos(adiferenciade
published_date)queestoscampossonrequeridos,asíqueDjango,pordefecto,espera
queesténdefinidos.
Tratadeguardarelformulariosin titley text.¡Adivinaquépasará!
FormulariosenDjango
123
DjangoGirlsTutorial
Djangoseencargadevalidarquetodosloscamposenelformularioesténcorrectos.¿No
esgenial?
ComorecientementehemosutilizadolainterfazdeadministradordeDjango,elsistema
piensaqueestamosconectadas.Hayalgunassituacionesquepodríanllevarnosa
desconectarnos(cerrandoelnavegador,reiniciandolabasededatos,etc.).Siestás
recibiendoerroresalcrearunpostqueindicanlafaltadeiniciodesesióndeusuario,
dirígetealapáginadeadministración http://127.0.0.1:8000/admineiniciasesión
nuevamente.Estoresolveráelproblematemporalmente.Hayunarreglopermanente
esperándoteenelcapítuloTarea:¡Añadirseguridadatusitioweb!despuésdel
tutorialprincipal.
FormulariosenDjango
124
DjangoGirlsTutorial
Editarformulario
Ahorasabemoscómoagregarunnuevoformulario.Pero,¿quépasasiqueremoseditaruno
existente?Esmuysimilaraloqueacabamosdehacer.Vamosacrearalgunascosas
importantesrápidamente(sinoentiendesalgo,pregúntaleatututororevisalocapítulos
anteriores,sontemasqueyahemoscubierto).
Abreelarchivo blog/templates/blog/post_detail.htmlyañadeestalínea:
<aclass="btnbtn-default"href="{%url'post_edit'pk=post.pk%}"><spanclass="glyphiconglyphic
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="glyphicongly
</div>
<h1>{{post.title}}</h1>
<p>{{post.text|linebreaks}}</p>
{%endblock%}
Enelarchivo blog/urls.pyañadimosestalínea:
url(r'^post/(?P<pk>[0-9]+)/edit/$',views.post_edit,name='post_edit'),
Vamosareusarlaplantilla blog/templates/blog/post_edit.html,asíqueloúltimoquenos
faltaesunaview.
Abramoselarchivo blog/views.pyyañadamosalfinalestalínea:
FormulariosenDjango
125
DjangoGirlsTutorial
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})
Estosevecasiexactamenteigualanuestraview post_new,¿no?Peronodeltodo.
Primero:pasamosunparámetroextra pkdelosurls.Luego:obtenemoselmodelo Post
quequeremoseditarcon get_object_or_404(Post,pk=pk)ydespués,alcrearelformulario
pasamosestepostcomouna instanciatantoalguardarelformulario:
form=PostForm(request.POST,instance=post)
comoalabrirunformularioconestepostparaeditarlo:
form=PostForm(instance=post)
Ok,¡vamosaprobarsifunciona!Dirígetealapágina post_detail.Debehaberahíun
botónparaeditarenlaesquinasuperiorderecha:
FormulariosenDjango
126
DjangoGirlsTutorial
Aldarclickahí,debesverelformularioconnuestropostdelblog:
¡Siéntetelibredecambiareltítulooeltextoyguardaloscambios!
¡Felicitaciones!¡Tuaplicaciónestácadavezmáscompleta!
SinecesitasmásinformaciónsobrelosformulariosdeDjango,debesleerla
documentació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/editblog
postinsidethesite."$gitpush
Luego,enunaconsolaBashdePythonAnywhere
$cdmy-first-blog$gitpull[...]
Finalmente,vealapestañaWebyhazclickenReload.
FormulariosenDjango
127
DjangoGirlsTutorial
¡Yesodeberíasertodo!Felicidades:)
FormulariosenDjango
128
DjangoGirlsTutorial
Dominio
PythonAnywheretehadadoundominiogratuito,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ómovincularloa
tuaplicaciónwebenPythonAnywhere.Sinembargo,deberíassaberquelamayoríadelos
dominiossonpagos,yPythonAnywheretecobraráunvaloradicionalparausartupropio
nombrededominio--noesdemasiadodineroentotal,peroesprobablementealgoque
quierashacersólosiestásmuycomprometidaconlacausa.
¿Donderegistrarundominio?
Undominiotípicocuestaalrededorde15dólaresestadounidensesanuales.Hayopciones
másbaratasymáscaras,dependiendodelproveedor.Hayunagrancantidaddeempresas
alasquepuedescomprarundominio:unasimplebúsquedaengoogledarácientosde
opciones.
NuestraopciónfavoritaesIwantmyname.Ellossepromocionancomounaopción
"indoloraparaelmanejodedominios"yrealmenteloson.
Tambiénpuedesobtenerdominiosgratuitos.dot.tkesunlugarparaobteneruno,pero
deberíamosadvertirtequelosdominiosgratuitosavecessesientenalgo"baratos"--situ
sitiovaaserunsitioparaunnegocioprofesional,seguramentequierasconsiderarcomprar
undominio"apropiado"quetermineen .com.
CómoapuntartudominioaPythonAnywhere
Sielegistelaopcióndeiwantmyname.com,hazclicken Domainsenelmenúyelijetu
nuevodominio.Luegoencuentraelvínculoa manageDNSrecords:
Ahoranecesitasencontraresteformulario:
Dominio
129
DjangoGirlsTutorial
Ycompletarloconlossiguientesdetalles:-Hostname:www-Type:CNAME-Value:tu
dominiodePythonAnywhere(porejemplo,djangogirls.pythonanywhere.com)-TTL:60
Enlaparteinferior,hazclickenelbotón"Agregar"yguardaloscambios.
NotaSiutilizasteunproveedordedominiosdiferente,lainterfazexactaparaencontrar
tusconfiguracionesdeDNS/CNAMEserádiferente,perotuobjetivoeselmismo:
configurarunCNAMEqueapunteatunuevodominioen
yourusername.pythonanywhere.com.
Puedetomarunosminutosparatudominioparaempezarafuncionar,¡sépaciente!
Configuraeldominioatravésdelaaplicación
webenPythonAnywhere
TambiénnecesitarásdecirleaPythonAnywherequequieresusartudominiopersonalizado.
VealapáginaPythonAnywhereAccountsyhazunaactualizacióndeltipodecuenta.La
opciónmáseconómica(elplan"Hacker")estábienparaempezar.Siemprepuedeselegirun
planconmayoresprestacionesdespuéscuandotevuelvassuper-famosaytengasmillones
devisitas.
Luego,vealapestañaWebyanotaunpardecosas:
Copialarutaatuvirtualenvyponlaenalgúnlugarseguro
AbretuarchivodeconfiguraciónWSGI,copiaelcontenido,ypégaloenalgúnlugar
seguro
Luego,hazclickenDeletedetuviejaaplicaciónweb.Notepreocupes,estonoeliminarátu
código,solamentecambiaráeldominioyourusername.pythonanywhere.com.Luego,crea
unanuevaaplicaciónwebysigueestospasos:
Ingresatunombrededominio
Elije"configuraciónmanual"
ElijePython3.4
¡Ylisto!
Cuandoseasredirigidaalapestañaweb.
Pegalarutaalvirtualenvqueguardasteanteriormente
AbretunuevoarchivodeconfiguraciónWSGIypegaelcontenidodetuviejoarchivode
configuración
Dominio
130
DjangoGirlsTutorial
Hazclickenactualizar,¡deberíasverquetusitioestáenlíneaenelnuevodominio!
Siteencuentrasconalgúnproblema,hazclickenelvínculo"Sendfeedback"enelsitiode
PythonAnywhere,yunodesusamigablesadministradorestecontactaráparaayudarteen
breve.
Dominio
131
DjangoGirlsTutorial
¿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ántodosmuy
recomendados!
Django'sofficialtutorial
NewCodertutorials
CodeAcademyPythoncourse
CodeAcademyHTML&CSScourse
DjangoCarrotstutorial
LearnPythonTheHardWaybook
GettingStartedWithDjangovideolessons
TwoScoopsofDjango:BestPracticesforDjangobook
¿Quésigue?
132
Descargar