Tabeladeconteúdos Introdução 1.1 Comofuncionaainternet? 1.2 Introduçãoàlinhadecomando 1.3 InstalaçãodoPython 1.4 EditordeCódigo 1.5 IntroduçãoaoPython 1.6 OqueéDjango? 1.7 InstalaçãodoDjango 1.8 Criandoumprojeto 1.9 ModelosdoDjango 1.10 Administração 1.11 Implantação! 1.12 Urls 1.13 Views-horadecriar! 1.14 IntroduçãoaHTML 1.15 DjangoORM(Querysets) 1.16 Dadosdinâmicosnostemplates 1.17 Templates 1.18 CSS-Deixemaisbonito 1.19 Estendendoostemplates 1.20 Ampliesuaaplicação 1.21 Formulários 1.22 Domínio 1.23 Oquevemdepois? 1.24 2 Introdução TutorialDjangoGirls EstetrabalhoélicenciadosobalicençaCreativeCommonsAttribution-ShareAlike4.0.Paraverumacópiadesta licença,visitehttps://creativecommons.org/licenses/by-sa/4.0/ Translation ThistutorialhasbeentranslatedfromEnglishtoPortuguesebyagroupofawesomevolunteers. Specialthanksforhelpgoesoutto: AdailtondoNascimentoAdamVictorNazarethBrandizziAntonioLuisAnnandaSousaAdjamiltonJuniorBernardoFontes CamillaAchuttiCarlaSuarezCleitonLimaclemente.jnrdanieltexEricHidekiFlavioBarrosFabioC.BarrionuevodaLuz ffabiorjGabrielaCavalcantedaSilvaLeandroSilvaAraujoLucasMagnum1pedroJoaoLuizLorencetti KatyannaMouraKleberCPinheiroLeandroBarbosaLeonardoAlvesdosSantosMarcelRibeiroDantasjoepreludian RafaelBiagionideFazioPabloPalaciosPauloAlemRaonyGuimaresCorreodoCarmoLisboaCardenasVivianMacedo WillieLawrence*RicardoManhãesSaviiWow!<3<3 Introdução Vocêjásentiucomoseomundofossecadavezmaissobretecnologiaequedealgumaformavocêtenhaficadopratrás? Vocêjáimaginoucomoseriacriarumwebsitemasnuncatevemotivaçãosuficienteparacomeçar?Vocêjápensouqueo mundodosoftwareécomplicadodemaisatéparatentarfazeralgumacoisasozinho? Bem,nóstemosboasnotíciasparavocê!Programaçãonãoétãodifícilquantopareceenósqueremostemostraroquão divertidopodeser. Estetutorialnãoirátetransformarmagicamenteemumprogramador.Sevocêquerserbomnissoprecisademesesou atémesmoanosdetreinoeprática.Masnósqueremostemostrarqueaprogramaçãooucriaçãodewebsitesnãoétão complicadaquantoparece.Nóstentaremosexplicarosdiferentespedaçostãobemquantopudermos,talquevocênãose sintaintimidadopelatecnologia. Nósesperamosconseguirfazervocêamaratecnologiatantoquantonósamamos! Oquevocêiráaprenderduranteotutorial? Quandovocêtiverterminadootutorialvocêteráumaaplicaçãowebsimplesefuncional:seupróprioblog.Nósvamos mostrarcomocolocá-loonline,paraqueoutrosvejamseutrabalho! Eleseparecerá(maisoumenos)comisso: 3 Introdução Sevocêseguirotutorialporcontaprópriaenãotiverumtreinadorparaajudaremcasodequalquerproblema,nós temosumchatparavocê: 1.Nóspedimosaosnossostreinadoreseparticipantesanteriorespara acessaremládetemposemtemposeajudaremoutroscomotutorial!Nãotenhamedodefazersuaperguntalá! OK,vamospelocomeço... Sobreotutorialecontribuições EstetutorialémantidoporDjangoGirls.Sevocêencontrarquaisquererrosouquiseratualizarotutorial,porfavorsigaas orientaçõesdecontribuição. Gostariadenosajudaratraduzirotutorialparaoutros idiomas? nomomento,astraduçõesestãosendomantidasnaplataformacrowdin.comem: https://crowdin.com/project/django-girls-tutorial Seoseuidiomanãoestálistadonocrowdin,porfavoropenanewissueinformandooidiomaparaquepossamos adicioná-lo. 4 Introdução 5 Comofuncionaainternet? Comofuncionaainternet Estecapítuloéinspiradonapalestra"ComoaInternetfunciona"deJessicaMcKellar (http://web.mit.edu/jesstess/www/). ApostamosquevocêusaaInternettodososdias.Masvocêsaberealmenteoqueacontecequandovocêdigitaum endereçocomohttps://djangogirls.orgemseunavegadorepressiona'Enter'? Aprimeiracoisaquevocêprecisaentenderéqueumsiteésóummontedearquivossalvosemumdiscorígido.Assim comoseusfilmes,músicasoufotos.Noentanto,existeumapartequeéexclusivaparasites:essaparteincluicódigode computadorchamadoHTML. Sevocênãoestiverfamiliarizadacomprogramação,podeserdifícilcompreenderoHTMLnocomeço,masseunavegador web(comooChrome,Safari,Firefox,etc)amaele.NavegadoresWebsãoprojetadosparaentenderessecódigo,seguir suasinstruçõeseapresentartodosessesarquivosdequeseusiteéfeito,exatamentedojeitoquevocêquerqueeles sejamapresentados. Igualàtodososarquivos,osarquivosHTMLprecisamserarmazenadosemumdiscorígido.Paraainternet,nósusamos especiaisepoderososcomputadoreschamadosdeservidores.Elesnãotêmtela,mouseouteclado,porquesuafinalidade principaléarmazenardadoseservi-los.Éporissoqueelessãochamadosdeservidores..--porqueelesservemavocê, dados. OK,masvocêquersabercomoquêainternetseparece,certo? Fizemosumdesenhopravocê!Veja: Pareceumabagunça,nãoé?Naverdadeéumarededemáquinasconectadas(osservidoresmencionadosacima). Centenasdemilharesdemáquinas!Muitos,muitosquilômetrosdecabosportodoomundo!Paraveroquãocomplicadaa interneté,vocêpodevisitarumsite(http://submarinecablemap.com/)quemostraummapacomoscabossubmarinos. Aquiestáumscreenshotdosite: 6 Comofuncionaainternet? Fascinante,não?Mas,obviamente,nãoépossívelterumfioconectadoatodamáquinaligadanainternet.Logo,para chegaremumamáquina(porexemploaquelaondehttps://djangogirls.orgestásalva)nósprecisamospassaruma requisiçãoatravésdemuitasemuitasmáquinasdiferentes. Separececomisso: 7 Comofuncionaainternet? Imaginequequandovocêdigitahttps://djangogirls.org,vocêenviaumacartaquediz:"QueridoDjangoGirls,eudesejover ositedjangogirls.org.Envieelepramim,porfavor!" Suacartavaiparaaagênciadoscorreiosmaispróximadevocê.Depoisvaiparaoutraqueéumpoucomaispertodeseu destinatário,depoisparaoutraeoutra,atéqueelasejaentregueaoseudestino.Oúnicodiferencialéquesevocêenviar cartas(pacotesdedados)comfreqüênciaparaomesmolugar,cadacartapodepassarpordiferentesagênciasde correios(roteadores),dependendodecomoelassãodistribuídasemcadaagência. 8 Comofuncionaainternet? Sim,ésimplesassim.Vocêenviamensagenseesperaalgumaresposta.Claro,aoinvésdepapelecanetavocêusabytes dedados,masaideiaéamesma! Aoinvésdeendereçoscomonomedarua,cidade,códigopostalenomedopaís,nósusamosendereçosIP.Primeiroseu computadorpedeaoDNS(DomainNameSystem-SistemadeNomedeDomínio)paratraduzirdjangogirls.orgparaum endereçoIP.Ofuncionamentodelesepareceumpoucocomasantigaslistastelefônicasondevocêpodeolharparao nomedapessoaquequerentraremcontatoeacharoseunúmerodetelefoneeendereço. Quandovocêenviaumacarta,elaprecisatercertascaracterísticasparaserentreguecorretamente:umendereço,selo, etc.Vocêtambémusaumalinguagemqueoreceptadorcompreende,certo?Omesmoacontececompacotesdedados quevocêenviaparaverumsite:vocêusaumprotocolochamadoHTTP(HypertextTransferProtocol-Protocolode TransferênciadeHipertexto). Então,basicamente,quandovocêtemumsite,vocêprecisaterumservidor(máquina)ondeeleficahospedado.O servidorestáàesperadequaisquerrequisiçõesrecebidas(cartasquesolicitamaoservidoroenviodoseusite)eele enviadevoltaseusite(emoutracarta). ComoesteéumtutorialdeDjangovocêvaiperguntaroqueoDjangofaz.Quandovocêenviaumarespostanemsempre vocêquerenviaramesmacoisaparatodomundo.Serámuitomelhorsesuascartasforempersonalizadas,diferenciada paraapessoaqueacaboudeescreverparavocê,certo?ODjangoajudavocêacriaressaspersonalizadase interessantescartas:). Chegadefalar,éhoradecriar! 9 Introduçãoàlinhadecomando Introduçãoàlinhadecomando Éemocionante,não?!Vocêvaiescreversuaprimeiralinhadecódigoempoucosminutos:) Deixe-nosapresentá-loaoseuprimeironovoamigo:alinhadecomando! Asetapasaseguirmostrarãoavocêcomousarajanelapretaquetodososhackersusam.Podeparecerumpouco assustadornocomeço,masrealmenteéapenasumpromptesperandoporcomandosdevocê. Qualéalinhadecomando? Ajanela,quenormalmenteéchamadadelinhadecomandoouinterfacedelinhadecomando,éumaplicativo baseadoemtextoparavisualização,manipulaçãoemanuseiodearquivosemseucomputador(comoporexemplo,o WindowsExplorerouoFindernoMac,masseminterfacegráfica).Outrosnomesparaalinhadecomandosão:cmd,CLI, prompt,consoleouterminal. Abraainterfacedelinhadecomando Paracomeçaralgunsexperimentos,precisamosabriranossainterfacedelinhadecomandoprimeiro. Windows VáemIniciar→TodososProgramas→Acessórios→Promptdecomando. MacOSX Applications→Utilities→Terminal. Linux ProvavelmentevocêvaiacharemApplications→Accessories→Terminal,masissodependedoseusistemaoperacional. QualquercoisaésóprocurarnoGoogle:) Prompt Agoravocêdeveverumajanelabrancaoupretaqueestáàesperadeseuscomandos. SevocêestiveremMacounumLinux,vocêprovavelmenteveráum``$,comoeste: $ NoWindows,éumsinalde >,comoeste: > Cadacomandoseráantecedidoporestesinaleumespaço,masvocênãoprecisadigitá-lo.Seucomputadorfaráissopor você:) Apenasumapequenanota:noseucaso,talvezháalgocomo C:\Users\ola>ou Olas-MacBookAir:~ola$antes dosinaldopromptistoestará100%correto.Nestetutorialnósapenassimplificaremoseleparaomínimo. 10 Introduçãoàlinhadecomando Seuprimeirocomando(YAY!) Vamoscomeçarcomalgosimples.Digiteoseguintecomando: $whoami ou >whoami DepoisteclaEnter.Essaénossasaída: $whoami olasitarska Comovocêpodever,ocomputadorsóapresentouseunomedeusuário.Elegante,né?:) Tentedigitarcadacomando,nãocopiarecolar.Vocêvaiselembrarmaisdessaforma! OBásico Cadasistemaoperacionaltemoseupróprioconjuntodeinstruçõesparaalinhadecomando,entãosecertifiquequevocê estáseguindoasinstruçõesdoseusistemaoperacional.Vamostentar,certo? Pastaatual Serialegalsaberemquepastaestamosagora,certo?Vamosver.Digiteoseguintecomandoseguidodeumenter: $pwd /Users/olasitarska SevocêestivernoWindows: >cd C:\Users\olasitarska Provavelmentevocêvaiveralgoparecidonasuamáquina.Umvezquevocêabrealinhadecomandovocêjácomeçana pastaHome. Nota:'pwd'significa'printworkingdirectory'. Listandoarquivosepastas Entãooquetemnele?Serialegaldescobrir.Vamosver: $ls Applications Desktop Downloads Music ... Windows: 11 Introduçãoàlinhadecomando >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 ... Entraremoutrapasta TalvezagentequeiraentrarnanossapastaDesktop? $cdDesktop Windows: >cdDesktop Vejaserealmenteentramosnapasta: $pwd /Users/olasitarska/Desktop Windows: >cd C:\Users\olasitarska\Desktop Aquiestá! Dicadeprofissional:sevocêdigitar cdDeapertaratecla tabnoseuteclado,alinhadecomandoirápreencher automaticamenteorestodonomeparaquevocêpossanavegarrapidamente.Sehouvermaisdeumapastaque comececom"D",aperteatecla tabduasvezesparaobterumalistadeopções. Criandoumapasta QuetalcriarumdiretórioDjangoGirlsnasuaáreadetrabalho?Vocêpodefazerassim: $mkdirdjangogirls Windows: >mkdirdjangogirls Estecomandovaicriarumapastacomonome djangogirlsnonossodesktop.Vocêpodeverificarseeleestálá,sóde olharnasuaáreadetrabalhoouexecutandoumcomando ls(MacouLinux)ou dir(Windows)!Experimente:) Dicadeprofissional:Sevocênãoquiserdigitaromesmocomandováriasvezes,tentepressionar setaparacimae setaparabaixonotecladoparapercorrercomandosusadosrecentemente. Exercite-se! 12 Introduçãoàlinhadecomando Umpequenodesafioparavocê:nasuamaisnovapastacriada djangogirlscrieumaoutrapastachamada teste.Use oscomandos cde mkdir. Solução: $cddjangogirls $mkdirteste $ls teste Windows: >cddjangogirls >mkdirteste >dir 05/08/201407:28PM<DIR>teste Parabéns!:) Limpando Nãoqueremosdeixarumabagunça,entãovamosremovertudooquefizemosatéagora. PrimeiroprecisamosvoltarparaapastaDesktop: $cd.. Windows: >cd.. Fazendo cdpara ..nósmudaremosdodiretórioatualparaodiretóriopai(quesignificaodiretórioquecontémo diretórioatual). Vejaondevocêestá: $pwd /Users/olasitarska/Desktop Windows: >cd C:\Users\olasitarska\Desktop Agoraéhoradeexcluirodiretório djangogirls. Atenção:Aexclusãodearquivosusando del, rmdirou rméirrecuperável,significandoArquivosexcluídosvão emboraparasempre!Então,tenhacuidadocomestecomando. $rm-rdjangogirls Windows: >rmdir/Sdjangogirls djangogirls,Temcerteza<S/N>?S 13 Introduçãoàlinhadecomando Pronto!Paratercertezaqueapastafoiexcluída,vamoschecar: $ls Windows: >dir Saindo Porenquantoéisso!Agoravocêfecharalinhadecomandocomsegurança.Vamosfazerdojeitohacker,certo?:) $exit Windows: >exit Legal,né?:) Sumário Aquivaiumalistadealgunscomandosúteis: Comando (Windows) Comando(MacOS/ Linux) Descrição Exemplo exit exit Fechaajanela exit cd cd Mudaapasta cdtest dir ls Listaaspastaseos arquivos dir copy cp Copiaumarquivo copyc:\test\test.txt c:\windows\test.txt move mv Moveumarquivo movec:\test\test.txt c:\windows\test.txt mkdir mkdir Criaumapasta mkdirtestdirectory del rm Deletaumapastae/ou arquivo delc:\test\test.txt Estessãoapenasalgunsdospoucoscomandosquevocêpodeexecutaremsualinhadecomando,masvocênãovai usarmaisnadadoqueistohoje. Sevocêestivercurioso,ss64.comcontémumareferênciacompletadecomandosparatodosossistemasoperacionais. Pronto? VamosmergulharnoPython! 14 InstalaçãodoPython VamoscomeçarcomPython Finalmentechegamosaqui! Masprimeiro,vamosfalarumpoucosobreoqueoPythoné.Pythonéumalinguagemdeprogramaçãomuitopopularque podeserusadaparacriarsites,jogos,softwarescientíficos,gráficosemuito,muitomais. OPythonéorigináriodadécadade1980eseuprincipalobjetivoéserlegívelporsereshumanos(nãoapenasmáquinas!), porissoeleparecemuitomaissimplesdoqueoutraslinguagensdeprogramação.Issofazelemaisfácildeaprender,mas nãoseengane,Pythontambémémuitopoderoso! InstalaçãodoPython EstesubcapítuloébaseadoemumtutorialcriadoporGeekGirlsCarrots(https://github.com/ggcarrots/djangocarrots) DjangoéescritoemPython.NósprecisamosdeleparafazerqualquercoisaemDjango.Vamoscomeçarcomsua instalação!NósqueremosquevocêinstaleoPython3.4,entãosevocêtemqualquerversãoanterior,vocêvaiprecisar atualizá-la. Windows VocêpodebaixaroPythonparaWindowsnowebsitehttps://www.python.org/downloads/release/python-343/.Depoisde fazerodownloaddoarquivo*.msi,vocêprecisaexecutá-lo(dandoumduplo-cliquenele)eseguirasinstruções.É importantelembrarocaminho(apasta)ondevocêinstalouoPython.Elaseráútildepois! Cuidadocomumacoisa:nasegundateladoassistentedeinstalação,marcado"Customize",certifique-sevocêrolarpara baixoeescolhaaopção"Adicionarpython.exeparaocaminho",comoem 15 InstalaçãodoPython Linux ÉmuitoprovávelquevocêjátenhaoPythoninstaladoeconfigurado.Paratercertezaseeleestáinstalado(equalasua versão),abraumterminaledigiteoseguintecomando: $python3--version Python3.4.2 SevocênãotemoPythoninstaladoouquerumaversãodiferente,vocêpodeinstalá-lodaseguintemaneira: Ubuntu Digiteoseguintecomandonoterminal: sudoapt-getinstallpython3.4 Fedora Useoseguintecomandonoterminal: sudoyuminstallpython3.4 openSUSE Useoseguintecomandonoterminal: sudozypperinstallpython3 OSX Vocêprecisaacessarositehttps://www.python.org/downloads/release/python-342/ebaixaroinstaladordoPython: downloaddoinstaladorMacOSX64-bit/32-bitDMG, Dêumduplo-cliqueparaabri-lo, Dêumduplo-cliquenoPython.mpkgparaexecutaroinstalador. VerifiqueseainstalaçãofoibemsucedidaabrindooTerminaledigitandoocomando python3: $python3--version Python3.4.2 Sevocêtiverqualquerdúvidaousealgumacoisadeuerradoevocênãosabeoquefazer-porfavorpergunteaoseu instrutor!Àsvezes,ascoisasnãoestãoindobemeémelhorpedirajudaaalguémcommaisexperiência. 16 EditordeCódigo EditordeCódigo Vocêestáprestesaescreversuaprimeiralinhadecódigo,entãoéhoradebaixarumeditordecódigo! Existemmuitoseditoresdiferenteseemgrandeparteseresumeapreferênciapessoal.Amaioriadosprogramadores Pythonusaascomplexas,masextremamentepoderosasIDEs(IntegratedDevelopmentEnvironments,ouemportuguês, AmbientededesenvolvimentoIntegrado),taiscomoPyCharm.Parauminiciante,entretanto,estasIDE'ssãomenos convenientes;nossasrecomendaçõessãobemmaissimples,porém,igualmentepoderosas. Nossassugestõesestãoabaixo,massinta-selivreparaperguntaraoseucoachquaissãoassuaspreferências-assim vaisermaisfácilobteraajudadeles. Gedit Geditéumeditoropen-source,gratuito,disponívelparatodosossistemasoperacionais. Baixeaqui SublimeText3 SublimeText3éumeditormuitopopularcomumperíododeavaliaçãogratuita.Éfácildeinstalareusar,eestádisponível paratodosossistemasoperacionais. Baixeaqui Atom AtoméumnovoeditordecódigocriadopeloGitHub.Eleégratuito,open-source,fácildeinstalarefácildeusar.Está disponívelparaWindows,OSXeLinux. Baixeaqui Porqueestamosinstalandoumeditordecódigo? Vocêdeveestarseperguntandoporqueestamosinstalandoessesoftwareeditordecódigoespecialaoinvésdeusaralgo comoWordouBlocodeNotas. Primeiroéquecódigoprecisasertextosemformatação,eoproblemacomprogramascomoWordeTexteditéqueeles naverdadenãoproduzemtextosemformatação,elesfazem"richtext"(comfonteseformatação),usandoformatos personalizadoscomoRTF. Asegundarazãoéqueeditoresdecódigosãoespecializadosemeditarcódigo,entãoelespodemoferecerrecursosúteis, comorealcedecódigocomcoresdeacordocomoseusignificado,ouautomaticamentefecharcitaçõesparavocê. Nósvamosverissoemaçãodepois.Embrevevocêteráseueditordecódigocomoumadassuasferramentasfavoritas. :) 17 IntroduçãoaoPython IntroduçãoaoPython PartedestecapítuloébaseadonosTutoriaisdeGeekGirlsCarrots(https://github.com/ggcarrots/django-carrots). Vamosescreverumpoucodecódigo! InterpretadorPython ParacomeçarabrincarcomPythonnósprecisamosabrirumalinhadecomandonoseucomputador.Vocêjádevesaber comofazerisso--vocêaprendeuissonocapítuloIntroduçãoàLinhadeComando.Assimqueestiverpronto,sigaas instruçõesabaixo. NósqueremosabriroPythonnumterminal,entãodigite python3etecleEnter. $python3 Python3.4.2(...) Type"copyright","credits"or"license"formoreinformation. >>> SeuprimeirocomandoPython! DepoisdeexecutarocomandoPython,opromptmudoupara >>>.Paranós,issosignificaqueporenquantosó utilizaremoscomandosnalinguagemPython.Vocênãoprecisadigitar >>>-OPythonfaráissoporvocê. SevocêdesejasairdoconsoledoPython,apenasdigite exit()ouuseoatalho Ctrl+ZnoWindowse Ctrl+Dno Mac/Linux.Entãovocênãovaivermaiso >>>. MasagoranãoqueremossairdalinhadecomandodoPython.Queremosaprendermaissobreele.Vamos,então,fazer algomuitosimples.Porexemplo,tentedigitaralgumaoperaçãomatemática,como 2+3eaperteEnter. >>>2+3 5 Incrível!Vêcomoarespostasimplesmenteaparece?OPythonconhecematemática!Vocêpodetentaroutroscomandos como:- 4*5- 5-1- 40/2 Divirta-secomissoporumtempoedepoisvolteaqui:). Comovocêpodever,oPythonéumaótimacalculadora.Sevocêestáseperguntandooquemaisvocêpodefazer... Strings Quetaloseunome?Digiteseuprimeironomeentreaspas,dessejeito: >>>"Ola" 'Ola' Vocêacaboudecriarsuaprimeirastring!Stringéumsequênciadecaracteresquepodemserprocessadapelo computador.Astringsempreprecisainiciareterminarcomomesmocaractere.Estepodeseraspasduplas( ')ou simples( ")-elasdizemaoPythonqueoqueestádentrodelaséumastring. Stringspodemserjuntadas.Tenteisto: 18 IntroduçãoaoPython >>>"Oi"+"Ola" 'OiOla' Vocêtambémpodemultiplicarstringsporumnúmero: >>>"Ola"*3 'OlaOlaOla' Sevocêprecisacolocarumaapóstrofedentrodesuastring,existemduasmaneirasdefazer. Usandoaspasduplas: >>>"Correndo'ladeiraabaixo" "Correndo'ladeiraabaixo" ouescapandoapóstrofocomumabarrainvertida( \): >>>"Correndo\'ladeiraabaixo" "Correndo'ladeiraabaixo" Legal,hein?Paraverseunomeemletrasmaiúsculas,bastadigitar: >>>"Ola".upper() 'OLA' Vocêacaboudeusarafunção uppernasuastring!Umafunção(como upper())éumconjuntodeinstruçõesqueo Pythonrealizaemumdeterminadoobjeto( "Ola"),semprequevocêchamarporele. Sevocêquersaberonúmerodeletrasdoseunome,existeumafunçãoparaissotambém! >>>len("Ola") 3 Seperguntandoporquealgumasvezesvocêchamafunçõescomum .nofimdeumastring(como "Ola".upper())e algumasvezesvocêprimeirochamaafunçãocolocandoastringnosparênteses?Bem,emalgunscasos,funções pertencemaobjetos,como upper(),quesópodeserutilizadaemstrings.Nessecaso,nóschamamosafunçãode método.Outrasvezes,funçõesnãopertencemanadaespecíficoepodemserusadasemdiferentestiposdeobjetos, assimcomo len().Éporissoquenósestamosfornecendo "Ola"comoumparâmetroparaafunção len. Sumário OK,chegadestrings.Atéagoravocêaprendeusobre: oprompt-digitarcomandos(códigos)nointerpretadorPythonresultaemrespostasemPython númerosestrings-noPython,númerossãousadosparamatemáticaestringsparaobjetosdetexto operadores-como+e*,combinamvaloresparaproduzirumnovovalor funções-comoupper()elen(),executamaçõesnosobjetos. Issoéobásicosobretodasaslinguagensdeprogramaçãoquevocêaprende.Prontoparaalgomaisdifícil?Apostamos quesim! Erros Vamostentaralgonovo.Podemosobterotamanhodeumnúmerodamesmaformaquepodemosencontrarotamanhodo nossonome?Digite len(304023)epressioneEnter: 19 IntroduçãoaoPython >>>len(304023) Traceback(mostrecentcalllast): File"<stdin>",line1,in<module> TypeError:objectoftype'int'hasnolen() Temosnossoprimeiroerro!Eledizqueobjetosdotipo"int"(inteiros,apenasnúmeros)nãotêmnenhumcomprimento. Entãooquepodemosfazeragora?Talvezpossamosescrevernossonúmerocomoumastring?Stringstêmum comprimento,certo? >>>len(str(304023)) 6 Funcionou!Usamosafunção strdentrodafunção len. str()convertetudoparastrings. Afunção strconverteascoisasemstrings Afunção intconverteascoisasemnúmerosinteiros Importante:podemosconverternúmerosemtexto,masnósnãopodemos,necessariamente,convertertextoem números-oque int('hello')querdizer? Variáveis Umconceitoimportantenaprogramaçãoéoconceitodevariáveis.Umavariávelnãoénadamaisdoqueumnomepara algumacoisa,detalformaquevocêpossausá-lamaistarde.Osprogramadoresusamessasvariáveisparaguardar dados,parafazerseuscódigosmaislegíveiseparanãoterqueselembrarsempreoquealgumascoisassignificam. Digamosquequeremoscriarumanovavariávelchamada nome: >>>nome="Ola" Vê?Éfácil!Ésófazer:nomeigualaOla. Comovocêpercebeu,seuprogramanãoretornounadacomofezanteriormente.Entãocomosabemosqueavariável realmenteexiste?Simplesmentedigite nomeetecleEnter: >>>nome 'Ola' Yippee!Suaprimeiravariável!:)Vocêsemprepodemudaroseuvalor: >>>nome="Sonja" >>>nome 'Sonja' Vocêpodeusá-latambémemfunções: >>>len(nome) 5 Incrívelnão?Claro,variáveispodemserqualquercoisa,entãopodemsernúmerostambém!Tenteisso: >>>a=4 >>>b=6 >>>a*b 24 20 IntroduçãoaoPython Mas,esedigitarmosonomeerrado?Vocêconsegueadivinharoqueaconteceria?Vamostentar! >>>city="Tokyo" >>>ctiy Traceback(mostrecentcalllast): File"<stdin>",line1,in<module> NameError:name'ctiy'isnotdefined Umerro!Comovocêpodever,PythontemdiferentestiposdeerroseesteéchamadoNameError.Pythondaráesteerro sevocêtentarusarumavariávelquenãofoidefinidaainda.Sevocêencontraresseerrodepois,vejasenoseucódigose vocênãodigitouonomedeumavariávelerrado. Brinquecomissoporumtempoevejaoquevocêconseguefazer! Afunçãoprint Tenteisso: >>>nome='Maria' >>>nome 'Maria' >>>print(nome) Maria Quandovocêapenasdigita nome,ointerpretadorPythonrespondecomarepresentaçãocomostringdavariável'name', quesãoasletrasM-a-r-i-a,entreaspassimples.Quandovocêdiz print(nome),Pythonvai"imprimir"oconteúdoda variávelnatela,semasaspas,oqueémaispuro. Comoveremosmaistarde, print()tambéméútilquandoqueremosimprimiralgodentrodefunções,ouquando queremosimprimiralgoemváriaslinhas. Listas Alémdestringseinteiros,oPythontemtodosostiposdiferentesdeobjetos.Vamosapresentarumchamadolista.Listas sãoexatamenteoquevocêachaqueelassão:elassãoobjetosquesãolistasdeoutrosobjetos:) Váemfrenteecrieumalista: >>>[] [] Sim,estaéumalistavazia.Nãoémuito,nãoé?Vamoscriarumalistadosnúmerosdaloteria.Comonãoqueremosficar repetindoocódigotodootempovamoscriarumavariávelparaela: >>>loteria=[3,42,12,19,30,59] Tudocerto,nóstemosumalista!Oquepodemosfazercomisso?Vamosverquantosnúmerosdeloteriaexistemnesta lista.Vocêtemideiadequalfunçãodeveusarparaisso?Vocêjásabedisso! >>>len(loteria) 6 Sim! len()podetedaronúmerodeobjetosquefazempartedeumalista.Umamãonaroda,não?Vamosorganizarisso agora: 21 IntroduçãoaoPython >>>loteria.sort() Issonãoretornanada,apenastrocaaordememqueosnúmerosaparecemnalista.Vamosimprimirissooutravezevero queacontece: >>>print(loteria) [3,12,19,30,42,59] Comovocêpodever,osnúmerosnanossalistaestãoordenadosdomenorparaomaior.Parabéns! Talvezagentequeirainverteressaordem?Vamosfazerisso! >>>loteria.reverse() >>>print(loteria) [59,42,30,19,12,3] Molezané?Sevocêquiseradicionaralgumacoisaàsualista,vocêpodefazeristodigitandooseguintecomando: >>>loteria.append(199) >>>print(loteria) [59,42,30,19,12,3,199] Sevocêquisermostrarapenasoprimeironúmerovocêpodeusaríndices.Umíndiceéumnúmeroquedizondeumitem dalistaestá.Oscomputadoresgostamdeiniciaracontagempor0,entãooprimeiroobjetotemíndice0,opróximotem índice1eporaívai.Tenteisso: >>>print(loteria[0]) 59 >>>print(loteria[1]) 42 Comovocêpodever,vocêpodeacessardiferentesobjetosnasualistausandoonomedalistaeoíndicedoobjetodentro doscolchetes. Pordiversãoextra,tentealgunsoutrosíndices:6,7,1000,-1,-6ou-1000.Vejasevocêconseguepreveroresultado antesdetentarocomando.Osresultadosfazemsentido? VocêpodeencontrarumalistadetodososmétodosdisponíveisnestecapítulonadocumentaçãodoPython: https://docs.python.org/3/tutorial/datastructures.html Dicionários Umdicionárioésemelhanteaumalista,masvocêpodeacessarvaloresatravésdeumachaveaoinvésdeumíndice. Umachavepodeserqualquerstringounúmero.Asintaxeparadefinirumdicionáriovazioé: >>>{} {} Issomostraquevocêacaboudecriarumdicionáriovazio.Hurra! Agora,tenteescreveroseguintecomando(tentesubstituircomassuasprópriasinformaçõestambém): >>>participante={'nome':'Ola','pais':'Polonia','numeros_favoritos':[7,42,92]} Comessecomando,vocêacaboudecriarumavariávelchamada participantcomtrêsparesdechave-valor: 22 IntroduçãoaoPython Achave nomeapontaparaovalor 'Ola'(umobjeto string), paisapontapara 'Polonia'(outra string), e numeros_favoritosapontampara [7,42,92](uma listcomtrêsnúmerosnela). Vocêpodechecaroconteúdodechavesindividuaiscomasintaxe: >>>print(participante['nome']) Ola Veja,ésimilaraumalista.Masvocênãoprecisalembraroíndice-apenasonome. OqueacontecesepedirmosaoPythonovalordeumachavequenãoexiste?Vocêconsegueadivinhar?Vamostentare descobrir! >>>participante['idade'] Traceback(mostrecentcalllast): File"<stdin>",line1,in<module> KeyError:'idade' Olha,outroerro!EsseéumKeyError.Pythonébastanteprestativoetedizqueachave 'idade'nãoexistenesse dicionário. Quandousarumdicionarioouumalista?Bem,umbompontopararefletir.Penseemumasoluçãoantesdeolhara respostanapróximalinha. Vocêprecisadeumasequênciaordenadadeitens?Useumalist. Vocêprecisaassociarvalorescomchaves,assimvocêpodeprocurá-loseficientemente(pelachave)maistarde?Use umdictionary. Dicionários,comolistas,sãomutáveis,ouseja,quepodemsermudadosdepoisquesãocriados.Vocêpodeadicionar novosparesdechave/valorparaodicionárioapóssuacriação,como: >>>participante['linguagem_favorita']='Python' Comoaslists,usarométodo len()emdicionáriosretornaonúmerodepareschave-valornodicionario.Váemfrentee digiteocomando: >>>len(participante) 4 Esperoqueagorafaçasentidoatéagora.:)Prontaparamaisdiversãocomdicionários?Pulenapróximalinhaparacoisas incríveis. Vocêpodeusarocomando pop()paradeletarumitemnodicionario.Digamos,sevocêquerexcluiraentrada correspondenteachave 'numeros_favoritos',bastadigitaroseguintecomando: >>>participante.pop('numeros_favoritos') >>>participante {'pais':'Polonia','linguagem_favorita':'Python','nome':'Ola'} Comovocêpodevernoretorno,oparchave-valorcorrespondenteàchave'numeros_favoritos'foiexcluído. Alémdissovocêpodemudarovalorassociadocomumachavejácriadanodicionário.Digite: >>>participante['pais']='Alemanha' >>>participante {'pais':'Alemanha','linguagem_favorita':'Python','nome':'Ola'} 23 IntroduçãoaoPython Comovocêpodever,ovalordachave 'pais'foialteradode 'Polonia'para 'Alemanha'.:)Emocionante?Hurra!Você acaboudeaprenderoutracoisaincrível. Sumário Incrível!Agoravocêsabemuitosobreprogramação.Nestaúltimapartevocêaprendeusobre: erros-agoravocêsabecomolereentendererrosqueaparecemseoPythonnãoentenderumcomandoquevocê deu variáveis-nomesparaobjetosquepermitemvocêprogramarfacilmenteedeixarseucódigomaislegível listas-listasdeobjetosarmazenadosemumaordemespecífica dicionários-objetosarmazenadoscomopareschave-valor Empolgado(a)paraopróximopasso?:) Comparecoisas Grandepartedaprogramaçãoconsisteemcompararcoisas.Oqueémaisfácildecomparar?Números,éclaro.Vamos vercomoissofunciona: >>>5>2 True >>>3<1 False >>>5>2*2 True >>>1==1 True >>>5!=2 True DemosaoPythonalgunsnúmerosparacomparar.Comovocêpodever,Pythonpodecompararnãosónúmerosmas tambémresultadosdemétodos.Legal,hein? Vocêestáseperguntandoporquecolocamosdoissinaisdeigual ==ladoaladoparacompararseosnúmerossão iguais?Nósusamosumúnico =paraatribuirvaloresavariáveis.Vocêsempre,sempreprecisacolocardois ==se quiserverificarseascoisassãoiguais.Tambémépossívelafirmarqueascoisassãodesiguaisentresi.Paraisso, usamososímbolo !=,conformemostradonoexemploacima. DêaoPythonmaisduastarefas: >>>6>=12/2 True >>>3<=2 False >e <sãofáceis,masoque >=e <=significam?Leiaelesdaseguinteforma: x >ysignifica:xémaiorquey x <ysignifica:xémenorquey x <=ysignifica:xémenorouigualay x >=ysignifica:xémaiorouigualay Fantástico!Quermais?Tenteisto: 24 IntroduçãoaoPython >>>6>2and2<3 True >>>3>2and2<1 False >>>3>2or2<1 True VocêpodedaraoPythonquantosnúmerosparacompararquantovocêquiser,eelevaitedarumaresposta!Espertinho, certo? and-sevocêusarooperador and,ambasascomparaçõesterãoqueserverdadeirasparaquetodoocomandoseja verdadeiro or-sevocêusarooperador or,apenasumadascomparaçõesprecisaserverdadeiraparaqueocomandotodo sejaverdadeiro Jáouviuaexpressão"compararmaçãscomlaranjas"?VamostentaroequivalenteemPython: >>>1>'django' Traceback(mostrecentcalllast): File"<stdin>",line1,in<module> TypeError:unorderabletypes:int()>str() Aquivemosqueassimcomonaexpressão,Pythonnãoécapazdecompararumnúmero( int)eumastring( str).Em vezdisso,elemostrouumTypeErrorenosdissequeosdoistiposnãopodemsercomparadosjuntos.</p> Booleano Acidentalmente,vocêaprendeusobreumnovotipodeobjetoemPython.Échamadodebooleano--eprovavelmenteo tipomaisfácilqueexiste. Existemapenasdoisobjetosbooleanos:-True(verdadeiro)-False(falso) MasparaoPythonentenderisso,vocêprecisasempreescreverTrue(primeiraletramaiúscula,comorestodasletrasem minúsculo).true,TRUE,tRUEnãovaifuncionar--sóTrueécorreto.(OmesmoseaplicaaoFalse,claro.) Booleanospodemservariáveistambém!Veja: >>>a=True >>>a True Vocêtambémpodefazerdessejeito: >>>a=2>5 >>>a False Pratiqueedivirta-secomosvaloresbooleanos,tentandoexecutarosseguintescomandos: TrueandTrue FalseandTrue Trueor1==1 1!=2 Parabéns!Booleanossãoumdosrecursosmaisinteressantesnaprogramação,evocêacaboudeaprendercomousá-los! Salvá-lo! 25 IntroduçãoaoPython Atéagoranósescrevemostodonossocódigoemuminterpretadorpython,quenoslimitaaumalinhadecódigoemum momento.Programasnormaissãosalvosemarquivoseexecutadospelonossointerpretadordelinguagemde programaçãooucompilador.Atéagorajácorremosnossosprogramasdeumalinhadecadaveznointerpretador Python.Nósvamosprecisardemaisdeumalinhadecódigoparaaspróximastarefas,entãoprecisaremosrapidamente: SairdointerpretadorPython Abriroeditordecódigodesuaescolha Salvaralgumcódigoemumnovoarquivopython Executá-lo! ParasairdointerpretadorPythonqueestamosusando,simplesmentedigiteafunção exit(): >>>exit() $ Issovaicolocá-lanopromptdecomando. Anteriormente,nósescolhemosumeditordecódigodaseçãodoeditordecódigo.Nósprecisamosabriroeditoragorae escreveralgumcódigoemumnovoarquivo: print('Hello,Djangogirls!') NotaVocêdeveobservarqueumadascoisasmaislegaissobreeditoresdecódigo:cores!NoconsoledoPython, tudoeradamesmacor,masagoravocêdeveverqueafunçãode Imprimiréumacordiferentedasequênciade caracteresnoseuinterior.Issoéchamadode"realcedesintaxe",eéumaajudamuitoútilquandoestá programando.Percebaacordascoisasevocêvaiobterumadicaparaquandovocêesquecerdefecharuma seqüênciadecaracteres,oufazerumerrodedigitaçãoemumnomedepalavra-chave(como defemumafunção, queveremosabaixo).Estaéumadasrazõespelasquaisquenósusamosumeditordecódigo:) Obviamente,vocêéumdesenvolvedorpythonbastanteexperienteagora,entãosinta-selivreparaescreverumcódigo quevocêaprendeuhoje. Agoratemosdesalvaroarquivoedêumnomedescritivo.Vamoschamaroarquivopython_intro.pyesalve-oemseu desktop.Podemosnomearoarquivotudooquequisermos,oimportanteaquiétercertezaqueoarquivoterminanopy, istodiznossocomputador,queéumarquivoexecutáveldepythonePythonpodeexecutá-lo. Comoarquivosalvo,éhoradeexecutá-lo!Usandoashabilidadesquevocêaprendeunaseçãodelinhadecomando,use oterminalaltereosdiretóriosparaodesktop. EmumMac,ocomandoseráparecidocomisto: cd~/Desktop NoLinux,seráassim(apalavra"Desktop"podesertraduzidoparaseuidioma): cd~/Desktop Enowindows,vaiserassim: cd%HomePath%\Desktop Sevocêficarpreso,sópedirajuda. Emseguida,usaroPythonparaexecutarocódigonoarquivoassim: $python3python_intro.py Hello,Djangogirls! 26 IntroduçãoaoPython Tudobem!Vocêacaboudeexecutarseuprimeiroprogramaempythonquefoisalvoemumarquivo.Sesenteótima? Vocêpodeagorapassarparaumaferramentaessencialnaprogramação: if...elif...else Muitascoisasnocódigosópodemserexecutadassedeterminadascondiçõesforematendidas.ÉporissoqueoPython temalgumacoisachamadadeclaraçãoif. Substituaocódigonoarquivopython_intro.pyparaisto: if3>2: Sesalvouesteeelefoiexecutado,nósveríamosumerrocomoeste: $python3python_intro.py File"python_intro.py",line2 ^ SyntaxError:unexpectedEOFwhileparsing Pythonesperaquenósforneçamosmaisinstruçõesqueserãosupostamenteexecutadascasoacondição 3>2venhaa serverdadeira(ou Truenessecaso).VamostentarfazeroPythonimprimir"Itworks!".Altereoseucódigonoseuarquivo python_intro.pyparaisto: if3>2: print('Itworks!') Vocêpercebeuqueidentamosapróximalinhacom4espaços?PrecisamosfazerissoparaqueoPythonsaibaqual códigoseráexecutadoseoresultadoforTrue.Vocêpodefazercom1espaço,masquasetodososprogramadoresPython fazemcom4paradeixarascoisasarrumadas.Umúnicotabtambémvaicontarcomo4espaços. Salvá-loeexecutenovamente: $python3python_intro.py Itworks! Esenão? Nosexemplosanteriores,ocódigofoiexecutadosomentequandoascondiçõeseramverdade.MasoPythontambémtem instruções elife else: if5>2: print('5érealmentemaiorque2') else: print('5nãoémaiorque2') Quandoforexecutadoiráimprimir: $python3python_intro.py 5érealmentemaiorque2 Se2forumnúmeromaiordoque5,entãoosegundocomandoseráexecutado.Fácil,né?Vamosvercomofuncionao elif: 27 IntroduçãoaoPython name='Sonja' ifname=='Ola': print('HeyOla!') elifname=='Sonja': print('HeySonja!') else: print('Heyanonymous!') eexecutado: $python3python_intro.py HeySonja! Viuoqueaconteceu? Sumário Nosúltimostrêsexercíciosvocêaprendeu: compararascoisas-emPython,vocêpodecompararascoisasusandoosoperadores >, >=, ==, <=, <eo and, or Booleano-umtipodeobjetoquesótemumdosdoisvalores: Trueou False Salvandoarquivos-armazenamentodecódigoemarquivosassimvocêpodeexecutarprogramasmaiores. if...elif...else-instruçõesquepermitemquevocêexecuteocódigosomentesedeterminadascondiçõesforem atendidas. Éhoradaúltimapartedestecapítulo! Suasprópriasfunções! Selembradefunçõescomo len()quevocêpodeexecutarnoPython?Bem,boasnotícias,agoravocêvaiaprendera escreversuasprópriasfunções! UmafunçãoéumasequênciadeinstruçõesqueoPythondeveexecutar.CadafunçãoemPythoncomeçacomapalavrachave def,seguidodeumnomeparaafunçãoeopcionalmenteumalistadeparâmetros.Vamoscomeçarcomuma funçãosimples.Substituaocódigonopython_intro.pycomoseguinte: defhi(): print('Hithere!') print('Howareyou?') hi() Ok,nossaprimeirafunçãoestápronta! Vocêpodeseperguntarporqueescrevemosonomedafunçãonaparteinferiordoarquivo.IstoéporquePythonlêo arquivoeexecutadecimaparabaixo.Então,parausaranossafunção,temosdeescrevê-lonaparteinferior. Vamosexecuta-loagoraeveroqueacontece: $python3python_intro.py Hithere! Howareyou? Issofoifácil!Vamosconstruirnossaprimeirafunçãocomparâmetros.Usaremosoexemploanterior-umafunçãoquediz 'hi'paraquemoexecuta-comumname: 28 IntroduçãoaoPython defhi(name): Comovocêpodever,agorademosumparâmetrochamado nameparanossafunção: defhi(name): ifname=='Ola': print('HiOla!') elifname=='Sonja': print('HiSonja!') else: print('Hianonymous!') hi() Comovocêpodever,nósprecisamoscolocardoisespaçosantesdafunção print,porque ifprecisasaberoquedeve acontecerquandoacondiçãoforatendida.Vamosvercomoissofuncionaagora: $python3python_intro.py Traceback(mostrecentcalllast): File"python_intro.py",line10,in<module> hi() TypeError:hi()missing1requiredpositionalargument:'name' Oops,umerro.Felizmente,Pythonnosforneceumamensagemdeerrobastanteútil.Eladizqueafunção hi()(aquela quedeclaramos)temumargumentoobrigatório(chamado name)equenósesquecemosdepassá-loaochamarafunção. Vamoscorrigi-lonaparteinferiordoarquivo: hi("Ola") eexecutenovamente: $python3python_intro.py HiOla! Esemudarmosonome? hi("Sonja") eexecutá-lo: $python3python_intro.py HiSonja! Agora,oqueachaquevaiacontecersevocêescreveroutronomelá?(SemserOlaouSonja)Experimentá-loeverse vocêestácerto.Eledeveimprimiristo: Hianonymous! Istoéincrível,não?Dessamaneiravocênãoprecisaserepetir(DRY-don'trepeatyourself,ouemportuguês,nãose repita)cadavezqueformudaronomedapessoaqueafunçãopretendecumprimentar.Eéexatamenteporissoque precisamosdefunções-vocênuncaquerrepetirseucódigo! Vamosfazeralgomaisinteligente..--existemmaisquedoisnomes,eescreverumacondiçãoparacadaumseriadifícil, certo? 29 IntroduçãoaoPython defhi(name): print('Hi'+name+'!') hi("Rachel") Vamoschamarocódigoagora: $python3python_intro.py HiRachel! Parabéns!Vocêacaboudeaprenderacriarfunções:)! Laços Jáéaúltimaparte.Foirápido,não?:) Comomencionamos,osprogramadoressãopreguiçosos,nãogostamderepetirasmesmascoisas.Programaçãofala sobrecomoautomatizarascoisas,entãonãoqueremoscumprimentarcadapessoapeloseunomemanualmente,certo? Éaíondeoslaçosvemacalhar. Aindaselembradaslistas?Vamosfazerumalistadegarotas: girls=['Rachel','Monica','Phoebe','Ola','You'] Queremoscumprimentartodaselaspelosseusnomes.Temosafunção hiparafazerisso,entãovamosusá-laemum loop: fornameingirls: O forsecomportadamesmaformaqueo if,ocódigoabaixoessesdoisprecisamserrecuadosquatroespaços. Aquiestáocódigocompletoqueserásalvonoarquivo: defhi(name): print('Hi'+name+'!') girls=['Rachel','Monica','Phoebe','Ola','You'] fornameingirls: hi(name) print('Nextgirl') equandoexecutá-lo: $python3python_intro.py HiRachel! Nextgirl HiMonica! Nextgirl HiPhoebe! Nextgirl HiOla! Nextgirl HiYou! Nextgirl Comovocêpodever,tudooquevocêvaicolocardentrodeumainstrução forcomespaçoserárepetidoparacada elementodalista girls. Vocêtambémpodeusaro foremnúmerosusandoafunção range: 30 IntroduçãoaoPython foriinrange(1,6): print(i) Queiriaimprimir: 1 2 3 4 5 rangeéumafunçãoquecriaumalistadenúmerosqueseseguemumapósooutro(essesnúmerossãodadosporvocê comoparâmetros). NotequeosegundodessesdoisnúmerosnãoestáincluídonalistaqueoPythonmostrou(em range(1,6),contade1a 5,maso6nãoéincluído). Sumário Éisso.Vocêétotalmentedemais!Nãoétãofácil,entãovocêdevesesentirorgulhosadesimesma.Estamos definitivamenteorgulhosasdevocêporterchegadoatéaqui! Talvezvocêqueirabrevementefazeralgomais-espreguiçar,andarumpouco,descansarosolhos-antesdeirparao próximocapítulo.:) 31 OqueéDjango? OqueéDjango? Djangoéumframeworkgratuitoedecódigoabertoparaacriaçãodeaplicaçõesweb,escritoemPython.Éumframework web,ouseja,éumconjuntodecomponentesqueajudaadesenvolversitesdeformamaisrápidaemaisfácil. Veja,quandovocêestáconstruindoumsite,vocêsempreprecisaumconjuntosimilardecomponentes:umamaneirade lidarcomaautenticaçãodousuário(inscrever-se,realizarlogin,realizarlogout),paineldegerenciamentoparaoseusite, formulários,uploaddearquivos,etc. Felizmenteparavocê,hámuitotempo,outraspessoasnotaramváriassemelhançasnosproblemasenfrentadospelos desenvolvedoreswebquandoestãocriandoumnovosite,entãoelesuniram-seecriaramosframeworks(Djangoéum deles)quelhedãocomponentesprontos,quevocêpodeusar. Frameworksexistemparasalvá-lodeterquereinventararodaeajudamaaliviarasobrecargaquandovocêestá construindoumnovosite. Porquevocêprecisadeumframework? ParaentenderoqueDjangoénaverdade,precisamosolharmaisdepertoosservidores.Aprimeiracoisaéqueoservidor precisasaberoquevocêquerparaservi-loumapáginadaWeb. Imagineumacaixadecorreio(porta)queémonitoradaporcartasrecebidas(requisição).Issoéfeitoporumservidorweb. Oservidorweblêacartaeenviaumarespostacomumapáginaweb.Mas,quandovocêquerenviaralgumacoisavocê precisaterumconteúdo.EoDjangoéaquiloquevailheajudaracriaresseconteúdo. Oqueacontecequandoalguémsolicitaumsitedoseu servidor? QuandochegaumarequisiçãoparaoservidorwebelaépassadaparaoDjangoquetentadescobrirdoqueelasetrata. Primeiroelepegaumendereçowebetentadescobriroquefazer.EssaparteéfeitapelourlresolverdoDjango.(Note queoendereçodeumsitesechamaURL-UniformResourceLocator,emportuguêsLocalizadordeRecursosUniforme, dessaformaonomeurlresolver,ouresolvedordeurls,fazsentido).Issonãoémuitointeligente-levaàumalistade padrõesetentacorresponderaURL.ODjangoverificapadrõesdecimaparabaixoesealgoécorrespondido,passaa solicitaçãoparaafunçãoassociada(queéchamadaview). Imagineumcarteirocomumacarta.Elaestáandandopelaruaeverificacadanúmerodecasacomaqueestánacarta. Seelecorresponder,elacolocaacartalá.Éassimquefuncionaourlresolver! Todasascoisasinteressantessãofeitasdentrodaview:podemosdarumaolhadanobancodedadosparaprocurar algumasinformações.Talvezousuárioqueiramudaralgonosdados?Comoumacartadizendo:"Porfavormudea descriçãodomeuemprego."-aviewchecasevocêtempermissãoparafazerissoeentãoatualizaadescriçãodo empregopravocê,enviandoemseguidaumamensagem:"Feito!".EntãoaviewgeraumarespostaeoDjangopode enviá-laparaonavegadordocliente. Claro,adescriçãoacimaémuitosimplificada,masvocênãoprecisasaberdetalhestécnicosainda.Terumaideiageraljá ésuficiente. Entãoemvezdemergulharemmuitosdetalhes,nóssimplesmentevamoscomeçarcriandoalgocomoDjangoe aprenderemostodasaspartesimportantesaolongodocaminho! 32 InstalaçãodoDjango InstalaçãodoDjango PartedestecapítuloébaseadonostutoriaisdoGeekGirlsCarrots(https://github.com/ggcarrots/django-carrots). Partedestecapítuloébaseadonodjango-marcadortutoriallicenciadosobreCreativeCommonsAttributionShareAlike4.0InternationalLicense.Otutorialdodjango-marcadoréprotegidopordireitosautoraisporMarkus Zapke-Gründemannetal. Ambientevirtual AntesdeinstalarmosoDjango,nósiremosinstalarumaferramentaextremamenteútilqueiráajudaramanterseu ambientededesenvolvimentoarrumadoemseucomputador.Épossívelignorarestepasso,maseleéaltamente recomendado.Começarcomamelhorconfiguraçãopossíveltesalvarádemuitosproblemasnofuturo! Então,vamoscriarumambientevirtual(tambémchamadoumvirtualenv).IssoisolarásuaconfiguraçãoPython/Django emumabaseporprojeto,significaquequaisquermudançasquefizeremumwebsitenãoafetaráquaisqueroutras aplicaçõesqueestiverdesenvolvendoaparte.Arrumado,certo? Tudooquevocêprecisafazeréencontrarumdiretórionoqualvocêdesejacriaro virtualenv;SeudiretórioHome,por exemplo.NoWindowspodeparecercomo C:\Usuário\Nome(onde Nomeéonomedoseulogin). Paraestetutorialusaremosumnovodiretório djangogirlsdoseudiretóriohome: mkdirdjangogirls cddjangogirls Nósvamosfazerumvirtualenvchamado myvenv.Oformatogeraldessecomandoé: python3-mvenvmyvenv Windows Paracriarumnovo virtualenv,vocêprecisaabriroconsole(Nósfalamossobreissoalgunscapítulosatrás,lembra-se?)e executar C:\Python34\python-mvenvmyvenv.Seráalgoparecidocomisto: C:\Usuário\Nome\djangogirls>C:\Python34\python-mvenvmyvenv onde C:\Python34\pythonéodiretórioemquevocêpreviamenteinstalouPythone myvenvéonomedasua virtualenv. Vocêpodeusarqualqueroutronome,massempreuseminúsculasesemespaços,acentosoucaracteresespeciais. Tambéméumaboaideiamanteronomecurto-vocêiráreferenciarmuitoaele! LinuxeOSX Criarum virtualenvtantonoLinuxcomoOSXésimplescomoexecutar python3-mvenvmyvenv.Seráalgoparecido comisto: ~/djangogirls$python3-mvenvmyvenv myvenvéonomedasua virtualenv.Vocêpodeusarqualqueroutronome,maspermaneçaemcaixabaixa(minúsculas) enãouseespaçosentreosnomes.Tambéméumaboaideiamanteronomecurto-vocêiráreferenciarmuitoaele! 33 InstalaçãodoDjango NOTA:IniciaroambientevirtualnoUbuntu14.04assimretornaráoseguinteerro: Error:Command'['/home/eddie/Slask/tmp/venv/bin/python3','-Im','ensurepip','--upgrade','--default-pip']' returnednon-zeroexitstatus1 Paracontornaresseproblema,useocomando virtualenv. ~/djangogirls$sudoapt-getinstallpython-virtualenv ~/djangogirls$virtualenv--python=python3.4myvenv Trabalhandocomovirtualenv Ocomandoacimacriaráumdiretóriochamado myvenv(ousejaonomequevocêescolheu)quecontémonosso ambientevirtual(basicamenteumconjuntodediretóriosearquivos).Tudooquequeremosporenquantoéiniciá-lo executando: C:\Usuário\Nome\djangogirls>myvenv\Scripts\activate noWindows,ou: ~/djangogirls$sourcemyvenv/bin/activate noOSXenoLinux. Lembre-sedesubstituir myvenvcomseunomeescolhidodo virtualenv! NOTE:àsvezes source(fonte)podenãoestardisponível.Nessescasos,tentefazerisso: ~/djangogirls$.myvenv/bin/activate Vocêvaisaberquetemum virtualenvfuncionandoquandoveropromptnoseuconsoleseparecercom: (myvenv)C:\Usuário\Nome\djangogirls> ou: (myvenv)~/djangogirls$ Percebaqueoprefixo (myvenv)aparece! Aotrabalhardentrodeumambientevirtual, pythoniráautomaticamentesereferiraversãocorretaparaquepossautilizar pythonemvezde python3. Ok,nóstemostodasasdependênciasimportantesnolugar.FinalmentepodemosinstalaroDjango! InstalandooDjango Agoraquevocêtemasua virtualenviniciado,vocêpodeinstalarDjangousando pip.Noconsole,execute pipinstall django==1.8.5(Percebaqueusamosumduplosinaldeigual: ==). 34 InstalaçãodoDjango (myvenv)~$pipinstalldjango==1.8.5 Downloading/unpackingdjango==1.8.5 Installingcollectedpackages:django Successfullyinstalleddjango Cleaningup... noWindows SevocêreceberumerroaochamaropipnaplataformaWindowsporfavor,verifiqueseocaminhodoprojeto contémespaços,acentosoucaracteresespeciais(exemplo, C:\Users\UserName\djangogirls).Sesimporfavor movaparaoutrolugarsemespaços,acentosoucaracteresespeciais(sugestãoé: C:\djangogirls).Apósa mudança,porfavortentenovamenteocomandoacima. NoLinux SevocêreceberumerroaochamarpipnoUbuntu12.04porfavorexecute python-mpipinstall-U--forcereinstallpipparacorrigirainstalaçãodopipnovirtualenv. Éisso!Agoravocêestá(finalmente)prontoparacriarumaaplicaçãoDjango! 35 Criandoumprojeto SeuprimeiroprojetoDjango! PartedestecapítuloébaseadonostutoriaisdoGeekGirlsCarrots(https://github.com/ggcarrots/django-carrots). Partedestecapítuloébaseadonodjango-marcadortutoriallicenciadosobreCreativeCommonsAttributionShareAlike4.0InternationalLicense.Otutorialdodjango-marcadoréprotegidopordireitosautoraisporMarkus Zapke-Gründemannetal. Nósvamoscriarumblogsimples! Oprimeiropassoparacriá-loécomeçarumnovoprojetodeDjango.Basicamente,istosignificaquevamosexecutar algunsscriptsfornecidospeloDjangoqueirácriaroesqueletodeumprojetoDjangoparanós:umbandodediretóriose arquivosqueusaremosmaistarde. OsnomesdealgunsarquivosediretóriossãomuitoimportantesparaoDjango.Nãorenomeieosarquivosqueestamos prestesacriar.Moverparaumlugardiferentetambémnãoéumaboaidéia.Djangoprecisamanterumadeterminada estruturaparasercapazdeencontrarcoisasimportantes. Lembre-sequetudonovirtualenv.Sevocênãovêumprefixo (myvenv)emseuconsole,vocêprecisaativaro virtualenv.NósexplicamoscomofazerissonocapítuloinstalaçãodoDjangonapartetrabalhandocom virtualenv.Vocêpodefazerissodigitandooseguintecomando: myvenv\Scripts\activatenoWindowsou myvenv/bin/activatenoMacOS/Linux. NotaVerifiquequevocêincluiuoponto( .)nofinaldocomando,éimportanteporquedizoscriptparainstalaro Djangoemseudiretórioatual. Noconsole,vocêdeveexecutar(Lembre-sedequevocênãopodedigitar ~/djangogirls$(myvenv),OK?): (myvenv)~/djangogirls$django-adminstartprojectmysite. noWindows: (myvenv)C:\Users\Name\djangogirls>pythonmyvenv\Scripts\django-admin.pystartprojectmysite. Django-adminéumscriptqueirácriarosdiretóriosearquivosparavocê.Agora,vocêdeveterumdiretórioestruturaque separececomisso: djangogirls ├───manage.py └───mysite settings.py urls.py wsgi.py __init__.py manage.pyéumscriptqueajudacomagestãodosite.Comissoseremoscapazesdeiniciarumservidordewebno nossocomputadorseminstalarnada,entreoutrascoisas. Oarquivo settings.pycontémaconfiguraçãodoseusite. Lembraquandofalamossobreumcarteiroverificandoondeentregarumacarta?arquivo urls.pycontémumalistados padrõesusadospor urlresolver. Vamosignorarosoutrosarquivosporagora-nósnãovamosmudá-los.Aúnicacoisaalembrarénãoexcluí-lospor acidente! 36 Criandoumprojeto Configurando Vamosfazeralgumasalteraçõesno mysite/settings.py.Abraoarquivousandooeditordecódigoquevocêinstalou anteriormente. Seriabomterahoracorretanonossosite.Váparaa<wikipediatimezoneslistecopieseufusohorário.(porexemplo. America/Sao_Paulo) Emsettings.py,localizealinhaquecontém TIME_ZONEemodifiqueparaescolherseuprópriofusohorário: TIME_ZONE='America/Sao_Paulo' Modifique"America/Sao_Paulo",conformeocaso Nóstambémprecisaramosadicionarumcaminhoparaarquivosestáticos(nósvamosdescobrirtudosobrearquivos estáticoseCSSmaistardenotutorial).Desçaatéofinaldoarquivoelogoabaixodaentrada STATIC_URL,adicioneum novoumchamado STATIC_ROOT: STATIC_URL='/static/' STATIC_ROOT=os.path.join(BASE_DIR,'static') Instalaçãodeumbancodedados Háváriossoftwaresdebancodedadosdiferentesquepodearmazenardadosparaoseusite.Nósvamosusaropadrão, sqlite3. Istojáestáconfiguradonestapartedoseuarquivo mysite/settings.py: DATABASES={ 'default':{ 'ENGINE':'django.db.backends.sqlite3', 'NAME':os.path.join(BASE_DIR,'db.sqlite3'), } } Paracriarumbancodedadosparaonossoblog,vamosfazeroseguintenoconsole.Digite: pythonmanage.pymigrate (precisamosestarnodiretórioquecontémoarquivo manage.py djangogirls).Seissodercerto,vocêdeveveralgocomo isto: (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 Eestápronto!Horadeiniciaroservidorwebeversenossositeestáfuncionando! Vocêprecisaestarnodiretórioquecontémoarquivo manage.py(odiretório djangogirls).Noconsole,nóspodemos iniciaroservidorwebexecutandoo pythonmanage.pyrunserver: (myvenv)~/djangogirls$pythonmanage.pyrunserver Agoratudoquevocêprecisafazeréverificarseseusiteestásendoexecutado-abraseunavegador(Firefox,Chrome, Safari,InternetExplorerouoquevocêusa)edigiteoendereço: 37 Criandoumprojeto http://127.0.0.1:8000/ Oservidorwebvaiassumirseupromptdecomandoatévocêpará-lo:paradigitarmaiscomandosouabrirumanova janeladoterminal(enãoseesqueçadeativarseuvirtualenvneletambém),oupararoservidordeweb,alternandode voltaparaajanelanaqualestáexecutandoepressionandoCTRL+C-botõesdecontroleeCjuntos(noWindows,você podeterquepressionarCtrl+Break). Parabéns!Vocêcriouseuprimeirositeeoexecutouusandoumservidordeweb!Nãoéimpressionante? Prontoparaopróximopasso?Estánahoradecriaralgumconteúdo! 38 ModelosdoDjango ModelosdoDjango Agoraoquenósqueremoscriaréalgoquearmazenetodosospostsnonossoblog.Masparafazerissoprecisamos aprenderumpoucomaissobrecoisaschamadas objetos. Objetos Existeumconceitonaprogramaçãochamado ProgramaçãoOrientadaàObjetos(POO).Aideiaéqueaoinvésdeescrever tudocomoumachatasequênciadeinstruçõesdeprogramaçãopodemosmodelarascoisasedefinircomoelasinteragem umascomasoutras. Entãooqueéumobjeto?Éumacoleçãodepropriedadeseações.Istopodeparecerestranho,masvamoslhedarum exemplo. Sequeremosmodelarumgatonóscriaremosumobjeto Gatoquepossuialgumaspropriedades,porexemplo cor, idade, humor(bom,mau,sonolento;)), dono(queéumobjetodaclasse Pessoaou,casosejaumgatoderua,essa propriedadeévazia). Eentãoo Gatotemalgumasações: ronronar, arranharou comer(noqualvamosdaraogatoalguma ComidaDeGato, quepoderiaserumobjetoseparadocompropriedades,como sabor). Gato -------cor idade humor dono ronronar() arranhar() comer(comida_de_gato) ComidaDeGato -------sabor Então,basicamente,aideiaédescrevercoisasreaisnocódigocompropriedades(chamadasde propriedadesdoobjeto) eações(chamadasde métodos). Comonósiremosmodelaraspostagensdoblogentão?Queremosconstruirumblog,certo? Precisamosresponderàpergunta:oqueéumapostagemdeblog?Quepropriedadesdeveter? Bem,comcertezanossoblogprecisadealgumapostagemcomoseuconteúdoeumtítulo,certo?Tambémseriabom saberquemaescreveu-entãoprecisamosdeumautor.Finalmente,queremossaberquandoapostagemfoicriadae publicada. Post -------title text author created_date published_date Quetipodecoisapodeserfeitacomumapostagem?Serialegalteralgum métodoquepubliqueapostagem,nãoé mesmo? Entãoprecisamosdeummétodochamado publicar. 39 ModelosdoDjango Comojásabemosoquequeremosalcançar,podemoscomeçaramodelagememDjango! ModelodoDjango Sabendooqueumobjetoé,nóscriaremosummodelonoDjangoparaapostagemdoblog. UmmodelonoDjangoéumtipoespecialdeobjeto-eleésalvoemum bancodedados.Umbancodedadoséuma coleçãodedados.Obancodedadoséumlocalemquevocêvaisalvardadossobreusuários,suaspostagens,etc. UsaremosumbancodedadoschamadoSQLiteparaarmazenarasnossasinformações.Esteéoadaptadordebancode dadospadrãoDjango--elevaiserosuficienteparanósnestemomento. Vocêpodepensaremummodelodebancodedadoscomoumaplanilhacomcolunas(campos)elinhas(dados). Criandoumaaplicação Paramantertudoarrumadovamoscriarumaplicativoseparadodentrodonossoprojeto.Émuitobomtertudoorganizado desdeoinício.Paracriarumaplicativoprecisamosexecutaroseguintecomandonoconsole(apartirdodiretório djangogirlsondeestáoarquivo manage.py): (myvenv)~/djangogirls$pythonmanage.pystartappblog Vocêvainotarqueumnovodiretório blogécriadoequeeleagoracontémumnúmerodearquivos.Nossosdiretóriose arquivosnonossoprojetodevemseparecercomeste: 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 DepoisdecriarumaplicativotambémprecisamosdizeraoDjangoquedeveusá-lo.Fazemosissonoarquivo mysite/settings.py.Precisamosencontraro INSTALLED_APPSeadicionarumalinhacom 'blog',logoacimado ).É assimqueoprodutofinaldeveficarassim: INSTALLED_APPS=( 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'blog', ) CriandoomodeloPostdonossoblog Noarquivo blog/models.pydefinimostodososobjetoschamados Modelos-esteéumlugaremquevamosdefinirnossa postagemdoblog. 40 ModelosdoDjango Vamosabrir blog/models.py,removatudodeleeescrevaocódigocomoeste: 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 Certifique-sedeterusadodoiscaracteres( _)emcadaladodo str.Aquelescaracteressãousados freqüentementeemPythoneàsvezesoschamamosde"dunder"(abreviaçãode"double-underscore"ou"duplo sublinhado"). Éassustador,não?Masnãosepreocupe,vamosexplicaroqueestaslinhassignificam! Todasaslinhascomeçandocom fromou importsãolinhasqueadicionamalgunspedaçosdeoutrosarquivos.Então aoinvésdecopiarecolarasmesmascoisasemcadaarquivo,podemosincluiralgumaspartescom from...import.... classPost(models.Model):-estalinhadefineonossomodelo(éum objeto). classéumapalavra-chaveespecialqueindicaqueestamosdefinindoumobjeto. Postéonomedonossomodelo,podemoslhedarumnomediferente(maséprecisoevitarosespaçosembrancoe caracteresespeciais).Semprecomeceumnomedeclassecomumaletramaiúscula. models.ModelsignificaqueoPostéummodelodeDjango,entãooDjangosabeelequedevesersalvonobancode dados. Agorapodemosdefiniraspropriedadesquediscutimos: titulo, texto, data_criacao, data_publicacaoe autor.Para issoprecisamosdefinirumtipodecampo(éumtexto?Éumnúmero?Umadata?Umarelaçãocomoutroobjeto,por exemplo,umusuário?). models.CharField-assimécomovocêdefineumtextocomumnúmerolimitadodecaracteres. models.TextField-esteéparatextoslongossemumlimite.Seráidealparaumconteúdodepostdeblog,certo? models.DateTimeField-esteéumadataehora. models.ForeignKey-esteéumlinkparaoutromodelo. Nósnãovamosexplicarcadapedaçodecódigoaqui,poisissolevariamuitotempo.Vocêdeveolharadocumentaçãodo DJangosevocêquisersabermaissobrecamposdoModelecomodefinircoisasalémdestasdescritasacima (https://docs.djangoproject.com/en/1.8/ref/models/fields/#field-types). Quetal defpublish(self):?Éexatamenteonossométodode publishquefalávamosantes. def,significaquese tratadeumfunção/método. publishéonomedométodo.Vocêpodealterar,sequiser.Aregraéqueusamosletras minúsculasesublinhadosemvezdeespaçosembranco(ouseja,sevocêquerterummétodoquecalculaopreçomédio, vocêpoderiachamá-lo calculate_average_price). Métodosmuitasvezes returnalgo.Háumexemplodeque,nométodo __str__.Nessecenário,quandochamamos __str__()teremosumtexto(string),comumtítulodoPost. Sealgoaindanãoestáclarosobremodelos,sinta-selivreparapediroseutreinador!Sabemosqueémuitocomplicado, especialmentequandovocêaprenderoquesãoobjetosefunçõesaomesmotempo.Masesperoqueelesepareceum poucomenosmágicaparavocêagora! 41 ModelosdoDjango Criandotabelasparanossosmodelosnobancodedados Oúltimopassoéadicionarnossonovomodeloparanossobancodedados.PrimeirotemosquefazeroDjangosaberque nóstemosalgumasmudançasemnossomodelo(sócriamosisso),digite pythonmanage.pymakemigrationsblog.Será algoparecidocomisto: (myvenv)~/djangogirls$pythonmanage.pymakemigrationsblog Migrationsfor'blog': 0001_initial.py: -CreatemodelPost Djangopreparaumarquivodemigraçãoquetemosdeaplicaragoraparanossobancodedados,tipo pythonmanage.py migrateblog,asaídadeveser: (myvenv)~/djangogirls$pythonmanage.pymigrateblog Operationstoperform: Applyallmigrations:blog Runningmigrations: Applyingblog.0001_initial...OK Viva!NossomodelodePostestáagoraemnossobancodedados,seriaumprazervê-lo,certo?Saltarparaopróximo capítuloparaveroaspectodoseuPost! 42 Administração Administração Paraadicionar,editareremoverpostagensquenóscriamosusaremosoDjangoadmin. Vamosabriroarquivo blog/admin.pyesubstituirseuconteúdopor: fromdjango.contribimportadmin from.modelsimportPost admin.site.register(Post) Comovocêpodever,nósimportamos(incluímos)omodeloPostdefinidonocapítuloanterior.Paratornarnossomodelo visívelnapáginadeadministração,nósprecisamosregistrá-locom: admin.site.register(Post). OK,horadeolharparaonossomodelodePost.Lembre-sedeexecutar pythonmanage.pyrunservernoconsolepara executaroservidorweb.Váparaonavegadoredigiteoendereçohttp://127.0.0.1:8000/admin/Vocêveráumapáginade loginassim: Parafazerloginvocêprecisacriarumsuperuser-umusuárioquepossuicontrolesobretudodosite.Volteparaoterminal edigite pythonmanage.pycreatesuperuser,pressioneenteredigiteseunomedeusuário(caixabaixa,semespaço), endereçodee-mailepasswordquandoelesforemrequisitados.Nãosepreocupequevocênãopodeverasenhaque vocêestádigitando-éassimquedeveser.Sódigitá-laepressione'Enter'paracontinuar.Asaídadeveparecercomessa (ondeUsernameeEmaildevemserosseus): (myvenv)~/djangogirls$pythonmanage.pycreatesuperuser Username:admin Emailaddress:[email protected] Password: Password(again): Superusercreatedsuccessfully. Volteparaaonavegadorefaçalogincomascredenciaisdesuperuserquevocêescolheu,vocêdevevisualizaropainel decontroledoDjangoadmin. 43 Administração Váparaaspostagenseexperimenteumpoucocomelas.Adicionecincoouseispostagens.Nãosepreocupecomo conteúdo-vocêpodecopiarecolaralgumtextodestetutorialparaoconteúdoparaeconomizartempo:). Certifique-sequepelomenosduasoutrêspostagens(masnãotodas)têmadatadepublicaçãodefinida.Issoseráútil depois. SevocêquisersabermaissobreoDjangoadmin,vocêdeveconferiradocumentaçãodoDjango: https://docs.djangoproject.com/en/1.8/ref/contrib/admin/ Esteéprovavelmenteumbommomentoparatomarumcafé(ouchocolate)oualgoparacomerparareporasenergias. VocêcriouseuprimeiromodelodeDjango-vocêmereceumpoucodedescanso! 44 Implantação! Implantação! NotaOcapítuloseguintepodeseràsvezesumpoucodifícildepassar.Persistaetermine-o;Implantaçãoéuma parteimportantedoprocessodedesenvolvimentodewebsite.Estecapítuloestálocalizadonomeiodotutorialpara queseututorpossalheajudarcomoprocessoligeiramentecomplexodecolocarseusiteonline.Istosignificaque vocêaindapodeterminarotutorialporcontaprópriasevocêcontinuaremoutromomento. Atéagoranossositesóestavadisponívelnoseucomputador,agoravocêvaiaprendercomopublicarelenainternet!A implantaçãoéoprocessodepublicaçãodoseuaplicativonaInternetdetalformaqueaspessoaspossam,finalmente,ver seuaplicativo:). Comovocêaprendeu,umwebsiteprecisaestarlocalizadonumservidor.Existemmuitosprovedores,masiremosutilizaro quetemumprocessodedeployrelativamentesimples:PythonAnywhere.PythonAnywhereégratuitoparaaplicações pequenasquenãopossuemmuitosvisitantes,entãoserásuficienteparavocêporenquanto. OoutroserviçoexternoqueusaremoséGitHub,queéumserviçodehospedagemdecódigo.Existemoutros,masquase todososprogramadorespossuemumacontanoGitHubatualmenteeagoravocêtambém! UsaremosoGitHubcomoumtrampolimparatransportarnossocódigoparaoPythinAnywhere. Git Gité"sistemadecontroledeversão"usadopormuitosprogramadores-umsoftwarequecontrolamudançasnosarquivos aolongodotempoparaquevocêpossarecuperarversõesespecíficasdepois.Umpoucocomo"controlarmudanças"no MicrosoftWord,masmuitomaispoderoso. InstalandooGit Windows VocêpodebaixarGitemgit-scm.com.Vocêpodeapertar"nextnextnext"emtodosospassosexcetoum;noquintopasso chamado"AdjustingyourPATHenvironment",escolha"RunGitandassociatedUnixtoolsfromtheWindowscommandline"(aopçãodebaixo).Alémdisso,opadrãoestáótimo.CheckoutestiloWindows,commitUnix-stylelinhasde confirmaçãoestábom. MacOS BaixarGitgit-scm.comesigaasinstruções. Linux Seelejánãoestiverinstalado,Gitdeveestardisponívelatravésdeseugerenciadordepacotes,entãotente: sudoapt-getinstallgit #or sudoyuminstallgit ComeçandonossorepositórionoGit Gitcontrolaasalteraçõesparaumdeterminadoconjuntodearquivosnoquechamamosderepositóriodecódigo(ou "repo").Vamoscomeçarumparanossoprojeto.Abraoconsoleeexecuteessescomandos,nodiretório djangogirls: 45 Implantação! Nota:Verifiqueoseudiretóriodetrabalhoatualcomum pwd(OSX/Linux)ouocomando cd(Windows)antesde inicializarorepositório.Vocêdeveestarnapasta djangogirls. $gitinit InitializedemptyGitrepositoryin~/djangogirls/.git/ $gitconfiguser.name"YourName" [email protected] Inicializarorepositóriogitéalgoquesóprecisamosfazerumavezporprojeto(evocênãoteráquere-introduzironome deusuárioee-mailnuncamais) Gitirácontrolarasalteraçõesparatodososarquivosepastasnestediretório,masexistemalgunsarquivosquequeremos ignorar.Fazemosissoatravésdacriaçãodeumarquivochamado .gitignorenodiretóriobase.Abraseueditorecrieum novoarquivocomoseguinteconteúdo: *.pyc __pycache__ myvenv db.sqlite3 .DS_Store Esalvecomo .gitignorenapastadenívelsuperior"djangogirls". Nota:Opontonoiníciodonomedoarquivoéimportante!Sevocêestátendoalgumadificuldadeemcriá-la(Macs nãogostamdecriararquivosquecomeçamcomumpontoatravésdoFinder,porexemplo),useorecurso"SaveAs" noseueditorquesemprefunciona. Éumaboaidéiaparausarumcomandode gitstatusantesde gitaddousemprequevocênãotivercertezadeque seráfeito,paraevitarsurpresas(porexemplo,serãoadicionadosarquivoserradosoucommitados).Ocomando git statusretornainformaçõessobretodososarquivoscontrolado/modificado/encenado,statusderamoemuitomais.O outputdevesersemelhantea: $gitstatus Onbranchmaster Initialcommit Untrackedfiles: (use"gitadd<file>..."toincludeinwhatwillbecommitted) .gitignore blog/ manage.py mysite/ nothingaddedtocommitbutuntrackedfilespresent(use"gitadd"totrack) Efinalmentenóssalvamosnossasalterações,Váparaoseuconsoleeexecuteestescomandos: $gitadd--all. $gitcommit-m"MyDjangoGirlsapp,firstcommit" [...] 13fileschanged,200insertions(+) createmode100644.gitignore [...] createmode100644mysite/wsgi.py EmpurrandoonossocódigoparaGitHub 46 Implantação! VáparaGitHub.comecadastreumanovaegratuitacontadeusuário.Emseguida,crieumnovorepositório,edêonome "my-first-blog".Deixeo"initialisewithaREADME"desmarcado,deixeaopção.gitignoreembranco(jáfizemosisso manualmente)ealicençacomoNone. NotaOnome my-first-blogéimportante--vocêpoderiaescolheroutracoisa,masvamosusá-lomuitasvezesnas instruçõesabaixoevocêteriaquesubstituí-locadavez.Éprovavelmentemaisfácilficarcomonome my-firstblog. Natelaseguinte,vocêserámostradaacloneURLdoseurepo.Escolhaaversão"HTTPS",copie,evamoscolá-lono terminalembreve: AgoraprecisamosligarorepositórioGitnoseucomputadorcomonoGitHub. $gitremoteaddoriginhttps://github.com/<your-github-username>/my-first-blog.git $gitpush-uoriginmaster 47 Implantação! DigiteseuGitHubusernameesenha,evocêdeveveralgocomoisto: Usernamefor'https://github.com':hjwp Passwordfor'https://[email protected]': Countingobjects:6,done. Writingobjects:100%(6/6),200bytes|0bytes/s,done. Total3(delta0),reused0(delta0) Tohttps://github.com/hjwp/my-first-blog.git *[newbranch]master->master Branchmastersetuptotrackremotebranchmasterfromorigin. SeucódigoagoraestánoGitHub.Váeconfira!Vocêsaberáqueestáemboacompanhia-Django,oDjangoGirlsTutorial emuitosoutrosgrandesprojetosdesoftwaredefonteabertatambémhospedamseucódigonoGitHub:) CriaçãodenossoblogemPythonAnywhere Emseguida,éhoradeseinscreverparaumacontagratuitade"Beginner"naPythonAnywhere. www.pythonanywhere.com Nota:aoescolherseunomedeutilizadoraqui,tenhaemmentequeaURLdoseublogteráoformulário yourusername.pythonanywhere.com,entãoescolhaseunicknameouonomedoqueéoblog. PullingourcodedownonPythonAnywhere QuandovocêseinscreveparaPythonAnywhere,vocêélevadoaoseupaineldecontroleoupágina"Consoles".Escolhaa opçãoiniciaroconsole"Bash"--queéaversãoPythonAnywheredeumconsole,comoaquelanoseuPC Nota:PythonAnywhereébaseadoemLinux,assimsevocêestivernoWindowsoconsolevaiparecerumpouco diferentedoqueestánoseucomputador. VamospuxarnossocódigodeGitHubemPythonAnywhereatravésdacriaçãodeum"clone"dorepo.Digiteoseguinte paraoconsolenaPythonAnywhere: $gitclonehttps://github.com/<your-github-username>/my-first-blog.git IstopuxaráumacópiadoseucódigoparaPythonAnywhere.Confiradigitando: $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 CriandoumvirtualenvnaPythonAnywhere Assimcomofezemseuprópriocomputador,vocêpodecriarumvirtualenvnaPythonAnywhere.NoconsoleBash,digite: 48 Implantação! 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.8.5whitenoise-2.0 Coletadearquivosestáticos. Vocêestavaimaginandooqueé"whitenoise"?Éumaferramentaparaserviroschamados"arquivosestáticos".Arquivos estáticosfuncionamdeformadiferentenosservidoresemcomparaçãocomnossoprópriocomputador,eprecisamosde umaferramentacomoo"whitenoise"paraatendê-los. Vamosdescobrirumpoucomaissobrearquivosestáticosmaistardenotutorial,quandovamoseditaroCSSparaonosso site. Porenquantosóprecisamosexecutarumcomandoextrachamado"collectstatic"noservidor.IssodizproDjangoreunir todososarquivosestáticosqueeleprecisanoservidor.Emsuamaioria,estessãoosarquivosestáticosquefazemosite doadminbonitonomomento. 20:20~$pythonmanage.pycollectstatic Youhaverequestedtocollectstaticfilesatthedestination locationasspecifiedinyoursettings: /home/edith/my-first-blog/static Thiswilloverwriteexistingfiles! Areyousureyouwanttodothis? Type'yes'tocontinue,or'no'tocancel:yes Digite"yes"(Sim)evaiembora!Vocênãoadorafazercomputadoresimprimirpáginasepáginasdetexto?Semprefaço pequenosruídosparaacompanhá-lo.Brp,brpbrp... Copying'/home/edith/.virtualenvs/mvenv/lib/python3.4/site-packages/django/contrib/admin/static/admin/js/actions.min. js' Copying'/home/edith/.virtualenvs/mvenv/lib/python3.4/site-packages/django/contrib/admin/static/admin/js/inlines.min. js' [...] Copying'/home/edith/.virtualenvs/mvenv/lib/python3.4/site-packages/django/contrib/admin/static/admin/css/changelists .css' Copying'/home/edith/.virtualenvs/mvenv/lib/python3.4/site-packages/django/contrib/admin/static/admin/css/base.css' 62staticfilescopiedto'/home/edith/my-first-blog/static'. CriandoobancodedadosemPythonAnywhere Aquiestáoutracoisaqueédiferenteentreseucomputadoreoservidor--eleusaumbancodedadosdiferente.Entãoas contasdeusuárioemensagenspodemserdiferentesnoservidorenoseucomputador. Entãonósvamosinicializarobancodedadosnoservidortalcomofizemosnoseuprópriocomputador,com migratee createsuperuser: 49 Implantação! (mvenv)20:20~$pythonmanage.pymigrate Operationstoperform: [...] Applyingsessions.0001_initial...OK (mvenv)20:20~$pythonmanage.pycreatesuperuser Publicaçãodonossoblogcomoumaplicativoweb AgoranossocódigoestánaPythonAnywhere,nossavirtualenvestápronta,osarquivosestáticosestãorecolhidoseo bancodedadosestáinicializado,estamosprontosparapublicá-locomoumaplicativodaweb. CliqueemvoltarparaoPythonAnywheredashboardclicandonoseulogotipoecliquenaguiaWebeváemAddanew webapp. Nacaixadediálogo,apósaconfirmaçãodeseunomededomínio,escolhamanualconfiguration(NBnãoaopção "Django").Emseguida,escolhaPython3.4ecliqueemNextparaconcluiroassistente. Notacertifique-sevocêescolheuaopção"Manualconfiguration",nãoa"Django".Nóssomosdemaisparaopadrão deconfiguraçãoDjangodaPythonAnywhere;-) Definindoovirtualenv VocêserálevadoparaateladeconfiguraçãodePythonAnywhereparaseuwebappqueéondevocêprecisarádeir quandoquiserfazeralteraçõesparaoaplicativonoservidor. Naseção"Virtualenv",cliquenotextovermelhoquediz"Enterthepathtoavirtualenv"edigite: /home/<your-username>/myfirst-blog/myvenv/ Nota:substituaseupróprionomedeusuárioconformeapropriado.Sevocêcometerumerro,PythonAnywhereirá mostrarumpequenoaviso. ConfigurandooarquivoWSGI 50 Implantação! DjangofuncionausandooWSGIprotocol,umpadrãoparaservirsitesusandoPython,queoferecesuportea PythonAnywhere.AmaneiraqueconfiguramosPythonAnywhereparareconhecernossoblogDjangoéeditandoum arquivodeconfiguraçãodoWSGI. Cliquenolink"WSGIconfigurationfile"(naseção"Code"pertodotopodapágina--elevaisernomeadoalgocomo /var/www/<your-username>_pythonanywhere_com_wsgi.py),evocêserálevadoparaumeditor. Excluatodooconteúdoatualesubstituacomalgoparecidocomisto: importos importsys path='/home/<your-username>/my-first-blog'#useyourownusernamehere 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()) Notanãoseesqueçadesubstituiremseupróprionomedeusuárioondediz <your-username> OqueessearquivofazédizerPythonAnywhereondemoraanossaaplicaçãowebequalonomedoarquivode configuraçõesDjango.Eletambémdefineaferramentadearquivosestáticos"whitenoise". AperteSaveeentãovolteparaaguiaWeb. Játerminamos!AperteobotãograndeverdedeReloadevocêserácapazdeirverosseuaplicativo.Vocêencontraráum linkparaelenotopodapágina. Dicasdedebugging Sevocêvirumerroquandovocêtentavisitaroseusite,oprimeirolugarparaprocuraralgumainformaçãodedebuggingé noseuerrorlog--vocêencontraráumlinkparaissonaguiawebPythonAnywhere.Versehámensagensdeerrolá.As maisrecentesestãonaparteinferior.Problemascomunsincluem esquecerumdospassosquefizemosnoconsole:criandoovirtualenv,ativá-lo,instalandooDjango,collectstatic, inicializandoobancodedados cometerumerronocaminhodovirtualenvnaguiaweb--haverágeralmenteumapequenamensagemdeerro vermelholá,seháumproblema cometerumerronoarquivodeconfiguraçãoWSGI..--vocêusouocaminhoparaapastadomy-first-blogcertinho? Otreinadorestáaquiparaajudar! Vocêestálive! Apáginapadrãoparaseusitedevedizer"Bem-vindoaoDjango",comoacontecenoseuPClocal.Tenteadicionar /admin/paraofinaldaURL,evocêserálevadoaositeadmin.Fazerlogincomonomedeusuárioesenha,evocêverá quevocêpodeadicionarnovasmensagensnoservidor. Dêemvocêmesmaumenormetapinhanascostas-implantaçõesdeservidorsãoumadaspartesmaisdifíceisdo desenvolvimentoweb,emuitasvezeslevaaspessoasváriosdiasantesdefazerfuncionar.Masvocêtemseusite publicado,nainternet,assim! 51 Implantação! 52 Urls Urls EstamosprestesaconstruirnossaprimeiraWebpage-umapáginainicialparaoseublog!Masprimeiro,vamosaprender umpoucomaissobreDjangourls. OqueéumaURL? UmaURLésimplesmenteumendereçodaweb,vocêpodeverumaURLtodavezquevocêvisitaqualquersite-évisível nabarradeendereçosdoseunavegador(Sim! 127.0.0.1:8000éumaURL!Ehttp://djangogirls.orgtambéméumaURL): CadapáginanaInternetprecisadesuaprópriaURL.Destaformaseuaplicativosabeoquedevemostraraumusuário queabreumaURL.EmDjango,nósusamosalgochamado URLconf(configuraçãodeURL),queéumconjuntode padrõesqueDjangovaitentarcoincidircomaURLrecebidaparaencontraravisãocorreta. ComofuncionamasURLsemDjango? Vamosabriroarquivo mysite/urls.pyevercomqueeleseparece: 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)), ] Comovocêpodever,oDjangojácolocoualgumacoisalápranós. Aslinhasquecomeçamcom #sãocomentários-issosignificaqueessaslinhasnãoserãoexecutadaspeloPython. Muitoútil,não? AURLdoadmin,quevocêvisitounocapítuloanteriorjáestáaqui: url(r'^admin/',include(admin.site.urls)), IssosignificaqueparacadaURLquecomeçacom admin/oDjangoiráencontrarumcorrespondentemododeexibição. NestecasonósestamosincluindoummontedeadminURLsparaqueissonãofiquetudoembaladonestepequeno arquivo..--émaislegívelemaislimpo. Regex 53 Urls VocêquersabercomooDjangocoincidecomURLsparaviews?Bem,estaparteécomplicada.oDjangousao regex-expressõesregulares.Regextemmuito(muito!)denormasqueformamumpadrãodepesquisa.Comoregexessãoum tópicoavançado,nósveremosemdetalhescomoelasfuncionam. Sevocêaindaquiserentendercomocriamosospadrões,aquiestáumexemplodoprocesso-sóprecisamosum subconjuntolimitadoderegrasparaexpressaropadrãoqueprocuramos,ouseja: ^paraoiníciodotexto $paraofinaldotexto \dparaumdígito +paraindicarqueoitemanteriordeveserrepetidopelomenosumavez ()paracapturarpartedopadrão Qualqueroutracoisanadefiniçãodeurlserálevadaliteralmente. Agoraimaginequevocêtemumsitecomoendereçoassim: http://www.mysite.com/post/12345/,onde 12345éonúmero doseupost. Escreverviewsseparadasparatodososnúmerosdepostseriamuitochato.Comexpressõesregularespodemoscriarum padrãoqueirácoincidircomaurleextraironúmeroparanós: ^post/(\d+)/$.Vamosaospoucosveroqueestamos fazendoaqui: ^post/estádizendoaoDjangoparapegartudoquetenha post/noiníciodaurl(logoapóso ^) (\d+)significaquehaveráumnúmero(umoumaisdígitos)equequeremosonúmerocapturadoeextraído /dizparaoDjangoquedeveseguiroutro / $indicaofinaldaURLsignificandoqueapenassequênciasterminandocomo /irãocorresponderaessepadrão SuaprimeiraurlDjango! ÉhoradecriarnossaprimeiraURL!Queremoshttp://127.0.0.1:8000/paraserumapáginainicialdonossoblogeexibir umalistadeposts. Tambémqueremosmanteroarquivode mysite/urls.pylimpo,aínósimportaremosurlsdanossaaplicação blogparao arquivoprincipal mysite/urls.py. Váemfrente,apagueaslinhascomentadas(aslinhasquecomeçamcom #)eadicioneumalinhaquevaiimportar blog.urlsparaaurlprincipal( ''). Oseuarquivo mysite/urls.pydeveagoraseparecercomisto: fromdjango.conf.urlsimportinclude,url fromdjango.contribimportadmin urlpatterns=[ url(r'^admin/',include(admin.site.urls)), url(r'',include('blog.urls')), ] ODjangoagorairáredirecionartudooqueentraem'http://127.0.0.1:8000/'para blog.urlseprocurarpornovas instruçõeslá. AoescreverasexpressõesregularesemPythonésemprefeitocom rnafrentedasequência-issoésóumadicaútil paraPythonqueaseqüênciapodecontercaracteresespeciaisquenãosãodestinadasparaPythonemsi,masemvez dissosãopartedaexpressãoregular. blog.urls Crieumnovoarquivovazio blog/urls.py.Tudobem!Adicioneestasduasprimeiraslinhas: 54 Urls fromdjango.conf.urlsimportinclude,url from.importviews AquinósestamosapenasimportandométodosdoDjangoetodososnossos viewsdoaplicativo blog(aindanãotemos nenhuma,masteremosemumminuto!) DepoisdissonóspodemosadicionarnossoprimeiraURLpadrão: urlpatterns=[ url(r'^$',views.post_list), ] Comovocêpodever,estamosagoraatribuindouma viewchamada post_listpara ^$URL.Essaexpressãoregular corresponderáa ^(umcomeço)seguidopor $(fim)-entãosomenteumaseqüênciavaziairácorresponder.Eissoé correto,porqueemresolvedoresdeDjangourl,'http://127.0.0.1:8000/'nãoéumapartedaURL.Estepadrãoirámostrar oDjangoque views.post_listéolugarcertoparair,sealguémentraemseusitenoendereço'http://127.0.0.1:8000/'. Tudocerto?Abrahttp://127.0.0.1:8000noseunavegadorpraveroresultado. Nãotemmais"ItWorks!'maisein?Nãosepreocupe,ésóumapáginadeerro,nadaatemer!Elassãonaverdademuito úteis: Vocêpodelerquenãohánoattribute'post_list'.Opost_listtelembraalgumacoisa?Istoécomochamamosonosso view!Issosignificaqueestátudonolugar,sónãocriamosnossaviewainda.Nãosepreocupe,nóschegaremoslá. SevocêquersabermaissobreDjangoURLconfs,vejaadocumentaçãooficial: https://docs.djangoproject.com/en/1.8/topics/http/urls/ 55 Views-horadecriar! Views-horadecriar! Éhoraderesolverobugquecriamosnocapítuloanterior:) Umaviewécolocadaondenóscolocamosa"lógica"danossaaplicação.Eleirásolicitarinformaçõesapartirdo model quevocêcriouantesepassá-loparaum templatequevocêvaicriarnopróximocapítulo.Views,nofundo,nãopassam demétodosescritosemPythonquesãoumpoucomaiscomplicadosdoqueaquiloquefizemosnocapítuloIntrodução aoPython. Asviewssãopostasnoarquivo views.py.Nósvamosadicionarnossasviewsnoarquivo blog/views.py. blog/views.py OK,vamosabriroarquivoeveroquetemnele: fromdjango.shortcutsimportrender #Createyourviewshere. Nãotemmuitacoisa.Aviewmaisbásicaseparececomisto. defpost_list(request): returnrender(request,'blog/post_list.html',{}) Comovocêpodever,nóscriamosummétodo( def)chamado post_listqueaceitao pedidoe retornarummétodo renderseráprocessado(paramontar)nossomodelo blog/post_list.html. Salveoarquivo,váparahttp://127.0.0.1:8000/evejaoquetemosagora. Outroerro!Leiaoqueestáacontecendoagora: Estaéfácil:TemplateDoesNotExist.Vamoscorrigirestebugecriarummodelonopróximocapítulo! AprendamaissobreasviewsdoDjangolendoadocumentaçãooficial: https://docs.djangoproject.com/en/1.8/topics/http/views/ 56 IntroduçãoaHTML IntroduçãoaHTML Vocêpodeseperguntar:eoqueéumtemplate? Umtemplateéumarquivoquenóspodemosreutilizarparaapresentardiferentesinformaçõesdeumaformaconsistente. Porexemplo,vocêpoderiausarumtemplateparateajudaraescreverumacarta,pois,emboracadacartapossuauma mensagemeumdestinodiferente,todasterãosempreomesmoformato. OformatodotemplatedoDjangoédescritoemumalinguagemchamadaHTML(esseéomesmHTMLquemencionamos noprimeirocapítuloComoaInternetfunciona). OqueéHTML? HTMLéumsimplescódigoqueéinterpretadopeloseunavegadorweb-comooChrome,oFirefoxouoSafari-para exibirumapáginadawebparaousuário. HTMLsignifica"HyperTextMarkupLanguage".HiperTextsignificaqueéumtipodetextoquesuportahiperlinksentre páginas.Marcaçãonadamaiséquemarcarumdocumentocomcódigosquedizemparaalguém(nessecaso,o navegadorweb)comoapáginadeveráserinterpretada.CódigoemHTMLéfeitocomtags,cadaumacomeçandocom <eterminandocom >.Essastagsmarcamoselementos. Seuprimeirotemplate! Criarumtemplatesignificacriarumarquivodetemplate.Tudoéumarquivo,certo?Provavelmentevocêjádeveternotado isso. Ostemplatessãosalvosnodiretório blog/templates.Logo,crieumdiretóriochamado templatesdentrododiretóriodo seublog.Emseguida,crieoutrodiretóriochamado blogdentrodadiretóriotemplates: blog └───templates └───blog (Vocêdeveestarseperguntandoporquenósprecisamosdedoisdiretórioschamados blog-comovocêdescobrirámais parafrente,essaéumasimpleseútilconvençãoquefacilitaavidaquandoascoisascomeçaremaficarmais complicadas.) Eagoranóscriamosoarquivo post_list.html(deixe-oembrancoporagora)dentrododiretório blog/templates/blog. Vejacomoonossositeestáseparecendoagora:http://127.0.0.1:8000/ Seocorrerumerrode TemplateDoesNotExiststentereiniciaroseuservidor.Entrenalinhadecomando,pareo servidorpressionandoCtrl+C(ControlseguidodateclaC,juntas)ereinicie-orodando pythonmanage.pyrunserver. 57 IntroduçãoaHTML Acabaram-seoserros!Parabéns:)Entretanto,nossositenãomostranadaanãoserumapáginaembranco.Issoporque onossotemplateestávazio.Entãoprecisamosconsertarisso. Adicioneaseguintelinhadentrodotemplate: <html> <p>Hithere!</p> <p>Itworks!</p> </html> Comonossositesepareceagora?Cliqueparadescobrir:http://127.0.0.1:8000/ Funcionou!Bomtrabalho:) Atagmaisbásica, <html>,estarásemprenocomeçodequalquerpáginadaweb,assimcomo, </html>sempre estaránofim.Comovocêpodever,todooconteúdodeumwebsiteseencontraentreatagdeinício <html>eentre atagdefim </html> <p>éatagquedenominaparágrafos; </p>determinaofimdecadaparágrafo Head&body CadapáginaHTMLtambémédivididaemdoiselementos:head(cabeça)ebody(corpo). headéumelementoquecontéminformaçõessobreodocumentoquenãosãomostradasnatela. bodyéumelementoquecontémtudooqueéexibidocomopartedeumapáginadeumsite. Nósusamosatag <head>paradizeraonavegadorsobreasconfiguraçõesdapágina.Porsuavez,atag <body>dizao navegadoroquehádeverdadenapágina. Porexemplo,vocêpodeporoelementotítulodeumapáginawebdentrodatag <head>.Veja: 58 IntroduçãoaHTML <html> <head> <title>Ola'sblog</title> </head> <body> <p>Hithere!</p> <p>Itworks!</p> </body> </html> Salveoarquivoeatualizesuapágina. Viucomoonavegadorentendeuque"Ola'sblog"éotítulodapágina?Eleinterpretou <title>Ola'sblog</title>e colocouotextonabarradetítulodoseunavegador(etambémseráusadoparaosfavoritoseoutrascoisasmais). Provavelmentevocêjádeveternotadoquecadatagdeaberturacasacomumatagdefechamento,comuma /,eque oselementosestãoaninhados(ex.:vocênãopodefecharumtagemparticularantesquetodasasoutrastagsque estiveremdentrodelajáestejamfechadas). Écomocolocarcoisasdentrodecaixas.Vocêtemumagrandecaixa, <html></html>;dentrodelahá <body></body>, sendoqueestaaindacontémcaixasmenors: <p></p>. Vocêprecisaseguiressasregrasdefechamentodetags,edeaninhamentodeelementos-sevocênãofizerisso,o navegadorpoderánãoestaraptoparainterpretarseucódigodemaneiracorretaesuapáginaseráexibidademaneira incorreta. Customizeseutemplate Agoravocêpodesedivertirumpoucotentandocustomizaroseutemplate!Aquiestãoalgumastagsúteisparaisso: <h1>Umtítulo</h1>-paraotítulomaisimportante <h2>Umsub-título</h2>paraumtítuloumnívelabaixo <h3>Umsub-sub-título</h3>...eporaívai,até <h6> <em>texto</em>enfatizaseutexto <strong>text</strong>enfatizafortementeseutexto <br/>pulaparaapróximalinha(vocênãopodecolocarnadadentrodebr) <ahref="https://djangogirls.org">link</a>criaumlink <ul><li>primeiroitem</li><li>segundoitem</li></ul>criaumalista,exatamentecomoessa! <div></div>defineumaseçãodapágina Aquiestáumexemplodeumtemplatecompleto: 59 IntroduçãoaHTML <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.Donecidelitnonmipo rtagravidaategetmetus.Fuscedapibus,tellusaccursuscommodo,tortormauriscondimentumnibh,utfermentummass ajustositametrisus.</p> </div> <div> <p>published:14.06.2014,12:14</p> <h2><ahref="">Mysecondpost</a></h2> <p>Aeneaneuleoquam.Pellentesqueornaresemlaciniaquamvenenatisvestibulum.Donecidelitnonmipo rtagravidaategetmetus.Fuscedapibus,tellusaccursuscommodo,tortormauriscondimentumnibh,utf.</p> </div> </body> </html> Nóscriamostrêsseções divaqui. Oprimeiroelemento divpossuiotítulodonossoblog-éumtítuloeumlink Osoutrosdoiselementos divpossuemnossaspostagenscomadatadepublicação, h2comotítulodapostagem queéclicáveledois ps(parágrafos)detexto,umparaadataeoutroparaotextodapostagem. Issonosdáoseguinteefeito: Yaaay!Mas,atéagora,nossotemplatemostraexatamantesempreamesmainformação-sendoque,anteriormente, nósfalávamossobretemplatescomoumamaneiraparaexibirinformaçõesdiferentesemummesmoformato. 60 IntroduçãoaHTML OquenósrealmentequeremosfazeréexibirpostagensreaisqueforamadicionadasnoDjangoadmin-eissoéoque faremosemseguida. Maisumacoisa:deploy! SeriabomvertudoistonaInternet,certo?VamosfazeroutrodeployPythonAnywhere: Commit,eponhaseucódigonoGitHub Primeirodetudo,vejamosquaisarquivosforamalteradosdesdeaúltimaimplantação: $gitstatus Verifiquesevocêestánodiretório djangogirlsevamosdizerao gitparaincluirtodasasmudançasdentrodeste diretório: $gitadd--all. Nota -A(abreviaçãode"all",tudoeminglês)significaqueo gittambémreconhecerásevocêdeletoualgum arquivo(porpadrão,ogitapenasreconhecearquivoscriados/modificados).Lembre-setambém(docapítulo3)que .significaodiretórioatual. Antesdenósfazermosouploaddetodososaqruivos,chequemosoqueo gitenviará(todososarquivosqueo gitfor enviardeveráapareceemverde): $gitstatus Estamosquaselá!Agoraéhoradedizeraeleparasalvaressamodificaçãoemseuhistórico.Nósdaremosaeleuma "mensagemdecommit"ondenósdescrevemosasmodificaçõesquefizemos.Vocêpodeescreveroquevocêquiser agora,masserámaisútilsevocêescreveralgumacoisamaisdescritiva,algoparavocêpoderselembrardascoisasque vocêfezfuturamente. $gitcommit-m"ChangedtheHTMLforthesite." Certifique-sequevocêusouaspasduplasparadelimitaramensagemdocommit. Quandofizermosisso,nósfazemosupload(envio)dasnossasmudançasparaoPythonAnywhere: gitpush BotedeunovocódigonoPythonAnywhereerecarregueoseuaplicativodaweb AbraapáginadeconsolesdePythonAnywhereeváparaoseuconsoleBash(oucomeçarumnovo).Emseguida, execute: $cd~/my-first-blog $sourcemyvenv/bin/activate (myvenv)$gitpull [...] (myvenv)$pythonmanage.pycollectstatic [...] 61 IntroduçãoaHTML Evejaseucódigosendobaixado.Sevocêdesejaverificarsejáchegou,podeirparaaFilestabeverseucódigono PythonAnywhere. Finalmente,puleparaaWebtabeaperteReloademseuaplicativoweb. Suaatualizaçãodeveestarlive!Váemfrenteeatualizeseusitenonavegador.Asalteraçõesdevemservisíveis:) 62 DjangoORM(Querysets) QuerySetseORMdoDjango NestecapítulovocêvaiaprendercomoDjangoseconectaaobancodedadosecomoelearmazenadados.Vamosnessa! OqueéumQuerySet? UmQuerySet(conjuntodepesquisa),nofundo,éumalistadeobjetosdeumdadomodelo.UmQuerySetpermiteque vocêleiaosdadosdobanco,filtreeordeneomesmo. Émaisfácilaprenderporexemplos.Vamostentar? OShelldoDjango Abraoterminaledigite: (myvenv)~/djangogirls$pythonmanage.pyshell Oresultadodeveser: (InteractiveConsole) >>> AgoravocêestánoconsoleinterativodoDjango.EleécomoopromptdoPythonsóquecomumasmágicasamais:). VocêpodeusartodososcomandosdoPythonaquitambém,éclaro. Todososobjetos Antes,vamostentarmostrartodasasnossaspostagens.Podemosfazerissocomoseguintecomando: >>>Post.objects.all() Traceback(mostrecentcalllast): File"<console>",line1,in<module> NameError:name'Post'isnotdefined Oops!Umerroapareceu.ElenosdizquenãoexistealgochamadoPost.Éverdade--nósesquecemosdeimportá-lo primeiro! >>>fromblog.modelsimportPost Issoésimples:importamosomodelo Postdedentrodo blog.models.Vamostentarmostrartodasaspostagens novamente: >>>Post.objects.all() [<Post:myposttitle>,<Post:anotherposttitle>] Éumalistadospostsquecriamosanteriormente!CriamosessespostsusandoainterfacedeadministraçãodoDjango.No entanto,agoraqueremoscriarnovasmensagensutilizandoopython,entãocomoéquefazemosisso? Criandoumobjeto ÉassimquevocêcriaumobjetoPostnobancodedados: 63 DjangoORM(Querysets) >>>Post.objects.create(author=me,title='Sampletitle',text='Test') Masaquitemosumingredientequefaltava: me.Precisamospassarumainstânciade Usermodelocomoautor.Como fazerisso? PrimeirovamosimportaromodeloUser: >>>fromdjango.contrib.auth.modelsimportUser Quaisusuáriostemosnonossobancodedados?Experimenteisso: >>>User.objects.all() [<User:ola>] Éosuperusuárioquecriamosanteriormente!Vamosobterumainstânciadeusuárioagora: me=User.objects.get(username='ola') Comovocêpodever,nósagorausamosum geta Userwitha usernameiguala'ola'.Claro,vocêtemqueadaptara seunomedeusuário. Agorafinalmentepodemoscriarnossaprimeirapostagem: >>>Post.objects.create(author=me,title='Sampletitle',text='Test') Viva!Querversefuncionou? >>>Post.objects.all() [<Post:Sampletitle>] Adicionemaispostagens Agora,vocêpodesedivertirumpoucoeadicionarmaispostagensparavercomofunciona.Adicionemais2-3esigapara apróximaparte. Filtrarobjetos UmagrandepartedeQuerySetséahabilidadedefiltrá-los.Digamosquequeremosencontrartodosaspostagensescritas pelousuárioola.Nósusaremoso filteremvezde allem Post.objects.all().Entreparêntesesindicamosqueas condiçõesprecisamseratendidasporumpostagemdeblogparaacabaremnossoqueryset.Emnossocasoé author queéiguala me.AmaneiradeescreverissonoDjangoé: author=me.Agoraonossotrechodecódigoparececomeste: >>>Post.objects.filter(author=me) [<Post:Sampletitle>,<Post:Postnumber2>,<Post:My3rdpost!>,<Post:4thtitleofpost>] Outalveznósqueremosvertodosospostsquecontenhamapalavra'title'nocampode title? >>>Post.objects.filter(title__contains='title') [<Post:Sampletitle>,<Post:4thtitleofpost>] NotaExistemdoiscaracteresdesublinhado( _)entreo titlee contains.DjangoORMusaestasintaxepara separarnomesdecampo("title")eoperaçõesoufiltros("contains").Sevocêusarapenasumsublinhado,você obteráumerrocomo"FieldError:Cannotresolvekeywordtitle_contains". 64 DjangoORM(Querysets) Vocêtambémpodeobterumalistadetodosospostspublicados.Fazemosissofiltrandotodosospostscom published_datedefinidonopassado: >>>fromdjango.utilsimporttimezone >>>Post.objects.filter(published_date__lte=timezone.now()) [] Infelizmente,nenhumdosnossospostsestãopublicadosainda.Nóspodemosmudarisso!Primeiroobtenhaumainstância deumpostquequeremospublicar: >>>post=Post.objects.get(id=1) Eentãopublicá-locomonossométodode publish! >>>post.publish() Agoratenteobteralistadepostspublicadosnovamente(pressioneasetaparacimabotão3vezesetecleEnter): >>>Post.objects.filter(published_date__lte=timezone.now()) [<Post:Sampletitle>] Ordenandoobjetos UmQuerySettambémnospermiteordenaralistadeobjetos.Vamostentarordenaraspostagenspelocampo created_date: >>>Post.objects.order_by('created_date') [<Post:Sampletitle>,<Post:Postnumber2>,<Post:My3rdpost!>,<Post:4thtitleofpost>] Vocêtambémpodeinverteraordemadicionando -noinício: >>>Post.objects.order_by('-created_date') [<Post:4thtitleofpost>,<Post:My3rdpost!>,<Post:Postnumber2>,<Post:Sampletitle>] Legal!Vocêjáestáprontoparaapróximaparte!Parafecharoterminaldigite: >>>exit() $ 65 Dadosdinâmicosnostemplates DjangoQuerysets Nóstemosdiferentespeçasaqui:omodel Postestádefinidoem models.py,nóstemos post_listno views.pyeo templateadicionado.Mascomonósfaremosdefatoparafazercomqueasnossaspostagensapareçamnonosso templateemHTML?Porqueéissoquenósqueremos:pegaralgumconteúdo(modelssalvosnobancodedados)eexibilodeumamaneirabacananonossotemplate,certo? Eissoéexatamenteoqueasviewsdevemfazer:conectarmodelsetemplates.Nanossaview post_listviewnós vamosprecisarpegarosmodelsquequeremosexibirepassá-losparaotemplate.Então,basicamente,emumaviewnós decidimosoque(ummodel)seráexibidonotemplate. Certo,ecomonósfaremosisso? Precisamosabrironosso blog/views.py.Atéagoraaview post_listseparececomisso: fromdjango.shortcutsimportrender defpost_list(request): returnrender(request,'blog/post_list.html',{}) Lembraquandofalamossobreainclusãodecódigoescritoemarquivosdiferentes?Agoraéomomentoemquetemosde incluiromodelquetemosescritoem models.py.Vamosadicionarestalinha from.modelsimportPostcomoeste: fromdjango.shortcutsimportrender from.modelsimportPost Opontodepoisde fromsignificaodiretórioatualouoaplicativoatual.Como views.pye models.pyestãonomesmo diretóriopodemossimplesmenteusar .eonomedoarquivo(sem .py).Entãonósimportamosonomedomodelo ( Post). Eoquevemagora?Parapegarospostsreaisdomodel Postnósprecisamosdeumacoisachamada QuerySet. QuerySet VocêjádeveestarfamiliarizadocomomodoqueosQuerySetsfuncionam.NósconversamossobreissonocapítuloORM doDjango(QuerySets).Agoranósestamosinteressadosemumalistadepostsquesãopublicadoseclassificadospor published_date,certo?NósjáfizemosissonocapítuloQuerySets! Post.objects.filter(published_date__lte=timezone.now()).order_by('published_date') Agoranóscolocamosestepedaçodecódigodentrodoarquivo blog/views.pyadicionando-oàfunção def post_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',{}) NotequecriamosumavariávelparanossooQuerySet: posts.TrateistocomoonomedonossoQuerySet.Deagoraem diantenóspodemosnosreferiraeleporestenome. AúltimapartequefaltaépassaroQuerySet postsparaotemplate(veremoscomoexibi-loemumpróximocapítulo). 66 Dadosdinâmicosnostemplates Nafunção renderjátemosoparâmetro request(tudooquerecebemosdousuárioatravésdaInternet)eumarquivode template 'blog/post_list.html'.Oúltimoparâmetro,queseparececomisso: {}éumlugaremquepodemos acrescentaralgumascoisasparaqueotemplateuse.Precisamosnomeá-los(ficaremoscom 'posts'porenquanto:)). Deveficarassim: {'posts':posts}.Observequeaparteantesde :estáentreaspas ''. Entãofinalmentenossoarquivo blog/views.pydeveseparecercomisto: 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}) Feito!HoradevoltarparaonossotemplateeexibiressaQuerySet! SequiserlermaissobreQuerySetsnoDjangovocêdevedarumaolhadaaqui: https://docs.djangoproject.com/en/1.8/ref/models/querysets/ 67 Templates Templates Horadeexibiralgumdado!Djangonosdátagsdetemplatesembutidasbastanteúteisparaisso. Oquesãotagsdetemplate? Comopodever,vocênãopodecolocarcódigoPythonnoHTML,porqueosnavegadoresnãoirãoentender.Elesapenas conhecemHTML.NóssabemosqueHTMLébastanteestático,enquantoPythonémuitomaisdinâmico. TagsdetemplateDjangonospermitetransformarobjetosPythonemcódigoHTML,paraquevocêpossaconstruirsites dinâmicosmaisrápidoemaisfácil.Uhuu! Modelodelistadepostdeexibição Nocapituloanterior,nósfornecemosaonossotemplateumalistadepostagenseavariávelposts.Agoravamosexibirem nossoHTML. ParaexibirumavariávelnoDjangotemplate,nósusamoscolchetesduploscomonomedavariáveldentro,exemplo: {{posts}} Tentarfazerissonoseutemplate blog/templates/blog/post_list.html(substituiaosegundoeoterceiropardetags <div ></div>pelalinha {{posts}}),salveoarquivoeatualizeapáginaparaverosresultados: Vocêpodever,tudoquetemosé: [<Post:Mysecondpost>,<Post:Myfirstpost>] IstosignificaqueoDjangoaentendecomoumalistadeobjetos.Lembre-sedeintroduçãoaoPythoncomopodemos exibirlistas?Sim,comosloops!EmumtemplateDjango,fazemosissodaseguintemaneira: {%forpostinposts%} {{post}} {%endfor%} Tentefazerissonoseutemplate. 68 Templates Funciona!Masnósqueremosqueelessejamexibidoscomoospostsestáticos,comoosquecriamosanteriormenteno capítulodeIntroduçãoaHTML.NóspodemosmisturarHTMLcomtagsdetemplate.Oconteúdodatag bodyficará assim: <div> <h1><ahref="/">DjangoGirlsBlog</a></h1> </div> {%forpostinposts%} <div> <p>published:{{post.published_date}}</p> <h1><ahref="">{{post.title}}</a></h1> <p>{{post.text|linebreaksbr}}</p> </div> {%endfor%} Tudoquevocêpõeentre {%for%}e {%endfor%}serárepetidoparacadaobjetonalista.Atualizesuapágina: Vocênotouquedessaveznósusamosumanotaçãoumpoucodiferente {{post.title}}ou {{post.text}}?Nós estamosacessandoosdadosemcadaumdoscamposquedefinimosnomodeldo Post.Alémdisso, |linebreaksbr estápassandootextodopostporumfiltro,convertendoquebrasdelinhaemparágrafos. 69 Templates Maisumacoisa Seriabomverseseusiteaindaestaráfuncionandonainternet,certo?VamostentarimplantaraPythonAnywhere novamente.Aquiestáumresumodospassos... Primeiro,envieseucódigoparaoGithub $gitstatus $gitadd--all. $gitstatus $gitcommit-m"Addedviewstocreate/editblogpostinsidethesite." $gitpush Emseguida,façaloginemPythonAnywhereeváparaseuBashconsole(oucomeceumnovo)eexecute: `$cdmy-first-blog$gitpull Finalmente,puleparaaWebtabeaperteReloademseuaplicativoweb.Suaatualizaçãodeveestarlive! Parabéns!AgoraváemfrenteetenteadicionarumnovopostemseuDjangoadmin(Lembre-sedeadicionar published_date!),emseguida,atualizeapáginaparaverseopostapareceporlá. Funcionacomomágica?Estamosorgulhosos!Afaste-sedoseucomputadorumpouco,vocêganhouumapausa.:) 70 CSS-Deixemaisbonito CSS-Deixemaisbonito! Nossoblogaindaparecefeio,certo?Estánahoradedeixarelemelhor!ParaissonósusaremosoCSS. OqueéCSS? Doinglês"CascadingStyleSheets",CSSéumalinguagemusadaparadescreveroaspectoeaformataçãodeumwebsite escritonumalinguagemdemarcação(comoHTML).Imagineelecomosendoumtipode"maquiagem"paranossosite;). Masnósnãoqueremosiniciardozerodenovo,certo?Nóstentaremos,maisumavez,usaralgoquefoifeitoe disponibilizadodegraçaporprogramadoresnainternet.Vocêsabe,reinventararodanãoénadadivertido. VamosusaroBootstrap! BootstrapéumdosmaisfamososepopularesframeworksdeHTMLeCSSparadesenvolversitesbonitos: https://getbootstrap.com/ FoiescritoporprogramadoresquetrabalharamnoTwittereagoraédesenvolvidoporvoluntáriosdetodoomundo. InstalarBootstrap ParainstalaroBootstrap,vocêprecisaadicionaraoseucabeçalho(natag <head>dentrodoseuarquivo .html) ( blog/templates/blog/post_list.html): <linkrel="stylesheet"href="//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css"> <linkrel="stylesheet"href="//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap-theme.min.css"> Issonãoadicionanenhumarquivoaoseuprojeto.Ocódigoapenasapontaparaarquivosqueexistemnainternet.Apenas sigaemfrente,abraseusiteeatualizeapágina.Aquieleestá! Jáparecendomelhor! ArquivosestáticosnoDjango 71 CSS-Deixemaisbonito Finalmentenósteremosumolharmaisatentonessascoisasquechamamosarquivosestáticos.Arquivosestáticossão todasassuasimagensearquivosCSS--arquivosquenãosãodinâmicos,entãoseuconteúdonãodependedocontexto darequisiçãoeseráomesmoparatodososusuários. OndecolocarosarquivosestáticosparaDjango Comovocêviuquandorodamos collectstaticnoservidor,Djangojásabeondeencontrarosarquivosestáticosparao built-in"admin"app.Agorasóprecisamosadicionaralgunsarquivosestáticosparanossopróprioapp, blog. Fazemosissoatravésdacriaçãodeumapastachamada staticdentrodoaplicativodoblog: djangogirls ├──blog │├──migrations │└──static └──mysite Djangoencontraráautomaticamentetodasaspastaschamadas"static"dentrodequalquerumadaspastasdosseus apps,eserácapazdeusarseuconteúdocomoarquivosestáticos. SeuprimeiroarquivoCSS! VamoscriarumarquivoCSSagora,paraadicionarseupróprioestiloparasuapáginadaweb.Crieumnovodiretório chamado cssdentrodeseudiretório static.Emseguida,crieumnovoarquivochamado blog.cssdentrododiretório css.Pronto? djangogirls └───blog └───static └───css └───blog.css HoradeescreverCSS!Abraoarquivo static/css/blog.cssnoseueditordecódigo. NãovamosnosaprofundarmuitoemcustomizareaprendersobreCSSaqui,porqueébemfácilevocêpodeaprenderno seupróprioapósesteworkshop.RecomendamosfortementefazeresteCodeacademyHTML&CSScouseparaaprender tudooquevocêprecisasabersobrecomotornarseussitesmaisbonitoscomCSS. Masvamosfazerpelomenosumpouco.Talvezpossamosmudaracordonossocabeçalho?Paraentenderascores, computadoresusamcódigosespeciais.Elescomeçamcom #esãoseguidospor6letras(A-F)enúmeros(0-9).Você podeencontrarexemplosdecódigosdecoresaqui:http://www.colorpicker.com/.Vocêpodetambémusarcores predefinidas,como rede green. Emseuarquivo static/css/blog.cssvocêdeveadicionaroseguintecódigo: h1a{ color:#FCA205; } h1aéumseletordeCSS.Issosignificaquenósestamosaplicandonossosestilosparaqualquerelemento adentrode umelemento h1(i.e.quandotivermosnocódigoalgocomo: <h1><ahref="">link</a></h1>).Nestecasonósestamos dizendoparamudaracorpara #FCA205,queélaranja.Claro,vocêpodecolocaracorquevocêquiseraqui! EmumarquivoCSSpodemosdeterminarestilosparaelementosnoarquivoHTML.Oselementossãoidentificadospelo nomedoelemento(ouseja, a, h1, body),oatributode classouoatributo id.Classeeidsãonomesquevocê mesmodáaoelemento.Classesdefinemgruposdeelementos,eidsapontamparaelementosespecíficos.Porexemplo,a 72 CSS-Deixemaisbonito seguintetagpodeseridentificadaporCSSusandoatagdenome a,aclasse link_externoouaidentificaçãode link_para_a_pagina_wiki: <ahref="https://en.wikipedia.org/wiki/Django"class="external_link"id="link_to_wiki_page"> LeiasobreSeletoresCSSemw3schools. Então,precisamostambémcontaronossotemplateHTMLquenósadicionamosCSS.Abraoarquivo blog/templates/blog/post_list.htmleadicioneessalinhanoiníciodomesmo: {%loadstaticfiles%} Estamosapenascarregandoarquivosestáticosaqui:).Depois,entreo <head> e/</head>,depoisdoslinksparaos arquivosdeCSSdoBootstrap(onavegadorlêosarquivosnaordemqueelessãodados,entãoocódigoemnosso arquivopodesubstituirocódigoemarquivosdeinicialização),adicioneestalinha: <linkrel="stylesheet"href="{%static'css/blog.css'%}"> SódissemosquenossomodeloondeseencontranossoarquivoCSS. Agora,seuarquivodeveficarassim: {%loadstaticfiles%} <html> <head> <title>DjangoGirlsblog</title> <linkrel="stylesheet"href="//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css"> <linkrel="stylesheet"href="//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap-theme.min.css"> <linkrel="stylesheet"href="{%static'css/blog.css'%}"> </head> <body> <div> <h1><ahref="/">DjangoGirlsBlog</a></h1> </div> {%forpostinposts%} <div> <p>published:{{post.published_date}}</p> <h1><ahref="">{{post.title}}</a></h1> <p>{{post.text|linebreaksbr}}</p> </div> {%endfor%} </body> </html> OK,salveoarquivoeatualizeosite! 73 CSS-Deixemaisbonito Bomtrabalho!Talvezagentetambémqueiradarumpoucodearaonossositeeaumentaramargemdoladoesquerdo? Vamostentar! body{ padding-left:15px; } AdicioneistoaoseuarquivoCSS,salveevejacomoelefunciona! Talvezagentepossacustomizarafontenonossocabeçalho?Colenaseção <head>doarquivo blog/templates/blog/post_list.htmloseguinte: <linkhref="https://fonts.googleapis.com/css?family=Lobster&subset=latin,latin-ext"rel="stylesheet"type="text/css"> EssalinhairáimportarumafontechamadaLobsterdoGoogleFonts(https://www.google.com/fonts). Agoraadicionealinha font-family:'Lobster';noCSSdoarquivo static/css/blog.cssdentrodoblocodedeclaração h1a(ocódigoentreaschaves {e })eatualizeapágina: 74 CSS-Deixemaisbonito h1a{ color:#FCA205; font-family:'Lobster'; } Incrível! Comomencionadoacima,CSSusaoconceitodeclasses,quebasicamentepermitequevocênomeiepartedocódigo HTMLeapliqueestilosapenasàestaparte,semafetarasoutras.Ésuperútilsevocêtiverduasdivs,maselesestão fazendoalgomuitodiferente(comooseucabeçalhoeseupost),entãovocênãoquerqueelesfiquemparecidos. VáemfrenteeonomeiealgumaspartesdocódigoHTML.Adicioneumaclassechamadade page-headerparao div quecontémocabeçalho,assim: <divclass="page-header"> <h1><ahref="/">DjangoGirlsBlog</a></h1> </div> Eagora,adicioneumaclasse postemsua divquecontémumpostdeblog. <divclass="post"> <p>published:{{post.published_date}}</p> <h1><ahref="">{{post.title}}</a></h1> <p>{{post.text|linebreaksbr}}</p> </div> Agoraadicionaremosblocosdedeclaraçãodeseletoresdiferentes.Seletorescomeçandocom .sereferemàsclasses. ExistemmuitostutoriaiseexplicaçõessobreCSSnaWebparaajudarvocêaentenderocódigoaseguir.Porenquanto, bastacopiarecolá-loemseuarquivo mysite/static/css/blog.css: 75 CSS-Deixemaisbonito .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; } EntãoenvolvaocódigoHTMLqueexibeasmensagenscomdeclaraçõesdeclasses.Substituaisto: {%forpostinposts%} <divclass="post"> <p>published:{{post.published_date}}</p> <h1><ahref="">{{post.title}}</a></h1> <p>{{post.text|linebreaksbr}}</p> </div> {%endfor%} noarquivo blog/templates/blog/post_list.htmlporisto: 76 CSS-Deixemaisbonito <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|linebreaksbr}}</p> </div> {%endfor%} </div> </div> </div> Salveessesarquivoseatualizeseusite. Uhuu!Ficouincrível,né?Ocódigoquenósacabamosdecolarnãoétãodifícildeentenderevocêdevesercapazde entenderamaiorparteapenaslendo. NãotenhamedodemexerumpoucocomesseCSSetentarmudaralgumascoisas.Sevocêquebraralgumacoisa,não sepreocupe,vocêsemprepodedesfazê-lo! Dequalquerforma,recomendamosquefaçaessecursoon-lineCodeacademyHTML&CSSCoursecomodeverdecasa pós-workshopparaaprendertudooquevocêprecisasabersobrecomotornarseussitesmaisbonitoscomCSS. Prontoparaopróximocapítulo?!:) 77 Estendendoostemplates Estendendoostemplates OutracoisaboaqueoDjangotempravocêéotemplateextending.Oqueissosignifica?Issosignificaquevocêpode usarasmesmaspartesdoseuHTMLemdiferentespáginasdoseusite. Dessaformavocênãoprecisaficarserepetindoemcadaarquivoquandoquiserusaramesmainformação/layout.Ese vocêquisermudaralgumacoisanãoprecisafazerissoemtodotemplate,sóumavez! Criartemplatebase Umtemplatebaseéotemplatemaisbásicoquevocêestenderáemcadapáginadoseusite. Vamoscriarumarquivo base.htmlnapasta blog/templates/blog/: blog └───templates └───blog base.html post_list.html Abra-oecopietudoqueestánoarquivo post_list.htmlpara base.html,dessejeito: {%loadstaticfiles%} <html> <head> <title>DjangoGirlsblog</title> <linkrel="stylesheet"href="//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css"> <linkrel="stylesheet"href="//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap-theme.min.css"> <linkhref='//fonts.googleapis.com/css?family=Lobster&subset=latin,latin-ext'rel='stylesheet'type='text/css' > <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|linebreaksbr}}</p> </div> {%endfor%} </div> </div> </div> </body> </html> Entãoem base.html,substituatodoseu <body>(tudoentre <body>e </body>)comisso: 78 Estendendoostemplates <body> <divclass="page-header"> <h1><ahref="/">DjangoGirlsBlog</a></h1> </div> <divclass="contentcontainer"> <divclass="row"> <divclass="col-md-8"> {%blockcontent%} {%endblock%} </div> </div> </div> </body> Basicamentenóssubstituimostudoentre {%forpostinposts%}{%endfor%}por: {%blockcontent%} {%endblock%} Oqueissosignifica?Vocêacaboudecriarum block(bloco),queéumatagdetemplatequetepermiteinserirHTML nesteblocoemoutrostemplatesqueestendem base.html.Nósvamostemostrarcomofazerissojájá. Salveeabraoarquivo blog/templates/blog/post_list.htmlnovamente.Apagueexatamentetudoquenãoestiverdentro datagbodyeapaguetambém <divclass="page-header"></div>,deformaqueoarquivofiquedaseguintemaneira: {%forpostinposts%} <divclass="post"> <divclass="date"> {{post.published_date}} </div> <h1><ahref="">{{post.title}}</a></h1> <p>{{post.text|linebreaksbr}}</p> </div> {%endfor%} Agoraadicioneestalinhaaoiníciodoarquivo: {%extends'blog/base.html'%} Issosignificaque,agora,nósestamosestendendootemplate base.htmlem post_list.html.Umaúltimacoisa:colocar tudo(excetopelalinhaqueacabamosdeadicionar)entre {%blockcontent%}e {%endblockcontent%}.Comoaseguir: {%extends'blog/base.html'%} {%blockcontent%} {%forpostinposts%} <divclass="post"> <divclass="date"> {{post.published_date}} </div> <h1><ahref="">{{post.title}}</a></h1> <p>{{post.text|linebreaksbr}}</p> </div> {%endfor%} {%endblockcontent%} Éisso!Vejaseoseusiteaindaestáfuncionandodireito:) Seocorrerumerrode TemplateDoesNotExists,quedizquenãoexistenenhumarquivochamado blog/base.htmle sevocêtivero runserverexecutandonoterminal,tentainterrompê-lo(precionandoCtrl+C-obotãoControlmaiso botãoCjuntos)ereinicieelerodandoocomando pythonmanage.pyrunserver. 79 Estendendoostemplates 80 Ampliesuaaplicação Ampliesuaaplicação Jáconcluímostodosospassosnecessáriosparaacriaçãodonossosite:sabemoscomocriarummodelo,umaurl,uma vieweumtemplate.Tambémsabemoscomomelhoraraaparênciadonossowebsite. Horadepraticar! Aprimeiracoisaqueprecisamosnonossoblogé,obviamente,umapáginaparamostrarumapostagem,certo? Játemosummodelode Post,entãonãoprecisamosadicionarnadaao models.py. Criarumlinknotemplate Vamoscomeçarcomaadiçãodeumlinkdentrodoarquivo blog/templates/blog/post_list.html.Nestemomentoeledeve separecercom: {%extends'blog/base.html'%} {%blockcontent%} {%forpostinposts%} <divclass="post"> <divclass="date"> {{post.published_date}} </div> <h1><ahref="">{{post.title}}</a></h1> <p>{{post.text|linebreaksbr}}</p> </div> {%endfor%} {%endblockcontent%} Queremosterumlinkparaumapáginadedetalhenotítulodopost.Vamostransformar <h1><href="">{{post.title }}</a></h1>emumlink: <h1><ahref="{%url'blog.views.post_detail'pk=post.pk%}">{{post.title}}</a></h1> Tempoparaexplicaromisterioso {%url'blog.views.post_detail'pk=post.pk%}.Comovocêpodesuspeitar,anotação de {%%}significaqueestamosusandoastagsdetemplatedoDjango.Destavezvamosusarumaquevaicriaruma URLparanós! blog.views.post_detailéumcaminhoparaum post_detailVistaquequeremoscriar.Presteatenção: blogéonome dasuaaplicação(odiretório blog), viewsvemdonomedoarquivo views.pye,aúltimaparte- post_detail-éo nomedaview. Agoraquandoformospara:http://127.0.0.1:8000/teremosumerro(comoesperado,jáquenãotemosumaURLouuma viewpara post_detail).Vaiseparecercomisso: 81 Ampliesuaaplicação VamoscriaraURLem urls.pyparaanossa post_detailview! URL:http://127.0.0.1:8000/post/1/ QueremoscriarumaURLparaguiaroDjangoparaaviewchamada post_detail,queirámostrarumpostcompletodo blog.Adicionealinha url(r'^post/(?P<pk>[0-9]+)/$',views.post_detail),aoarquivo blog/urls.py.Deveficarassim: fromdjango.conf.urlsimporturl from.importviews urlpatterns=[ url(r'^$',views.post_list), url(r'^post/(?P<pk>[0-9]+)/$',views.post_detail), ] Pareceassustador,masnãosepreocupe-vamosexplicareleparavocê:-começacom ^denovo..."oinício"- post/ significaapenasqueapósocomeço,daURLdeveterapalavraposte/.Atéaqui,tudobem.- (?P<pk>[0-9]+)-essa parteémaiscomplicada.IssosignificaqueoDjangovailevartudoquevocêcolocaraquietransferirparaumaviewcomo umavariávelchamada pk. [0-9]tambémnosdizquesópodeserumnúmero,nãoumaletra(tudoentre0e9). + significaqueprecisaexistirumoumaisdígitos.Entãoalgocomo http://127.0.0.1:8000/post//nãoéválido,mas http://127.0.0.1:8000/post/1234567890/éperfeitamenteok!- /-entãoprecisamosde/outravez- $-"ofim"! Issosignificaquesevocêdigitar http://127.0.0.1:8000/post/5/emseunavegador,Djangovaientenderquevocêestá procurandoumaviewchamada post_detailetransferirainformaçãodeque pkéiguala 5paraaquelaview. pkéumaabreviaçãopara primarykey(chaveprimária).EssenomegeralmenteéusadonosprojetosfeitosemDjango. Masvocêpodedaronomequequiseràsvariáveis(lembre-se:minúsculoe _aoinvésdeespaçosembranco!).Por exemploemvezde (?P<pk>[0-9]+)podemosterumavariável post_id,entãoestaparteficariacomo: (?P<post_id>[09]+). Razoável!Vamosatualizarapágina:http://127.0.0.1:8000/Boom!Aindaoutroerro!Comoesperado! 82 Ampliesuaaplicação Vocêselembraqualéopróximopasso?Claro:adicionandoumaview! post_detailview Destavezanossaviewrecebeumparâmetroextra pk.Nossaviewprecisapegá-la,certo?Entãovamosdefinirnossa funçãocomo defpost_detail(request,pk):.Observequeprecisamosusarexatamenteomesmonomeque especificamosemurls( pk).Omitiressavariáveléerradoeresultaráemumerro! Agoraqueremosreceberapenasumpostdoblog.Paraissopodemosusarquerysetscomoeste: Post.objects.get(pk=pk) Masestecódigotemumproblema.Senãohouvernenhum Postcoma chaveprimária( pk)fornecidateremosumerro horroroso! Nãoqueremosisso!Mas,claro,oDjangovemcomalgoquevailidarcomissoparanós: get_object_or_404.Casonão hajanenhum Postcomodado pkexibiráumapáginamuitomaisagradável(chamada PageNotFound404-página nãoencontrada). 83 Ampliesuaaplicação Aboanotíciaéquevocêrealmentepodecriarsuaprópriapáginade Pagenotfoundetorná-lotãobonitaquantovocê quiser.Masissonãoésuperimportanteagora,entãonósvamosignorá-la. Ok,horadeadicionarumaviewaonossoarquivo views.py! Devemosabrir blog/views.pyeadicionaroseguintecódigo: fromdjango.shortcutsimportrender,get_object_or_404 Pertodeoutraslinhas from.Enofinaldoarquivo,adicionaremosanossaview: defpost_detail(request,pk): post=get_object_or_404(Post,pk=pk) returnrender(request,'blog/post_detail.html',{'post':post}) Sim.Estánahoradeatualizarapágina:http://127.0.0.1:8000/ 84 Ampliesuaaplicação Funcionou!Masoqueacontecequandovocêclicaemumlinknotítulodopostdoblog? Ahnão!Outroerro!Masnósjásabemoscomolidarcomisso,né?Precisamosadicionarumtemplate! Vamoscriarumarquivoem blog/templates/blogchamado post_detail.html. Seráalgoparecidocomisto: 85 Ampliesuaaplicação {%extends'blog/base.html'%} {%blockcontent%} <divclass="post"> {%ifpost.published_date%} <divclass="date"> {{post.published_date}} </div> {%endif%} <h1>{{post.title}}</h1> <p>{{post.text|linebreaksbr}}</p> </div> {%endblock%} Maisumavezestamosestendendo base.html.Noblocode contentqueremosexibiropublished_date(datade publicação)dopost(sehouver),títuloetexto.Masdevemosdiscutiralgumascoisasimportantes,certo? {%if...%}...{%endif%}éumatagdetemplatequepodemosusarquandoqueremosverificaralgo(Lembre-se if ...else...docapítulointroduçãoaoPython?).Nestecenário,queremosverificarse published_datedeumpostnão estávazia. Ok,podemosatualizarnossapáginaeverse Pagenotfoundjásefoi. Yay!Funciona! Maisumacoisa:horadeimplantar! SeriabomverseseusiteaindaestarátrabalhandoemPythonAnywhere,certo?Vamostentarfazerdeploynovamente. $gitstatus $gitadd--all. $gitstatus $gitcommit-m"Addedviewstocreate/editblogpostinsidethesite." $gitpush 86 Ampliesuaaplicação Então,emumconsolePythonAnywhereBash: $cdmy-first-blog $gitpull Finalmente,puleparaaWebtabeaperteReload. Edeveserisso!Parabéns:) 87 Formulários Formulários Porúltimoqueremosumaformalegaldeadicionareeditaraspostagensdonossoblog.A ferramentadeadministraçãodo Djangoélegal,maselaéumpoucodifícildecustomizarededeixarmaisbonita.Seusarmos formuláriosteremos controleabsolutosobrenossainterface-podemosfazerqualquercoisaqueimaginarmos! UmacoisalegaldoDjangoéquenóspodemostantocriarumformuláriodozerocomopodemoscriarum ModelFormque salvaoresultadodoformulárioparaumdeterminadomodelo. Issoéexatamenteoquenósqueremosfazer:criaremosumformulárioparaonossomodelo Post. AssimcomotodaparteimportantedoDjango,formstemseupróprioarquivo: forms.py. Precisamoscriarumarquivocomestenomedentrodapasta blog. blog └──forms.py Ok,vamosabri-loeescreverneleoseguinte: fromdjangoimportforms from.modelsimportPost classPostForm(forms.ModelForm): classMeta: model=Post fields=('title','text',) PrimeiroprecisamosimportaromódulodeformuláriosdoDjango( fromdjangoimportforms)e,obviamente,nosso modelo Post( from.modelsimportPost). PostForm,comovocêjádevesuspeitar,éonomedonossoformulário.PrecisamosdizeraoDjangoqueesteformulárioé um ModelForm(assimoDjangopodefazeramágicapragente)-o forms.ModelForméoresponsávelporisso. Segundo,nóstemosaclasse MetaondedizemosaoDjangoqualmodelodeveriaserusadoparacriaresteformulário ( model=Post). Finalmente,nóspodemosdizerqual(is)campo(s)deveriamentraremnossoformulário.Nessecenárionósqueremos apenaso titlee textparaserexposto- authordeveriaserapessoaqueestálogadanosistema(nessecaso,você!) e created_datedeveriasersetadoautomaticamentequandonóscriamosumpost(nocódigo),correto? Eéissoaí!Tudooqueprecisamosfazeragoraéusaroformulárioemumaviewemostrá-loemumtemplate. Então,maisumavez,nósiremoscriar:umlinkparaapágina,umaURL,umavieweumtemplate. Linkparaapáginacomoformulário Éhoradeabrir blog/templates/blog/base.html.Nósiremosadicionarumlinkem divnomeado page-header: <ahref="{%url'blog.views.post_new'%}"class="top-menu"><spanclass="glyphiconglyphicon-plus"></span></a> Notequenósqueremoschamarnossanovavisão post_new. Depoisdeadicionaralinha,seuhtmldeveseparecercomisso: 88 Formulários {%loadstaticfiles%} <html> <head> <title>DjangoGirlsblog</title> <linkrel="stylesheet"href="//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css"> <linkrel="stylesheet"href="//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap-theme.min.css"> <linkhref='//fonts.googleapis.com/css?family=Lobster&subset=latin,latin-ext'rel='stylesheet'type='text/css' > <linkrel="stylesheet"href="{%static'css/blog.css'%}"> </head> <body> <divclass="page-header"> <ahref="{%url'blog.views.post_new'%}"class="top-menu"><spanclass="glyphiconglyphicon-plus"></span> </a> <h1><ahref="/">DjangoGirlsBlog</a></h1> </div> <divclass="contentcontainer"> <divclass="row"> <divclass="col-md-8"> {%blockcontent%} {%endblock%} </div> </div> </div> </body> </html> Depoisdesalvarerecarregarapágina http://127.0.0.1:8000vocêverá,obviamente,umerrofamiliar NoReverseMatch certo? URL Vamosabriroarquivo blog/urls.pyeescrever: url(r'^post/new/$',views.post_new,name='post_new'), Ocódigofinaldeveseparecercomisso: fromdjango.conf.urlsimporturl 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'), ] Apósrecarregarosite,nósveremosum AttributeError,desdequenósnãotemosavisão post_newimplementada. Vamosadicioná-laagora. post_newview Horadeabriroarquivo blog/views.pyeadicionaraslinhasseguintescomorestodaslinhas from: from.formsimportPostForm enossaview: 89 Formulários defpost_new(request): form=PostForm() returnrender(request,'blog/post_edit.html',{'form':form}) Paracriarumnovoformulario Post,nósdevemoschamar PostForm()epassá-loparaotemplate.Nósiremosvoltar paraestaview,masporagoravamoscriarrapidamenteumtemplateparaoformulário. Template(modelos) Precisamoscriarumarquivo post_edit.htmlnapasta blog/templates/blog.Prafazeroformuláriofuncionarprecisamos demuitascoisas: Temosqueexibiroformulário.Podemosfazerissosimplesmentecomum``. AlinhaacimaprecisaestardentrodeumatagHTMLform: <formmethod="POST">...</form> Precisamosdeumbotão Salvar.FazemosissocomumbotãoHTML: <buttontype="submit">Save</button> Efinalmente,depoisdeabriratag <form...>precisamosadicionarum {%csrf_token%}.Issoémuitoimportante, poiséissoquefazonossoformulárioficarseguro!ODJangovaireclamarsevocêesquecerdeadicionarissoe simplesmentesalvaroformulário: Beleza,entãovamosvercomoficouoHTML 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">Guardar</button> </form> {%endblock%} Horadeatualizar!Há!Seuformulárioapareceu! 90 Formulários Mas,espereumminuto!Quandovocêdigitaalgumacoisanoscampos titlee textetentasalvaroqueacontece? Nada!Estamosnovamentenamesmapáginaenossotextosumiu...Enenhumpostfoiadicionado.Entãooquedeu errado? Arespostaé:nada.Precisamostrabalharumpoucomaisnanossaview. Salvandooformulário Abra blog/views.pymaisumavez.Atualmentetudoquetemosnavisão post_newé: defpost_new(request): form=PostForm() returnrender(request,'blog/post_edit.html',{'form':form}) Quandonósenviamosoformulário,somostrazidosdevoltaparaamesmavisão,masdestaveztemosmaisalgunsdados no request,maisespecificamenteem request.POST(onomenãotemnadacom"post"deblog,temavercomofatode queestamos"postando"dados).VocêselembraquenoarquivoHTMLnossadefiniçãode <form>temavariável method="POST"?Todososcamposvindosdo"form"estarãodisponíveisagoraem request.POST.Vocênãodeveria renomear POSTparanadadiferentedisso(oúnicooutrovalorválidopara methodé GET,masnósnãotemostempo paraexplicarqualéadiferença). Entãonanossaviewnóstemosduassituaçõesseparadasparalidar.Aprimeiraéquantoacessamosapáginapela primeiravezequeremosumformulárioembranco.Easegunda,équandonóstemosquevoltarparaaviewcomtodosos dadosdoformulárioquenósdigitamos.Dessemodo,precisamosadicionarumacondição(usaremos ifparaisso). 91 Formulários ifrequest.method=="POST": [...] else: form=PostForm() Estánahoradepreencherospontos [...].Se methodé POSTentãonósqueremosconstruiro PostFormcomos dadosqueveemdoformulário,certo?Nósiremosfazerassim: form=PostForm(request.POST) Fácil!Próximacoisaéverificarseoformulárioestácorreto(todososcamposrequeridossãodefinidosevaloresincorretos nãoserãosalvos).Fazemosissocom form.is_valid(). Verificamosseoformulárioéválidoeseestivertudocerto,podemossalvá-lo! ifform.is_valid(): post=form.save(commit=False) post.author=request.user post.published_date=timezone.now() post.save() Basicamente,temosduascoisasaqui:Salvamosoformuláriocom form.saveeadicionadosumautor(desdequenãohaja ocampo authorem PostForm,eestecampoéobrigatório!). commit=Falsesignificaquenãoqueremossalvaromodelo Postainda-queremosadicionarautorprimeiro.Namaioriadasvezesvocêiráusar form.save(),sem commit=False, masnestecaso,precisamosfazerisso. post.save()irápreservarasalterações(adicionandoautor)eécriadoumnovo postnoblog! Finalmente,nãoseriafantásticosenóspudéssemosimediatamenteiràpáginade post_detailparaorecém-criadoblog post,certo?Parafazerissonósprecisaremosdemaisumaimportação: fromdjango.shortcutsimportredirect Adicione-ologonoiníciodoseuarquivo.Eagorapodemosdizer:váparaapágina post_detailparaumrecém-criado post. returnredirect('blog.views.post_detail',pk=post.pk) blog.views.post_detailéonomedaviewquequeremosir.Lembre-sequeessaviewexigeumavariável pk?Para passarissonas viewsusamos pk=post.pk,ondepostéorecém-criadoblogpost. Ok,nósfalamosmuito,masprovavelmentequeremosveroquetodaaviewirápareceragora,certo? defpost_new(request): ifrequest.method=="POST": form=PostForm(request.POST) ifform.is_valid(): post=form.save(commit=False) post.author=request.user post.published_date=timezone.now() post.save() returnredirect('blog.views.post_detail',pk=post.pk) else: form=PostForm() returnrender(request,'blog/post_edit.html',{'form':form}) Vamosversefunciona.Váparaopáginahttp://127.0.0.1:8000/post/new/,adicioneum titleeo text,salve...evoilà!O novoblogpostéadicionadoenóssomosredirecionadosparaapáginade post_detail! 92 Formulários Vocêprovavelmentenotouquenósnãoestamosdefinindoadatadepublicaçãoemtudo.Vamosintroduzirumbotãode publicaçãoemDjangoGirlsTutorial:Extensões. Issoéincrível! Validaçãodeformulários Agora,nóslhemostraremoscomoosfórmulariossãolegais.Opostdoblogprecisateroscampos titlee text.Em nossomodelo Postnãodissemos(emoposiçãoa published_date)queessescamposnãosãonecessários,então Django,porpadrão,espera-osaserdefinido. Tentesalvaroformuláriosem titlee text.Adivinheoquevaiacontecer! Djangoestátomandocontadevalidarsetodososcamposdenossoformulárioestãocorretos.Nãoéincrível? ComorecentementeusamosainterfacedeadministraçãodoDjangoosistemaentendequeestamoslogados. Existemalgumassituaçõesquepoderiamlevarasermosdeslogadosdosistema(fecharonavegador,reiniciar bancodedadosetc.).Sevocêperceberqueerrosestãoaparecendoaocriarumpostquereferenciaumusuário quenãoestálogado,váparaapáginaadminhttp://127.0.0.1:8000eloguenovamente.Issovairesolveroproblema temporariamente.Háumajustepermanenteesperandoporvocêemliçãodecasa:adicionarsegurançanoseu site!,capítuloapósotutorialprincipal. 93 Formulários Editandooformulário Agorasabemoscomoadicionarumnovoformulário.Masesequisermoseditarumjáexistente?Émuitosemelhanteao quefizemos.Vamoscriaralgumascoisasimportantesrapidamente(sevocênãoentenderalgumacoisa-vocêdeve perguntaraseuprofessorouvejaoscapítulosanteriores,jácobrimostodasessasetapasanteriormente). Abra blog/templates/blog/post_detail.htmleadicionealinha: <aclass="btnbtn-default"href="{%url'post_edit'pk=post.pk%}"><spanclass="glyphiconglyphicon-pencil"></span></a > Agoraomodeloestaráparecidocom: {%extends'blog/base.html'%} {%blockcontent%} <divclass="date"> {%ifpost.published_date%} {{post.published_date}} {%endif%} <aclass="btnbtn-default"href="{%url'post_edit'pk=post.pk%}"><spanclass="glyphiconglyphicon-pencil"></span ></a> </div> <h1>{{post.title}}</h1> <p>{{post.text|linebreaksbr}}</p> {%endblock%} Em blog/urls.pyadicionamosestalinha: url(r'^post/(?P<pk>[0-9]+)/edit/$',views.post_edit,name='post_edit'), Nósreutilizaremosomodelo blog/templates/blog/post_edit.html,entãoaúltimacoisaquefaltaéumaview. Vamosabrir blog/views.pyeadicionarnofinaldoarquivo: 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.published_date=timezone.now() post.save() returnredirect('blog.views.post_detail',pk=post.pk) else: form=PostForm(instance=post) returnrender(request,'blog/post_edit.html',{'form':form}) 94 Formulários Issoéquaseexatamenteigualanossaviewde post_new,certo?Masnãototalmente.Primeiracoisa:passamosum parâmetroextradaurl pk.Emseguida:pegamosomodelo Postquequeremoseditarcom get_object_or_404(Post, pk=pk)eentão,quandocriamosumformuláriopassamosestepostcomouma instância,tantoquandosalvamoso formulário: form=PostForm(request.POST,instance=post) comoquandonósapenasabrimosumformuláriocomestepostparaeditar: form=PostForm(instance=post) Ok,vamostestarsefunciona!Vamosparaapágina post_detail.Devehaverumbotãoeditarnocantosuperiordireito: Quandovocêclicarnelevocêveráoformuláriocomanossapostagem: 95 Formulários Sinta-selivreparamudarotítuloouotextoesalvarasmudanças! Parabéns!Suaaplicaçãoestáficandocadavezmaiscompleta! SevocêprecisardemaisinformaçõessobreformuláriosdoDjangovocêdeveleradocumentação: https://docs.djangoproject.com/en/1.8/topics/forms/ Maisumacoisa:horadeimplantar! VamosversetudoissofuncionanaPythonAnywhere.Tempoparaoutrodeploy! Primeiro,commitoseunovocódigoecoloquenoGithub $gitstatus $gitadd--all. $gitstatus $gitcommit-m"Addedviewstocreate/editblogpostinsidethesite." $gitpush Então,emumconsolePythonAnywhereBash: $cdmy-first-blog $gitpull Finalmente,puleparaaWebtabeaperteReload. Edeveserisso!Parabéns:) 96 Formulários 97 Domínio Domínio PythonAnywheretedeuumdomíniogratuito,mastalvezvocênãoqueirater".pythonanywhere.com"nofinaldaURLdo seublog.Talvezvocêqueiraseublogapenas"www.infinite-kitten-pictures.org"ou"www.3d-printed-steam-engineparts.com"ou"www.antique-buttons.com"ou"www.mutant-unicornz.net",ousejaoquevaiser. Aquivamosfalarumpoucosobreondeobterumdomínioecomoligá-loaseuaplicativodawebemPythonAnywhere.No entanto,vocêdevesaberqueamaioriadosdomínioscustamdinheiroePythonAnyweretambémcobraumataxamensal parausarseupróprionomededomínio--nãoémuitodinheiro,nototal,masissoprovavelmenteéalgoquevocêsóquer fazersevocêestárealmentecomprometido! Onderegistrarumdomínio? Umdomínionormalcustamaisoumenos15dólaresporano.Existemdomíniosmaiscarosemaisbaratosdependendo doprovedor.Existemumasériedeempresasdasquaisvocêpodecomprarumdomínio:umasimplespesquisanogoogle podelistarumasériedelas. OnossofavoritoéoIwantmyname(euqueromeunome).Elesanunciamseuserviçocomo"gestãodedomínioindolor", eele,realmente,éindolor. Vocêtambémpodeobterdomíniosgratuitamente.dot.tkéumlugarparapegarum,masvocêdeveestarcientedeque domíniosgrátisàsvezesparecemmuitobaratos--seseusitevaiserparaumprofissionaldenegócios,vocêdevepensar empagarporumdomínio"correto"queterminaem .com. ComoapontarseudomínionoPythonAnywhere Sevocêpassouporiwantmyname.com,cliqueem domíniosnomenueescolhaseudomíniorecém-adquirido.Em seguida,localizeecliquenolink manageDNSrecords: Agoravocêprecisalocalizaresteformulário: Epreenchercomosseguintesdetalhes:-Hostname:www-tipo:CNAME-valor:seudomíniodePythonAnywhere(por exemplodjangogirls.pythonanywhere.com)-TTL:60 CliquenobotãoAdicionaresalveasmudançasnapartedebaixo. NotaSevocêusouumprovedordedomíniodiferente,oUIexataparaencontraroseuDNS/configuraçõesde CNAMEserádiferente,masseuobjetivoéomesmo:paraconfigurarumCNAMEqueapontaseunovodomíniono yourusername.pythonanywhere.com. 98 Domínio Podelevaralgunsminutosparaoseudomíniocomeçaratrabalhar,entãosejapaciente! Configureodomínioatravésdeumwebappna PythonAnywhere. VocêtambémprecisadizerPythonAnywherequevocêdesejausaroseudomíniopersonalizado. VáparaapáginaPythonAnywherecontaseupgradesuaconta.Aopçãomaisbarata(umplanode"Hacker")ébompara começar,vocêpodesempreatualizá-lomaistardequandovocêficarsuperfamosoetivermilhõesdeacessos. Emseguida,vánaWebtabeanotealgumascoisas: Copieocaminhoparaseuvirtualenvecoloqueemumlugarseguro Cliqueparaseuarquivodeconfiguraçãodowsgi,copieoconteúdoecoleemumlugarseguro. Emseguida,excluaseuantigowebapp.Nãosepreocupe,issonãovaiexcluirnadadoseucódigo,eleapenasiráse desligardodomínioyourusername.pythonanywhere.com.Emseguida,crieumnovoaplicativowebesigaestespassos: Digiteseunomededomínionovo Escolha"manualconfiguration" EscolhaPython3.4 Eéisso! Quandovocêtivervoltadoparaawebtab. Colarocaminhovirtualenvquevocêsalvouantes Clicarnoarquivodeconfiguraçãowsgiecolaroconteúdodoseuarquivodeconfiguraçãoantigo Cliqueemreloadwebappevocêdeveencontrarseusitelivenonovodomínio! Sevocêtiverqualquerproblema,cliquenolink"Enviarfeedback"nositePythonAnywhere,eumdosseusadministradores amigáveisvaiestarláparaajudá-lo. 99 Oquevemdepois? Oquevemdepois? Parabéns!Vocêédemais.Estamosorgulhosos!<3 Oquefazeragora? Façaumapausaerelaxe.Vocêacaboudefazeralgorealmentegrande. Depoisdisso: SigaDjangogirlsnoFacebookouTwitterparaficaratualizada Vocêpoderecomendaroutrasfontes? Sim!Primeiro,váemfrenteetentenossooutrolivro,chamadoDjangoGirlsTutorial:Extensions. Depoisvocêpodetentarasfonteslistadasabaixo.Todaselassãorecomendadas! Django'sofficialtutorial NewCodertutorials CodeAcademyPythoncourse CodeAcademyHTML&CSScourse DjangoCarrotstutorial LearnPythonTheHardWaybook GettingStartedWithDjangovideolessons TwoScoopsofDjango:BestPracticesforDjangobook 100