Tabela de conteúdos - we.riseup.net · Se você estiver em Mac ou num Linux, você provavelmente...

100

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

Introdução

5

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"

[email protected]

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

Implantação!

52

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

Estendendoostemplates

80

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

Formulários

97

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