Tabela de conteúdos - we.riseup.net · Se você estiver em Mac ou num Linux, você provavelmente...
Transcript of Tabela de conteúdos - we.riseup.net · Se você estiver em Mac ou num Linux, você provavelmente...
1.1
1.2
1.3
1.4
1.5
1.6
1.7
1.8
1.9
1.10
1.11
1.12
1.13
1.14
1.15
1.16
1.17
1.18
1.19
1.20
1.21
1.22
1.23
1.24
TabeladeconteúdosIntrodução
Comofuncionaainternet?
Introduçãoàlinhadecomando
InstalaçãodoPython
EditordeCódigo
IntroduçãoaoPython
OqueéDjango?
InstalaçãodoDjango
Criandoumprojeto
ModelosdoDjango
Administração
Implantação!
Urls
Views-horadecriar!
IntroduçãoaHTML
DjangoORM(Querysets)
Dadosdinâmicosnostemplates
Templates
CSS-Deixemaisbonito
Estendendoostemplates
Ampliesuaaplicação
Formulários
Domínio
Oquevemdepois?
2
TutorialDjangoGirls
EstetrabalhoélicenciadosobalicençaCreativeCommonsAttribution-ShareAlike4.0.Paraverumacópiadestalicença,visitehttps://creativecommons.org/licenses/by-sa/4.0/
TranslationThistutorialhasbeentranslatedfromEnglishtoPortuguesebyagroupofawesomevolunteers.
Specialthanksforhelpgoesoutto:
AdailtondoNascimentoAdamVictorNazarethBrandizziAntonioLuisAnnandaSousaAdjamiltonJuniorBernardoFontesCamillaAchuttiCarlaSuarezCleitonLimaclemente.jnrdanieltexEricHidekiFlavioBarrosFabioC.BarrionuevodaLuzffabiorjGabrielaCavalcantedaSilvaLeandroSilvaAraujoLucasMagnum1pedroJoaoLuizLorencettiKatyannaMouraKleberCPinheiroLeandroBarbosaLeonardoAlvesdosSantosMarcelRibeiroDantasjoepreludianRafaelBiagionideFazioPabloPalaciosPauloAlemRaonyGuimaresCorreodoCarmoLisboaCardenasVivianMacedoWillieLawrence*RicardoManhãesSaviiWow!<3<3
IntroduçãoVocêjásentiucomoseomundofossecadavezmaissobretecnologiaequedealgumaformavocêtenhaficadopratrás?Vocêjáimaginoucomoseriacriarumwebsitemasnuncatevemotivaçãosuficienteparacomeçar?Vocêjápensouqueomundodosoftwareécomplicadodemaisatéparatentarfazeralgumacoisasozinho?
Bem,nóstemosboasnotíciasparavocê!Programaçãonãoétãodifícilquantopareceenósqueremostemostraroquãodivertidopodeser.
Estetutorialnãoirátetransformarmagicamenteemumprogramador.Sevocêquerserbomnissoprecisademesesouatémesmoanosdetreinoeprática.Masnósqueremostemostrarqueaprogramaçãooucriaçãodewebsitesnãoétãocomplicadaquantoparece.Nóstentaremosexplicarosdiferentespedaçostãobemquantopudermos,talquevocênãosesintaintimidadopelatecnologia.
Nósesperamosconseguirfazervocêamaratecnologiatantoquantonósamamos!
Oquevocêiráaprenderduranteotutorial?Quandovocêtiverterminadootutorialvocêteráumaaplicaçãowebsimplesefuncional:seupróprioblog.Nósvamosmostrarcomocolocá-loonline,paraqueoutrosvejamseutrabalho!
Eleseparecerá(maisoumenos)comisso:
Introdução
3
Sevocêseguirotutorialporcontaprópriaenãotiverumtreinadorparaajudaremcasodequalquerproblema,nós
temosumchatparavocê: 1.Nóspedimosaosnossostreinadoreseparticipantesanterioresparaacessaremládetemposemtemposeajudaremoutroscomotutorial!Nãotenhamedodefazersuaperguntalá!
OK,vamospelocomeço...
SobreotutorialecontribuiçõesEstetutorialémantidoporDjangoGirls.Sevocêencontrarquaisquererrosouquiseratualizarotutorial,porfavorsigaasorientaçõesdecontribuição.
Gostariadenosajudaratraduzirotutorialparaoutrosidiomas?nomomento,astraduçõesestãosendomantidasnaplataformacrowdin.comem:
https://crowdin.com/project/django-girls-tutorial
Seoseuidiomanãoestálistadonocrowdin,porfavoropenanewissueinformandooidiomaparaquepossamosadicioná-lo.
Introdução
4
ComofuncionaainternetEstecapítuloéinspiradonapalestra"ComoaInternetfunciona"deJessicaMcKellar(http://web.mit.edu/jesstess/www/).
ApostamosquevocêusaaInternettodososdias.Masvocêsaberealmenteoqueacontecequandovocêdigitaumendereçocomohttps://djangogirls.orgemseunavegadorepressiona'Enter'?
Aprimeiracoisaquevocêprecisaentenderéqueumsiteésóummontedearquivossalvosemumdiscorígido.Assimcomoseusfilmes,músicasoufotos.Noentanto,existeumapartequeéexclusivaparasites:essaparteincluicódigodecomputadorchamadoHTML.
Sevocênãoestiverfamiliarizadacomprogramação,podeserdifícilcompreenderoHTMLnocomeço,masseunavegadorweb(comooChrome,Safari,Firefox,etc)amaele.NavegadoresWebsãoprojetadosparaentenderessecódigo,seguirsuasinstruçõeseapresentartodosessesarquivosdequeseusiteéfeito,exatamentedojeitoquevocêquerqueelessejamapresentados.
Igualàtodososarquivos,osarquivosHTMLprecisamserarmazenadosemumdiscorígido.Paraainternet,nósusamosespeciaisepoderososcomputadoreschamadosdeservidores.Elesnãotêmtela,mouseouteclado,porquesuafinalidadeprincipalé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ãocomplicadaainterneté,vocêpodevisitarumsite(http://submarinecablemap.com/)quemostraummapacomoscabossubmarinos.Aquiestáumscreenshotdosite:
Comofuncionaainternet?
6
Fascinante,não?Mas,obviamente,nãoépossívelterumfioconectadoatodamáquinaligadanainternet.Logo,parachegaremumamáquina(porexemploaquelaondehttps://djangogirls.orgestásalva)nósprecisamospassarumarequisiçãoatravésdemuitasemuitasmáquinasdiferentes.
Separececomisso:
Comofuncionaainternet?
7
Imaginequequandovocêdigitahttps://djangogirls.org,vocêenviaumacartaquediz:"QueridoDjangoGirls,eudesejoverositedjangogirls.org.Envieelepramim,porfavor!"
Suacartavaiparaaagênciadoscorreiosmaispróximadevocê.Depoisvaiparaoutraqueéumpoucomaispertodeseudestinatário,depoisparaoutraeoutra,atéqueelasejaentregueaoseudestino.Oúnicodiferencialéquesevocêenviarcartas(pacotesdedados)comfreqüênciaparaomesmolugar,cadacartapodepassarpordiferentesagênciasdecorreios(roteadores),dependendodecomoelassãodistribuídasemcadaagência.
Comofuncionaainternet?
8
Sim,ésimplesassim.Vocêenviamensagenseesperaalgumaresposta.Claro,aoinvésdepapelecanetavocêusabytesdedados,masaideiaéamesma!
Aoinvésdeendereçoscomonomedarua,cidade,códigopostalenomedopaís,nósusamosendereçosIP.PrimeiroseucomputadorpedeaoDNS(DomainNameSystem-SistemadeNomedeDomínio)paratraduzirdjangogirls.orgparaumendereçoIP.Ofuncionamentodelesepareceumpoucocomasantigaslistastelefônicasondevocêpodeolharparaonomedapessoaquequerentraremcontatoeacharoseunúmerodetelefoneeendereço.
Quandovocêenviaumacarta,elaprecisatercertascaracterísticasparaserentreguecorretamente:umendereço,selo,etc.Vocêtambémusaumalinguagemqueoreceptadorcompreende,certo?Omesmoacontececompacotesdedadosquevocêenviaparaverumsite:vocêusaumprotocolochamadoHTTP(HypertextTransferProtocol-ProtocolodeTransferênciadeHipertexto).
Então,basicamente,quandovocêtemumsite,vocêprecisaterumservidor(máquina)ondeeleficahospedado.Oservidorestáàesperadequaisquerrequisiçõesrecebidas(cartasquesolicitamaoservidoroenviodoseusite)eeleenviadevoltaseusite(emoutracarta).
ComoesteéumtutorialdeDjangovocêvaiperguntaroqueoDjangofaz.Quandovocêenviaumarespostanemsemprevocêquerenviaramesmacoisaparatodomundo.Serámuitomelhorsesuascartasforempersonalizadas,diferenciadaparaapessoaqueacaboudeescreverparavocê,certo?ODjangoajudavocêacriaressaspersonalizadaseinteressantescartas:).
Chegadefalar,éhoradecriar!
Comofuncionaainternet?
9
IntroduçãoàlinhadecomandoÉemocionante,não?!Vocêvaiescreversuaprimeiralinhadecódigoempoucosminutos:)
Deixe-nosapresentá-loaoseuprimeironovoamigo:alinhadecomando!
Asetapasaseguirmostrarãoavocêcomousarajanelapretaquetodososhackersusam.Podeparecerumpoucoassustadornocomeço,masrealmenteéapenasumpromptesperandoporcomandosdevocê.
Qualéalinhadecomando?Ajanela,quenormalmenteéchamadadelinhadecomandoouinterfacedelinhadecomando,éumaplicativobaseadoemtextoparavisualização,manipulaçãoemanuseiodearquivosemseucomputador(comoporexemplo,oWindowsExplorerouoFindernoMac,masseminterfacegráfica).Outrosnomesparaalinhadecomandosão:cmd,CLI,prompt,consoleouterminal.
AbraainterfacedelinhadecomandoParacomeçaralgunsexperimentos,precisamosabriranossainterfacedelinhadecomandoprimeiro.
WindowsVáemIniciar→TodososProgramas→Acessórios→Promptdecomando.
MacOSXApplications→Utilities→Terminal.
LinuxProvavelmentevocêvaiacharemApplications→Accessories→Terminal,masissodependedoseusistemaoperacional.QualquercoisaésóprocurarnoGoogle:)
PromptAgoravocêdeveverumajanelabrancaoupretaqueestáàesperadeseuscomandos.
SevocêestiveremMacounumLinux,vocêprovavelmenteveráum``$,comoeste:
$
NoWindows,éumsinalde>,comoeste:
>
Cadacomandoseráantecedidoporestesinaleumespaço,masvocênãoprecisadigitá-lo.Seucomputadorfaráissoporvocê:)
Apenasumapequenanota:noseucaso,talvezháalgocomoC:\Users\ola>ouOlas-MacBookAir:~ola$antesdosinaldopromptistoestará100%correto.Nestetutorialnósapenassimplificaremoseleparaomínimo.
Introduçãoàlinhadecomando
10
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ásicoCadasistemaoperacionaltemoseupróprioconjuntodeinstruçõesparaalinhadecomando,entãosecertifiquequevocêestáseguindoasinstruçõesdoseusistemaoperacional.Vamostentar,certo?
PastaatualSerialegalsaberemquepastaestamosagora,certo?Vamosver.Digiteoseguintecomandoseguidodeumenter:
$pwd
/Users/olasitarska
SevocêestivernoWindows:
>cd
C:\Users\olasitarska
Provavelmentevocêvaiveralgoparecidonasuamáquina.UmvezquevocêabrealinhadecomandovocêjácomeçanapastaHome.
Nota:'pwd'significa'printworkingdirectory'.
Listandoarquivosepastas
Entãooquetemnele?Serialegaldescobrir.Vamosver:
$ls
Applications
Desktop
Downloads
Music
...
Windows:
Introduçãoàlinhadecomando
11
>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êdigitarcdDeapertarateclatabnoseuteclado,alinhadecomandoirápreencherautomaticamenteorestodonomeparaquevocêpossanavegarrapidamente.Sehouvermaisdeumapastaquecomececom"D",aperteateclatabduasvezesparaobterumalistadeopções.
Criandoumapasta
QuetalcriarumdiretórioDjangoGirlsnasuaáreadetrabalho?Vocêpodefazerassim:
$mkdirdjangogirls
Windows:
>mkdirdjangogirls
Estecomandovaicriarumapastacomonomedjangogirlsnonossodesktop.Vocêpodeverificarseeleestálá,sódeolharnasuaáreadetrabalhoouexecutandoumcomandols(MacouLinux)oudir(Windows)!Experimente:)
Dicadeprofissional:Sevocênãoquiserdigitaromesmocomandováriasvezes,tentepressionarsetaparacimaesetaparabaixonotecladoparapercorrercomandosusadosrecentemente.
Exercite-se!
Introduçãoàlinhadecomando
12
Umpequenodesafioparavocê:nasuamaisnovapastacriadadjangogirlscrieumaoutrapastachamadateste.Useoscomandoscdemkdir.
Solução:
$cddjangogirls
$mkdirteste
$ls
teste
Windows:
>cddjangogirls
>mkdirteste
>dir
05/08/201407:28PM<DIR>teste
Parabéns!:)
LimpandoNãoqueremosdeixarumabagunça,entãovamosremovertudooquefizemosatéagora.
PrimeiroprecisamosvoltarparaapastaDesktop:
$cd..
Windows:
>cd..
Fazendocdpara..nósmudaremosdodiretórioatualparaodiretóriopai(quesignificaodiretórioquecontémodiretórioatual).
Vejaondevocêestá:
$pwd
/Users/olasitarska/Desktop
Windows:
>cd
C:\Users\olasitarska\Desktop
Agoraéhoradeexcluirodiretóriodjangogirls.
Atenção:Aexclusãodearquivosusandodel,rmdirourméirrecuperável,significandoArquivosexcluídosvãoemboraparasempre!Então,tenhacuidadocomestecomando.
$rm-rdjangogirls
Windows:
>rmdir/Sdjangogirls
djangogirls,Temcerteza<S/N>?S
Introduçãoàlinhadecomando
13
Pronto!Paratercertezaqueapastafoiexcluída,vamoschecar:
$ls
Windows:
>dir
SaindoPorenquantoéisso!Agoravocêfecharalinhadecomandocomsegurança.Vamosfazerdojeitohacker,certo?:)
$exit
Windows:
>exit
Legal,né?:)
SumárioAquivaiumalistadealgunscomandosúteis:
Comando(Windows)
Comando(MacOS/Linux) Descrição Exemplo
exit exit Fechaajanela exit
cd cd Mudaapasta cdtest
dir ls Listaaspastaseosarquivos dir
copy cp Copiaumarquivo copyc:\test\test.txtc:\windows\test.txt
move mv Moveumarquivo movec:\test\test.txtc:\windows\test.txt
mkdir mkdir Criaumapasta mkdirtestdirectory
del rm Deletaumapastae/ouarquivo delc:\test\test.txt
Estessãoapenasalgunsdospoucoscomandosquevocêpodeexecutaremsualinhadecomando,masvocênãovaiusarmaisnadadoqueistohoje.
Sevocêestivercurioso,ss64.comcontémumareferênciacompletadecomandosparatodosossistemasoperacionais.
Pronto?VamosmergulharnoPython!
Introduçãoàlinhadecomando
14
VamoscomeçarcomPythonFinalmentechegamosaqui!
Masprimeiro,vamosfalarumpoucosobreoqueoPythoné.Pythonéumalinguagemdeprogramaçãomuitopopularquepodeserusadaparacriarsites,jogos,softwarescientíficos,gráficosemuito,muitomais.
OPythonéorigináriodadécadade1980eseuprincipalobjetivoéserlegívelporsereshumanos(nãoapenasmáquinas!),porissoeleparecemuitomaissimplesdoqueoutraslinguagensdeprogramação.Issofazelemaisfácildeaprender,masnãoseengane,Pythontambémémuitopoderoso!
InstalaçãodoPythonEstesubcapítuloébaseadoemumtutorialcriadoporGeekGirlsCarrots(https://github.com/ggcarrots/django-carrots)
DjangoéescritoemPython.NósprecisamosdeleparafazerqualquercoisaemDjango.Vamoscomeçarcomsuainstalação!NósqueremosquevocêinstaleoPython3.4,entãosevocêtemqualquerversãoanterior,vocêvaiprecisaratualizá-la.
Windows
VocêpodebaixaroPythonparaWindowsnowebsitehttps://www.python.org/downloads/release/python-343/.Depoisdefazerodownloaddoarquivo*.msi,vocêprecisaexecutá-lo(dandoumduplo-cliquenele)eseguirasinstruções.Éimportantelembrarocaminho(apasta)ondevocêinstalouoPython.Elaseráútildepois!
Cuidadocomumacoisa:nasegundateladoassistentedeinstalação,marcado"Customize",certifique-sevocêrolarparabaixoeescolhaaopção"Adicionarpython.exeparaocaminho",comoem
InstalaçãodoPython
15
Linux
ÉmuitoprovávelquevocêjátenhaoPythoninstaladoeconfigurado.Paratercertezaseeleestáinstalado(equalasuaversã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çãofoibemsucedidaabrindooTerminaledigitandoocomandopython3:
$python3--version
Python3.4.2
Sevocêtiverqualquerdúvidaousealgumacoisadeuerradoevocênãosabeoquefazer-porfavorpergunteaoseuinstrutor!Àsvezes,ascoisasnãoestãoindobemeémelhorpedirajudaaalguémcommaisexperiência.
InstalaçãodoPython
16
EditordeCódigoVocêestáprestesaescreversuaprimeiralinhadecódigo,entãoéhoradebaixarumeditordecódigo!
Existemmuitoseditoresdiferenteseemgrandeparteseresumeapreferênciapessoal.AmaioriadosprogramadoresPythonusaascomplexas,masextremamentepoderosasIDEs(IntegratedDevelopmentEnvironments,ouemportuguês,AmbientededesenvolvimentoIntegrado),taiscomoPyCharm.Parauminiciante,entretanto,estasIDE'ssãomenosconvenientes;nossasrecomendaçõessãobemmaissimples,porém,igualmentepoderosas.
Nossassugestõesestãoabaixo,massinta-selivreparaperguntaraoseucoachquaissãoassuaspreferências-assimvaisermaisfácilobteraajudadeles.
GeditGeditéumeditoropen-source,gratuito,disponívelparatodosossistemasoperacionais.
Baixeaqui
SublimeText3SublimeText3éumeditormuitopopularcomumperíododeavaliaçãogratuita.Éfácildeinstalareusar,eestádisponívelparatodosossistemasoperacionais.
Baixeaqui
AtomAtoméumnovoeditordecódigocriadopeloGitHub.Eleégratuito,open-source,fácildeinstalarefácildeusar.EstádisponívelparaWindows,OSXeLinux.
Baixeaqui
Porqueestamosinstalandoumeditordecódigo?VocêdeveestarseperguntandoporqueestamosinstalandoessesoftwareeditordecódigoespecialaoinvésdeusaralgocomoWordouBlocodeNotas.
Primeiroéquecódigoprecisasertextosemformatação,eoproblemacomprogramascomoWordeTexteditéqueelesnaverdadenãoproduzemtextosemformatação,elesfazem"richtext"(comfonteseformatação),usandoformatospersonalizadoscomoRTF.
Asegundarazãoéqueeditoresdecódigosãoespecializadosemeditarcódigo,entãoelespodemoferecerrecursosúteis,comorealcedecódigocomcoresdeacordocomoseusignificado,ouautomaticamentefecharcitaçõesparavocê.
Nósvamosverissoemaçãodepois.Embrevevocêteráseueditordecódigocomoumadassuasferramentasfavoritas.:)
EditordeCódigo
17
IntroduçãoaoPythonPartedestecapítuloébaseadonosTutoriaisdeGeekGirlsCarrots(https://github.com/ggcarrots/django-carrots).
Vamosescreverumpoucodecódigo!
InterpretadorPythonParacomeçarabrincarcomPythonnósprecisamosabrirumalinhadecomandonoseucomputador.Vocêjádevesabercomofazerisso--vocêaprendeuissonocapítuloIntroduçãoàLinhadeComando.Assimqueestiverpronto,sigaasinstruçõesabaixo.
NósqueremosabriroPythonnumterminal,entãodigitepython3etecleEnter.
$python3
Python3.4.2(...)
Type"copyright","credits"or"license"formoreinformation.
>>>
SeuprimeirocomandoPython!DepoisdeexecutarocomandoPython,opromptmudoupara>>>.Paranós,issosignificaqueporenquantosóutilizaremoscomandosnalinguagemPython.Vocênãoprecisadigitar>>>-OPythonfaráissoporvocê.
SevocêdesejasairdoconsoledoPython,apenasdigiteexit()ouuseoatalhoCtrl+ZnoWindowseCtrl+DnoMac/Linux.Entãovocênãovaivermaiso>>>.
MasagoranãoqueremossairdalinhadecomandodoPython.Queremosaprendermaissobreele.Vamos,então,fazeralgomuitosimples.Porexemplo,tentedigitaralgumaoperaçãomatemática,como2+3eaperteEnter.
>>>2+3
5
Incrível!Vêcomoarespostasimplesmenteaparece?OPythonconhecematemática!Vocêpodetentaroutroscomandoscomo:-4*5-5-1-40/2
Divirta-secomissoporumtempoedepoisvolteaqui:).
Comovocêpodever,oPythonéumaótimacalculadora.Sevocêestáseperguntandooquemaisvocêpodefazer...
StringsQuetaloseunome?Digiteseuprimeironomeentreaspas,dessejeito:
>>>"Ola"
'Ola'
Vocêacaboudecriarsuaprimeirastring!Stringéumsequênciadecaracteresquepodemserprocessadapelocomputador.Astringsempreprecisainiciareterminarcomomesmocaractere.Estepodeseraspasduplas(')ousimples(")-elasdizemaoPythonqueoqueestádentrodelaséumastring.
Stringspodemserjuntadas.Tenteisto:
IntroduçãoaoPython
18
>>>"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çãouppernasuastring!Umafunção(comoupper())éumconjuntodeinstruçõesqueoPythonrealizaemumdeterminadoobjeto("Ola"),semprequevocêchamarporele.
Sevocêquersaberonúmerodeletrasdoseunome,existeumafunçãoparaissotambém!
>>>len("Ola")
3
Seperguntandoporquealgumasvezesvocêchamafunçõescomum.nofimdeumastring(como"Ola".upper())ealgumasvezesvocêprimeirochamaafunçãocolocandoastringnosparênteses?Bem,emalgunscasos,funçõespertencemaobjetos,comoupper(),quesópodeserutilizadaemstrings.Nessecaso,nóschamamosafunçãodemétodo.Outrasvezes,funçõesnãopertencemanadaespecíficoepodemserusadasemdiferentestiposdeobjetos,assimcomolen().Éporissoquenósestamosfornecendo"Ola"comoumparâmetroparaafunçãolen.
Sumário
OK,chegadestrings.Atéagoravocêaprendeusobre:
oprompt-digitarcomandos(códigos)nointerpretadorPythonresultaemrespostasemPythonnúmerosestrings-noPython,númerossãousadosparamatemáticaestringsparaobjetosdetextooperadores-como+e*,combinamvaloresparaproduzirumnovovalorfunções-comoupper()elen(),executamaçõesnosobjetos.
Issoéobásicosobretodasaslinguagensdeprogramaçãoquevocêaprende.Prontoparaalgomaisdifícil?Apostamosquesim!
ErrosVamostentaralgonovo.Podemosobterotamanhodeumnúmerodamesmaformaquepodemosencontrarotamanhodonossonome?Digitelen(304023)epressioneEnter:
IntroduçãoaoPython
19
>>>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êmumcomprimento,certo?
>>>len(str(304023))
6
Funcionou!Usamosafunçãostrdentrodafunçãolen.str()convertetudoparastrings.
AfunçãostrconverteascoisasemstringsAfunçãointconverteascoisasemnúmerosinteiros
Importante:podemosconverternúmerosemtexto,masnósnãopodemos,necessariamente,convertertextoemnúmeros-oqueint('hello')querdizer?
VariáveisUmconceitoimportantenaprogramaçãoéoconceitodevariáveis.Umavariávelnãoénadamaisdoqueumnomeparaalgumacoisa,detalformaquevocêpossausá-lamaistarde.Osprogramadoresusamessasvariáveisparaguardardados,parafazerseuscódigosmaislegíveiseparanãoterqueselembrarsempreoquealgumascoisassignificam.
Digamosquequeremoscriarumanovavariávelchamadanome:
>>>nome="Ola"
Vê?Éfácil!Ésófazer:nomeigualaOla.
Comovocêpercebeu,seuprogramanãoretornounadacomofezanteriormente.Entãocomosabemosqueavariávelrealmenteexiste?SimplesmentedigitenomeetecleEnter:
>>>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
IntroduçãoaoPython
20
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áesteerrosevocêtentarusarumavariávelquenãofoidefinidaainda.Sevocêencontraresseerrodepois,vejasenoseucódigosevocênãodigitouonomedeumavariávelerrado.
Brinquecomissoporumtempoevejaoquevocêconseguefazer!
AfunçãoprintTenteisso:
>>>nome='Maria'
>>>nome
'Maria'
>>>print(nome)
Maria
Quandovocêapenasdigitanome,ointerpretadorPythonrespondecomarepresentaçãocomostringdavariável'name',quesãoasletrasM-a-r-i-a,entreaspassimples.Quandovocêdizprint(nome),Pythonvai"imprimir"oconteúdodavariávelnatela,semasaspas,oqueémaispuro.
Comoveremosmaistarde,print()tambéméútilquandoqueremosimprimiralgodentrodefunções,ouquandoqueremosimprimiralgoemváriaslinhas.
ListasAlémdestringseinteiros,oPythontemtodosostiposdiferentesdeobjetos.Vamosapresentarumchamadolista.Listassãoexatamenteoquevocêachaqueelassão:elassãoobjetosquesãolistasdeoutrosobjetos:)
Váemfrenteecrieumalista:
>>>[]
[]
Sim,estaéumalistavazia.Nãoémuito,nãoé?Vamoscriarumalistadosnúmerosdaloteria.Comonãoqueremosficarrepetindoocódigotodootempovamoscriarumavariávelparaela:
>>>loteria=[3,42,12,19,30,59]
Tudocerto,nóstemosumalista!Oquepodemosfazercomisso?Vamosverquantosnúmerosdeloteriaexistemnestalista.Vocêtemideiadequalfunçãodeveusarparaisso?Vocêjásabedisso!
>>>len(loteria)
6
Sim!len()podetedaronúmerodeobjetosquefazempartedeumalista.Umamãonaroda,não?Vamosorganizarissoagora:
IntroduçãoaoPython
21
>>>loteria.sort()
Issonãoretornanada,apenastrocaaordememqueosnúmerosaparecemnalista.Vamosimprimirissooutravezeveroqueacontece:
>>>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úmeroquedizondeumitemdalistaestá.Oscomputadoresgostamdeiniciaracontagempor0,entãooprimeiroobjetotemíndice0,opróximotemíndice1eporaívai.Tenteisso:
>>>print(loteria[0])
59
>>>print(loteria[1])
42
Comovocêpodever,vocêpodeacessardiferentesobjetosnasualistausandoonomedalistaeoíndicedoobjetodentrodoscolchetes.
Pordiversãoextra,tentealgunsoutrosíndices:6,7,1000,-1,-6ou-1000.Vejasevocêconseguepreveroresultadoantesdetentarocomando.Osresultadosfazemsentido?
VocêpodeencontrarumalistadetodososmétodosdisponíveisnestecapítulonadocumentaçãodoPython:https://docs.python.org/3/tutorial/datastructures.html
DicionáriosUmdicioná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ávelchamadaparticipantcomtrêsparesdechave-valor:
IntroduçãoaoPython
22
Achavenomeapontaparaovalor'Ola'(umobjetostring),paisapontapara'Polonia'(outrastring),enumeros_favoritosapontampara[7,42,92](umalistcomtrêsnúmerosnela).
Vocêpodechecaroconteúdodechavesindividuaiscomasintaxe:
>>>print(participante['nome'])
Ola
Veja,ésimilaraumalista.Masvocênãoprecisalembraroíndice-apenasonome.
OqueacontecesepedirmosaoPythonovalordeumachavequenãoexiste?Vocêconsegueadivinhar?Vamostentaredescobrir!
>>>participante['idade']
Traceback(mostrecentcalllast):
File"<stdin>",line1,in<module>
KeyError:'idade'
Olha,outroerro!EsseéumKeyError.Pythonébastanteprestativoetedizqueachave'idade'nãoexistenessedicionário.
Quandousarumdicionarioouumalista?Bem,umbompontopararefletir.Penseemumasoluçãoantesdeolhararespostanapróximalinha.
Vocêprecisadeumasequênciaordenadadeitens?Useumalist.Vocêprecisaassociarvalorescomchaves,assimvocêpodeprocurá-loseficientemente(pelachave)maistarde?Useumdictionary.
Dicionários,comolistas,sãomutáveis,ouseja,quepodemsermudadosdepoisquesãocriados.Vocêpodeadicionarnovosparesdechave/valorparaodicionárioapóssuacriação,como:
>>>participante['linguagem_favorita']='Python'
Comoaslists,usarométodolen()emdicionáriosretornaonúmerodepareschave-valornodicionario.Váemfrenteedigiteocomando:
>>>len(participante)
4
Esperoqueagorafaçasentidoatéagora.:)Prontaparamaisdiversãocomdicionários?Pulenapróximalinhaparacoisasincríveis.
Vocêpodeusarocomandopop()paradeletarumitemnodicionario.Digamos,sevocêquerexcluiraentradacorrespondenteachave'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'}
IntroduçãoaoPython
23
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êdeuvariáveis-nomesparaobjetosquepermitemvocêprogramarfacilmenteedeixarseucódigomaislegívellistas-listasdeobjetosarmazenadosemumaordemespecíficadicionários-objetosarmazenadoscomopareschave-valor
Empolgado(a)paraopróximopasso?:)
ComparecoisasGrandepartedaprogramaçãoconsisteemcompararcoisas.Oqueémaisfácildecomparar?Números,éclaro.Vamosvercomoissofunciona:
>>>5>2
True
>>>3<1
False
>>>5>2*2
True
>>>1==1
True
>>>5!=2
True
DemosaoPythonalgunsnúmerosparacomparar.Comovocêpodever,Pythonpodecompararnãosónúmerosmastambémresultadosdemétodos.Legal,hein?
Vocêestáseperguntandoporquecolocamosdoissinaisdeigual==ladoaladoparacompararseosnúmerossãoiguais?Nósusamosumúnico=paraatribuirvaloresavariáveis.Vocêsempre,sempreprecisacolocardois==sequiserverificarseascoisassã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émaiorqueyx<ysignifica:xémenorqueyx<=ysignifica:xémenorouigualayx>=ysignifica:xémaiorouigualay
Fantástico!Quermais?Tenteisto:
IntroduçãoaoPython
24
>>>6>2and2<3
True
>>>3>2and2<1
False
>>>3>2or2<1
True
VocêpodedaraoPythonquantosnúmerosparacompararquantovocêquiser,eelevaitedarumaresposta!Espertinho,certo?
and-sevocêusarooperadorand,ambasascomparaçõesterãoqueserverdadeirasparaquetodoocomandosejaverdadeiroor-sevocêusarooperadoror,apenasumadascomparaçõesprecisaserverdadeiraparaqueocomandotodosejaverdadeiro
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).Emvezdisso,elemostrouumTypeErrorenosdissequeosdoistiposnãopodemsercomparadosjuntos.</p>
BooleanoAcidentalmente,vocêaprendeusobreumnovotipodeobjetoemPython.Échamadodebooleano--eprovavelmenteotipomaisfácilqueexiste.
Existemapenasdoisobjetosbooleanos:-True(verdadeiro)-False(falso)
MasparaoPythonentenderisso,vocêprecisasempreescreverTrue(primeiraletramaiúscula,comorestodasletrasemminú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!
IntroduçãoaoPython
25
Atéagoranósescrevemostodonossocódigoemuminterpretadorpython,quenoslimitaaumalinhadecódigoemummomento.Programasnormaissãosalvosemarquivoseexecutadospelonossointerpretadordelinguagemdeprogramaçãooucompilador.AtéagorajácorremosnossosprogramasdeumalinhadecadaveznointerpretadorPython.Nósvamosprecisardemaisdeumalinhadecódigoparaaspróximastarefas,entãoprecisaremosrapidamente:
SairdointerpretadorPythonAbriroeditordecódigodesuaescolhaSalvaralgumcódigoemumnovoarquivopythonExecutá-lo!
ParasairdointerpretadorPythonqueestamosusando,simplesmentedigiteafunçãoexit():
>>>exit()
$
Issovaicolocá-lanopromptdecomando.
Anteriormente,nósescolhemosumeditordecódigodaseçãodoeditordecódigo.Nósprecisamosabriroeditoragoraeescreveralgumcódigoemumnovoarquivo:
print('Hello,Djangogirls!')
NotaVocêdeveobservarqueumadascoisasmaislegaissobreeditoresdecódigo:cores!NoconsoledoPython,tudoeradamesmacor,masagoravocêdeveverqueafunçãodeImprimiréumacordiferentedasequênciadecaracteresnoseuinterior.Issoéchamadode"realcedesintaxe",eéumaajudamuitoútilquandoestáprogramando.Percebaacordascoisasevocêvaiobterumadicaparaquandovocêesquecerdefecharumaseqüênciadecaracteres,oufazerumerrodedigitaçãoemumnomedepalavra-chave(comodefemumafunção,queveremosabaixo).Estaéumadasrazõespelasquaisquenósusamosumeditordecódigo:)
Obviamente,vocêéumdesenvolvedorpythonbastanteexperienteagora,entãosinta-selivreparaescreverumcódigoquevocêaprendeuhoje.
Agoratemosdesalvaroarquivoedêumnomedescritivo.Vamoschamaroarquivopython_intro.pyesalve-oemseudesktop.Podemosnomearoarquivotudooquequisermos,oimportanteaquiétercertezaqueoarquivoterminanopy,istodiznossocomputador,queéumarquivoexecutáveldepythonePythonpodeexecutá-lo.
Comoarquivosalvo,éhoradeexecutá-lo!Usandoashabilidadesquevocêaprendeunaseçãodelinhadecomando,useoterminalaltereosdiretó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!
IntroduçãoaoPython
26
Tudobem!Vocêacaboudeexecutarseuprimeiroprogramaempythonquefoisalvoemumarquivo.Sesenteótima?
Vocêpodeagorapassarparaumaferramentaessencialnaprogramação:
if...elif...elseMuitascoisasnocódigosópodemserexecutadassedeterminadascondiçõesforematendidas.ÉporissoqueoPythontemalgumacoisachamadadeclaraçã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ção3>2venhaaserverdadeira(ouTruenessecaso).VamostentarfazeroPythonimprimir"Itworks!".Altereoseucódigonoseuarquivopython_intro.pyparaisto:
if3>2:
print('Itworks!')
Vocêpercebeuqueidentamosapróximalinhacom4espaços?PrecisamosfazerissoparaqueoPythonsaibaqualcódigoseráexecutadoseoresultadoforTrue.Vocêpodefazercom1espaço,masquasetodososprogramadoresPythonfazemcom4paradeixarascoisasarrumadas.Umúnicotabtambémvaicontarcomo4espaços.
Salvá-loeexecutenovamente:
$python3python_intro.py
Itworks!
Esenão?
Nosexemplosanteriores,ocódigofoiexecutadosomentequandoascondiçõeseramverdade.MasoPythontambémteminstruçõeselifeelse:
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é?Vamosvercomofuncionaoelif:
IntroduçãoaoPython
27
name='Sonja'
ifname=='Ola':
print('HeyOla!')
elifname=='Sonja':
print('HeySonja!')
else:
print('Heyanonymous!')
eexecutado:
$python3python_intro.py
HeySonja!
Viuoqueaconteceu?
SumárioNosúltimostrêsexercíciosvocêaprendeu:
compararascoisas-emPython,vocêpodecompararascoisasusandoosoperadores>,>=,==,<=,<eoand,orBooleano-umtipodeobjetoquesótemumdosdoisvalores:TrueouFalseSalvandoarquivos-armazenamentodecódigoemarquivosassimvocêpodeexecutarprogramasmaiores.if...elif...else-instruçõesquepermitemquevocêexecuteocódigosomentesedeterminadascondiçõesforematendidas.
Éhoradaúltimapartedestecapítulo!
Suasprópriasfunções!Selembradefunçõescomolen()quevocêpodeexecutarnoPython?Bem,boasnotícias,agoravocêvaiaprenderaescreversuasprópriasfunções!
UmafunçãoéumasequênciadeinstruçõesqueoPythondeveexecutar.CadafunçãoemPythoncomeçacomapalavra-chavedef,seguidodeumnomeparaafunçãoeopcionalmenteumalistadeparâmetros.Vamoscomeçarcomumafunçãosimples.Substituaocódigonopython_intro.pycomoseguinte:
defhi():
print('Hithere!')
print('Howareyou?')
hi()
Ok,nossaprimeirafunçãoestápronta!
Vocêpodeseperguntarporqueescrevemosonomedafunçãonaparteinferiordoarquivo.IstoéporquePythonlêoarquivoeexecutadecimaparabaixo.Então,parausaranossafunção,temosdeescrevê-lonaparteinferior.
Vamosexecuta-loagoraeveroqueacontece:
$python3python_intro.py
Hithere!
Howareyou?
Issofoifácil!Vamosconstruirnossaprimeirafunçãocomparâmetros.Usaremosoexemploanterior-umafunçãoquediz'hi'paraquemoexecuta-comumname:
IntroduçãoaoPython
28
defhi(name):
Comovocêpodever,agorademosumparâmetrochamadonameparanossafunção:
defhi(name):
ifname=='Ola':
print('HiOla!')
elifname=='Sonja':
print('HiSonja!')
else:
print('Hianonymous!')
hi()
Comovocêpodever,nósprecisamoscolocardoisespaçosantesdafunçãoprint,porqueifprecisasaberoquedeveacontecerquandoacondiçã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çãohi()(aquelaquedeclaramos)temumargumentoobrigatório(chamadoname)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á-loeversevocêestácerto.Eledeveimprimiristo:
Hianonymous!
Istoéincrível,não?Dessamaneiravocênãoprecisaserepetir(DRY-don'trepeatyourself,ouemportuguês,nãoserepita)cadavezqueformudaronomedapessoaqueafunçãopretendecumprimentar.Eéexatamenteporissoqueprecisamosdefunções-vocênuncaquerrepetirseucódigo!
Vamosfazeralgomaisinteligente..--existemmaisquedoisnomes,eescreverumacondiçãoparacadaumseriadifícil,certo?
IntroduçãoaoPython
29
defhi(name):
print('Hi'+name+'!')
hi("Rachel")
Vamoschamarocódigoagora:
$python3python_intro.py
HiRachel!
Parabéns!Vocêacaboudeaprenderacriarfunções:)!
LaçosJáéaúltimaparte.Foirápido,não?:)
Comomencionamos,osprogramadoressãopreguiçosos,nãogostamderepetirasmesmascoisas.Programaçãofalasobrecomoautomatizarascoisas,entãonãoqueremoscumprimentarcadapessoapeloseunomemanualmente,certo?Éaíondeoslaçosvemacalhar.
Aindaselembradaslistas?Vamosfazerumalistadegarotas:
girls=['Rachel','Monica','Phoebe','Ola','You']
Queremoscumprimentartodaselaspelosseusnomes.Temosafunçãohiparafazerisso,entãovamosusá-laemumloop:
fornameingirls:
Oforsecomportadamesmaformaqueoif,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çãoforcomespaçoserárepetidoparacadaelementodalistagirls.
Vocêtambémpodeusaroforemnúmerosusandoafunçãorange:
IntroduçãoaoPython
30
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(emrange(1,6),contade1a5,maso6nãoéincluído).
SumárioÉisso.Vocêétotalmentedemais!Nãoétãofácil,entãovocêdevesesentirorgulhosadesimesma.Estamosdefinitivamenteorgulhosasdevocêporterchegadoatéaqui!
Talvezvocêqueirabrevementefazeralgomais-espreguiçar,andarumpouco,descansarosolhos-antesdeirparaopróximocapítulo.:)
IntroduçãoaoPython
31
OqueéDjango?Djangoéumframeworkgratuitoedecódigoabertoparaacriaçãodeaplicaçõesweb,escritoemPython.Éumframeworkweb,ouseja,éumconjuntodecomponentesqueajudaadesenvolversitesdeformamaisrápidaemaisfácil.
Veja,quandovocêestáconstruindoumsite,vocêsempreprecisaumconjuntosimilardecomponentes:umamaneiradelidarcomaautenticaçãodousuário(inscrever-se,realizarlogin,realizarlogout),paineldegerenciamentoparaoseusite,formulários,uploaddearquivos,etc.
Felizmenteparavocê,hámuitotempo,outraspessoasnotaramváriassemelhançasnosproblemasenfrentadospelosdesenvolvedoreswebquandoestãocriandoumnovosite,entãoelesuniram-seecriaramosframeworks(Djangoéumdeles)quelhedãocomponentesprontos,quevocêpodeusar.
Frameworksexistemparasalvá-lodeterquereinventararodaeajudamaaliviarasobrecargaquandovocêestáconstruindoumnovosite.
Porquevocêprecisadeumframework?ParaentenderoqueDjangoénaverdade,precisamosolharmaisdepertoosservidores.Aprimeiracoisaéqueoservidorprecisasaberoquevocêquerparaservi-loumapáginadaWeb.
Imagineumacaixadecorreio(porta)queémonitoradaporcartasrecebidas(requisição).Issoéfeitoporumservidorweb.Oservidorweblêacartaeenviaumarespostacomumapáginaweb.Mas,quandovocêquerenviaralgumacoisavocêprecisaterumconteúdo.EoDjangoéaquiloquevailheajudaracriaresseconteúdo.
Oqueacontecequandoalguémsolicitaumsitedoseuservidor?QuandochegaumarequisiçãoparaoservidorwebelaépassadaparaoDjangoquetentadescobrirdoqueelasetrata.Primeiroelepegaumendereçowebetentadescobriroquefazer.EssaparteéfeitapelourlresolverdoDjango.(NotequeoendereçodeumsitesechamaURL-UniformResourceLocator,emportuguêsLocalizadordeRecursosUniforme,dessaformaonomeurlresolver,ouresolvedordeurls,fazsentido).Issonãoémuitointeligente-levaàumalistadepadrõesetentacorresponderaURL.ODjangoverificapadrõesdecimaparabaixoesealgoécorrespondido,passaasolicitaçãoparaafunçãoassociada(queéchamadaview).
Imagineumcarteirocomumacarta.Elaestáandandopelaruaeverificacadanúmerodecasacomaqueestánacarta.Seelecorresponder,elacolocaacartalá.Éassimquefuncionaourlresolver!
Todasascoisasinteressantessãofeitasdentrodaview:podemosdarumaolhadanobancodedadosparaprocuraralgumasinformações.Talvezousuárioqueiramudaralgonosdados?Comoumacartadizendo:"Porfavormudeadescriçãodomeuemprego."-aviewchecasevocêtempermissãoparafazerissoeentãoatualizaadescriçãodoempregopravocê,enviandoemseguidaumamensagem:"Feito!".EntãoaviewgeraumarespostaeoDjangopodeenviá-laparaonavegadordocliente.
Claro,adescriçãoacimaémuitosimplificada,masvocênãoprecisasaberdetalhestécnicosainda.Terumaideiageraljáésuficiente.
Entãoemvezdemergulharemmuitosdetalhes,nóssimplesmentevamoscomeçarcriandoalgocomoDjangoeaprenderemostodasaspartesimportantesaolongodocaminho!
OqueéDjango?
32
InstalaçãodoDjangoPartedestecapítuloébaseadonostutoriaisdoGeekGirlsCarrots(https://github.com/ggcarrots/django-carrots).
Partedestecapítuloébaseadonodjango-marcadortutoriallicenciadosobreCreativeCommonsAttribution-ShareAlike4.0InternationalLicense.Otutorialdodjango-marcadoréprotegidopordireitosautoraisporMarkusZapke-Gründemannetal.
AmbientevirtualAntesdeinstalarmosoDjango,nósiremosinstalarumaferramentaextremamenteútilqueiráajudaramanterseuambientededesenvolvimentoarrumadoemseucomputador.Épossívelignorarestepasso,maseleéaltamenterecomendado.Começarcomamelhorconfiguraçãopossíveltesalvarádemuitosproblemasnofuturo!
Então,vamoscriarumambientevirtual(tambémchamadoumvirtualenv).IssoisolarásuaconfiguraçãoPython/Djangoemumabaseporprojeto,significaquequaisquermudançasquefizeremumwebsitenãoafetaráquaisqueroutrasaplicaçõesqueestiverdesenvolvendoaparte.Arrumado,certo?
Tudooquevocêprecisafazeréencontrarumdiretórionoqualvocêdesejacriarovirtualenv;SeudiretórioHome,porexemplo.NoWindowspodeparecercomoC:\Usuário\Nome(ondeNomeéonomedoseulogin).
Paraestetutorialusaremosumnovodiretóriodjangogirlsdoseudiretóriohome:
mkdirdjangogirls
cddjangogirls
Nósvamosfazerumvirtualenvchamadomyvenv.Oformatogeraldessecomandoé:
python3-mvenvmyvenv
Windows
Paracriarumnovovirtualenv,vocêprecisaabriroconsole(Nósfalamossobreissoalgunscapítulosatrás,lembra-se?)eexecutarC:\Python34\python-mvenvmyvenv.Seráalgoparecidocomisto:
C:\Usuário\Nome\djangogirls>C:\Python34\python-mvenvmyvenv
ondeC:\Python34\pythonéodiretórioemquevocêpreviamenteinstalouPythonemyvenvéonomedasuavirtualenv.Vocêpodeusarqualqueroutronome,massempreuseminúsculasesemespaços,acentosoucaracteresespeciais.Tambéméumaboaideiamanteronomecurto-vocêiráreferenciarmuitoaele!
LinuxeOSX
CriarumvirtualenvtantonoLinuxcomoOSXésimplescomoexecutarpython3-mvenvmyvenv.Seráalgoparecidocomisto:
~/djangogirls$python3-mvenvmyvenv
myvenvéonomedasuavirtualenv.Vocêpodeusarqualqueroutronome,maspermaneçaemcaixabaixa(minúsculas)enãouseespaçosentreosnomes.Tambéméumaboaideiamanteronomecurto-vocêiráreferenciarmuitoaele!
InstalaçãodoDjango
33
NOTA:IniciaroambientevirtualnoUbuntu14.04assimretornaráoseguinteerro:
Error:Command'['/home/eddie/Slask/tmp/venv/bin/python3','-Im','ensurepip','--upgrade','--default-pip']'
returnednon-zeroexitstatus1
Paracontornaresseproblema,useocomandovirtualenv.
~/djangogirls$sudoapt-getinstallpython-virtualenv
~/djangogirls$virtualenv--python=python3.4myvenv
TrabalhandocomovirtualenvOcomandoacimacriaráumdiretóriochamadomyvenv(ousejaonomequevocêescolheu)quecontémonossoambientevirtual(basicamenteumconjuntodediretóriosearquivos).Tudooquequeremosporenquantoéiniciá-loexecutando:
C:\Usuário\Nome\djangogirls>myvenv\Scripts\activate
noWindows,ou:
~/djangogirls$sourcemyvenv/bin/activate
noOSXenoLinux.
Lembre-sedesubstituirmyvenvcomseunomeescolhidodovirtualenv!
NOTE:àsvezessource(fonte)podenãoestardisponível.Nessescasos,tentefazerisso:
~/djangogirls$.myvenv/bin/activate
Vocêvaisaberquetemumvirtualenvfuncionandoquandoveropromptnoseuconsoleseparecercom:
(myvenv)C:\Usuário\Nome\djangogirls>
ou:
(myvenv)~/djangogirls$
Percebaqueoprefixo(myvenv)aparece!
Aotrabalhardentrodeumambientevirtual,pythoniráautomaticamentesereferiraversãocorretaparaquepossautilizarpythonemvezdepython3.
Ok,nóstemostodasasdependênciasimportantesnolugar.FinalmentepodemosinstalaroDjango!
InstalandooDjangoAgoraquevocêtemasuavirtualenviniciado,vocêpodeinstalarDjangousandopip.Noconsole,executepipinstalldjango==1.8.5(Percebaqueusamosumduplosinaldeigual:==).
InstalaçãodoDjango
34
(myvenv)~$pipinstalldjango==1.8.5
Downloading/unpackingdjango==1.8.5
Installingcollectedpackages:django
Successfullyinstalleddjango
Cleaningup...
noWindows
SevocêreceberumerroaochamaropipnaplataformaWindowsporfavor,verifiqueseocaminhodoprojetocontémespaços,acentosoucaracteresespeciais(exemplo,C:\Users\UserName\djangogirls).Sesimporfavormovaparaoutrolugarsemespaços,acentosoucaracteresespeciais(sugestãoé:C:\djangogirls).Apósamudança,porfavortentenovamenteocomandoacima.
NoLinux
SevocêreceberumerroaochamarpipnoUbuntu12.04porfavorexecutepython-mpipinstall-U--force-reinstallpipparacorrigirainstalaçãodopipnovirtualenv.
Éisso!Agoravocêestá(finalmente)prontoparacriarumaaplicaçãoDjango!
InstalaçãodoDjango
35
SeuprimeiroprojetoDjango!PartedestecapítuloébaseadonostutoriaisdoGeekGirlsCarrots(https://github.com/ggcarrots/django-carrots).
Partedestecapítuloébaseadonodjango-marcadortutoriallicenciadosobreCreativeCommonsAttribution-ShareAlike4.0InternationalLicense.Otutorialdodjango-marcadoréprotegidopordireitosautoraisporMarkusZapke-Gründemannetal.
Nósvamoscriarumblogsimples!
Oprimeiropassoparacriá-loécomeçarumnovoprojetodeDjango.Basicamente,istosignificaquevamosexecutaralgunsscriptsfornecidospeloDjangoqueirácriaroesqueletodeumprojetoDjangoparanós:umbandodediretóriosearquivosqueusaremosmaistarde.
OsnomesdealgunsarquivosediretóriossãomuitoimportantesparaoDjango.Nãorenomeieosarquivosqueestamosprestesacriar.Moverparaumlugardiferentetambémnãoéumaboaidéia.Djangoprecisamanterumadeterminadaestruturaparasercapazdeencontrarcoisasimportantes.
Lembre-sequetudonovirtualenv.Sevocênãovêumprefixo(myvenv)emseuconsole,vocêprecisaativarovirtualenv.NósexplicamoscomofazerissonocapítuloinstalaçãodoDjangonapartetrabalhandocomvirtualenv.Vocêpodefazerissodigitandooseguintecomando:myvenv\Scripts\activatenoWindowsoumyvenv/bin/activatenoMacOS/Linux.
NotaVerifiquequevocêincluiuoponto(.)nofinaldocomando,éimportanteporquedizoscriptparainstalaroDjangoemseudiretó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órioestruturaqueseparececomisso:
djangogirls
├───manage.py
└───mysite
settings.py
urls.py
wsgi.py
__init__.py
manage.pyéumscriptqueajudacomagestãodosite.Comissoseremoscapazesdeiniciarumservidordewebnonossocomputadorseminstalarnada,entreoutrascoisas.
Oarquivosettings.pycontémaconfiguraçãodoseusite.
Lembraquandofalamossobreumcarteiroverificandoondeentregarumacarta?arquivourls.pycontémumalistadospadrõesusadosporurlresolver.
Vamosignorarosoutrosarquivosporagora-nósnãovamosmudá-los.Aúnicacoisaalembrarénãoexcluí-losporacidente!
Criandoumprojeto
36
ConfigurandoVamosfazeralgumasalteraçõesnomysite/settings.py.Abraoarquivousandooeditordecódigoquevocêinstalouanteriormente.
Seriabomterahoracorretanonossosite.Váparaa<wikipediatimezoneslistecopieseufusohorário.(porexemplo.America/Sao_Paulo)
Emsettings.py,localizealinhaquecontémTIME_ZONEemodifiqueparaescolherseuprópriofusohorário:
TIME_ZONE='America/Sao_Paulo'
Modifique"America/Sao_Paulo",conformeocaso
Nóstambémprecisaramosadicionarumcaminhoparaarquivosestáticos(nósvamosdescobrirtudosobrearquivosestáticoseCSSmaistardenotutorial).DesçaatéofinaldoarquivoelogoabaixodaentradaSTATIC_URL,adicioneumnovoumchamadoSTATIC_ROOT:
STATIC_URL='/static/'
STATIC_ROOT=os.path.join(BASE_DIR,'static')
InstalaçãodeumbancodedadosHáváriossoftwaresdebancodedadosdiferentesquepodearmazenardadosparaoseusite.Nósvamosusaropadrão,sqlite3.
Istojáestáconfiguradonestapartedoseuarquivomysite/settings.py:
DATABASES={
'default':{
'ENGINE':'django.db.backends.sqlite3',
'NAME':os.path.join(BASE_DIR,'db.sqlite3'),
}
}
Paracriarumbancodedadosparaonossoblog,vamosfazeroseguintenoconsole.Digite:pythonmanage.pymigrate(precisamosestarnodiretórioquecontémoarquivomanage.pydjangogirls).Seissodercerto,vocêdeveveralgocomoisto:
(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émoarquivomanage.py(odiretóriodjangogirls).Noconsole,nóspodemosiniciaroservidorwebexecutandoopythonmanage.pyrunserver:
(myvenv)~/djangogirls$pythonmanage.pyrunserver
Agoratudoquevocêprecisafazeréverificarseseusiteestásendoexecutado-abraseunavegador(Firefox,Chrome,Safari,InternetExplorerouoquevocêusa)edigiteoendereço:
Criandoumprojeto
37
http://127.0.0.1:8000/
Oservidorwebvaiassumirseupromptdecomandoatévocêpará-lo:paradigitarmaiscomandosouabrirumanovajaneladoterminal(enãoseesqueçadeativarseuvirtualenvneletambém),oupararoservidordeweb,alternandodevoltaparaajanelanaqualestáexecutandoepressionandoCTRL+C-botõesdecontroleeCjuntos(noWindows,vocêpodeterquepressionarCtrl+Break).
Parabéns!Vocêcriouseuprimeirositeeoexecutouusandoumservidordeweb!Nãoéimpressionante?
Prontoparaopróximopasso?Estánahoradecriaralgumconteúdo!
Criandoumprojeto
38
ModelosdoDjangoAgoraoquenósqueremoscriaréalgoquearmazenetodosospostsnonossoblog.Masparafazerissoprecisamosaprenderumpoucomaissobrecoisaschamadasobjetos.
ObjetosExisteumconceitonaprogramaçãochamadoProgramaçãoOrientadaàObjetos(POO).Aideiaéqueaoinvésdeescrevertudocomoumachatasequênciadeinstruçõesdeprogramaçãopodemosmodelarascoisasedefinircomoelasinteragemumascomasoutras.
Entãooqueéumobjeto?Éumacoleçãodepropriedadeseações.Istopodeparecerestranho,masvamoslhedarumexemplo.
SequeremosmodelarumgatonóscriaremosumobjetoGatoquepossuialgumaspropriedades,porexemplocor,idade,humor(bom,mau,sonolento;)),dono(queéumobjetodaclassePessoaou,casosejaumgatoderua,essapropriedadeévazia).
EentãooGatotemalgumasações:ronronar,arranharoucomer(noqualvamosdaraogatoalgumaComidaDeGato,quepoderiaserumobjetoseparadocompropriedades,comosabor).
Gato
--------
cor
idade
humor
dono
ronronar()
arranhar()
comer(comida_de_gato)
ComidaDeGato
--------
sabor
Então,basicamente,aideiaédescrevercoisasreaisnocódigocompropriedades(chamadasdepropriedadesdoobjeto)eações(chamadasdemétodos).
Comonósiremosmodelaraspostagensdoblogentão?Queremosconstruirumblog,certo?
Precisamosresponderàpergunta:oqueéumapostagemdeblog?Quepropriedadesdeveter?
Bem,comcertezanossoblogprecisadealgumapostagemcomoseuconteúdoeumtítulo,certo?Tambémseriabomsaberquemaescreveu-entãoprecisamosdeumautor.Finalmente,queremossaberquandoapostagemfoicriadaepublicada.
Post
--------
title
text
author
created_date
published_date
Quetipodecoisapodeserfeitacomumapostagem?Serialegalteralgummétodoquepubliqueapostagem,nãoémesmo?
Entãoprecisamosdeummétodochamadopublicar.
ModelosdoDjango
39
Comojásabemosoquequeremosalcançar,podemoscomeçaramodelagememDjango!
ModelodoDjangoSabendooqueumobjetoé,nóscriaremosummodelonoDjangoparaapostagemdoblog.
UmmodelonoDjangoéumtipoespecialdeobjeto-eleésalvoemumbancodedados.Umbancodedadoséumacoleçãodedados.Obancodedadoséumlocalemquevocêvaisalvardadossobreusuários,suaspostagens,etc.UsaremosumbancodedadoschamadoSQLiteparaarmazenarasnossasinformações.EsteéoadaptadordebancodedadospadrãoDjango--elevaiserosuficienteparanósnestemomento.
Vocêpodepensaremummodelodebancodedadoscomoumaplanilhacomcolunas(campos)elinhas(dados).
CriandoumaaplicaçãoParamantertudoarrumadovamoscriarumaplicativoseparadodentrodonossoprojeto.Émuitobomtertudoorganizadodesdeoinício.Paracriarumaplicativoprecisamosexecutaroseguintecomandonoconsole(apartirdodiretóriodjangogirlsondeestáoarquivomanage.py):
(myvenv)~/djangogirls$pythonmanage.pystartappblog
Vocêvainotarqueumnovodiretórioblogécriadoequeeleagoracontémumnúmerodearquivos.Nossosdiretóriosearquivosnonossoprojetodevemseparecercomeste:
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.Fazemosissonoarquivomysite/settings.py.PrecisamosencontraroINSTALLED_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
Noarquivoblog/models.pydefinimostodososobjetoschamadosModelos-esteéumlugaremquevamosdefinirnossapostagemdoblog.
ModelosdoDjango
40
Vamosabrirblog/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(_)emcadaladodostr.AquelescaracteressãousadosfreqüentementeemPythoneàsvezesoschamamosde"dunder"(abreviaçãode"double-underscore"ou"duplosublinhado").
Éassustador,não?Masnãosepreocupe,vamosexplicaroqueestaslinhassignificam!
Todasaslinhascomeçandocomfromouimportsãolinhasqueadicionamalgunspedaçosdeoutrosarquivos.Entãoaoinvésdecopiarecolarasmesmascoisasemcadaarquivo,podemosincluiralgumaspartescomfrom...import....
classPost(models.Model):-estalinhadefineonossomodelo(éumobjeto).
classéumapalavra-chaveespecialqueindicaqueestamosdefinindoumobjeto.Postéonomedonossomodelo,podemoslhedarumnomediferente(maséprecisoevitarosespaçosembrancoecaracteresespeciais).Semprecomeceumnomedeclassecomumaletramaiúscula.models.ModelsignificaqueoPostéummodelodeDjango,entãooDjangosabeelequedevesersalvonobancodedados.
Agorapodemosdefiniraspropriedadesquediscutimos:titulo,texto,data_criacao,data_publicacaoeautor.Paraissoprecisamosdefinirumtipodecampo(éumtexto?Éumnúmero?Umadata?Umarelaçãocomoutroobjeto,porexemplo,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çãodoDJangosevocêquisersabermaissobrecamposdoModelecomodefinircoisasalémdestasdescritasacima(https://docs.djangoproject.com/en/1.8/ref/models/fields/#field-types).
Quetaldefpublish(self):?Éexatamenteonossométododepublishquefalávamosantes.def,significaquesetratadeumfunção/método.publishéonomedométodo.Vocêpodealterar,sequiser.Aregraéqueusamosletrasminúsculasesublinhadosemvezdeespaçosembranco(ouseja,sevocêquerterummétodoquecalculaopreçomédio,vocêpoderiachamá-localculate_average_price).
Métodosmuitasvezesreturnalgo.Háumexemplodeque,nométodo__str__.Nessecenário,quandochamamos__str__()teremosumtexto(string),comumtítulodoPost.
Sealgoaindanãoestáclarosobremodelos,sinta-selivreparapediroseutreinador!Sabemosqueémuitocomplicado,especialmentequandovocêaprenderoquesãoobjetosefunçõesaomesmotempo.Masesperoqueelesepareceumpoucomenosmágicaparavocêagora!
ModelosdoDjango
41
Criandotabelasparanossosmodelosnobancodedados
Oúltimopassoéadicionarnossonovomodeloparanossobancodedados.PrimeirotemosquefazeroDjangosaberquenóstemosalgumasmudançasemnossomodelo(sócriamosisso),digitepythonmanage.pymakemigrationsblog.Seráalgoparecidocomisto:
(myvenv)~/djangogirls$pythonmanage.pymakemigrationsblog
Migrationsfor'blog':
0001_initial.py:
-CreatemodelPost
Djangopreparaumarquivodemigraçãoquetemosdeaplicaragoraparanossobancodedados,tipopythonmanage.pymigrateblog,asaídadeveser:
(myvenv)~/djangogirls$pythonmanage.pymigrateblog
Operationstoperform:
Applyallmigrations:blog
Runningmigrations:
Applyingblog.0001_initial...OK
Viva!NossomodelodePostestáagoraemnossobancodedados,seriaumprazervê-lo,certo?SaltarparaopróximocapítuloparaveroaspectodoseuPost!
ModelosdoDjango
42
AdministraçãoParaadicionar,editareremoverpostagensquenóscriamosusaremosoDjangoadmin.
Vamosabriroarquivoblog/admin.pyesubstituirseuconteúdopor:
fromdjango.contribimportadmin
from.modelsimportPost
admin.site.register(Post)
Comovocêpodever,nósimportamos(incluímos)omodeloPostdefinidonocapítuloanterior.Paratornarnossomodelovisívelnapáginadeadministração,nósprecisamosregistrá-locom:admin.site.register(Post).
OK,horadeolharparaonossomodelodePost.Lembre-sedeexecutarpythonmanage.pyrunservernoconsoleparaexecutaroservidorweb.Váparaonavegadoredigiteoendereçohttp://127.0.0.1:8000/admin/Vocêveráumapáginadeloginassim:
Parafazerloginvocêprecisacriarumsuperuser-umusuárioquepossuicontrolesobretudodosite.Volteparaoterminaledigitepythonmanage.pycreatesuperuser,pressioneenteredigiteseunomedeusuário(caixabaixa,semespaço),endereçodee-mailepasswordquandoelesforemrequisitados.Nãosepreocupequevocênãopodeverasenhaquevocê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êdevevisualizaropaineldecontroledoDjangoadmin.
Administração
43
Váparaaspostagenseexperimenteumpoucocomelas.Adicionecincoouseispostagens.Nãosepreocupecomoconteúdo-vocêpodecopiarecolaralgumtextodestetutorialparaoconteúdoparaeconomizartempo:).
Certifique-sequepelomenosduasoutrêspostagens(masnãotodas)têmadatadepublicaçãodefinida.Issoseráútildepois.
SevocêquisersabermaissobreoDjangoadmin,vocêdeveconferiradocumentaçãodoDjango:https://docs.djangoproject.com/en/1.8/ref/contrib/admin/
Esteéprovavelmenteumbommomentoparatomarumcafé(ouchocolate)oualgoparacomerparareporasenergias.VocêcriouseuprimeiromodelodeDjango-vocêmereceumpoucodedescanso!
Administração
44
Implantação!NotaOcapítuloseguintepodeseràsvezesumpoucodifícildepassar.Persistaetermine-o;Implantaçãoéumaparteimportantedoprocessodedesenvolvimentodewebsite.Estecapítuloestálocalizadonomeiodotutorialparaqueseututorpossalheajudarcomoprocessoligeiramentecomplexodecolocarseusiteonline.Istosignificaquevocêaindapodeterminarotutorialporcontaprópriasevocêcontinuaremoutromomento.
Atéagoranossositesóestavadisponívelnoseucomputador,agoravocêvaiaprendercomopublicarelenainternet!AimplantaçãoéoprocessodepublicaçãodoseuaplicativonaInternetdetalformaqueaspessoaspossam,finalmente,verseuaplicativo:).
Comovocêaprendeu,umwebsiteprecisaestarlocalizadonumservidor.Existemmuitosprovedores,masiremosutilizaroquetemumprocessodedeployrelativamentesimples:PythonAnywhere.PythonAnywhereégratuitoparaaplicaçõespequenasquenãopossuemmuitosvisitantes,entãoserásuficienteparavocêporenquanto.
OoutroserviçoexternoqueusaremoséGitHub,queéumserviçodehospedagemdecódigo.Existemoutros,masquasetodososprogramadorespossuemumacontanoGitHubatualmenteeagoravocêtambém!
UsaremosoGitHubcomoumtrampolimparatransportarnossocódigoparaoPythinAnywhere.
GitGité"sistemadecontroledeversão"usadopormuitosprogramadores-umsoftwarequecontrolamudançasnosarquivosaolongodotempoparaquevocêpossarecuperarversõesespecíficasdepois.Umpoucocomo"controlarmudanças"noMicrosoftWord,masmuitomaispoderoso.
InstalandooGit
Windows
VocêpodebaixarGitemgit-scm.com.Vocêpodeapertar"nextnextnext"emtodosospassosexcetoum;noquintopassochamado"AdjustingyourPATHenvironment",escolha"RunGitandassociatedUnixtoolsfromtheWindowscommand-line"(aopçãodebaixo).Alémdisso,opadrãoestáótimo.CheckoutestiloWindows,commitUnix-stylelinhasdeconfirmaçãoestábom.
MacOS
BaixarGitgit-scm.comesigaasinstruções.
Linux
Seelejánãoestiverinstalado,Gitdeveestardisponívelatravésdeseugerenciadordepacotes,entãotente:
sudoapt-getinstallgit
#or
sudoyuminstallgit
ComeçandonossorepositórionoGitGitcontrolaasalteraçõesparaumdeterminadoconjuntodearquivosnoquechamamosderepositóriodecódigo(ou"repo").Vamoscomeçarumparanossoprojeto.Abraoconsoleeexecuteessescomandos,nodiretóriodjangogirls:
Implantação!
45
Nota:Verifiqueoseudiretóriodetrabalhoatualcomumpwd(OSX/Linux)ouocomandocd(Windows)antesdeinicializarorepositório.Vocêdeveestarnapastadjangogirls.
$gitinit
InitializedemptyGitrepositoryin~/djangogirls/.git/
$gitconfiguser.name"YourName"
Inicializarorepositóriogitéalgoquesóprecisamosfazerumavezporprojeto(evocênãoteráquere-introduzironomedeusuárioee-mailnuncamais)
Gitirácontrolarasalteraçõesparatodososarquivosepastasnestediretório,masexistemalgunsarquivosquequeremosignorar.Fazemosissoatravésdacriaçãodeumarquivochamado.gitignorenodiretóriobase.Abraseueditorecrieumnovoarquivocomoseguinteconteúdo:
*.pyc
__pycache__
myvenv
db.sqlite3
.DS_Store
Esalvecomo.gitignorenapastadenívelsuperior"djangogirls".
Nota:Opontonoiníciodonomedoarquivoéimportante!Sevocêestátendoalgumadificuldadeemcriá-la(MacsnãogostamdecriararquivosquecomeçamcomumpontoatravésdoFinder,porexemplo),useorecurso"SaveAs"noseueditorquesemprefunciona.
Éumaboaidéiaparausarumcomandodegitstatusantesdegitaddousemprequevocênãotivercertezadequeseráfeito,paraevitarsurpresas(porexemplo,serãoadicionadosarquivoserradosoucommitados).Ocomandogitstatusretornainformaçõessobretodososarquivoscontrolado/modificado/encenado,statusderamoemuitomais.Ooutputdevesersemelhantea:
$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
Implantação!
46
VáparaGitHub.comecadastreumanovaegratuitacontadeusuário.Emseguida,crieumnovorepositório,edêonome"my-first-blog".Deixeo"initialisewithaREADME"desmarcado,deixeaopção.gitignoreembranco(jáfizemosissomanualmente)ealicençacomoNone.
NotaOnomemy-first-blogéimportante--vocêpoderiaescolheroutracoisa,masvamosusá-lomuitasvezesnasinstruçõesabaixoevocêteriaquesubstituí-locadavez.Éprovavelmentemaisfácilficarcomonomemy-first-blog.
Natelaseguinte,vocêserámostradaacloneURLdoseurepo.Escolhaaversão"HTTPS",copie,evamoscolá-lonoterminalembreve:
AgoraprecisamosligarorepositórioGitnoseucomputadorcomonoGitHub.
$gitremoteaddoriginhttps://github.com/<your-github-username>/my-first-blog.git
$gitpush-uoriginmaster
Implantação!
47
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,oDjangoGirlsTutorialemuitosoutrosgrandesprojetosdesoftwaredefonteabertatambémhospedamseucódigonoGitHub:)
CriaçãodenossoblogemPythonAnywhereEmseguida,éhoradeseinscreverparaumacontagratuitade"Beginner"naPythonAnywhere.
www.pythonanywhere.com
Nota:aoescolherseunomedeutilizadoraqui,tenhaemmentequeaURLdoseublogteráoformulárioyourusername.pythonanywhere.com,entãoescolhaseunicknameouonomedoqueéoblog.
PullingourcodedownonPythonAnywhereQuandovocêseinscreveparaPythonAnywhere,vocêélevadoaoseupaineldecontroleoupágina"Consoles".Escolhaaopçãoiniciaroconsole"Bash"--queéaversãoPythonAnywheredeumconsole,comoaquelanoseuPC
Nota:PythonAnywhereébaseadoemLinux,assimsevocêestivernoWindowsoconsolevaiparecerumpoucodiferentedoqueestánoseucomputador.
VamospuxarnossocódigodeGitHubemPythonAnywhereatravésdacriaçãodeum"clone"dorepo.DigiteoseguinteparaoconsolenaPythonAnywhere:
$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:
Implantação!
48
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".Arquivosestáticosfuncionamdeformadiferentenosservidoresemcomparaçãocomnossoprópriocomputador,eprecisamosdeumaferramentacomoo"whitenoise"paraatendê-los.
Vamosdescobrirumpoucomaissobrearquivosestáticosmaistardenotutorial,quandovamoseditaroCSSparaonossosite.
Porenquantosóprecisamosexecutarumcomandoextrachamado"collectstatic"noservidor.IssodizproDjangoreunirtodososarquivosestáticosqueeleprecisanoservidor.Emsuamaioria,estessãoosarquivosestáticosquefazemositedoadminbonitonomomento.
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çopequenosruí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ãoascontasdeusuárioemensagenspodemserdiferentesnoservidorenoseucomputador.
Entãonósvamosinicializarobancodedadosnoservidortalcomofizemosnoseuprópriocomputador,commigrateecreatesuperuser:
Implantação!
49
(mvenv)20:20~$pythonmanage.pymigrate
Operationstoperform:
[...]
Applyingsessions.0001_initial...OK
(mvenv)20:20~$pythonmanage.pycreatesuperuser
PublicaçãodonossoblogcomoumaplicativowebAgoranossocódigoestánaPythonAnywhere,nossavirtualenvestápronta,osarquivosestáticosestãorecolhidoseobancodedadosestáinicializado,estamosprontosparapublicá-locomoumaplicativodaweb.
CliqueemvoltarparaoPythonAnywheredashboardclicandonoseulogotipoecliquenaguiaWebeváemAddanewwebapp.
Nacaixadediálogo,apósaconfirmaçãodeseunomededomínio,escolhamanualconfiguration(NBnãoaopção"Django").Emseguida,escolhaPython3.4ecliqueemNextparaconcluiroassistente.
Notacertifique-sevocêescolheuaopção"Manualconfiguration",nãoa"Django".NóssomosdemaisparaopadrãodeconfiguraçãoDjangodaPythonAnywhere;-)
DefinindoovirtualenvVocêserálevadoparaateladeconfiguraçãodePythonAnywhereparaseuwebappqueéondevocêprecisarádeirquandoquiserfazeralteraçõesparaoaplicativonoservidor.
Naseção"Virtualenv",cliquenotextovermelhoquediz"Enterthepathtoavirtualenv"edigite:/home/<your-username>/my-first-blog/myvenv/
Nota:substituaseupróprionomedeusuárioconformeapropriado.Sevocêcometerumerro,PythonAnywhereirámostrarumpequenoaviso.
ConfigurandooarquivoWSGI
Implantação!
50
DjangofuncionausandooWSGIprotocol,umpadrãoparaservirsitesusandoPython,queoferecesuporteaPythonAnywhere.AmaneiraqueconfiguramosPythonAnywhereparareconhecernossoblogDjangoéeditandoumarquivodeconfiguraçã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çãowebequalonomedoarquivodeconfiguraçõesDjango.Eletambémdefineaferramentadearquivosestáticos"whitenoise".
AperteSaveeentãovolteparaaguiaWeb.
Játerminamos!AperteobotãograndeverdedeReloadevocêserácapazdeirverosseuaplicativo.Vocêencontraráumlinkparaelenotopodapágina.
DicasdedebuggingSevocêvirumerroquandovocêtentavisitaroseusite,oprimeirolugarparaprocuraralgumainformaçãodedebuggingénoseuerrorlog--vocêencontraráumlinkparaissonaguiawebPythonAnywhere.Versehámensagensdeerrolá.Asmaisrecentesestãonaparteinferior.Problemascomunsincluem
esquecerumdospassosquefizemosnoconsole:criandoovirtualenv,ativá-lo,instalandooDjango,collectstatic,inicializandoobancodedadoscometerumerronocaminhodovirtualenvnaguiaweb--haverágeralmenteumapequenamensagemdeerrovermelholá,seháumproblemacometerumerronoarquivodeconfiguraçã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íceisdodesenvolvimentoweb,emuitasvezeslevaaspessoasváriosdiasantesdefazerfuncionar.Masvocêtemseusitepublicado,nainternet,assim!
Implantação!
51
UrlsEstamosprestesaconstruirnossaprimeiraWebpage-umapáginainicialparaoseublog!Masprimeiro,vamosaprenderumpoucomaissobreDjangourls.
OqueéumaURL?UmaURLésimplesmenteumendereçodaweb,vocêpodeverumaURLtodavezquevocêvisitaqualquersite-évisívelnabarradeendereçosdoseunavegador(Sim!127.0.0.1:8000éumaURL!Ehttp://djangogirls.orgtambéméumaURL):
CadapáginanaInternetprecisadesuaprópriaURL.DestaformaseuaplicativosabeoquedevemostraraumusuárioqueabreumaURL.EmDjango,nósusamosalgochamadoURLconf(configuraçãodeURL),queéumconjuntodepadrõesqueDjangovaitentarcoincidircomaURLrecebidaparaencontraravisãocorreta.
ComofuncionamasURLsemDjango?Vamosabriroarquivomysite/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çacomadmin/oDjangoiráencontrarumcorrespondentemododeexibição.NestecasonósestamosincluindoummontedeadminURLsparaqueissonãofiquetudoembaladonestepequenoarquivo..--émaislegívelemaislimpo.
Regex
Urls
53
VocêquersabercomooDjangocoincidecomURLsparaviews?Bem,estaparteécomplicada.oDjangousaoregex--expressõesregulares.Regextemmuito(muito!)denormasqueformamumpadrãodepesquisa.Comoregexessãoumtópicoavançado,nósveremosemdetalhescomoelasfuncionam.
Sevocêaindaquiserentendercomocriamosospadrões,aquiestáumexemplodoprocesso-sóprecisamosumsubconjuntolimitadoderegrasparaexpressaropadrãoqueprocuramos,ouseja:
^paraoiníciodotexto
$paraofinaldotexto
\dparaumdígito
+paraindicarqueoitemanteriordeveserrepetidopelomenosumavez
()paracapturarpartedopadrão
Qualqueroutracoisanadefiniçãodeurlserálevadaliteralmente.
Agoraimaginequevocêtemumsitecomoendereçoassim:http://www.mysite.com/post/12345/,onde12345éonúmerodoseupost.
Escreverviewsseparadasparatodososnúmerosdepostseriamuitochato.Comexpressõesregularespodemoscriarumpadrãoqueirácoincidircomaurleextraironúmeroparanós: post/(\d+)/$.Vamosaospoucosveroqueestamosfazendoaqui:
^post/estádizendoaoDjangoparapegartudoquetenhapost/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áginainicialdonossoblogeexibirumalistadeposts.
Tambémqueremosmanteroarquivodemysite/urls.pylimpo,aínósimportaremosurlsdanossaaplicaçãoblogparaoarquivoprincipalmysite/urls.py.
Váemfrente,apagueaslinhascomentadas(aslinhasquecomeçamcom#)eadicioneumalinhaquevaiimportarblog.urlsparaaurlprincipal('').
Oseuarquivomysite/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/'parablog.urlseprocurarpornovasinstruçõeslá.
AoescreverasexpressõesregularesemPythonésemprefeitocomrnafrentedasequência-issoésóumadicaútilparaPythonqueaseqüênciapodecontercaracteresespeciaisquenãosãodestinadasparaPythonemsi,masemvezdissosãopartedaexpressãoregular.
blog.urlsCrieumnovoarquivovazioblog/urls.py.Tudobem!Adicioneestasduasprimeiraslinhas:
Urls
54
fromdjango.conf.urlsimportinclude,url
from.importviews
AquinósestamosapenasimportandométodosdoDjangoetodososnossosviewsdoaplicativoblog(aindanãotemosnenhuma,masteremosemumminuto!)
DepoisdissonóspodemosadicionarnossoprimeiraURLpadrão:
urlpatterns=[
url(r'^$',views.post_list),
]
Comovocêpodever,estamosagoraatribuindoumaviewchamadapost_listpara $URL.Essaexpressãoregularcorresponderáa (umcomeço)seguidopor$(fim)-entãosomenteumaseqüênciavaziairácorresponder.Eissoécorreto,porqueemresolvedoresdeDjangourl,'http://127.0.0.1:8000/'nãoéumapartedaURL.EstepadrãoirámostraroDjangoqueviews.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écomochamamosonossoview!Issosignificaqueestátudonolugar,sónãocriamosnossaviewainda.Nãosepreocupe,nóschegaremoslá.
SevocêquersabermaissobreDjangoURLconfs,vejaadocumentaçãooficial:https://docs.djangoproject.com/en/1.8/topics/http/urls/
Urls
55
Views-horadecriar!Éhoraderesolverobugquecriamosnocapítuloanterior:)
Umaviewécolocadaondenóscolocamosa"lógica"danossaaplicação.Eleirásolicitarinformaçõesapartirdomodelquevocêcriouantesepassá-loparaumtemplatequevocêvaicriarnopróximocapítulo.Views,nofundo,nãopassamdemétodosescritosemPythonquesãoumpoucomaiscomplicadosdoqueaquiloquefizemosnocapítuloIntroduçãoaoPython.
Asviewssãopostasnoarquivoviews.py.Nósvamosadicionarnossasviewsnoarquivoblog/views.py.
blog/views.pyOK,vamosabriroarquivoeveroquetemnele:
fromdjango.shortcutsimportrender
#Createyourviewshere.
Nãotemmuitacoisa.Aviewmaisbásicaseparececomisto.
defpost_list(request):
returnrender(request,'blog/post_list.html',{})
Comovocêpodever,nóscriamosummétodo(def)chamadopost_listqueaceitaopedidoeretornarummétodorenderseráprocessado(paramontar)nossomodeloblog/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/
Views-horadecriar!
56
IntroduçãoaHTMLVocêpodeseperguntar:eoqueéumtemplate?
Umtemplateéumarquivoquenóspodemosreutilizarparaapresentardiferentesinformaçõesdeumaformaconsistente.Porexemplo,vocêpoderiausarumtemplateparateajudaraescreverumacarta,pois,emboracadacartapossuaumamensagemeumdestinodiferente,todasterãosempreomesmoformato.
OformatodotemplatedoDjangoédescritoemumalinguagemchamadaHTML(esseéomesmHTMLquemencionamosnoprimeirocapítuloComoaInternetfunciona).
OqueéHTML?HTMLéumsimplescódigoqueéinterpretadopeloseunavegadorweb-comooChrome,oFirefoxouoSafari-paraexibirumapáginadawebparaousuário.
HTMLsignifica"HyperTextMarkupLanguage".HiperTextsignificaqueéumtipodetextoquesuportahiperlinksentrepáginas.Marcaçãonadamaiséquemarcarumdocumentocomcódigosquedizemparaalguém(nessecaso,onavegadorweb)comoapáginadeveráserinterpretada.CódigoemHTMLéfeitocomtags,cadaumacomeçandocom<eterminandocom>.Essastagsmarcamoselementos.
Seuprimeirotemplate!Criarumtemplatesignificacriarumarquivodetemplate.Tudoéumarquivo,certo?Provavelmentevocêjádeveternotadoisso.
Ostemplatessãosalvosnodiretórioblog/templates.Logo,crieumdiretóriochamadotemplatesdentrododiretóriodoseublog.Emseguida,crieoutrodiretóriochamadoblogdentrodadiretóriotemplates:
blog
└───templates
└───blog
(Vocêdeveestarseperguntandoporquenósprecisamosdedoisdiretórioschamadosblog-comovocêdescobrirámaisparafrente,essaéumasimpleseútilconvençãoquefacilitaavidaquandoascoisascomeçaremaficarmaiscomplicadas.)
Eagoranóscriamosoarquivopost_list.html(deixe-oembrancoporagora)dentrododiretórioblog/templates/blog.
Vejacomoonossositeestáseparecendoagora:http://127.0.0.1:8000/
SeocorrerumerrodeTemplateDoesNotExiststentereiniciaroseuservidor.Entrenalinhadecomando,pareoservidorpressionandoCtrl+C(ControlseguidodateclaC,juntas)ereinicie-orodandopythonmanage.pyrunserver.
IntroduçãoaHTML
57
Acabaram-seoserros!Parabéns:)Entretanto,nossositenãomostranadaanãoserumapáginaembranco.Issoporqueonossotemplateestá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>sempreestaránofim.Comovocêpodever,todooconteúdodeumwebsiteseencontraentreatagdeinício<html>eentreatagdefim</html><p>éatagquedenominaparágrafos;</p>determinaofimdecadaparágrafo
Head&bodyCadapá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>dizaonavegadoroquehádeverdadenapágina.
Porexemplo,vocêpodeporoelementotítulodeumapáginawebdentrodatag<head>.Veja:
IntroduçãoaHTML
58
<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>ecolocouotextonabarradetítulodoseunavegador(etambémseráusadoparaosfavoritoseoutrascoisasmais).
Provavelmentevocêjádeveternotadoquecadatagdeaberturacasacomumatagdefechamento,comuma/,equeoselementosestãoaninhados(ex.:vocênãopodefecharumtagemparticularantesquetodasasoutrastagsqueestiveremdentrodelajáestejamfechadas).
Écomocolocarcoisasdentrodecaixas.Vocêtemumagrandecaixa,<html></html>;dentrodelahá<body></body>,sendoqueestaaindacontémcaixasmenors:<p></p>.
Vocêprecisaseguiressasregrasdefechamentodetags,edeaninhamentodeelementos-sevocênãofizerisso,onavegadorpoderánãoestaraptoparainterpretarseucódigodemaneiracorretaesuapáginaseráexibidademaneiraincorreta.
CustomizeseutemplateAgoravocê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:
IntroduçãoaHTML
59
<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çõesdivaqui.
Oprimeiroelementodivpossuiotítulodonossoblog-éumtítuloeumlinkOsoutrosdoiselementosdivpossuemnossaspostagenscomadatadepublicação,h2comotítulodapostagemqueéclicáveledoisps(parágrafos)detexto,umparaadataeoutroparaotextodapostagem.
Issonosdáoseguinteefeito:
Yaaay!Mas,atéagora,nossotemplatemostraexatamantesempreamesmainformação-sendoque,anteriormente,nósfalávamossobretemplatescomoumamaneiraparaexibirinformaçõesdiferentesemummesmoformato.
IntroduçãoaHTML
60
OquenósrealmentequeremosfazeréexibirpostagensreaisqueforamadicionadasnoDjangoadmin-eissoéoquefaremosemseguida.
Maisumacoisa:deploy!SeriabomvertudoistonaInternet,certo?VamosfazeroutrodeployPythonAnywhere:
Commit,eponhaseucódigonoGitHub
Primeirodetudo,vejamosquaisarquivosforamalteradosdesdeaúltimaimplantação:
$gitstatus
Verifiquesevocêestánodiretóriodjangogirlsevamosdizeraogitparaincluirtodasasmudançasdentrodestediretório:
$gitadd--all.
Nota-A(abreviaçãode"all",tudoeminglês)significaqueogittambémreconhecerásevocêdeletoualgumarquivo(porpadrão,ogitapenasreconhecearquivoscriados/modificados).Lembre-setambém(docapítulo3)que.significaodiretórioatual.
Antesdenósfazermosouploaddetodososaqruivos,chequemosoqueogitenviará(todososarquivosqueogitforenviardeveráapareceemverde):
$gitstatus
Estamosquaselá!Agoraéhoradedizeraeleparasalvaressamodificaçãoemseuhistórico.Nósdaremosaeleuma"mensagemdecommit"ondenósdescrevemosasmodificaçõesquefizemos.Vocêpodeescreveroquevocêquiseragora,masserámaisútilsevocêescreveralgumacoisamaisdescritiva,algoparavocêpoderselembrardascoisasquevocêfezfuturamente.
$gitcommit-m"ChangedtheHTMLforthesite."
Certifique-sequevocêusouaspasduplasparadelimitaramensagemdocommit.
Quandofizermosisso,nósfazemosupload(envio)dasnossasmudançasparaoPythonAnywhere:
gitpush
BotedeunovocódigonoPythonAnywhereerecarregueoseuaplicativodawebAbraapáginadeconsolesdePythonAnywhereeváparaoseuconsoleBash(oucomeçarumnovo).Emseguida,execute:
$cd~/my-first-blog
$sourcemyvenv/bin/activate
(myvenv)$gitpull
[...]
(myvenv)$pythonmanage.pycollectstatic
[...]
IntroduçãoaHTML
61
Evejaseucódigosendobaixado.Sevocêdesejaverificarsejáchegou,podeirparaaFilestabeverseucódigonoPythonAnywhere.
Finalmente,puleparaaWebtabeaperteReloademseuaplicativoweb.
Suaatualizaçãodeveestarlive!Váemfrenteeatualizeseusitenonavegador.Asalteraçõesdevemservisíveis:)
IntroduçãoaHTML
62
QuerySetseORMdoDjangoNestecapítulovocêvaiaprendercomoDjangoseconectaaobancodedadosecomoelearmazenadados.Vamosnessa!
OqueéumQuerySet?UmQuerySet(conjuntodepesquisa),nofundo,éumalistadeobjetosdeumdadomodelo.UmQuerySetpermitequevocêleiaosdadosdobanco,filtreeordeneomesmo.
Émaisfácilaprenderporexemplos.Vamostentar?
OShelldoDjangoAbraoterminaledigite:
(myvenv)~/djangogirls$pythonmanage.pyshell
Oresultadodeveser:
(InteractiveConsole)
>>>
AgoravocêestánoconsoleinterativodoDjango.EleécomoopromptdoPythonsóquecomumasmágicasamais:).VocêpodeusartodososcomandosdoPythonaquitambém,éclaro.
TodososobjetosAntes,vamostentarmostrartodasasnossaspostagens.Podemosfazerissocomoseguintecomando:
>>>Post.objects.all()
Traceback(mostrecentcalllast):
File"<console>",line1,in<module>
NameError:name'Post'isnotdefined
Oops!Umerroapareceu.ElenosdizquenãoexistealgochamadoPost.Éverdade--nósesquecemosdeimportá-loprimeiro!
>>>fromblog.modelsimportPost
Issoésimples:importamosomodeloPostdedentrodoblog.models.Vamostentarmostrartodasaspostagensnovamente:
>>>Post.objects.all()
[<Post:myposttitle>,<Post:anotherposttitle>]
Éumalistadospostsquecriamosanteriormente!CriamosessespostsusandoainterfacedeadministraçãodoDjango.Noentanto,agoraqueremoscriarnovasmensagensutilizandoopython,entãocomoéquefazemosisso?
CriandoumobjetoÉassimquevocêcriaumobjetoPostnobancodedados:
DjangoORM(Querysets)
63
>>>Post.objects.create(author=me,title='Sampletitle',text='Test')
Masaquitemosumingredientequefaltava:me.PrecisamospassarumainstânciadeUsermodelocomoautor.Comofazerisso?
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ósagorausamosumgetaUserwithausernameiguala'ola'.Claro,vocêtemqueadaptaraseunomedeusuário.
Agorafinalmentepodemoscriarnossaprimeirapostagem:
>>>Post.objects.create(author=me,title='Sampletitle',text='Test')
Viva!Querversefuncionou?
>>>Post.objects.all()
[<Post:Sampletitle>]
AdicionemaispostagensAgora,vocêpodesedivertirumpoucoeadicionarmaispostagensparavercomofunciona.Adicionemais2-3esigaparaapróximaparte.
FiltrarobjetosUmagrandepartedeQuerySetséahabilidadedefiltrá-los.Digamosquequeremosencontrartodosaspostagensescritaspelousuárioola.NósusaremosofilteremvezdeallemPost.objects.all().Entreparêntesesindicamosqueascondiçõesprecisamseratendidasporumpostagemdeblogparaacabaremnossoqueryset.Emnossocasoéauthorqueéigualame.AmaneiradeescreverissonoDjangoé:author=me.Agoraonossotrechodecódigoparececomeste:
>>>Post.objects.filter(author=me)
[<Post:Sampletitle>,<Post:Postnumber2>,<Post:My3rdpost!>,<Post:4thtitleofpost>]
Outalveznósqueremosvertodosospostsquecontenhamapalavra'title'nocampodetitle?
>>>Post.objects.filter(title__contains='title')
[<Post:Sampletitle>,<Post:4thtitleofpost>]
NotaExistemdoiscaracteresdesublinhado(_)entreotitleecontains.DjangoORMusaestasintaxeparasepararnomesdecampo("title")eoperaçõesoufiltros("contains").Sevocêusarapenasumsublinhado,vocêobteráumerrocomo"FieldError:Cannotresolvekeywordtitle_contains".
DjangoORM(Querysets)
64
Vocêtambémpodeobterumalistadetodosospostspublicados.Fazemosissofiltrandotodosospostscompublished_datedefinidonopassado:
>>>fromdjango.utilsimporttimezone
>>>Post.objects.filter(published_date__lte=timezone.now())
[]
Infelizmente,nenhumdosnossospostsestãopublicadosainda.Nóspodemosmudarisso!Primeiroobtenhaumainstânciadeumpostquequeremospublicar:
>>>post=Post.objects.get(id=1)
Eentãopublicá-locomonossométododepublish!
>>>post.publish()
Agoratenteobteralistadepostspublicadosnovamente(pressioneasetaparacimabotão3vezesetecleEnter):
>>>Post.objects.filter(published_date__lte=timezone.now())
[<Post:Sampletitle>]
Ordenandoobjetos
UmQuerySettambémnospermiteordenaralistadeobjetos.Vamostentarordenaraspostagenspelocampocreated_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()
$
DjangoORM(Querysets)
65
DjangoQuerysetsNóstemosdiferentespeçasaqui:omodelPostestádefinidoemmodels.py,nóstemospost_listnoviews.pyeotemplateadicionado.MascomonósfaremosdefatoparafazercomqueasnossaspostagensapareçamnonossotemplateemHTML?Porqueéissoquenósqueremos:pegaralgumconteúdo(modelssalvosnobancodedados)eexibi-lodeumamaneirabacananonossotemplate,certo?
Eissoéexatamenteoqueasviewsdevemfazer:conectarmodelsetemplates.Nanossaviewpost_listviewnósvamosprecisarpegarosmodelsquequeremosexibirepassá-losparaotemplate.Então,basicamente,emumaviewnósdecidimosoque(ummodel)seráexibidonotemplate.
Certo,ecomonósfaremosisso?
Precisamosabrironossoblog/views.py.Atéagoraaviewpost_listseparececomisso:
fromdjango.shortcutsimportrender
defpost_list(request):
returnrender(request,'blog/post_list.html',{})
Lembraquandofalamossobreainclusãodecódigoescritoemarquivosdiferentes?Agoraéomomentoemquetemosdeincluiromodelquetemosescritoemmodels.py.Vamosadicionarestalinhafrom.modelsimportPostcomoeste:
fromdjango.shortcutsimportrender
from.modelsimportPost
Opontodepoisdefromsignificaodiretórioatualouoaplicativoatual.Comoviews.pyemodels.pyestãonomesmodiretóriopodemossimplesmenteusar.eonomedoarquivo(sem.py).Entãonósimportamosonomedomodelo(Post).
Eoquevemagora?ParapegarospostsreaisdomodelPostnósprecisamosdeumacoisachamadaQuerySet.
QuerySetVocêjádeveestarfamiliarizadocomomodoqueosQuerySetsfuncionam.NósconversamossobreissonocapítuloORMdoDjango(QuerySets).Agoranósestamosinteressadosemumalistadepostsquesãopublicadoseclassificadosporpublished_date,certo?NósjáfizemosissonocapítuloQuerySets!
Post.objects.filter(published_date__lte=timezone.now()).order_by('published_date')
Agoranóscolocamosestepedaçodecódigodentrodoarquivoblog/views.pyadicionando-oàfunçãodefpost_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.Deagoraemdiantenóspodemosnosreferiraeleporestenome.
AúltimapartequefaltaépassaroQuerySetpostsparaotemplate(veremoscomoexibi-loemumpróximocapítulo).
Dadosdinâmicosnostemplates
66
Nafunçãorenderjátemosoparâmetrorequest(tudooquerecebemosdousuárioatravésdaInternet)eumarquivodetemplate'blog/post_list.html'.Oúltimoparâmetro,queseparececomisso:{}éumlugaremquepodemosacrescentaralgumascoisasparaqueotemplateuse.Precisamosnomeá-los(ficaremoscom'posts'porenquanto:)).Deveficarassim:{'posts':posts}.Observequeaparteantesde:estáentreaspas''.
Entãofinalmentenossoarquivoblog/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/
Dadosdinâmicosnostemplates
67
TemplatesHoradeexibiralgumdado!Djangonosdátagsdetemplatesembutidasbastanteúteisparaisso.
Oquesãotagsdetemplate?Comopodever,vocênãopodecolocarcódigoPythonnoHTML,porqueosnavegadoresnãoirãoentender.ElesapenasconhecemHTML.NóssabemosqueHTMLébastanteestático,enquantoPythonémuitomaisdinâmico.
TagsdetemplateDjangonospermitetransformarobjetosPythonemcódigoHTML,paraquevocêpossaconstruirsitesdinâmicosmaisrápidoemaisfácil.Uhuu!
ModelodelistadepostdeexibiçãoNocapituloanterior,nósfornecemosaonossotemplateumalistadepostagenseavariávelposts.AgoravamosexibiremnossoHTML.
ParaexibirumavariávelnoDjangotemplate,nósusamoscolchetesduploscomonomedavariáveldentro,exemplo:
{{posts}}
Tentarfazerissonoseutemplateblog/templates/blog/post_list.html(substituiaosegundoeoterceiropardetags<div></div>pelalinha{{posts}}),salveoarquivoeatualizeapáginaparaverosresultados:
Vocêpodever,tudoquetemosé:
[<Post:Mysecondpost>,<Post:Myfirstpost>]
IstosignificaqueoDjangoaentendecomoumalistadeobjetos.Lembre-sedeintroduçãoaoPythoncomopodemosexibirlistas?Sim,comosloops!EmumtemplateDjango,fazemosissodaseguintemaneira:
{%forpostinposts%}
{{post}}
{%endfor%}
Tentefazerissonoseutemplate.
Templates
68
Funciona!Masnósqueremosqueelessejamexibidoscomoospostsestáticos,comoosquecriamosanteriormentenocapítulodeIntroduçãoaHTML.NóspodemosmisturarHTMLcomtagsdetemplate.Oconteúdodatagbodyficará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ósestamosacessandoosdadosemcadaumdoscamposquedefinimosnomodeldoPost.Alémdisso,|linebreaksbrestápassandootextodopostporumfiltro,convertendoquebrasdelinhaemparágrafos.
Templates
69
MaisumacoisaSeriabomverseseusiteaindaestaráfuncionandonainternet,certo?VamostentarimplantaraPythonAnywherenovamente.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-sedeadicionarpublished_date!),emseguida,atualizeapáginaparaverseopostapareceporlá.
Funcionacomomágica?Estamosorgulhosos!Afaste-sedoseucomputadorumpouco,vocêganhouumapausa.:)
Templates
70
CSS-Deixemaisbonito!Nossoblogaindaparecefeio,certo?Estánahoradedeixarelemelhor!ParaissonósusaremosoCSS.
OqueéCSS?Doinglês"CascadingStyleSheets",CSSéumalinguagemusadaparadescreveroaspectoeaformataçãodeumwebsiteescritonumalinguagemdemarcação(comoHTML).Imagineelecomosendoumtipode"maquiagem"paranossosite;).
Masnósnãoqueremosiniciardozerodenovo,certo?Nóstentaremos,maisumavez,usaralgoquefoifeitoedisponibilizadodegraçaporprogramadoresnainternet.Vocêsabe,reinventararodanãoénadadivertido.
VamosusaroBootstrap!BootstrapéumdosmaisfamososepopularesframeworksdeHTMLeCSSparadesenvolversitesbonitos:https://getbootstrap.com/
FoiescritoporprogramadoresquetrabalharamnoTwittereagoraédesenvolvidoporvoluntáriosdetodoomundo.
InstalarBootstrapParainstalaroBootstrap,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.Apenassigaemfrente,abraseusiteeatualizeapágina.Aquieleestá!
Jáparecendomelhor!
ArquivosestáticosnoDjango
CSS-Deixemaisbonito
71
Finalmentenósteremosumolharmaisatentonessascoisasquechamamosarquivosestáticos.ArquivosestáticossãotodasassuasimagensearquivosCSS--arquivosquenãosãodinâmicos,entãoseuconteúdonãodependedocontextodarequisiçãoeseráomesmoparatodososusuários.
OndecolocarosarquivosestáticosparaDjango
Comovocêviuquandorodamoscollectstaticnoservidor,Djangojásabeondeencontrarosarquivosestáticosparaobuilt-in"admin"app.Agorasóprecisamosadicionaralgunsarquivosestáticosparanossopróprioapp,blog.
Fazemosissoatravésdacriaçãodeumapastachamadastaticdentrodoaplicativodoblog:
djangogirls
├──blog
│├──migrations
│└──static
└──mysite
Djangoencontraráautomaticamentetodasaspastaschamadas"static"dentrodequalquerumadaspastasdosseusapps,eserácapazdeusarseuconteúdocomoarquivosestáticos.
SeuprimeiroarquivoCSS!VamoscriarumarquivoCSSagora,paraadicionarseupróprioestiloparasuapáginadaweb.Crieumnovodiretóriochamadocssdentrodeseudiretóriostatic.Emseguida,crieumnovoarquivochamadoblog.cssdentrododiretóriocss.Pronto?
djangogirls
└───blog
└───static
└───css
└───blog.css
HoradeescreverCSS!Abraoarquivostatic/css/blog.cssnoseueditordecódigo.
NãovamosnosaprofundarmuitoemcustomizareaprendersobreCSSaqui,porqueébemfácilevocêpodeaprendernoseupróprioapósesteworkshop.RecomendamosfortementefazeresteCodeacademyHTML&CSScouseparaaprendertudooquevocê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émusarcorespredefinidas,comoredegreen.
Emseuarquivostatic/css/blog.cssvocêdeveadicionaroseguintecódigo:
h1a{
color:#FCA205;
}
h1aéumseletordeCSS.Issosignificaquenósestamosaplicandonossosestilosparaqualquerelementoadentrodeumelementoh1(i.e.quandotivermosnocódigoalgocomo:<h1><ahref="">link</a></h1>).Nestecasonósestamosdizendoparamudaracorpara#FCA205,queélaranja.Claro,vocêpodecolocaracorquevocêquiseraqui!
EmumarquivoCSSpodemosdeterminarestilosparaelementosnoarquivoHTML.Oselementossãoidentificadospelonomedoelemento(ouseja,a,h1,body),oatributodeclassouoatributoid.Classeeidsãonomesquevocêmesmodáaoelemento.Classesdefinemgruposdeelementos,eidsapontamparaelementosespecíficos.Porexemplo,a
CSS-Deixemaisbonito
72
seguintetagpodeseridentificadaporCSSusandoatagdenomea,aclasselink_externoouaidentificaçãodelink_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.Abraoarquivoblog/templates/blog/post_list.htmleadicioneessalinhanoiníciodomesmo:
{%loadstaticfiles%}
Estamosapenascarregandoarquivosestáticosaqui:).Depois,entreo<head>e/</head>,depoisdoslinksparaosarquivosdeCSSdoBootstrap(onavegadorlêosarquivosnaordemqueelessãodados,entãoocódigoemnossoarquivopodesubstituirocó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!
CSS-Deixemaisbonito
73
Bomtrabalho!Talvezagentetambémqueiradarumpoucodearaonossositeeaumentaramargemdoladoesquerdo?Vamostentar!
body{
padding-left:15px;
}
AdicioneistoaoseuarquivoCSS,salveevejacomoelefunciona!
Talvezagentepossacustomizarafontenonossocabeçalho?Colenaseção<head>doarquivoblog/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).
Agoraadicionealinhafont-family:'Lobster';noCSSdoarquivostatic/css/blog.cssdentrodoblocodedeclaraçãoh1a(ocódigoentreaschaves{e})eatualizeapágina:
CSS-Deixemaisbonito
74
h1a{
color:#FCA205;
font-family:'Lobster';
}
Incrível!
Comomencionadoacima,CSSusaoconceitodeclasses,quebasicamentepermitequevocênomeiepartedocódigoHTMLeapliqueestilosapenasàestaparte,semafetarasoutras.Ésuperútilsevocêtiverduasdivs,maselesestãofazendoalgomuitodiferente(comooseucabeçalhoeseupost),entãovocênãoquerqueelesfiquemparecidos.
VáemfrenteeonomeiealgumaspartesdocódigoHTML.Adicioneumaclassechamadadepage-headerparaodivquecontémocabeçalho,assim:
<divclass="page-header">
<h1><ahref="/">DjangoGirlsBlog</a></h1>
</div>
Eagora,adicioneumaclassepostemsuadivqueconté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á-loemseuarquivomysite/static/css/blog.css:
CSS-Deixemaisbonito
75
.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%}
noarquivoblog/templates/blog/post_list.htmlporisto:
CSS-Deixemaisbonito
76
<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êdevesercapazdeentenderamaiorparteapenaslendo.
NãotenhamedodemexerumpoucocomesseCSSetentarmudaralgumascoisas.Sevocêquebraralgumacoisa,nãosepreocupe,vocêsemprepodedesfazê-lo!
Dequalquerforma,recomendamosquefaçaessecursoon-lineCodeacademyHTML&CSSCoursecomodeverdecasapós-workshopparaaprendertudooquevocêprecisasabersobrecomotornarseussitesmaisbonitoscomCSS.
Prontoparaopróximocapítulo?!:)
CSS-Deixemaisbonito
77
EstendendoostemplatesOutracoisaboaqueoDjangotempravocêéotemplateextending.Oqueissosignifica?IssosignificaquevocêpodeusarasmesmaspartesdoseuHTMLemdiferentespáginasdoseusite.
Dessaformavocênãoprecisaficarserepetindoemcadaarquivoquandoquiserusaramesmainformação/layout.Esevocêquisermudaralgumacoisanãoprecisafazerissoemtodotemplate,sóumavez!
CriartemplatebaseUmtemplatebaseéotemplatemaisbásicoquevocêestenderáemcadapáginadoseusite.
Vamoscriarumarquivobase.htmlnapastablog/templates/blog/:
blog
└───templates
└───blog
base.html
post_list.html
Abra-oecopietudoqueestánoarquivopost_list.htmlparabase.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ãoembase.html,substituatodoseu<body>(tudoentre<body>e</body>)comisso:
Estendendoostemplates
78
<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êacaboudecriarumblock(bloco),queéumatagdetemplatequetepermiteinserirHTMLnesteblocoemoutrostemplatesqueestendembase.html.Nósvamostemostrarcomofazerissojájá.
Salveeabraoarquivoblog/templates/blog/post_list.htmlnovamente.Apagueexatamentetudoquenãoestiverdentrodatagbodyeapaguetambé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ósestamosestendendootemplatebase.htmlempost_list.html.Umaúltimacoisa:colocartudo(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:)
SeocorrerumerrodeTemplateDoesNotExists,quedizquenãoexistenenhumarquivochamadoblog/base.htmlesevocêtiverorunserverexecutandonoterminal,tentainterrompê-lo(precionandoCtrl+C-obotãoControlmaisobotãoCjuntos)ereinicieelerodandoocomandopythonmanage.pyrunserver.
Estendendoostemplates
79
AmpliesuaaplicaçãoJáconcluímostodosospassosnecessáriosparaacriaçãodonossosite:sabemoscomocriarummodelo,umaurl,umavieweumtemplate.Tambémsabemoscomomelhoraraaparênciadonossowebsite.
Horadepraticar!
Aprimeiracoisaqueprecisamosnonossoblogé,obviamente,umapáginaparamostrarumapostagem,certo?
JátemosummodelodePost,entãonãoprecisamosadicionarnadaaomodels.py.
CriarumlinknotemplateVamoscomeçarcomaadiçãodeumlinkdentrodoarquivoblog/templates/blog/post_list.html.Nestemomentoeledeveseparecercom:
{%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çãode{%%}significaqueestamosusandoastagsdetemplatedoDjango.DestavezvamosusarumaquevaicriarumaURLparanós!
blog.views.post_detailéumcaminhoparaumpost_detailVistaquequeremoscriar.Presteatenção:blogéonomedasuaaplicação(odiretórioblog),viewsvemdonomedoarquivoviews.pye,aúltimaparte-post_detail-éonomedaview.
Agoraquandoformospara:http://127.0.0.1:8000/teremosumerro(comoesperado,jáquenãotemosumaURLouumaviewparapost_detail).Vaiseparecercomisso:
Ampliesuaaplicação
81
VamoscriaraURLemurls.pyparaanossapost_detailview!
URL:http://127.0.0.1:8000/post/1/
QueremoscriarumaURLparaguiaroDjangoparaaviewchamadapost_detail,queirámostrarumpostcompletodoblog.Adicionealinhaurl(r'^post/(?P<pk>[0-9]+)/$',views.post_detail),aoarquivoblog/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]+)-essaparteémaiscomplicada.IssosignificaqueoDjangovailevartudoquevocêcolocaraquietransferirparaumaviewcomoumavariávelchamadapk.[0-9]tambémnosdizquesópodeserumnúmero,nãoumaletra(tudoentre0e9).+significaqueprecisaexistirumoumaisdígitos.Entãoalgocomohttp://127.0.0.1:8000/post//nãoéválido,mashttp://127.0.0.1:8000/post/1234567890/éperfeitamenteok!-/-entãoprecisamosde/outravez-$-"ofim"!
Issosignificaquesevocêdigitarhttp://127.0.0.1:8000/post/5/emseunavegador,Djangovaientenderquevocêestáprocurandoumaviewchamadapost_detailetransferirainformaçãodequepkéiguala5paraaquelaview.
pkéumaabreviaçãoparaprimarykey(chaveprimária).EssenomegeralmenteéusadonosprojetosfeitosemDjango.Masvocêpodedaronomequequiseràsvariáveis(lembre-se:minúsculoe_aoinvésdeespaçosembranco!).Porexemploemvezde(?P<pk>[0-9]+)podemosterumavariávelpost_id,entãoestaparteficariacomo:(?P<post_id>[0-9]+).
Razoável!Vamosatualizarapágina:http://127.0.0.1:8000/Boom!Aindaoutroerro!Comoesperado!
Ampliesuaaplicação
82
Vocêselembraqualéopróximopasso?Claro:adicionandoumaview!
post_detailviewDestavezanossaviewrecebeumparâmetroextrapk.Nossaviewprecisapegá-la,certo?Entãovamosdefinirnossafunçãocomodefpost_detail(request,pk):.Observequeprecisamosusarexatamenteomesmonomequeespecificamosemurls(pk).Omitiressavariáveléerradoeresultaráemumerro!
Agoraqueremosreceberapenasumpostdoblog.Paraissopodemosusarquerysetscomoeste:
Post.objects.get(pk=pk)
Masestecódigotemumproblema.SenãohouvernenhumPostcomachaveprimária(pk)fornecidateremosumerrohorroroso!
Nãoqueremosisso!Mas,claro,oDjangovemcomalgoquevailidarcomissoparanós:get_object_or_404.CasonãohajanenhumPostcomodadopkexibiráumapáginamuitomaisagradável(chamadaPageNotFound404-páginanãoencontrada).
Ampliesuaaplicação
83
AboanotíciaéquevocêrealmentepodecriarsuaprópriapáginadePagenotfoundetorná-lotãobonitaquantovocêquiser.Masissonãoésuperimportanteagora,entãonósvamosignorá-la.
Ok,horadeadicionarumaviewaonossoarquivoviews.py!
Devemosabrirblog/views.pyeadicionaroseguintecódigo:
fromdjango.shortcutsimportrender,get_object_or_404
Pertodeoutraslinhasfrom.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/
Ampliesuaaplicação
84
Funcionou!Masoqueacontecequandovocêclicaemumlinknotítulodopostdoblog?
Ahnão!Outroerro!Masnósjásabemoscomolidarcomisso,né?Precisamosadicionarumtemplate!
Vamoscriarumarquivoemblog/templates/blogchamadopost_detail.html.
Seráalgoparecidocomisto:
Ampliesuaaplicação
85
{%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%}
Maisumavezestamosestendendobase.html.Noblocodecontentqueremosexibiropublished_date(datadepublicação)dopost(sehouver),títuloetexto.Masdevemosdiscutiralgumascoisasimportantes,certo?
{%if...%}...{%endif%}éumatagdetemplatequepodemosusarquandoqueremosverificaralgo(Lembre-seif...else...docapítulointroduçãoaoPython?).Nestecenário,queremosverificarsepublished_datedeumpostnãoestávazia.
Ok,podemosatualizarnossapáginaeversePagenotfoundjásefoi.
Yay!Funciona!
Maisumacoisa:horadeimplantar!SeriabomverseseusiteaindaestarátrabalhandoemPythonAnywhere,certo?Vamostentarfazerdeploynovamente.
$gitstatus
$gitadd--all.
$gitstatus
$gitcommit-m"Addedviewstocreate/editblogpostinsidethesite."
$gitpush
Ampliesuaaplicação
86
Então,emumconsolePythonAnywhereBash:
$cdmy-first-blog
$gitpull
Finalmente,puleparaaWebtabeaperteReload.
Edeveserisso!Parabéns:)
Ampliesuaaplicação
87
FormuláriosPorúltimoqueremosumaformalegaldeadicionareeditaraspostagensdonossoblog.AferramentadeadministraçãodoDjangoélegal,maselaéumpoucodifícildecustomizarededeixarmaisbonita.Seusarmosformuláriosteremoscontroleabsolutosobrenossainterface-podemosfazerqualquercoisaqueimaginarmos!
UmacoisalegaldoDjangoéquenóspodemostantocriarumformuláriodozerocomopodemoscriarumModelFormquesalvaoresultadodoformulárioparaumdeterminadomodelo.
Issoéexatamenteoquenósqueremosfazer:criaremosumformulárioparaonossomodeloPost.
AssimcomotodaparteimportantedoDjango,formstemseupróprioarquivo:forms.py.
Precisamoscriarumarquivocomestenomedentrodapastablog.
blog
└──forms.py
Ok,vamosabri-loeescreverneleoseguinte:
fromdjangoimportforms
from.modelsimportPost
classPostForm(forms.ModelForm):
classMeta:
model=Post
fields=('title','text',)
PrimeiroprecisamosimportaromódulodeformuláriosdoDjango(fromdjangoimportforms)e,obviamente,nossomodeloPost(from.modelsimportPost).
PostForm,comovocêjádevesuspeitar,éonomedonossoformulário.PrecisamosdizeraoDjangoqueesteformulárioéumModelForm(assimoDjangopodefazeramágicapragente)-oforms.ModelForméoresponsávelporisso.
Segundo,nóstemosaclasseMetaondedizemosaoDjangoqualmodelodeveriaserusadoparacriaresteformulário(model=Post).
Finalmente,nóspodemosdizerqual(is)campo(s)deveriamentraremnossoformulário.Nessecenárionósqueremosapenasotitleetextparaserexposto-authordeveriaserapessoaqueestálogadanosistema(nessecaso,você!)ecreated_datedeveriasersetadoautomaticamentequandonóscriamosumpost(nocódigo),correto?
Eéissoaí!Tudooqueprecisamosfazeragoraéusaroformulárioemumaviewemostrá-loemumtemplate.
Então,maisumavez,nósiremoscriar:umlinkparaapágina,umaURL,umavieweumtemplate.
LinkparaapáginacomoformulárioÉhoradeabrirblog/templates/blog/base.html.Nósiremosadicionarumlinkemdivnomeadopage-header:
<ahref="{%url'blog.views.post_new'%}"class="top-menu"><spanclass="glyphiconglyphicon-plus"></span></a>
Notequenósqueremoschamarnossanovavisãopost_new.
Depoisdeadicionaralinha,seuhtmldeveseparecercomisso:
Formulários
88
{%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áginahttp://127.0.0.1:8000vocêverá,obviamente,umerrofamiliarNoReverseMatchcerto?
URLVamosabriroarquivoblog/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ósveremosumAttributeError,desdequenósnãotemosavisãopost_newimplementada.Vamosadicioná-laagora.
post_newviewHoradeabriroarquivoblog/views.pyeadicionaraslinhasseguintescomorestodaslinhasfrom:
from.formsimportPostForm
enossaview:
Formulários
89
defpost_new(request):
form=PostForm()
returnrender(request,'blog/post_edit.html',{'form':form})
ParacriarumnovoformularioPost,nósdevemoschamarPostForm()epassá-loparaotemplate.Nósiremosvoltarparaestaview,masporagoravamoscriarrapidamenteumtemplateparaoformulário.
Template(modelos)Precisamoscriarumarquivopost_edit.htmlnapastablog/templates/blog.Prafazeroformuláriofuncionarprecisamosdemuitascoisas:
Temosqueexibiroformulário.Podemosfazerissosimplesmentecomum``.AlinhaacimaprecisaestardentrodeumatagHTMLform:<formmethod="POST">...</form>PrecisamosdeumbotãoSalvar.FazemosissocomumbotãoHTML:<buttontype="submit">Save</button>Efinalmente,depoisdeabriratag<form...>precisamosadicionarum{%csrf_token%}.Issoémuitoimportante,poiséissoquefazonossoformulárioficarseguro!ODJangovaireclamarsevocêesquecerdeadicionarissoesimplesmentesalvaroformulário:
Beleza,entãovamosvercomoficouoHTMLpost_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!
Formulários
90
Mas,espereumminuto!Quandovocêdigitaalgumacoisanoscampostitleetextetentasalvaroqueacontece?
Nada!Estamosnovamentenamesmapáginaenossotextosumiu...Enenhumpostfoiadicionado.Entãooquedeuerrado?
Arespostaé:nada.Precisamostrabalharumpoucomaisnanossaview.
SalvandooformulárioAbrablog/views.pymaisumavez.Atualmentetudoquetemosnavisãopost_newé:
defpost_new(request):
form=PostForm()
returnrender(request,'blog/post_edit.html',{'form':form})
Quandonósenviamosoformulário,somostrazidosdevoltaparaamesmavisão,masdestaveztemosmaisalgunsdadosnorequest,maisespecificamenteemrequest.POST(onomenãotemnadacom"post"deblog,temavercomofatodequeestamos"postando"dados).VocêselembraquenoarquivoHTMLnossadefiniçãode<form>temavariávelmethod="POST"?Todososcamposvindosdo"form"estarãodisponíveisagoraemrequest.POST.VocênãodeveriarenomearPOSTparanadadiferentedisso(oúnicooutrovalorválidoparamethodéGET,masnósnãotemostempoparaexplicarqualéadiferença).
Entãonanossaviewnóstemosduassituaçõesseparadasparalidar.Aprimeiraéquantoacessamosapáginapelaprimeiravezequeremosumformulárioembranco.Easegunda,équandonóstemosquevoltarparaaviewcomtodososdadosdoformulárioquenósdigitamos.Dessemodo,precisamosadicionarumacondição(usaremosifparaisso).
Formulários
91
ifrequest.method=="POST":
[...]
else:
form=PostForm()
Estánahoradepreencherospontos[...].SemethodéPOSTentãonósqueremosconstruiroPostFormcomosdadosqueveemdoformulário,certo?Nósiremosfazerassim:
form=PostForm(request.POST)
Fácil!Próximacoisaéverificarseoformulárioestácorreto(todososcamposrequeridossãodefinidosevaloresincorretosnãoserãosalvos).Fazemosissocomform.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áriocomform.saveeadicionadosumautor(desdequenãohajaocampoauthoremPostForm,eestecampoéobrigatório!).commit=FalsesignificaquenãoqueremossalvaromodeloPostainda-queremosadicionarautorprimeiro.Namaioriadasvezesvocêiráusarform.save(),semcommit=False,masnestecaso,precisamosfazerisso.post.save()irápreservarasalterações(adicionandoautor)eécriadoumnovopostnoblog!
Finalmente,nãoseriafantásticosenóspudéssemosimediatamenteiràpáginadepost_detailparaorecém-criadoblogpost,certo?Parafazerissonósprecisaremosdemaisumaimportação:
fromdjango.shortcutsimportredirect
Adicione-ologonoiníciodoseuarquivo.Eagorapodemosdizer:váparaapáginapost_detailparaumrecém-criadopost.
returnredirect('blog.views.post_detail',pk=post.pk)
blog.views.post_detailéonomedaviewquequeremosir.Lembre-sequeessaviewexigeumavariávelpk?Parapassarissonasviewsusamospk=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/,adicioneumtitleeotext,salve...evoilà!Onovoblogpostéadicionadoenóssomosredirecionadosparaapáginadepost_detail!
Formulários
92
Vocêprovavelmentenotouquenósnãoestamosdefinindoadatadepublicaçãoemtudo.VamosintroduzirumbotãodepublicaçãoemDjangoGirlsTutorial:Extensões.
Issoéincrível!
ValidaçãodeformuláriosAgora,nóslhemostraremoscomoosfórmulariossãolegais.Opostdoblogprecisateroscampostitleetext.EmnossomodeloPostnãodissemos(emoposiçãoapublished_date)queessescamposnãosãonecessários,entãoDjango,porpadrão,espera-osaserdefinido.
Tentesalvaroformuláriosemtitleetext.Adivinheoquevaiacontecer!
Djangoestátomandocontadevalidarsetodososcamposdenossoformulárioestãocorretos.Nãoéincrível?
ComorecentementeusamosainterfacedeadministraçãodoDjangoosistemaentendequeestamoslogados.Existemalgumassituaçõesquepoderiamlevarasermosdeslogadosdosistema(fecharonavegador,reiniciarbancodedadosetc.).Sevocêperceberqueerrosestãoaparecendoaocriarumpostquereferenciaumusuárioquenãoestálogado,váparaapáginaadminhttp://127.0.0.1:8000eloguenovamente.Issovairesolveroproblematemporariamente.Háumajustepermanenteesperandoporvocêemliçãodecasa:adicionarsegurançanoseusite!,capítuloapósotutorialprincipal.
Formulários
93
EditandooformulárioAgorasabemoscomoadicionarumnovoformulário.Masesequisermoseditarumjáexistente?Émuitosemelhanteaoquefizemos.Vamoscriaralgumascoisasimportantesrapidamente(sevocênãoentenderalgumacoisa-vocêdeveperguntaraseuprofessorouvejaoscapítulosanteriores,jácobrimostodasessasetapasanteriormente).
Abrablog/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%}
Emblog/urls.pyadicionamosestalinha:
url(r'^post/(?P<pk>[0-9]+)/edit/$',views.post_edit,name='post_edit'),
Nósreutilizaremosomodeloblog/templates/blog/post_edit.html,entãoaúltimacoisaquefaltaéumaview.
Vamosabrirblog/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})
Formulários
94
Issoéquaseexatamenteigualanossaviewdepost_new,certo?Masnãototalmente.Primeiracoisa:passamosumparâmetroextradaurlpk.Emseguida:pegamosomodeloPostquequeremoseditarcomget_object_or_404(Post,pk=pk)eentão,quandocriamosumformuláriopassamosestepostcomoumainstância,tantoquandosalvamosoformulário:
form=PostForm(request.POST,instance=post)
comoquandonósapenasabrimosumformuláriocomestepostparaeditar:
form=PostForm(instance=post)
Ok,vamostestarsefunciona!Vamosparaapáginapost_detail.Devehaverumbotãoeditarnocantosuperiordireito:
Quandovocêclicarnelevocêveráoformuláriocomanossapostagem:
Formulários
95
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:)
Formulários
96
DomínioPythonAnywheretedeuumdomíniogratuito,mastalvezvocênãoqueirater".pythonanywhere.com"nofinaldaURLdoseublog.Talvezvocêqueiraseublogapenas"www.infinite-kitten-pictures.org"ou"www.3d-printed-steam-engine-parts.com"ou"www.antique-buttons.com"ou"www.mutant-unicornz.net",ousejaoquevaiser.
Aquivamosfalarumpoucosobreondeobterumdomínioecomoligá-loaseuaplicativodawebemPythonAnywhere.Noentanto,vocêdevesaberqueamaioriadosdomínioscustamdinheiroePythonAnyweretambémcobraumataxamensalparausarseupróprionomededomínio--nãoémuitodinheiro,nototal,masissoprovavelmenteéalgoquevocêsóquerfazersevocêestárealmentecomprometido!
Onderegistrarumdomínio?Umdomínionormalcustamaisoumenos15dólaresporano.Existemdomíniosmaiscarosemaisbaratosdependendodoprovedor.Existemumasériedeempresasdasquaisvocêpodecomprarumdomínio:umasimplespesquisanogooglepodelistarumasériedelas.
OnossofavoritoéoIwantmyname(euqueromeunome).Elesanunciamseuserviçocomo"gestãodedomínioindolor",eele,realmente,éindolor.
Vocêtambémpodeobterdomíniosgratuitamente.dot.tkéumlugarparapegarum,masvocêdeveestarcientedequedomíniosgrátisàsvezesparecemmuitobaratos--seseusitevaiserparaumprofissionaldenegócios,vocêdevepensarempagarporumdomínio"correto"queterminaem.com.
ComoapontarseudomínionoPythonAnywhereSevocêpassouporiwantmyname.com,cliqueemdomíniosnomenueescolhaseudomíniorecém-adquirido.Emseguida,localizeecliquenolinkmanageDNSrecords:
Agoravocêprecisalocalizaresteformulário:
Epreenchercomosseguintesdetalhes:-Hostname:www-tipo:CNAME-valor:seudomíniodePythonAnywhere(porexemplodjangogirls.pythonanywhere.com)-TTL:60
CliquenobotãoAdicionaresalveasmudançasnapartedebaixo.
NotaSevocêusouumprovedordedomíniodiferente,oUIexataparaencontraroseuDNS/configuraçõesdeCNAMEserádiferente,masseuobjetivoéomesmo:paraconfigurarumCNAMEqueapontaseunovodomínionoyourusername.pythonanywhere.com.
Domínio
98
Podelevaralgunsminutosparaoseudomíniocomeçaratrabalhar,entãosejapaciente!
ConfigureodomínioatravésdeumwebappnaPythonAnywhere.VocêtambémprecisadizerPythonAnywherequevocêdesejausaroseudomíniopersonalizado.
VáparaapáginaPythonAnywherecontaseupgradesuaconta.Aopçãomaisbarata(umplanode"Hacker")ébomparacomeçar,vocêpodesempreatualizá-lomaistardequandovocêficarsuperfamosoetivermilhõesdeacessos.
Emseguida,vánaWebtabeanotealgumascoisas:
CopieocaminhoparaseuvirtualenvecoloqueemumlugarseguroCliqueparaseuarquivodeconfiguraçãodowsgi,copieoconteúdoecoleemumlugarseguro.
Emseguida,excluaseuantigowebapp.Nãosepreocupe,issonãovaiexcluirnadadoseucódigo,eleapenasirásedesligardodomínioyourusername.pythonanywhere.com.Emseguida,crieumnovoaplicativowebesigaestespassos:
DigiteseunomededomínionovoEscolha"manualconfiguration"EscolhaPython3.4Eéisso!
Quandovocêtivervoltadoparaawebtab.
ColarocaminhovirtualenvquevocêsalvouantesClicarnoarquivodeconfiguraçãowsgiecolaroconteúdodoseuarquivodeconfiguraçãoantigo
Cliqueemreloadwebappevocêdeveencontrarseusitelivenonovodomínio!
Sevocêtiverqualquerproblema,cliquenolink"Enviarfeedback"nositePythonAnywhere,eumdosseusadministradoresamigáveisvaiestarláparaajudá-lo.
Domínio
99
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'sofficialtutorialNewCodertutorialsCodeAcademyPythoncourseCodeAcademyHTML&CSScourseDjangoCarrotstutorialLearnPythonTheHardWaybookGettingStartedWithDjangovideolessonsTwoScoopsofDjango:BestPracticesforDjangobook
Oquevemdepois?
100