table of contents - bedford-computing.co.ukbedford-computing.co.uk/learning/wp-content/... ·...

Post on 27-Feb-2020

6 Views

Category:

Documents

0 Downloads

Preview:

Click to see full reader

TRANSCRIPT

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

TableofContentsIntroduction

Installation

HowtheInternetworks

Introductiontocommandline

Pythoninstallation

Codeeditor

IntroductiontoPython

WhatisDjango?

Djangoinstallation

YourfirstDjangoproject!

Djangomodels

Djangoadmin

Deploy!

Djangourls

Djangoviews-timetocreate!

IntroductiontoHTML

DjangoORM(Querysets)

Dynamicdataintemplates

Djangotemplates

CSS-makeitpretty

Templateextending

Extendyourapplication

DjangoForms

What'snext?

2

DjangoGirlsTutorial

ThisworkislicensedundertheCreativeCommonsAttribution-ShareAlike4.0InternationalLicense.Toviewacopyofthislicense,visithttps://creativecommons.org/licenses/by-sa/4.0/

IntroductionHaveyoueverfeltthattheworldismoreandmoreabouttechnologyandyouaresomehowleftbehind?Haveyoueverwonderedhowtocreateawebsitebuthaveneverhadenoughmotivationtostart?Haveyoueverthoughtthatthesoftwareworldistoocomplicatedforyoutoeventrydoingsomethingonyourown?

Well,wehavegoodnewsforyou!Programmingisnotashardasitseemsandwewanttoshowyouhowfunitcanbe.

Thistutorialwillnotmagicallyturnyouintoaprogrammer.Ifyouwanttobegoodatit,youneedmonthsorevenyearsoflearningandpractice.Butwewanttoshowyouthatprogrammingorcreatingwebsitesisnotascomplicatedasitseems.Wewilltrytoexplaindifferentbitsandpiecesaswellaswecan,soyouwillnotfeelintimidatedbytechnology.

Wehopethatwe'llbeabletomakeyoulovetechnologyasmuchaswedo!

Whatwillyoulearnduringthetutorial?Onceyou'vefinishedthetutorial,youwillhaveasimple,workingwebapplication:yourownblog.Wewillshowyouhowtoputitonline,sootherswillseeyourwork!

Itwill(moreorless)looklikethis:

Introduction

3

Ifyouworkwiththetutorialonyourownanddon'thaveacoachwhowillhelpyouincaseofanyproblem,wehavea

chatsystemforyou: .Weaskedourcoachesandpreviousattendeestobetherefromtimetotimeandhelpotherswiththetutorial!Don'tbeafraidtoaskyourquestionthere!

OK,let'sstartatthebeginning…

FollowingthetutorialathomeItisamazingtotakepartinaDjangoGirlsworkshop,butweareawarethatitisnotalwayspossibletoattendone.Thisiswhyweencourageyoutotryfollowingthistutorialathome.Forreadersathomewearecurrentlypreparingvideosthatwillmakeiteasiertofollowthetutorialonyourown.Itisstillaworkinprogress,butmoreandmorethingswillbecoveredsoonattheCodingisforgirlsYouTubechannel.

Ineverychapteralreadycovered,thereisalinkthatpointstothecorrectvideo.

AboutandcontributingThistutorialismaintainedbyDjangoGirls.Ifyoufindanymistakesorwanttoupdatethetutorialpleasefollowthecontributingguidelines.

Wouldyouliketohelpustranslatethetutorialtootherlanguages?

Introduction

4

Currently,translationsarebeingkeptoncrowdin.complatformat:

https://crowdin.com/project/django-girls-tutorial

Ifyourlanguageisnotlistedoncrowdin,pleaseopenanewissueinformingusofthelanguagesowecanaddit.

Introduction

5

Ifyou'redoingthetutorialathomeIfyou'redoingthetutorialathome,notatoneoftheDjangoGirlsevents,youcancompletelyskipthischapternowandgostraighttotheHowtheInternetworks?chapter.

Thisisbecausewecoverthesethingsinthewholetutorialanyway,andthisisjustanadditionalpagethatgathersalloftheinstallationinstructionsinoneplace.TheDjangoGirlseventincludesone"Installationevening"whereweinstalleverythingsowedon'tneedtobotherwithitduringtheworkshop,sothisisusefulforus.

Ifyoufindituseful,youcanfollowthroughthischaptertoo.Butifyouwanttostartlearningthingsbeforeinstallingabunchofstuffonyourcomputer,skipthischapterandwewillexplaintheinstallationparttoyoulateron.

Goodluck!

InstallationIntheworkshopyouwillbebuildingablog,andthereareafewsetuptasksinthetutorialwhichwouldbegoodtoworkthroughbeforehandsothatyouarereadytostartcodingontheday.

Chromebooksetup(ifyou'reusingone)Youcanskiprightoverthissectionifyou'renotusingaChromebook.Ifyouare,yourinstallationexperiencewillbealittledifferent.Youcanignoretherestoftheinstallationinstructions.

Cloud9

Cloud9isatoolthatgivesyouacodeeditorandaccesstoacomputerrunningontheinternetwhereyoucaninstall,write,andrunsoftware.Forthedurationofthetutorial,Cloud9willactasyourlocalmachine.You'llstillberunningcommandsinaterminalinterfacejustlikeyourclassmatesonOSX,Ubuntu,orWindows,butyourterminalwillbeconnectedtoacomputerrunningsomewhereelsethatCloud9setsupforyou.

1. InstallCloud9fromtheChromewebstore2. Gotoc9.io3. Signupforanaccount4. ClickCreateaNewWorkspace5. Nameitdjango-girls6. SelecttheBlank(secondfromtherightonthebottomrowwithorangelogo)

Nowyoushouldseeaninterfacewithasidebar,abigmainwindowwithsometext,andasmallwindowatthebottomthatlookssomethinglike:

Cloud9

yourusername:~/workspace$

Thisbottomareaisyourterminal,whereyouwillgivethecomputerCloud9haspreparedforyouinstructions.Youcanresizethatwindowtomakeitabitbigger.

VirtualEnvironment

Installation

6

Avirtualenvironment(alsocalledavirtualenv)islikeaprivateboxwecanstuffusefulcomputercodeintoforaprojectwe'reworkingon.Weusethemtokeepthevariousbitsofcodewewantforourvariousprojectsseparatesothingsdon'tgetmixedupbetweenprojects.

InyourterminalatthebottomoftheCloud9interface,runthefollowing:

Cloud9

sudoaptinstallpython3.5-venv

Ifthisstilldoesn'twork,askyourcoachforsomehelp.

Next,run:

Cloud9

mkdirdjangogirls

cddjangogirls

python3.5-mvenvmyvenv

sourcemyvenv/bin/activate

pipinstalldjango~=1.9.0

(notethatonthelastlineweuseatildefollowedbyanequalsign:~=).

Github

MakeaGithubaccount.

PythonAnywhere

TheDjangoGirlstutorialincludesasectiononwhatiscalledDeployment,whichistheprocessoftakingthecodethatpowersyournewwebapplicationandmovingittoapubliclyaccessiblecomputer(calledaserver)sootherpeoplecanseeyourwork.

ThispartisalittleoddwhendoingthetutorialonaChromebooksincewe'realreadyusingacomputerthatisontheinternet(asopposedto,say,alaptop).However,it'sstilluseful,aswecanthinkofourCloud9workspaceasaplaceorour"inprogress"workandPythonAnywhereasaplacetoshowoffourstuffasitbecomesmorecomplete.

Thus,signupforanewPythonAnywhereaccountatwww.pythonanywhere.com.

InstallPythonForreadersathome:thischapteriscoveredintheInstallingPython&CodeEditorvideo.

ThissectionisbasedonatutorialbyGeekGirlsCarrots(https://github.com/ggcarrots/django-carrots)

DjangoiswritteninPython.WeneedPythontodoanythinginDjango.Let'sstartbyinstallingit!WewantyoutoinstallPython3.5,soifyouhaveanyearlierversion,youwillneedtoupgradeit.

WindowsYoucandownloadPythonforWindowsfromthewebsitehttps://www.python.org/downloads/release/python-351/.Afterdownloadingthe*.msifile,youshouldrunit(double-clickonit)andfollowtheinstructionsthere.Itisimportanttorememberthepath(thedirectory)whereyouinstalledPython.Itwillbeneededlater!

Onethingtowatchoutfor:onthesecondscreenoftheinstallationwizard,marked"Customize",makesureyouscrolldowntothe"Addpython.exetothePath"optionandselect"Willbeinstalledonlocalharddrive",asshownhere:

Installation

7

Inupcomingsteps,you'llbeusingtheWindowsCommandLine(whichwe'llalsotellyouabout).Fornow,ifyouneedtotypeinsomecommands,gotoStartmenu→AllPrograms→Accessories→CommandPrompt.(OnnewerversionsofWindows,youmighthavetosearchfor"CommandPrompt"sinceit'ssometimeshidden.)

Linux

ItisverylikelythatyoualreadyhavePythoninstalledoutofthebox.Tocheckifyouhaveitinstalled(andwhichversionitis),openaconsoleandtypethefollowingcommand:

command-line

$python3--version

Python3.5.1

Ifyouhaveadifferent'microversion'ofPythoninstalled,e.g.3.5.0,thenyoudon'thavetoupgrade.Ifyoudon'thavePythoninstalled,orifyouwantadifferentversion,youcaninstallitasfollows:

DebianorUbuntu

Typethiscommandintoyourconsole:

command-line

$sudoapt-getinstallpython3.5

Fedora(upto21)

Usethiscommandinyourconsole:

command-line

Installation

8

$sudoyuminstallpython3

Fedora(22+)Usethiscommandinyourconsole:

command-line

$sudodnfinstallpython3

openSUSE

Usethiscommandinyourconsole:

command-line

$sudozypperinstallpython3

OSXBeforeyouinstallPythononOSX,youshouldensureyourMacsettingsallowinstallingpackagesthataren'tfromtheAppStore.GotoSystemPreferences(it'sintheApplicationsfolder),click"Security&Privacy,"andthenthe"General"tab.Ifyour"Allowappsdownloadedfrom:"issetto"MacAppStore,"changeitto"MacAppStoreandidentifieddevelopers."

Youneedtogotothewebsitehttps://www.python.org/downloads/release/python-351/anddownloadthePythoninstaller:

DownloadtheMacOSX64-bit/32-bitinstallerfile,Doubleclickpython-3.5.1-macosx10.6.pkgtoruntheinstaller.

VerifytheinstallationwassuccessfulbyopeningtheTerminalapplicationandrunningthepython3command:

command-line

$python3--version

Python3.5.1

Ifyouhaveanydoubts,orifsomethingwentwrongandyouhavenoideawhattodonext,pleaseaskyourcoach!Sometimesthingsdon'tgosmoothlyandit'sbettertoaskforhelpfromsomeonewithmoreexperience.

SetupvirtualenvandinstallDjangoPartofthissectionisbasedontutorialsbyGeekGirlsCarrots(https://github.com/ggcarrots/django-carrots).

Partofthissectionisbasedonthedjango-marcadortutoriallicensedundertheCreativeCommonsAttribution-ShareAlike4.0InternationalLicense.Thedjango-marcadortutorialiscopyrightedbyMarkusZapke-Gründemannetal.

Virtualenvironment

Installation

9

BeforeweinstallDjangowewillgetyoutoinstallanextremelyusefultooltohelpkeepyourcodingenvironmenttidyonyourcomputer.It'spossibletoskipthisstep,butit'shighlyrecommended.Startingwiththebestpossiblesetupwillsaveyoualotoftroubleinthefuture!

So,let'screateavirtualenvironment(alsocalledavirtualenv).VirtualenvwillisolateyourPython/Djangosetuponaper-projectbasis.Thismeansthatanychangesyoumaketoonewebsitewon'taffectanyothersyou'realsodeveloping.Neat,right?

Allyouneedtodoisfindadirectoryinwhichyouwanttocreatethevirtualenv;yourhomedirectory,forexample.OnWindowsitmightlooklikeC:\Users\Name\(whereNameisthenameofyourlogin).

NOTE:OnWindows,makesurethatthisdirectorydoesnotcontainaccentedorspecialcharacters;ifyourusernamecontainsaccentedcharacters,useadifferentdirectory,forexampleC:\djangogirls.

Forthistutorialwewillbeusinganewdirectorydjangogirlsfromyourhomedirectory:

command-line

$mkdirdjangogirls

$cddjangogirls

Wewillmakeavirtualenvcalledmyvenv.Thegeneralcommandwillbeintheformat:

command-line

$python3-mvenvmyvenv

Windows

Tocreateanewvirtualenv,youneedtoopentheconsole(wetoldyouaboutthatafewchaptersago–remember?)andrunC:\Python35\python-mvenvmyvenv.Itwilllooklikethis:

command-line

C:\Users\Name\djangogirls>C:\Python35\python-mvenvmyvenv

whereC:\Python35\pythonisthedirectoryinwhichyoupreviouslyinstalledPythonandmyvenvisthenameofyourvirtualenv.Youcanuseanyothername,butsticktolowercaseandusenospaces,accentsorspecialcharacters.Itisalsogoodideatokeepthenameshort–you'llbereferencingitalot!

LinuxandOSX

CreatingavirtualenvonbothLinuxandOSXisassimpleasrunningpython3-mvenvmyvenv.Itwilllooklikethis:

command-line

$python3-mvenvmyvenv

myvenvisthenameofyourvirtualenv.Youcanuseanyothername,butsticktolowercaseandusenospaces.Itisalsogoodideatokeepthenameshortasyou'llbereferencingitalot!

Installation

10

NOTE:OnsomeversionsofDebian/Ubuntuyoumayreceivethefollowingerror:

command-line

Thevirtualenvironmentwasnotcreatedsuccessfullybecauseensurepipisnotavailable.OnDebian/Ubuntusys

tems,youneedtoinstallthepython3-venvpackageusingthefollowingcommand.

apt-getinstallpython3-venv

Youmayneedtousesudowiththatcommand.Afterinstallingthepython3-venvpackage,recreateyourvirtual

environment.

Inthiscase,followtheinstructionsaboveandinstallthepython3-venvpackage:

command-line

$sudoapt-getinstallpython3-venv

NOTE:OnsomeversionsofDebian/Ubuntuinitiatingthevirtualenvironmentlikethiscurrentlygivesthefollowingerror:

command-line

Error:Command'['/home/eddie/Slask/tmp/venv/bin/python3','-Im','ensurepip','--upgrade','--default-pip']'

returnednon-zeroexitstatus1

Togetaroundthis,usethevirtualenvcommandinstead.

command-line

$sudoapt-getinstallpython-virtualenv

$virtualenv--python=python3.5myvenv

NOTE:Ifyougetanerrorlike

command-line

E:Unabletolocatepackagepython3-venv

theninsteadrun:

command-line

sudoaptinstallpython3.5-venv

WorkingwithvirtualenvThecommandabovewillcreateadirectorycalledmyvenv(orwhatevernameyouchose)thatcontainsourvirtualenvironment(basicallyabunchofdirectoryandfiles).

WindowsStartyourvirtualenvironmentbyrunning:

command-line

C:\Users\Name\djangogirls>myvenv\Scripts\activate

Installation

11

NOTE:onWindows10youmightgetanerrorintheWindowsPowerShellsaysexecutionofscriptsisdisabledonthissystem.InthosecasesopenanotherWindowsPowerShellandRunasAdministratortrydoingthisbeforecontinue:

command-line

C:\WINDOWS\system32>Set-ExecutionPolicy-ExecutionPolicyRemoteSigned

ExecutionPolicyChange

Theexecutionpolicyhelpsprotectyoufromscriptsthatyoudonottrust.Changingtheexecutionpolicym

ightexposeyoutothesecurityrisksdescribedintheabout_Execution_Policieshelptopicathttp://go.micros

oft.com/fwlink/?LinkID=135170.Doyouwanttochangetheexecutionpolicy?[Y]Yes[A]YestoAll[N]No[L

]NotoAll[S]Suspend[?]Help(defaultis"N"):A

LinuxandOSX

Startyourvirtualenvironmentbyrunning:

command-line

$sourcemyvenv/bin/activate

Remembertoreplacemyvenvwithyourchosenvirtualenvname!

NOTE:sometimessourcemightnotbeavailable.Inthosecasestrydoingthisinstead:

command-line

$.myvenv/bin/activate

Youwillknowthatyouhavevirtualenvstartedwhenyouseethatthepromptinyourconsoleisprefixedwith(myvenv).

Whenworkingwithinavirtualenvironment,pythonwillautomaticallyrefertothecorrectversionsoyoucanusepythoninsteadofpython3.

OK,wehaveallimportantdependenciesinplace.WecanfinallyinstallDjango!

InstallingDjangoNowthatyouhaveyourvirtualenvstarted,youcaninstallDjango.

Beforewedothat,weshouldmakesurewehavethelatestversionofpip,thesoftwarethatweusetoinstallDjango.Intheconsole,runpipinstall--upgradepip.

Thenrunpipinstalldjango~=1.9.0(notethatweuseatildefollowedbyanequalsign:~=)toinstallDjango.

command-line

(myvenv)~$pipinstalldjango~=1.9.0

Downloading/unpackingdjango==1.9

Installingcollectedpackages:django

Successfullyinstalleddjango

Cleaningup...

onWindows

Installation

12

IfyougetanerrorwhencallingpiponWindowsplatform,pleasecheckifyourprojectpathnamecontainsspaces,accentsorspecialcharacters(forexample,C:\Users\UserName\djangogirls).Ifitdoes,pleaseconsiderusinganotherplacewithoutspaces,accentsorspecialcharacters(suggestion:C:\djangogirls).Createanewvirtualenvinthenewdirectory,thendeletetheoldoneandtrytheabovecommandagain.(Movingthevirtualenvdirectorywon'tworksincevirtualenvusesabsolutepaths.)

onWindows8andWindows10

YourcommandlinemightfreezeafterwhenyoutrytoinstallDjango.Ifthishappens,insteadoftheabovecommanduse:

command-line

C:\Users\Name\djangogirls>python-mpipinstalldjango~=1.9.0

onLinux

IfyougetanerrorwhencallingpiponUbuntu12.04pleaserunpython-mpipinstall-U--force-reinstallpiptofixthepipinstallationinthevirtualenv.

That'sit!You'renow(finally)readytocreateaDjangoapplication!

InstallacodeeditorTherearealotofdifferenteditorsanditlargelyboilsdowntopersonalpreference.MostPythonprogrammersusecomplexbutextremelypowerfulIDEs(IntegratedDevelopmentEnvironments),suchasPyCharm.Asabeginner,however,that'sprobablylesssuitable;ourrecommendationsareequallypowerful,butalotsimpler.

Oursuggestionsarebelow,butfeelfreetoaskyourcoachwhattheirpreferencesare–it'llbeeasiertogethelpfromthem.

GeditGeditisanopen-source,freeeditor,availableforalloperatingsystems.

Downloadithere

SublimeText2SublimeTextisaverypopulareditorwithafreeevaluationperiod.It'seasytoinstallanduse,andit'savailableforalloperatingsystems.

Downloadithere

AtomAtomisanextremelynewcodeeditorcreatedbyGitHub.It'sfree,open-source,easytoinstallandeasytouse.It'savailableforWindows,OSXandLinux.

Downloadithere

Whyareweinstallingacodeeditor?Youmightbewonderingwhyweareinstallingthisspecialcodeeditorsoftware,ratherthanusingsomethinglikeWordorNotepad.

Installation

13

Thefirstreasonisthatcodeneedstobeplaintext,andtheproblemwithprogramslikeWordandTexteditisthattheydon'tactuallyproduceplaintext,theyproducerichtext(withfontsandformatting),usingcustomformatslikeRTF(RichTextFormat).

Thesecondreasonisthatcodeeditorsarespecialisedforeditingcode,sotheycanprovidehelpfulfeatureslikehighlightingcodewithcolouraccordingtoitsmeaning,orautomaticallyclosingquotesforyou.

We'llseeallthisinactionlater.Soon,you'llcometothinkofyourtrustyoldcodeeditorasoneofyourfavouritetools.:)

InstallGitWindows

YoucandownloadGitfromgit-scm.com.Youcanhit"next"onallstepsexceptforone;inthefifthstepentitled"AdjustingyourPATHenvironment",choose"UseGitandoptionalUnixtoolsfromtheWindowsCommandPrompt"(thebottomoption).Otherthanthat,thedefaultsarefine.CheckoutWindows-style,commitUnix-stylelineendingsisgood.

MacOS

DownloadGitfromgit-scm.comandjustfollowtheinstructions.

Linux

Ifitisn'tinstalledalready,gitshouldbeavailableviayourpackagemanager,sotry:

DebianorUbuntu

command-line

$sudoapt-getinstallgit

Fedora(upto21)

command-line

$sudoyuminstallgit

Fedora(22+)

command-line

$sudodnfinstallgit

openSUSE

command-line

$sudozypperinstallgit

CreateaGitHubaccountGotoGitHub.comandsignupforanew,freeuseraccount.

Installation

14

CreateaPythonAnywhereaccountNextit'stimetosignupforafree"Beginner"accountonPythonAnywhere.

www.pythonanywhere.com

Whenchoosingyourusernamehere,bearinmindthatyourblog'sURLwilltaketheformyourusername.pythonanywhere.com,sochooseeitheryourownnickname,oranameforwhatyourblogisallabout.

StartreadingCongratulations,youareallsetupandreadytogo!Ifyoustillhavesometimebeforetheworkshop,itwouldbeusefultostartreadingafewofthebeginningchapters:

Howtheinternetworks

Introductiontothecommandline

IntroductiontoPython

WhatisDjango?

Enjoytheworkshop!Whenyoubegintheworkshop,you'llbeabletogostraighttoYourfirstDjangoproject!becauseyoualreadycoveredthematerialintheearlierchapters.

Installation

15

HowtheInternetworksForreadersathome:thischapteriscoveredintheHowtheInternetWorksvideo.

Thischapterisinspiredbythetalk"HowtheInternetworks"byJessicaMcKellar(http://web.mit.edu/jesstess/www/).

WebetyouusetheInterneteveryday.Butdoyouactuallyknowwhathappenswhenyoutypeanaddresslikehttps://djangogirls.orgintoyourbrowserandpressenter?

Thefirstthingyouneedtounderstandisthatawebsiteisjustabunchoffilessavedonaharddisk.Justlikeyourmovies,music,orpictures.However,thereisonepartthatisuniqueforwebsites:theyincludecomputercodecalledHTML.

Ifyou'renotfamiliarwithprogrammingitcanbehardtograspHTMLatfirst,butyourwebbrowsers(likeChrome,Safari,Firefox,etc.)loveit.Webbrowsersaredesignedtounderstandthiscode,followitsinstructions,andpresentthesefilesthatyourwebsiteismadeof,exactlythewayyouwant.

Aswitheveryfile,weneedtostoreHTMLfilessomewhereonaharddisk.FortheInternet,weusespecial,powerfulcomputerscalledservers.Theydon'thaveascreen,mouseorakeyboard,becausetheirmainpurposeistostoredataandserveit.That'swhythey'recalledservers–becausetheyserveyoudata.

OK,butyouwanttoknowhowtheInternetlooks,right?

Wedrewyouapicture!Itlookslikethis:

Lookslikeamess,right?Infactitisanetworkofconnectedmachines(theabove-mentionedservers).Hundredsofthousandsofmachines!Many,manykilometersofcablesaroundtheworld!YoucanvisitaSubmarineCableMapwebsite(http://submarinecablemap.com)toseehowcomplicatedthenetis.Hereisascreenshotfromthewebsite:

HowtheInternetworks

16

Itisfascinating,isn'tit?Butobviously,itisnotpossibletohaveawirebetweeneverymachineconnectedtotheInternet.So,toreachamachine(forexample,theonewherehttps://djangogirls.orgissaved)weneedtopassarequestthroughmany,manydifferentmachines.

Itlookslikethis:

HowtheInternetworks

17

Imaginethatwhenyoutypehttps://djangogirls.org,yousendaletterthatsays:"DearDjangoGirls,Iwanttoseethedjangogirls.orgwebsite.Sendittome,please!"

Yourlettergoestothepostofficeclosesttoyou.Thenitgoestoanotherthatisabitnearertoyouraddressee,thentoanother,andanotheruntilitisdeliveredatitsdestination.Theonlyuniquethingisthatifyousendmanyletters(datapackets)tothesameplace,theycouldgothroughtotallydifferentpostoffices(routers).Thisdependsonhowtheyaredistributedateachoffice.

HowtheInternetworks

18

Yes,itisassimpleasthat.Yousendmessagesandyouexpectsomeresponse.Ofcourse,insteadofpaperandpenyouusebytesofdata,buttheideaisthesame!

Insteadofaddresseswithastreetname,city,zipcodeandcountryname,weuseIPaddresses.YourcomputerfirstaskstheDNS(DomainNameSystem)totranslatedjangogirls.orgintoanIPaddress.Itworksalittlebitlikeold-fashionedphonebookswhereyoucanlookupthenameofthepersonyouwanttocontactandfindtheirphonenumberandaddress.

Whenyousendaletter,itneedstohavecertainfeaturestobedeliveredcorrectly:anaddress,astamp,etc.Youalsousealanguagethatthereceiverunderstands,right?Thesameappliestothedatapacketsyousendtoseeawebsite.WeuseaprotocolcalledHTTP(HypertextTransferProtocol).

So,basically,whenyouhaveawebsite,youneedtohaveaserver(machine)whereitlives.Whentheserverreceivesanincomingrequest(inaletter),itsendsbackyourwebsite(inanotherletter).

SincethisisaDjangotutorial,youmightaskwhatDjangodoes.Whenyousendaresponse,youdon'talwayswanttosendthesamethingtoeverybody.Itissomuchbetterifyourlettersarepersonalized,especiallyforthepersonthathasjustwrittentoyou,right?Djangohelpsyouwithcreatingthesepersonalized,interestingletters.:)

Enoughtalk–timetocreate!

HowtheInternetworks

19

Introductiontothecommand-lineinterfaceForreadersathome:thischapteriscoveredintheYournewfriend:CommandLinevideo.

It'sexciting,right?!You'llwriteyourfirstlineofcodeinjustafewminutes!:)

Letusintroduceyoutoyourfirstnewfriend:thecommandline!

Thefollowingstepswillshowyouhowtousetheblackwindowallhackersuse.Itmightlookabitscaryatfirstbutreallyit'sjustapromptwaitingforcommandsfromyou.

Pleasenotethatthroughoutthisbookweusetheterms'directory'and'folder'interchangeablybuttheyareoneandthesamething.

Whatisthecommandline?Thewindow,whichisusuallycalledthecommandlineorcommand-lineinterface,isatext-basedapplicationforviewing,handling,andmanipulatingfilesonyourcomputer.It'smuchlikeWindowsExplorerorFinderontheMac,butwithoutthegraphicalinterface.Othernamesforthecommandlineare:cmd,CLI,prompt,consoleorterminal.

Openthecommand-lineinterfaceTostartsomeexperimentsweneedtoopenourcommand-lineinterfacefirst.

Windows

GotoStartmenu→AllPrograms→Accessories→CommandPrompt.

MacOSX

Applications→Utilities→Terminal.

Linux

It'sprobablyunderApplications→Accessories→Terminal,butthatmaydependonyoursystem.Ifit'snotthere,justGoogleit.:)

PromptYounowshouldseeawhiteorblackwindowthatiswaitingforyourcommands.

Ifyou'reonMacorLinux,youprobablysee$,justlikethis:

command-line

$

OnWindows,it'sa>sign,likethis:

command-line

>

Introductiontocommandline

20

Eachcommandwillbeprependedbythissignandonespace,butyoudon'thavetotypeit.Yourcomputerwilldoitforyou.:)

Justasmallnote:inyourcasetheremaybesomethinglikeC:\Users\ola>orOlas-MacBook-Air:~ola$beforethepromptsign,andthisis100%OK.

Thepartuptoandincludingthe$orthe>iscalledthecommandlineprompt,orpromptforshort.Itpromptsyoutoinputsomethingthere.

Inthetutorial,whenwewantyoutotypeinacommand,wewillincludethe$or>,andoccasionallymoretotheleft.Youcanignoretheleftpartandjusttypeinthecommandwhichstartsaftertheprompt.

Yourfirstcommand(YAY!)Let'sstartwithsomethingsimple.Typethiscommand:

command-line

$whoami

or

command-line

>whoami

Andthenhitenter.Thisisourresult:

command-line

$whoami

olasitarska

Asyoucansee,thecomputerhasjustprintedyourusername.Neat,huh?:)

Trytotypeeachcommand;donotcopy-paste.You'llremembermorethisway!

BasicsEachoperatingsystemhasaslightlydifferentsetofcommandsforthecommandline,somakesuretofollowinstructionsforyouroperatingsystem.Let'strythis,shallwe?

CurrentdirectoryIt'dbenicetoknowwherearewenow,right?Let'ssee.Typethiscommandandhitenter:

command-line

$pwd

/Users/olasitarska

Ifyou'reonWindows:

command-line

Introductiontocommandline

21

>cd

C:\Users\olasitarska

You'llprobablyseesomethingsimilaronyourmachine.Onceyouopenthecommandlineyouusuallystartatyouruser'shomedirectory.

Note:'pwd'standsfor'printworkingdirectory'.

Listfilesanddirectories

Sowhat'sinit?It'dbecooltofindout.Let'ssee:

command-line

$ls

Applications

Desktop

Downloads

Music

...

Windows:

command-line

>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

...

ChangecurrentdirectoryNow,let'sgotoourDesktopdirectory:

command-line

$cdDesktop

Windows:

command-line

>cdDesktop

Checkifit'sreallychanged:

command-line

$pwd

/Users/olasitarska/Desktop

Windows:

command-line

Introductiontocommandline

22

>cd

C:\Users\olasitarska\Desktop

Hereitis!

PROtip:ifyoutypecdDandthenhittabonyourkeyboard,thecommandlinewillautomaticallyfillintherestofthenamesoyoucannavigatefaster.Ifthereismorethanonefolderstartingwith"D",hitthetabbuttontwicetogetalistofoptions.

Createdirectory

Howaboutcreatingapracticedirectoryonyourdesktop?Youcandoitthisway:

command-line

$mkdirpractice

Windows:

command-line

>mkdirpractice

Thislittlecommandwillcreateafolderwiththenamepracticeonyourdesktop.Youcancheckifit'stherejustbylookingonyourDesktoporbyrunningalsordircommand!Tryit.:)

PROtip:Ifyoudon'twanttotypethesamecommandsoverandover,trypressingtheuparrowanddownarrowonyourkeyboardtocyclethroughrecentlyusedcommands.

Exercise!Asmallchallengeforyou:inyournewlycreatedpracticedirectory,createadirectorycalledtest.(Usethecdandmkdircommands.)

Solution:command-line

$cdpractice

$mkdirtest

$ls

test

Windows:

command-line

>cdpractice

>mkdirtest

>dir

05/08/201407:28PM<DIR>test

Congrats!:)

Introductiontocommandline

23

Cleanup

Wedon'twanttoleaveamess,solet'sremoveeverythingwediduntilthatpoint.

First,weneedtogetbacktoDesktop:

command-line

$cd..

Windows:

command-line

>cd..

Using..withthecdcommandwillchangeyourcurrentdirectorytotheparentdirectory(thatis,thedirectorythatcontainsyourcurrentdirectory).

Checkwhereyouare:

command-line

$pwd

/Users/olasitarska/Desktop

Windows:

command-line

>cd

C:\Users\olasitarska\Desktop

Nowtimetodeletethepracticedirectory:

Attention:Deletingfilesusingdel,rmdirorrmisirrecoverable,meaningthedeletedfileswillbegoneforever!Sobeverycarefulwiththiscommand.

command-line

$rm-rpractice

Windows:

command-line

>rmdir/Spractice

practice,Areyousure<Y/N>?Y

Done!Tobesureit'sactuallydeleted,let'scheckit:

command-line

$ls

Windows:

command-line

Introductiontocommandline

24

>dir

ExitThat'sitfornow!Youcansafelyclosethecommandlinenow.Let'sdoitthehackerway,alright?:)

command-line

$exit

Windows:

command-line

>exit

Cool,huh?:)

SummaryHereisasummaryofsomeusefulcommands:

Command(Windows)

Command(MacOS/Linux) Description Example

exit exit closethewindow exit

cd cd changedirectory cdtest

dir ls listdirectories/files dir

copy cp copyfile copyc:\test\test.txtc:\windows\test.txt

move mv movefile movec:\test\test.txtc:\windows\test.txt

mkdir mkdir createanewdirectory mkdirtestdirectory

rmdir(ordel) rm deleteafile delc:\test\test.txt

rmdir\S rm-r deleteadirectory rm-rtestdirectory

Thesearejustaveryfewofthecommandsyoucanruninyourcommandline,butyou'renotgoingtouseanythingmorethanthattoday.

Ifyou'recurious,ss64.comcontainsacompletereferenceofcommandsforalloperatingsystems.

Ready?Let'sdiveintoPython!

Introductiontocommandline

25

Let’sstartwithPythonWe'refinallyhere!

Butfirst,letustellyouwhatPythonis.Pythonisaverypopularprogramminglanguagethatcanbeusedforcreatingwebsites,games,scientificsoftware,graphics,andmuch,muchmore.

Pythonoriginatedinthelate1980sanditsmaingoalistobereadablebyhumanbeings(notonlymachines!).Thisiswhyitlooksmuchsimplerthanotherprogramminglanguages.Thismakesiteasytolearn,butdon'tworry–Pythonisalsoreallypowerful!

PythoninstallationIfyou'reusingaChromebook,skipthischapterandmakesureyoufollowtheChromebookSetupinstructions.

NoteIfyoualreadyworkedthroughtheInstallationsteps,there'snoneedtodothisagain–youcanskipstraightaheadtothenextchapter!

Forreadersathome:thischapteriscoveredintheInstallingPython&CodeEditorvideo.

ThissectionisbasedonatutorialbyGeekGirlsCarrots(https://github.com/ggcarrots/django-carrots)

DjangoiswritteninPython.WeneedPythontodoanythinginDjango.Let'sstartbyinstallingit!WewantyoutoinstallPython3.5,soifyouhaveanyearlierversion,youwillneedtoupgradeit.

WindowsYoucandownloadPythonforWindowsfromthewebsitehttps://www.python.org/downloads/release/python-351/.Afterdownloadingthe*.msifile,youshouldrunit(double-clickonit)andfollowtheinstructionsthere.Itisimportanttorememberthepath(thedirectory)whereyouinstalledPython.Itwillbeneededlater!

Onethingtowatchoutfor:onthesecondscreenoftheinstallationwizard,marked"Customize",makesureyouscrolldowntothe"Addpython.exetothePath"optionandselect"Willbeinstalledonlocalharddrive",asshownhere:

Pythoninstallation

26

Inupcomingsteps,you'llbeusingtheWindowsCommandLine(whichwe'llalsotellyouabout).Fornow,ifyouneedtotypeinsomecommands,gotoStartmenu→AllPrograms→Accessories→CommandPrompt.(OnnewerversionsofWindows,youmighthavetosearchfor"CommandPrompt"sinceit'ssometimeshidden.)

Linux

ItisverylikelythatyoualreadyhavePythoninstalledoutofthebox.Tocheckifyouhaveitinstalled(andwhichversionitis),openaconsoleandtypethefollowingcommand:

command-line

$python3--version

Python3.5.1

Ifyouhaveadifferent'microversion'ofPythoninstalled,e.g.3.5.0,thenyoudon'thavetoupgrade.Ifyoudon'thavePythoninstalled,orifyouwantadifferentversion,youcaninstallitasfollows:

DebianorUbuntu

Typethiscommandintoyourconsole:

command-line

$sudoapt-getinstallpython3.5

Fedora(upto21)

Usethiscommandinyourconsole:

command-line

Pythoninstallation

27

$sudoyuminstallpython3

Fedora(22+)Usethiscommandinyourconsole:

command-line

$sudodnfinstallpython3

openSUSE

Usethiscommandinyourconsole:

command-line

$sudozypperinstallpython3

OSXBeforeyouinstallPythononOSX,youshouldensureyourMacsettingsallowinstallingpackagesthataren'tfromtheAppStore.GotoSystemPreferences(it'sintheApplicationsfolder),click"Security&Privacy,"andthenthe"General"tab.Ifyour"Allowappsdownloadedfrom:"issetto"MacAppStore,"changeitto"MacAppStoreandidentifieddevelopers."

Youneedtogotothewebsitehttps://www.python.org/downloads/release/python-351/anddownloadthePythoninstaller:

DownloadtheMacOSX64-bit/32-bitinstallerfile,Doubleclickpython-3.5.1-macosx10.6.pkgtoruntheinstaller.

VerifytheinstallationwassuccessfulbyopeningtheTerminalapplicationandrunningthepython3command:

command-line

$python3--version

Python3.5.1

Ifyouhaveanydoubts,orifsomethingwentwrongandyouhavenoideawhattodonext,pleaseaskyourcoach!Sometimesthingsdon'tgosmoothlyandit'sbettertoaskforhelpfromsomeonewithmoreexperience.

Pythoninstallation

28

CodeeditorForreadersathome:thischapteriscoveredintheInstallingPython&CodeEditorvideo.

You'reabouttowriteyourfirstlineofcode,soit'stimetodownloadacodeeditor!

Ifyou'reusingaChromebook,skipthischapterandmakesureyoufollowtheChromebookSetupinstructions.

NoteYoumighthavedonethisearlierintheInstallationchapter–ifso,youcanskiprightaheadtothenextchapter!

Therearealotofdifferenteditorsanditlargelyboilsdowntopersonalpreference.MostPythonprogrammersusecomplexbutextremelypowerfulIDEs(IntegratedDevelopmentEnvironments),suchasPyCharm.Asabeginner,however,that'sprobablylesssuitable;ourrecommendationsareequallypowerful,butalotsimpler.

Oursuggestionsarebelow,butfeelfreetoaskyourcoachwhattheirpreferencesare–it'llbeeasiertogethelpfromthem.

GeditGeditisanopen-source,freeeditor,availableforalloperatingsystems.

Downloadithere

SublimeText2SublimeTextisaverypopulareditorwithafreeevaluationperiod.It'seasytoinstallanduse,andit'savailableforalloperatingsystems.

Downloadithere

AtomAtomisanextremelynewcodeeditorcreatedbyGitHub.It'sfree,open-source,easytoinstallandeasytouse.It'savailableforWindows,OSXandLinux.

Downloadithere

Whyareweinstallingacodeeditor?Youmightbewonderingwhyweareinstallingthisspecialcodeeditorsoftware,ratherthanusingsomethinglikeWordorNotepad.

Thefirstreasonisthatcodeneedstobeplaintext,andtheproblemwithprogramslikeWordandTexteditisthattheydon'tactuallyproduceplaintext,theyproducerichtext(withfontsandformatting),usingcustomformatslikeRTF(RichTextFormat).

Thesecondreasonisthatcodeeditorsarespecialisedforeditingcode,sotheycanprovidehelpfulfeatureslikehighlightingcodewithcolouraccordingtoitsmeaning,orautomaticallyclosingquotesforyou.

We'llseeallthisinactionlater.Soon,you'llcometothinkofyourtrustyoldcodeeditorasoneofyourfavouritetools.:)

Codeeditor

29

Codeeditor

30

IntroductiontoPythonPartofthischapterisbasedontutorialsbyGeekGirlsCarrots(https://github.com/ggcarrots/django-carrots).

Let'swritesomecode!

PythonpromptForreadersathome:thispartiscoveredinthePythonBasics:Integers,Strings,Lists,VariablesandErrorsvideo.

TostartplayingwithPython,weneedtoopenupacommandlineonyourcomputer.Youshouldalreadyknowhowtodothat–youlearneditintheIntrotoCommandLinechapter.

Onceyou'reready,followtheinstructionsbelow.

WewanttoopenupaPythonconsole,sotypeinpythononWindowsorpython3onMacOS/Linuxandhitenter.

command-line

$python3

Python3.5.1(...)

Type"help","copyright","credits"or"license"formoreinformation.

>>>

YourfirstPythoncommand!AfterrunningthePythoncommand,thepromptchangedto>>>.ForusthismeansthatfornowwemayonlyusecommandsinthePythonlanguage.Youdon'thavetotypein>>>–Pythonwilldothatforyou.

IfyouwanttoexitthePythonconsoleatanypoint,justtypeexit()orusetheshortcutCtrl+ZforWindowsandCtrl+DforMac/Linux.Thenyouwon'tsee>>>anylonger.

Fornow,wedon'twanttoexitthePythonconsole.Wewanttolearnmoreaboutit.Let'sstartwithsomethingreallysimple.Forexample,trytypingsomemath,like2+3andhitenter.

command-line

>>>2+3

5

Nice!Seehowtheanswerpoppedout?Pythonknowsmath!Youcouldtryothercommandslike:

4*5

5-1

40/2

Havefunwiththisforalittlewhileandthengetbackhere.:)

Asyoucansee,Pythonisagreatcalculator.Ifyou'rewonderingwhatelseyoucando…

StringsHowaboutyourname?Typeyourfirstnameinquoteslikethis:

command-line

IntroductiontoPython

31

>>>"Ola"

'Ola'

You'venowcreatedyourfirststring!It'sasequenceofcharactersthatcanbeprocessedbyacomputer.Thestringmustalwaysbeginandendwiththesamecharacter.Thismaybesingle(')ordouble(")quotes(thereisnodifference!)ThequotestellPythonthatwhat'sinsideofthemisastring.

Stringscanbestrungtogether.Trythis:

command-line

>>>"Hithere"+"Ola"

'HithereOla'

Youcanalsomultiplystringswithanumber:

command-line

>>>"Ola"*3

'OlaOlaOla'

Ifyouneedtoputanapostropheinsideyourstring,youhavetwowaystodoit.

Usingdoublequotes:

command-line

>>>"Runnin'downthehill"

"Runnin'downthehill"

orescapingtheapostrophewithabackslash(\):

command-line

>>>'Runnin\'downthehill'

"Runnin'downthehill"

Nice,huh?Toseeyournameinuppercaseletters,simplytype:

command-line

>>>"Ola".upper()

'OLA'

Youjustusedtheuppermethodonyourstring!Amethod(likeupper())isasequenceofinstructionsthatPythonhastoperformonagivenobject("Ola")onceyoucallit.

Ifyouwanttoknowthenumberofletterscontainedinyourname,thereisafunctionforthattoo!

command-line

>>>len("Ola")

3

Wonderwhysometimesyoucallfunctionswitha.attheendofastring(like"Ola".upper())andsometimesyoufirstcallafunctionandplacethestringinparentheses?Well,insomecases,functionsbelongtoobjects,likeupper(),whichcanonlybeperformedonstrings.Inthiscase,wecallthefunctionamethod.Othertimes,functionsdon'tbelongtoanything

IntroductiontoPython

32

specificandcanbeusedondifferenttypesofobjects,justlikelen().That'swhywe'regiving"Ola"asaparametertothelenfunction.

Summary

OK,enoughofstrings.Sofaryou'velearnedabout:

theprompt–typingcommands(code)intothePythonpromptresultsinanswersinPythonnumbersandstrings–inPythonnumbersareusedformathandstringsfortextobjectsoperators–like+and\*,combinevaluestoproduceanewonefunctions–likeupper()andlen(),performactionsonobjects.

Thesearethebasicsofeveryprogramminglanguageyoulearn.Readyforsomethingharder?Webetyouare!

ErrorsLet'strysomethingnew.Canwegetthelengthofanumberthesamewaywecouldfindoutthelengthofourname?Typeinlen(304023)andhitenter:

command-line

>>>len(304023)

Traceback(mostrecentcalllast):

File"<stdin>",line1,in<module>

TypeError:objectoftype'int'hasnolen()

Wegotourfirsterror!Itsaysthatobjectsoftype"int"(integers,wholenumbers)havenolength.Sowhatcanwedonow?Maybewecanwriteournumberasastring?Stringshavealength,right?

command-line

>>>len(str(304023))

6

Itworked!Weusedthestrfunctioninsideofthelenfunction.str()convertseverythingtostrings.

ThestrfunctionconvertsthingsintostringsTheintfunctionconvertsthingsintointegers

Important:wecanconvertnumbersintotext,butwecan'tnecessarilyconverttextintonumbers–whatwouldint('hello')beanyway?

VariablesAnimportantconceptinprogrammingisvariables.Avariableisnothingmorethananameforsomethingsoyoucanuseitlater.Programmersusethesevariablestostoredata,maketheircodemorereadableandsotheydon'thavetokeeprememberingwhatthingsare.

Let'ssaywewanttocreateanewvariablecalledname:

command-line

>>>name="Ola"

Yousee?It'seasy!It'ssimply:nameequalsOla.

IntroductiontoPython

33

Asyou'venoticed,yourprogramdidn'treturnanythinglikeitdidbefore.Sohowdoweknowthatthevariableactuallyexists?Simplyenternameandhitenter:

command-line

>>>name

'Ola'

Yippee!Yourfirstvariable!:)Youcanalwayschangewhatitrefersto:

command-line

>>>name="Sonja"

>>>name

'Sonja'

Youcanuseitinfunctionstoo:

command-line

>>>len(name)

5

Awesome,right?Ofcourse,variablescanbeanything–numberstoo!Trythis:

command-line

>>>a=4

>>>b=6

>>>a*b

24

Butwhatifweusedthewrongname?Canyouguesswhatwouldhappen?Let'stry!

command-line

>>>city="Tokyo"

>>>ctiy

Traceback(mostrecentcalllast):

File"<stdin>",line1,in<module>

NameError:name'ctiy'isnotdefined

Anerror!Asyoucansee,PythonhasdifferenttypesoferrorsandthisoneiscalledaNameError.Pythonwillgiveyouthiserrorifyoutrytouseavariablethathasn'tbeendefinedyet.Ifyouencounterthiserrorlater,checkyourcodetoseeifyou'vemistypedanynames.

Playwiththisforawhileandseewhatyoucando!

TheprintfunctionTrythis:

command-line

>>>name='Maria'

>>>name

'Maria'

>>>print(name)

Maria

IntroductiontoPython

34

Whenyoujusttypename,thePythoninterpreterrespondswiththestringrepresentationofthevariable'name',whichisthelettersM-a-r-i-a,surroundedbysinglequotes,''.Whenyousayprint(name),Pythonwill"print"thecontentsofthevariabletothescreen,withoutthequotes,whichisneater.

Aswe'llseelater,print()isalsousefulwhenwewanttoprintthingsfrominsidefunctions,orwhenwewanttoprintthingsonmultiplelines.

ListsBesidestringsandintegers,Pythonhasallsortsofdifferenttypesofobjects.Nowwe'regoingtointroduceonecalledlist.Listsareexactlywhatyouthinktheyare:objectswhicharelistsofotherobjects.:)

Goaheadandcreatealist:

command-line

>>>[]

[]

Yes,thislistisempty.Notveryuseful,right?Let'screatealistoflotterynumbers.Wedon'twanttorepeatourselvesallthetime,sowewillputitinavariable,too:

command-line

>>>lottery=[3,42,12,19,30,59]

Allright,wehavealist!Whatcanwedowithit?Let'sseehowmanylotterynumbersthereareinalist.Doyouhaveanyideawhichfunctionyoushoulduseforthat?Youknowthisalready!

command-line

>>>len(lottery)

6

Yes!len()cangiveyouanumberofobjectsinalist.Handy,right?Maybewewillsortitnow:

command-line

>>>lottery.sort()

Thisdoesn'treturnanything,itjustchangedtheorderinwhichthenumbersappearinthelist.Let'sprintitoutagainandseewhathappened:

command-line

>>>print(lottery)

[3,12,19,30,42,59]

Asyoucansee,thenumbersinyourlistarenowsortedfromthelowesttohighestvalue.Congrats!

Maybewewanttoreversethatorder?Let'sdothat!

command-line

>>>lottery.reverse()

>>>print(lottery)

[59,42,30,19,12,3]

IntroductiontoPython

35

Easy,right?Ifyouwanttoaddsomethingtoyourlist,youcandothisbytypingthiscommand:

command-line

>>>lottery.append(199)

>>>print(lottery)

[59,42,30,19,12,3,199]

Ifyouwanttoshowonlythefirstnumber,youcandothisbyusingindexes.Anindexisthenumberthatsayswhereinalistanitemoccurs.Programmersprefertostartcountingat0,sothefirstobjectinyourlistisatindex0,thenextoneisat1,andsoon.Trythis:

command-line

>>>print(lottery[0])

59

>>>print(lottery[1])

42

Asyoucansee,youcanaccessdifferentobjectsinyourlistbyusingthelist'snameandtheobject'sindexinsideofsquarebrackets.

Todeletesomethingfromyourlistyouwillneedtouseindexesaswelearntaboveandthepop()method.Let'stryanexampleandreinforcewhatwelearntpreviously;wewillbedeletingthefirstnumberofourlist.

command-line

>>>print(lottery)

[59,42,30,19,12,3,199]

>>>print(lottery[0])

59

>>>lottery.pop(0)

>>>print(lottery)

[42,30,19,12,3,199]

Thatworkedlikeacharm!

Forextrafun,trysomeotherindexes:6,7,1000,-1,-6or-1000.Seeifyoucanpredicttheresultbeforetryingthecommand.Dotheresultsmakesense?

YoucanfindalistofallavailablelistmethodsinthischapterofthePythondocumentation:https://docs.python.org/3/tutorial/datastructures.html

DictionariesForreadersathome:thispartiscoveredinthePythonBasics:Dictionariesvideo.

Adictionaryissimilartoalist,butyouaccessvaluesbylookingupakeyinsteadofanumericindex.Akeycanbeanystringornumber.Thesyntaxtodefineanemptydictionaryis:

command-line

>>>{}

{}

Thisshowsthatyoujustcreatedanemptydictionary.Hurray!

Now,trywritingthefollowingcommand(trysubstitutingyourowninformation,too):

command-line

IntroductiontoPython

36

>>>participant={'name':'Ola','country':'Poland','favorite_numbers':[7,42,92]}

Withthiscommand,youjustcreatedavariablenamedparticipantwiththreekey–valuepairs:

Thekeynamepointstothevalue'Ola'(astringobject),countrypointsto'Poland'(anotherstring),andfavorite_numberspointsto[7,42,92](alistwiththreenumbersinit).

Youcancheckthecontentofindividualkeyswiththissyntax:

command-line

>>>print(participant['name'])

Ola

See,it'ssimilartoalist.Butyoudon'tneedtoremembertheindex–justthename.

WhathappensifweaskPythonthevalueofakeythatdoesn'texist?Canyouguess?Let'stryitandsee!

command-line

>>>participant['age']

Traceback(mostrecentcalllast):

File"<stdin>",line1,in<module>

KeyError:'age'

Look,anothererror!ThisoneisaKeyError.Pythonishelpfulandtellsyouthatthekey'age'doesn'texistinthisdictionary.

Whenshouldyouuseadictionaryoralist?Well,that'sagoodpointtoponder.Justhaveasolutioninmindbeforelookingattheanswerinthenextline.

Doyoujustneedanorderedsequenceofitems?Goforalist.Doyouneedtoassociatevalueswithkeys,soyoucanlookthemupefficiently(bykey)lateron?Useadictionary.

Dictionaries,likelists,aremutable,meaningthattheycanbechangedaftertheyarecreated.Youcanaddnewkey–valuepairstoadictionaryafteritiscreated,likethis:

command-line

>>>participant['favorite_language']='Python'

Likelists,usingthelen()methodonthedictionariesreturnsthenumberofkey–valuepairsinthedictionary.Goaheadandtypeinthiscommand:

command-line

>>>len(participant)

4

Ihopeitmakessenseuptonow.:)Readyforsomemorefunwithdictionaries?Readonforsomeamazingthings.

Youcanusethepop()methodtodeleteaniteminthedictionary.Say,ifyouwanttodeletetheentrycorrespondingtothekey'favorite_numbers',justtypeinthefollowingcommand:

command-line

>>>participant.pop('favorite_numbers')

>>>participant

{'country':'Poland','favorite_language':'Python','name':'Ola'}

IntroductiontoPython

37

Asyoucanseefromtheoutput,thekey–valuepaircorrespondingtothe'favorite_numbers'keyhasbeendeleted.

Aswellasthis,youcanalsochangeavalueassociatedwithanalready-createdkeyinthedictionary.Typethis:

command-line

>>>participant['country']='Germany'

>>>participant

{'country':'Germany','favorite_language':'Python','name':'Ola'}

Asyoucansee,thevalueofthekey'country'hasbeenalteredfrom'Poland'to'Germany'.:)Exciting?Hurrah!Youjustlearntanotheramazingthing.

Summary

Awesome!Youknowalotaboutprogrammingnow.Inthislastpartyoulearnedabout:

errors–younowknowhowtoreadandunderstanderrorsthatshowupifPythondoesn'tunderstandacommandyou'vegivenitvariables–namesforobjectsthatallowyoutocodemoreeasilyandtomakeyourcodemorereadablelists–listsofobjectsstoredinaparticularorderdictionaries–objectsstoredaskey–valuepairs

Excitedforthenextpart?:)

ComparethingsForreadersathome:thispartiscoveredinthePythonBasics:Comparisonsvideo.

Abigpartofprogramminginvolvescomparingthings.What'stheeasiestthingtocompare?Numbers,ofcourse.Let'sseehowthatworks:

command-line

>>>5>2

True

>>>3<1

False

>>>5>2*2

True

>>>1==1

True

>>>5!=2

True

WegavePythonsomenumberstocompare.Asyoucansee,notonlycanPythoncomparenumbers,butitcanalsocomparemethodresults.Nice,huh?

Doyouwonderwhyweputtwoequalsigns==nexttoeachothertocompareifnumbersareequal?Weuseasingle=forassigningvaluestovariables.Youalways,alwaysneedtoputtwoofthem–==–ifyouwanttocheckifthingsareequaltoeachother.Wecanalsostatethatthingsareunequaltoeachother.Forthat,weusethesymbol!=,asshownintheexampleabove.

GivePythontwomoretasks:

command-line

IntroductiontoPython

38

>>>6>=12/2

True

>>>3<=2

False

>and<areeasy,butwhatdo>=and<=mean?Readthemlikethis:

x>ymeans:xisgreaterthanyx<ymeans:xislessthanyx<=ymeans:xislessthanorequaltoyx>=ymeans:xisgreaterthanorequaltoy

Awesome!Wannadoonemore?Trythis:

command-line

>>>6>2and2<3

True

>>>3>2and2<1

False

>>>3>2or2<1

True

YoucangivePythonasmanynumberstocompareasyouwant,anditwillgiveyouananswer!Prettysmart,right?

and–ifyouusetheandoperator,bothcomparisonshavetobeTrueinorderforthewholecommandtobeTrueor–ifyouusetheoroperator,onlyoneofthecomparisonshastobeTrueinorderforthewholecommandtobeTrue

Haveyouheardoftheexpression"comparingapplestooranges"?Let'strythePythonequivalent:

command-line

>>>1>'django'

Traceback(mostrecentcalllast):

File"<stdin>",line1,in<module>

TypeError:unorderabletypes:int()>str()

Hereyouseethatjustlikeintheexpression,Pythonisnotabletocompareanumber(int)andastring(str).Instead,itshowsaTypeErrorandtellsusthetwotypescan'tbecomparedtogether.

BooleanIncidentally,youjustlearnedaboutanewtypeofobjectinPython.It'scalledBoolean,anditisprobablytheeasiesttypethereis.

ThereareonlytwoBooleanobjects:

TrueFalse

ButforPythontounderstandthis,youneedtoalwayswriteitas'True'(firstletteruppercased,withtherestoftheletterlowercased).true,TRUE,andtRUEwon'twork–onlyTrueiscorrect.(Thesameappliesto'False'aswell,ofcourse.)

Booleanscanbevariables,too!Seehere:

command-line

IntroductiontoPython

39

>>>a=True

>>>a

True

Youcanalsodoitthisway:

command-line

>>>a=2>5

>>>a

False

PracticeandhavefunwithBooleansbytryingtorunthefollowingcommands:

TrueandTrue

FalseandTrue

Trueor1==1

1!=2

Congrats!Booleansareoneofthecoolestfeaturesinprogramming,andyoujustlearnedhowtousethem!

Saveit!Forreadersathome:thispartiscoveredinthePythonBasics:Savingfilesand"If"statementvideo.

Sofarwe'vebeenwritingallourpythoncodeintheinterpreter,whichlimitsustoenteringonelineofcodeatatime.Normalprogramsaresavedinfilesandexecutedbyourprogramminglanguageinterpreterorcompiler.Sofarwe'vebeenrunningourprogramsonelineatatimeinthePythoninterpreter.We'regoingtoneedmorethanonelineofcodeforthenextfewtasks,sowe'llquicklyneedto:

ExitthePythoninterpreterOpenupourcodeeditorofchoiceSavesomecodeintoanewpythonfileRunit!

ToexitfromthePythoninterpreterthatwe'vebeenusing,simplytypetheexit()function

command-line

>>>exit()

$

Thiswillputyoubackintothecommandprompt.

Earlier,wepickedoutacodeeditorfromthecodeeditorsection.We'llneedtoopentheeditornowandwritesomecodeintoanewfile:

editor

print('Hello,Djangogirls!')

Obviously,you'reaprettyseasonedPythondevelopernow,sofeelfreetowritesomecodethatyou'velearnedtoday.

Nowweneedtosavethefileandgiveitadescriptivename.Let'scallthefilepython_intro.pyandsaveittoyourdesktop.Wecannamethefileanythingwewant,buttheimportantparthereistomakesurethefileendsin.py.The.pyextensiontellsouroperatingsystemthatthisisaPythonexecutablefileandPythoncanrunit.

IntroductiontoPython

40

Youshouldnoticeoneofthecoolestthingaboutcodeeditors:colours!InthePythonconsole,everythingwasthesamecolour;nowyoushouldseethattheprintfunctionisadifferentcolourfromthestring.Thisiscalled"syntaxhighlighting",andit'sareallyusefulfeaturewhencoding.Thecolourofthingswillgiveyouhints,suchasunclosedstringsoratypoinakeywordname(likethedefinafunction,whichwe'llseebelow).Thisisoneofthereasonsweuseacodeeditor.:)

Withthefilesaved,it'stimetorunit!Usingtheskillsyou'velearnedinthecommandlinesection,usetheterminaltochangedirectoriestothedesktop.(Note:Replace<your_name>includingthe<and>withyourusername.)

OnaMac,thecommandwilllooksomethinglikethis:

command-line

$cd/Users/<your_name>/Desktop

OnLinux,itwillbelikethis(theword"Desktop"mightbetranslatedtoyourlocallanguage):

command-line

$cd/home/<your_name>/Desktop

AndonWindows,itwillbelikethis:

command-line

>cdC:\Users\<your_name>\Desktop

Ifyougetstuck,justaskforhelp.

NowusePythontoexecutethecodeinthefilelikethis:

command-line

$python3python_intro.py

Hello,Djangogirls!

Note:onWindows'python3'isnotrecognizedasacommand.Instead,use'python'toexecutethefile:

command-line

>pythonpython_intro.py

Alright!YoujustranyourfirstPythonprogramthatwassavedtoafile.Feelawesome?

Youcannowmoveontoanessentialtoolinprogramming:

If…elif…elseLotsofthingsincodeshouldbeexecutedonlywhengivenconditionsaremet.That'swhyPythonhassomethingcalledifstatements.

Replacethecodeinyourpython_intro.pyfilewiththis:

python_intro.py

if3>2:

IntroductiontoPython

41

Ifweweretosaveandrunthis,we'dseeanerrorlikethis:

command-line

$python3python_intro.py

File"python_intro.py",line2

^

SyntaxError:unexpectedEOFwhileparsing

Pythonexpectsustogivefurtherinstructionstoitwhichareexecutedifthecondition3>2turnsouttobetrue(orTrueforthatmatter).Let’strytomakePythonprint“Itworks!”.Changeyourcodeinyourpython_intro.pyfiletothis:

python_intro.py

if3>2:

print('Itworks!')

Noticehowwe'veindentedthenextlineofcodeby4spaces?WeneedtodothissoPythonknowswhatcodetoruniftheresultistrue.Youcandoonespace,butnearlyallPythonprogrammersdo4tomakethingslookneat.Asingletabwillalsocountas4spaces.

Saveitandgiveitanotherrun:

command-line

$python3python_intro.py

Itworks!

Note:RememberthatonWindows,'python3'isnotrecognizedasacommand.Fromnowon,replace'python3'with'python'toexecutethefile.

Whatifaconditionisn'tTrue?Inpreviousexamples,codewasexecutedonlywhentheconditionswereTrue.ButPythonalsohaselifandelsestatements:

python_intro.py

if5>2:

print('5isindeedgreaterthan2')

else:

print('5isnotgreaterthan2')

Whenthisisrunitwillprintout:

command-line

$python3python_intro.py

5isindeedgreaterthan2

If2wereagreaternumberthan5,thenthesecondcommandwouldbeexecuted.Easy,right?Let'sseehowelifworks:

python_intro.py

IntroductiontoPython

42

name='Sonja'

ifname=='Ola':

print('HeyOla!')

elifname=='Sonja':

print('HeySonja!')

else:

print('Heyanonymous!')

andexecuted:

command-line

$python3python_intro.py

HeySonja!

Seewhathappenedthere?elifletsyouaddextraconditionsthatrunifthepreviousconditionsfail.

Youcanaddasmanyelifstatementsasyoulikeafteryourinitialifstatement.Forexample:

python_intro.py

volume=57

ifvolume<20:

print("It'skindaquiet.")

elif20<=volume<40:

print("It'sniceforbackgroundmusic")

elif40<=volume<60:

print("Perfect,Icanhearallthedetails")

elif60<=volume<80:

print("Niceforparties")

elif80<=volume<100:

print("Abitloud!")

else:

print("Myearsarehurting!:(")

Pythonrunsthrougheachtestinsequenceandprints:

command-line

$python3python_intro.py

Perfect,Icanhearallthedetails

CommentsCommentsarelinesbeginningwith#.Youcanwritewhateveryouwantafterthe#andPythonwillignoreit.Commentscanmakeyourcodeeasierforotherpeopletounderstand.

Let'sseehowthatlooks:

python_intro.py

#Changethevolumeifit'stooloudortooquiet

ifvolume<20orvolume>80:

volume=50

print("That'sbetter!")

Youdon'tneedtowriteacommentforeverylineofcode,buttheyareusefulforexplainingwhyyourcodeisdoingsomething,orprovidingasummarywhenit'sdoingsomethingcomplex.

Summary

IntroductiontoPython

43

Inthelastfewexercisesyoulearnedabout:

comparingthings–inPythonyoucancomparethingsbyusing>,>=,==,<=,<andtheand,oroperatorsBoolean–atypeofobjectthatcanonlyhaveoneoftwovalues:TrueorFalseSavingfiles–storingcodeinfilessoyoucanexecutelargerprograms.if…elif…else–statementsthatallowyoutoexecutecodeonlywhencertainconditionsaremet.comments-linesthatPythonwon'trunwhichletyoudocumentyourcode

Timeforthelastpartofthischapter!

Yourownfunctions!Forreadersathome:thispartiscoveredinthePythonBasics:Functionsvideo.

Rememberfunctionslikelen()thatyoucanexecuteinPython?Well,goodnews–youwilllearnhowtowriteyourownfunctionsnow!

AfunctionisasequenceofinstructionsthatPythonshouldexecute.EachfunctioninPythonstartswiththekeyworddef,isgivenaname,andcanhavesomeparameters.Let'sstartwithaneasyone.Replacethecodeinpython_intro.pywiththefollowing:

python_intro.py

defhi():

print('Hithere!')

print('Howareyou?')

hi()

Okay,ourfirstfunctionisready!

Youmaywonderwhywe'vewrittenthenameofthefunctionatthebottomofthefile.ThisisbecausePythonreadsthefileandexecutesitfromtoptobottom.Soinordertouseourfunction,wehavetore-writeitatthebottom.

Let'srunthisnowandseewhathappens:

command-line

$python3python_intro.py

Hithere!

Howareyou?

Thatwaseasy!Let'sbuildourfirstfunctionwithparameters.Wewillusethepreviousexample–afunctionthatsays'hi'tothepersonrunningit–withaname:

python_intro.py

defhi(name):

Asyoucansee,wenowgaveourfunctionaparameterthatwecalledname:

python_intro.py

IntroductiontoPython

44

defhi(name):

ifname=='Ola':

print('HiOla!')

elifname=='Sonja':

print('HiSonja!')

else:

print('Hianonymous!')

hi()

Remember:Theprintfunctionisindentedfourspaceswithintheifstatement.Thisisbecausethefunctionrunswhentheconditionismet.Let'sseehowitworksnow:

command-line

$python3python_intro.py

Traceback(mostrecentcalllast):

File"python_intro.py",line10,in<module>

hi()

TypeError:hi()missing1requiredpositionalargument:'name'

Oops,anerror.Luckily,Pythongivesusaprettyusefulerrormessage.Ittellsusthatthefunctionhi()(theonewedefined)hasonerequiredargument(calledname)andthatweforgottopassitwhencallingthefunction.Let'sfixitatthebottomofthefile:

python_intro.py

hi("Ola")

Andrunitagain:

command-line

$python3python_intro.py

HiOla!

Andifwechangethename?

python_intro.py

hi("Sonja")

Andrunit:

command-line

$python3python_intro.py

HiSonja!

Now,whatdoyouthinkwillhappenifyouwriteanothernameinthere?(NotOlaorSonja.)Giveitatryandseeifyou'reright.Itshouldprintoutthis:

command-line

Hianonymous!

Thisisawesome,right?Thiswayyoudon'thavetorepeatyourselfeverytimeyouwanttochangethenameofthepersonthefunctionissupposedtogreet.Andthat'sexactlywhyweneedfunctions–youneverwanttorepeatyourcode!

IntroductiontoPython

45

Let'sdosomethingsmarter–therearemorenamesthantwo,andwritingaconditionforeachwouldbehard,right?

python_intro.py

defhi(name):

print('Hi'+name+'!')

hi("Rachel")

Let'scallthecodenow:

command-line

$python3python_intro.py

HiRachel!

Congratulations!Youjustlearnedhowtowritefunctions!:)

LoopsForreadersathome:thispartiscoveredinthePythonBasics:ForLoopvideo.

Thisisthelastpartalready.Thatwasquick,right?:)

Programmersdon'tliketorepeatthemselves.Programmingisallaboutautomatingthings,sowedon'twanttogreeteverypersonbytheirnamemanually,right?That'swhereloopscomeinhandy.

Stillrememberlists?Let'sdoalistofgirls:

python_intro.py

girls=['Rachel','Monica','Phoebe','Ola','You']

Wewanttogreetallofthembytheirname.Wehavethehifunctiontodothat,solet'suseitinaloop:

python_intro.py

fornameingirls:

Theforstatementbehavessimilarlytotheifstatement;codebelowbothoftheseneedtobeindentedfourspaces.

Hereisthefullcodethatwillbeinthefile:

python_intro.py

defhi(name):

print('Hi'+name+'!')

girls=['Rachel','Monica','Phoebe','Ola','You']

fornameingirls:

hi(name)

print('Nextgirl')

Andwhenwerunit:

command-line

IntroductiontoPython

46

$python3python_intro.py

HiRachel!

Nextgirl

HiMonica!

Nextgirl

HiPhoebe!

Nextgirl

HiOla!

Nextgirl

HiYou!

Nextgirl

Asyoucansee,everythingyouputinsideaforstatementwithanindentwillberepeatedforeveryelementofthelistgirls.

Youcanalsouseforonnumbersusingtherangefunction:

python_intro.py

foriinrange(1,6):

print(i)

Whichwouldprint:

command-line

1

2

3

4

5

rangeisafunctionthatcreatesalistofnumbersfollowingoneaftertheother(thesenumbersareprovidedbyyouasparameters).

NotethatthesecondofthesetwonumbersisnotincludedinthelistthatisoutputbyPython(meaningrange(1,6)countsfrom1to5,butdoesnotincludethenumber6).Thatisbecause"range"ishalf-open,andbythatwemeanitincludesthefirstvalue,butnotthelast.

SummaryThat'sit.Youtotallyrock!Thiswasatrickychapter,soyoushouldfeelproudofyourself.We'redefinitelyproudofyouformakingitthisfar!

Youmightwanttobrieflydosomethingelse–stretch,walkaroundforabit,restyoureyes–beforegoingontothenextchapter.:)

IntroductiontoPython

47

IntroductiontoPython

48

WhatisDjango?Django(/ˈdʒæŋɡoʊ/jang-goh)isafreeandopensourcewebapplicationframework,writteninPython.Awebframeworkisasetofcomponentsthathelpsyoutodevelopwebsitesfasterandeasier.

Whenyou'rebuildingawebsite,youalwaysneedasimilarsetofcomponents:awaytohandleuserauthentication(signingup,signingin,signingout),amanagementpanelforyourwebsite,forms,awaytouploadfiles,etc.

Luckilyforyouotherpeoplelongagonoticedthatwebdevelopersfacesimilarproblemswhenbuildinganewsite,sotheyteamedupandcreatedframeworks(Djangoisoneofthem)thatgiveyouready-madecomponentsyoucanuse.

Frameworksexisttosaveyoufromhavingtoreinventthewheelandhelpalleviatesomeoftheoverheadwhenyou’rebuildinganewsite.

Whydoyouneedaframework?TounderstandwhatDjangoactuallyisfor,weneedtotakeacloserlookattheservers.Thefirstthingisthattheserverneedstoknowthatyouwantittoserveyouawebpage.

Imagineamailbox(port)whichismonitoredforincomingletters(requests).Thisisdonebyawebserver.Thewebserverreadstheletter,andsendsaresponsewithawebpage.Butwhenyouwanttosendsomething,youneedtohavesomecontent.AndDjangoissomethingthathelpsyoucreatethecontent.

Whathappenswhensomeonerequestsawebsitefromyourserver?Whenarequestcomestoawebserverit'spassedtoDjangowhichtriestofigureoutwhatactuallyisrequested.Ittakesawebpageaddressfirstandtriestofigureoutwhattodo.ThispartisdonebyDjango'surlresolver(notethatawebsiteaddressiscalledaURL-UniformResourceLocator-sothenameurlresolvermakessense).Itisnotverysmart-ittakesalistofpatternsandtriestomatchtheURL.DjangocheckspatternsfromtoptothebottomandifsomethingismatchedthenDjangopassestherequesttotheassociatedfunction(whichiscalledview).

Imagineamailcarrierwithaletter.Sheiswalkingdownthestreetandcheckseachhousenumberagainsttheoneontheletter.Ifitmatches,sheputstheletterthere.Thisishowtheurlresolverworks!

Intheviewfunctionalltheinterestingthingsaredone:wecanlookatadatabasetolookforsomeinformation.Maybetheuseraskedtochangesomethinginthedata?Likealettersaying"Pleasechangethedescriptionofmyjob."Theviewcancheckifyouareallowedtodothat,thenupdatethejobdescriptionforyouandsendbackamessage:"Done!".ThentheviewgeneratesaresponseandDjangocansendittotheuser'swebbrowser.

Ofcourse,thedescriptionaboveisalittlebitsimplified,butyoudon'tneedtoknowallthetechnicalthingsyet.Havingageneralideaisenough.

Soinsteadofdivingtoomuchintodetails,wewillsimplystartcreatingsomethingwithDjangoandwewilllearnalltheimportantpartsalongtheway!

WhatisDjango?

49

DjangoinstallationIfyou'reusingaChromebook,skipthischapterandmakesureyoufollowtheChromebookSetupinstructions.

NoteIfyoualreadyworkedthroughtheInstallationstepsthenyou'vealreadydonethis-youcangostraighttothenextchapter!

PartofthissectionisbasedontutorialsbyGeekGirlsCarrots(https://github.com/ggcarrots/django-carrots).

Partofthissectionisbasedonthedjango-marcadortutoriallicensedundertheCreativeCommonsAttribution-ShareAlike4.0InternationalLicense.Thedjango-marcadortutorialiscopyrightedbyMarkusZapke-Gründemannetal.

VirtualenvironmentBeforeweinstallDjangowewillgetyoutoinstallanextremelyusefultooltohelpkeepyourcodingenvironmenttidyonyourcomputer.It'spossibletoskipthisstep,butit'shighlyrecommended.Startingwiththebestpossiblesetupwillsaveyoualotoftroubleinthefuture!

So,let'screateavirtualenvironment(alsocalledavirtualenv).VirtualenvwillisolateyourPython/Djangosetuponaper-projectbasis.Thismeansthatanychangesyoumaketoonewebsitewon'taffectanyothersyou'realsodeveloping.Neat,right?

Allyouneedtodoisfindadirectoryinwhichyouwanttocreatethevirtualenv;yourhomedirectory,forexample.OnWindowsitmightlooklikeC:\Users\Name\(whereNameisthenameofyourlogin).

NOTE:OnWindows,makesurethatthisdirectorydoesnotcontainaccentedorspecialcharacters;ifyourusernamecontainsaccentedcharacters,useadifferentdirectory,forexampleC:\djangogirls.

Forthistutorialwewillbeusinganewdirectorydjangogirlsfromyourhomedirectory:

command-line

$mkdirdjangogirls

$cddjangogirls

Wewillmakeavirtualenvcalledmyvenv.Thegeneralcommandwillbeintheformat:

command-line

$python3-mvenvmyvenv

WindowsTocreateanewvirtualenv,youneedtoopentheconsole(wetoldyouaboutthatafewchaptersago–remember?)andrunC:\Python35\python-mvenvmyvenv.Itwilllooklikethis:

command-line

C:\Users\Name\djangogirls>C:\Python35\python-mvenvmyvenv

whereC:\Python35\pythonisthedirectoryinwhichyoupreviouslyinstalledPythonandmyvenvisthenameofyourvirtualenv.Youcanuseanyothername,butsticktolowercaseandusenospaces,accentsorspecialcharacters.Itisalsogoodideatokeepthenameshort–you'llbereferencingitalot!

Djangoinstallation

50

LinuxandOSX

CreatingavirtualenvonbothLinuxandOSXisassimpleasrunningpython3-mvenvmyvenv.Itwilllooklikethis:

command-line

$python3-mvenvmyvenv

myvenvisthenameofyourvirtualenv.Youcanuseanyothername,butsticktolowercaseandusenospaces.Itisalsogoodideatokeepthenameshortasyou'llbereferencingitalot!

NOTE:OnsomeversionsofDebian/Ubuntuyoumayreceivethefollowingerror:

command-line

Thevirtualenvironmentwasnotcreatedsuccessfullybecauseensurepipisnotavailable.OnDebian/Ubuntusys

tems,youneedtoinstallthepython3-venvpackageusingthefollowingcommand.

apt-getinstallpython3-venv

Youmayneedtousesudowiththatcommand.Afterinstallingthepython3-venvpackage,recreateyourvirtual

environment.

Inthiscase,followtheinstructionsaboveandinstallthepython3-venvpackage:

command-line

$sudoapt-getinstallpython3-venv

NOTE:OnsomeversionsofDebian/Ubuntuinitiatingthevirtualenvironmentlikethiscurrentlygivesthefollowingerror:

command-line

Error:Command'['/home/eddie/Slask/tmp/venv/bin/python3','-Im','ensurepip','--upgrade','--default-pip']'

returnednon-zeroexitstatus1

Togetaroundthis,usethevirtualenvcommandinstead.

command-line

$sudoapt-getinstallpython-virtualenv

$virtualenv--python=python3.5myvenv

NOTE:Ifyougetanerrorlike

command-line

E:Unabletolocatepackagepython3-venv

theninsteadrun:

command-line

sudoaptinstallpython3.5-venv

Workingwithvirtualenv

Djangoinstallation

51

Thecommandabovewillcreateadirectorycalledmyvenv(orwhatevernameyouchose)thatcontainsourvirtualenvironment(basicallyabunchofdirectoryandfiles).

Windows

Startyourvirtualenvironmentbyrunning:

command-line

C:\Users\Name\djangogirls>myvenv\Scripts\activate

NOTE:onWindows10youmightgetanerrorintheWindowsPowerShellsaysexecutionofscriptsisdisabledonthissystem.InthosecasesopenanotherWindowsPowerShellandRunasAdministratortrydoingthisbeforecontinue:

command-line

C:\WINDOWS\system32>Set-ExecutionPolicy-ExecutionPolicyRemoteSigned

ExecutionPolicyChange

Theexecutionpolicyhelpsprotectyoufromscriptsthatyoudonottrust.Changingtheexecutionpolicym

ightexposeyoutothesecurityrisksdescribedintheabout_Execution_Policieshelptopicathttp://go.micros

oft.com/fwlink/?LinkID=135170.Doyouwanttochangetheexecutionpolicy?[Y]Yes[A]YestoAll[N]No[L

]NotoAll[S]Suspend[?]Help(defaultis"N"):A

LinuxandOSXStartyourvirtualenvironmentbyrunning:

command-line

$sourcemyvenv/bin/activate

Remembertoreplacemyvenvwithyourchosenvirtualenvname!

NOTE:sometimessourcemightnotbeavailable.Inthosecasestrydoingthisinstead:

command-line

$.myvenv/bin/activate

Youwillknowthatyouhavevirtualenvstartedwhenyouseethatthepromptinyourconsoleisprefixedwith(myvenv).

Whenworkingwithinavirtualenvironment,pythonwillautomaticallyrefertothecorrectversionsoyoucanusepythoninsteadofpython3.

OK,wehaveallimportantdependenciesinplace.WecanfinallyinstallDjango!

InstallingDjangoNowthatyouhaveyourvirtualenvstarted,youcaninstallDjango.

Beforewedothat,weshouldmakesurewehavethelatestversionofpip,thesoftwarethatweusetoinstallDjango.Intheconsole,runpipinstall--upgradepip.

Thenrunpipinstalldjango~=1.9.0(notethatweuseatildefollowedbyanequalsign:~=)toinstallDjango.

command-line

Djangoinstallation

52

(myvenv)~$pipinstalldjango~=1.9.0

Downloading/unpackingdjango==1.9

Installingcollectedpackages:django

Successfullyinstalleddjango

Cleaningup...

onWindows

IfyougetanerrorwhencallingpiponWindowsplatform,pleasecheckifyourprojectpathnamecontainsspaces,accentsorspecialcharacters(forexample,C:\Users\UserName\djangogirls).Ifitdoes,pleaseconsiderusinganotherplacewithoutspaces,accentsorspecialcharacters(suggestion:C:\djangogirls).Createanewvirtualenvinthenewdirectory,thendeletetheoldoneandtrytheabovecommandagain.(Movingthevirtualenvdirectorywon'tworksincevirtualenvusesabsolutepaths.)

onWindows8andWindows10

YourcommandlinemightfreezeafterwhenyoutrytoinstallDjango.Ifthishappens,insteadoftheabovecommanduse:

command-line

C:\Users\Name\djangogirls>python-mpipinstalldjango~=1.9.0

onLinux

IfyougetanerrorwhencallingpiponUbuntu12.04pleaserunpython-mpipinstall-U--force-reinstallpiptofixthepipinstallationinthevirtualenv.

That'sit!You'renow(finally)readytocreateaDjangoapplication!

Djangoinstallation

53

YourfirstDjangoproject!PartofthischapterisbasedontutorialsbyGeekGirlsCarrots(https://github.com/ggcarrots/django-carrots).

Partsofthischapterarebasedonthedjango-marcadortutoriallicensedunderCreativeCommonsAttribution-ShareAlike4.0InternationalLicense.Thedjango-marcadortutorialiscopyrightedbyMarkusZapke-Gründemannetal.

We'regoingtocreateasimpleblog!

ThefirststepistostartanewDjangoproject.Basically,thismeansthatwe'llrunsomescriptsprovidedbyDjangothatwillcreatetheskeletonofaDjangoprojectforus.Thisisjustabunchofdirectoriesandfilesthatwewilluselater.

ThenamesofsomefilesanddirectoriesareveryimportantforDjango.Youshouldnotrenamethefilesthatweareabouttocreate.Movingthemtoadifferentplaceisalsonotagoodidea.Djangoneedstomaintainacertainstructuretobeabletofindimportantthings.

Remembertoruneverythinginthevirtualenv.Ifyoudon'tseeaprefix(myvenv)inyourconsoleyouneedtoactivateyourvirtualenv.WeexplainedhowtodothatintheDjangoinstallationchapterintheWorkingwithvirtualenvpart.Typingmyvenv\Scripts\activateonWindowsorsourcemyvenv/bin/activateonMacOS/Linuxwilldothisforyou.

InyourMacOSorLinuxconsoleyoushouldrunthefollowingcommand;don'tforgettoaddtheperiod(ordot).attheend:

command-line

(myvenv)~/djangogirls$django-adminstartprojectmysite.

OnWindows;don'tforgettoaddtheperiod(ordot).attheend:

command-line

(myvenv)C:\Users\Name\djangogirls>django-admin.pystartprojectmysite.

Theperiod.iscrucialbecauseittellsthescripttoinstallDjangoinyourcurrentdirectory(forwhichtheperiod.isashort-handreference)

NoteWhentypingthecommandsabove,rememberthatyouonlytypethepartwhichstartsdjango-adminordjango-admin.py.The(myvenv)~/djangogirls$and(myvenv)C:\Users\Name\djangogirls>partsshownherearejustexamplesofthepromptthatwillbeinvitingyourinputonyourcommandline.

django-admin.pyisascriptthatwillcreatethedirectoriesandfilesforyou.Youshouldnowhaveadirectorystructurewhichlookslikethis:

djangogirls

├───manage.py

└───mysite

settings.py

urls.py

wsgi.py

__init__.py

manage.pyisascriptthathelpswithmanagementofthesite.Withitwewillbeabletostartawebserveronourcomputerwithoutinstallinganythingelse,amongstotherthings.

Thesettings.pyfilecontainstheconfigurationofyourwebsite.

YourfirstDjangoproject!

54

Rememberwhenwetalkedaboutamailcarriercheckingwheretodeliveraletter?urls.pyfilecontainsalistofpatternsusedbyurlresolver.

Let'signoretheotherfilesfornowaswewon'tchangethem.Theonlythingtorememberisnottodeletethembyaccident!

ChangingsettingsLet'smakesomechangesinmysite/settings.py.Openthefileusingthecodeeditoryouinstalledearlier.

Itwouldbenicetohavethecorrecttimeonourwebsite.Gotothewikipediatimezoneslistandcopyyourrelevanttimezone(TZ).(eg.Europe/Berlin)

Insettings.py,findthelinethatcontainsTIME_ZONEandmodifyittochooseyourowntimezone:

mysite/settings.py

TIME_ZONE='Europe/Berlin'

Modifying"Europe/Berlin"asappropriate

We'llalsoneedtoaddapathforstaticfiles(we'llfindoutallaboutstaticfilesandCSSlaterinthetutorial).Godowntotheendofthefile,andjustunderneaththeSTATIC_URLentry,addanewonecalledSTATIC_ROOT:

mysite/settings.py

STATIC_URL='/static/'

STATIC_ROOT=os.path.join(BASE_DIR,'static')

:Ifyou'reusingaChromebook,addthislineatthebottomofyoursettings.pyfile:MESSAGE_STORAGE='django.contrib.messages.storage.session.SessionStorage'

SetupadatabaseThere'salotofdifferentdatabasesoftwarethatcanstoredataforyoursite.We'llusethedefaultone,sqlite3.

Thisisalreadysetupinthispartofyourmysite/settings.pyfile:

mysite/settings.py

DATABASES={

'default':{

'ENGINE':'django.db.backends.sqlite3',

'NAME':os.path.join(BASE_DIR,'db.sqlite3'),

}

}

Tocreateadatabaseforourblog,let'srunthefollowingintheconsole:pythonmanage.pymigrate(weneedtobeinthedjangogirlsdirectorythatcontainsthemanage.pyfile).Ifthatgoeswell,youshouldseesomethinglikethis:

command-line

YourfirstDjangoproject!

55

(myvenv)~/djangogirls$pythonmanage.pymigrate

Operationstoperform:

Applyallmigrations:auth,admin,contenttypes,sessions

Runningmigrations:

Renderingmodelstates...DONE

Applyingcontenttypes.0001_initial...OK

Applyingauth.0001_initial...OK

Applyingadmin.0001_initial...OK

Applyingadmin.0002_logentry_remove_auto_add...OK

Applyingcontenttypes.0002_remove_content_type_name...OK

Applyingauth.0002_alter_permission_name_max_length...OK

Applyingauth.0003_alter_user_email_max_length...OK

Applyingauth.0004_alter_user_username_opts...OK

Applyingauth.0005_alter_user_last_login_null...OK

Applyingauth.0006_require_contenttypes_0002...OK

Applyingauth.0007_alter_validators_add_error_messages...OK

Applyingsessions.0001_initial...OK

Andwe'redone!Timetostartthewebserverandseeifourwebsiteisworking!

StartingthewebserverYouneedtobeinthedirectorythatcontainsthemanage.pyfile(thedjangogirlsdirectory).Intheconsole,wecanstartthewebserverbyrunningpythonmanage.pyrunserver:

command-line

(myvenv)~/djangogirls$pythonmanage.pyrunserver

IfyouareonaChromebook,usethiscommandinstead:

Cloud9

(myvenv)~/djangogirls$pythonmanage.pyrunserver0.0.0.0:8080

IfyouareonWindowsandthisfailswithUnicodeDecodeError,usethiscommandinstead:

command-line

(myvenv)~/djangogirls$pythonmanage.pyrunserver0:8000

Nowallyouneedtodoischeckthatyourwebsiteisrunning.Openyourbrowser(Firefox,Chrome,Safari,InternetExplorerorwhateveryouuse)andentertheaddress:

browser

http://127.0.0.1:8000/

Ifyou'reusingaChromebook,you'llalwaysvisityourtestserverbyaccessing:

browser

https://django-girls-<yourcloud9username>.c9users.io

Congratulations!You'vejustcreatedyourfirstwebsiteandrunitusingawebserver!Isn'tthatawesome?

YourfirstDjangoproject!

56

Whilethewebserverisrunning,youwon'tseeanewcommandlineprompttoenteradditonalcommands.Theterminalwillacceptnewtextbutwillnotexecutenewcommands.Thisisbecausethewebservercontinuouslyrunsinordertolistenforincomingrequests.

WereviewedhowwebserversworkintheHowtheInternetworkschapter.

Totypeadditionalcommandswhilethewebserverisrunning,openanewterminalwindowandactivateyourvirtualenv.Tostopthewebserver,switchbacktothewindowinwhichit'srunningandpressCTRL+C-ControlandCbuttonstogether(onWindows,youmighthavetopressCtrl+Break).

Readyforthenextstep?It'stimetocreatesomecontent!

YourfirstDjangoproject!

57

DjangomodelsWhatwewanttocreatenowissomethingthatwillstoreallthepostsinourblog.Buttobeabletodothatweneedtotalkalittlebitaboutthingscalledobjects.

ObjectsThereisaconceptinprogrammingcalledObject-orientedprogramming.Theideaisthatinsteadofwritingeverythingasaboringsequenceofprogramminginstructionswecanmodelthingsanddefinehowtheyinteractwitheachother.

Sowhatisanobject?Itisacollectionofpropertiesandactions.Itsoundsweird,butwewillgiveyouanexample.

IfwewanttomodelacatwewillcreateanobjectCatthathassomepropertiessuchas:color,age,mood(likegood,bad,orsleepy;)),andowner(thatisaPersonobjectormaybe,incaseofastraycat,thispropertyisempty).

ThentheCathassomeactions:purr,scratch,orfeed(inwhichcase,wewillgivethecatsomeCatFood,whichcouldbeaseparateobjectwithproperties,liketaste).

Cat

--------

color

age

mood

owner

purr()

scratch()

feed(cat_food)

CatFood

--------

taste

Sobasicallytheideaistodescriberealthingsincodewithproperties(calledobjectproperties)andactions(calledmethods).

Howwillwemodelblogpoststhen?Wewanttobuildablog,right?

Weneedtoanswerthequestion:Whatisablogpost?Whatpropertiesshouldithave?

Well,forsureourblogpostneedssometextwithitscontentandatitle,right?Itwouldbealsonicetoknowwhowroteit-soweneedanauthor.Finally,wewanttoknowwhenthepostwascreatedandpublished.

Post

--------

title

text

author

created_date

published_date

Whatkindofthingscouldbedonewithablogpost?Itwouldbenicetohavesomemethodthatpublishesthepost,right?

Sowewillneedapublishmethod.

Sincewealreadyknowwhatwewanttoachieve,let'sstartmodelingitinDjango!

Djangomodel

Djangomodels

58

Knowingwhatanobjectis,wecancreateaDjangomodelforourblogpost.

AmodelinDjangoisaspecialkindofobject-itissavedinthedatabase.Adatabaseisacollectionofdata.Thisisaplaceinwhichyouwillstoreinformationaboutusers,yourblogposts,etc.WewillbeusingaSQLitedatabasetostoreourdata.ThisisthedefaultDjangodatabaseadapter--it'llbeenoughforusrightnow.

Youcanthinkofamodelinthedatabaseasaspreadsheetwithcolumns(fields)androws(data).

CreatinganapplicationTokeepeverythingtidy,wewillcreateaseparateapplicationinsideourproject.Itisverynicetohaveeverythingorganizedfromtheverybeginning.Tocreateanapplicationweneedtorunthefollowingcommandintheconsole(fromdjangogirlsdirectorywheremanage.pyfileis):

command-line

(myvenv)~/djangogirls$pythonmanage.pystartappblog

Youwillnoticethatanewblogdirectoryiscreatedanditcontainsanumberoffilesnow.Ourdirectoriesandfilesinourprojectshouldlooklikethis:

djangogirls

├──blog

│├──__init__.py

│├──admin.py

│├──apps.py

│├──migrations

││└──__init__.py

│├──models.py

│├──tests.py

│└──views.py

├──db.sqlite3

├──manage.py

└──mysite

├──__init__.py

├──settings.py

├──urls.py

└──wsgi.py

AftercreatinganapplicationwealsoneedtotellDjangothatitshoulduseit.Wedothatinthefilemysite/settings.py.WeneedtofindINSTALLED_APPSandaddalinecontaining'blog',justabove).Sothefinalproductshouldlooklikethis:

mysite/settings.py

INSTALLED_APPS=(

'django.contrib.admin',

'django.contrib.auth',

'django.contrib.contenttypes',

'django.contrib.sessions',

'django.contrib.messages',

'django.contrib.staticfiles',

'blog',

)

Creatingablogpostmodel

Intheblog/models.pyfilewedefineallobjectscalledModels-thisisaplaceinwhichwewilldefineourblogpost.

Let'sopenblog/models.py,removeeverythingfromitandwritecodelikethis:

blog/models.py

Djangomodels

59

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

Double-checkthatyouusetwounderscorecharacters(_)oneachsideofstr.ThisconventionisusedfrequentlyinPythonandsometimeswealsocallthem"dunder"(shortfor"double-underscore").

Itlooksscary,right?Butnoworrieswewillexplainwhattheselinesmean!

Alllinesstartingwithfromorimportarelinesthataddsomebitsfromotherfiles.Soinsteadofcopyingandpastingthesamethingsineveryfile,wecanincludesomepartswithfrom...import....

classPost(models.Model):-thislinedefinesourmodel(itisanobject).

classisaspecialkeywordthatindicatesthatwearedefininganobject.Postisthenameofourmodel.Wecangiveitadifferentname(butwemustavoidspecialcharactersandwhitespaces).Alwaysstartaclassnamewithanuppercaseletter.models.ModelmeansthatthePostisaDjangoModel,soDjangoknowsthatitshouldbesavedinthedatabase.

Nowwedefinethepropertiesweweretalkingabout:title,text,created_date,published_dateandauthor.Todothatweneedtodefineatypeofeachfield(Isittext?Anumber?Adate?Arelationtoanotherobject,likeaUser?).

models.CharField-thisishowyoudefinetextwithalimitednumberofcharacters.models.TextField-thisisforlongtextwithoutalimit.Soundsidealforblogpostcontent,right?models.DateTimeField-thisisadateandtime.models.ForeignKey-thisisalinktoanothermodel.

Wewillnotexplaineverybitofcodeheresinceitwouldtaketoomuchtime.YoushouldtakealookatDjango'sdocumentationifyouwanttoknowmoreaboutModelfieldsandhowtodefinethingsotherthanthosedescribedabove(https://docs.djangoproject.com/en/1.9/ref/models/fields/#field-types).

Whataboutdefpublish(self):?Itisexactlythepublishmethodweweretalkingaboutbefore.defmeansthatthisisafunction/methodandpublishisthenameofthemethod.Youcanchangethenameofthemethod,ifyouwant.Thenamingruleisthatweuselowercaseandunderscoresinsteadofwhitespaces.Forexample,amethodthatcalculatesaveragepricecouldbecalledcalculate_average_price.

Methodsoftenreturnsomething.Thereisanexampleofthatinthe__str__method.Inthisscenario,whenwecall__str__()wewillgetatext(string)withaPosttitle.

Alsonoticethatbothdefpublish(self):,anddef__str__(self):areindentedinsideourclass.BecausePythonissensitivetowhitespace,weneedtoindentourmethodsinsidetheclass.Otherwise,themethodswon'tbelongtotheclass,andyoucangetsomeunexpectedbehavior.

Ifsomethingisstillnotclearaboutmodels,feelfreetoaskyourcoach!Weknowitiscomplicated,especiallywhenyoulearnwhatobjectsandfunctionsareatthesametime.Buthopefullyitlooksslightlylessmagicforyounow!

Djangomodels

60

Createtablesformodelsinyourdatabase

Thelaststephereistoaddournewmodeltoourdatabase.FirstwehavetomakeDjangoknowthatwehavesomechangesinourmodel(wehavejustcreatedit!).Gotoyourconsolewindowandtypepythonmanage.pymakemigrationsblog.Itwilllooklikethis:

command-line

(myvenv)~/djangogirls$pythonmanage.pymakemigrationsblog

Migrationsfor'blog':

0001_initial.py:

-CreatemodelPost

Djangopreparedforusamigrationfilethatwehavetoapplynowtoourdatabase.Typepythonmanage.pymigrateblogandtheoutputshouldbe:

command-line

(myvenv)~/djangogirls$pythonmanage.pymigrateblog

Operationstoperform:

Applyallmigrations:blog

Runningmigrations:

Renderingmodelstates...DONE

Applyingblog.0001_initial...OK

Hurray!OurPostmodelisnowinourdatabase!Itwouldbenicetoseeit,right?JumptothenextchaptertoseewhatyourPostlookslike!

Djangomodels

61

DjangoadminToadd,editanddeletepostswe'vejustmodeled,wewilluseDjangoadmin.

Let'sopentheblog/admin.pyfileandreplaceitscontentwiththis:

blog/admin.py

fromdjango.contribimportadmin

from.modelsimportPost

admin.site.register(Post)

Asyoucansee,weimport(include)thePostmodeldefinedinthepreviouschapter.Tomakeourmodelvisibleontheadminpage,weneedtoregisterthemodelwithadmin.site.register(Post).

OK,timetolookatourPostmodel.Remembertorunpythonmanage.pyrunserverintheconsoletorunthewebserver.Gotothebrowserandtypetheaddresshttp://127.0.0.1:8000/admin/Youwillseealoginpagelikethis:

Tologin,youneedtocreateasuperuser-auserwhichhascontrolovereverythingonthesite.Gobacktothecommand-lineandtypepythonmanage.pycreatesuperuser,andpressenter.

Remember,towritenewcommandswhilethewebserverisrunning,openanewterminalwindowandactivateyourvirtualenv.WereviewedhowtowritenewcommandsintheYourfirstDjangoproject!chapter,intheStartingthewebserversection.

Whenprompted,typeyourusername(lowercase,nospaces),emailaddress,andpassword.Don'tworrythatyoucan'tseethepasswordyou'retypingin-that'showit'ssupposedtobe.Justtypeitinandpressentertocontinue.Theoutputshouldlooklikethis(whereusernameandemailshouldbeyourownones):

command-line

(myvenv)~/djangogirls$pythonmanage.pycreatesuperuser

Username:admin

Emailaddress:admin@admin.com

Password:

Password(again):

Superusercreatedsuccessfully.

Djangoadmin

62

Returntoyourbrowser.Loginwiththesuperuser'scredentialsyouchose;youshouldseetheDjangoadmindashboard.

GotoPostsandexperimentalittlebitwithit.Addfiveorsixblogposts.Don'tworryaboutthecontent-youcansimplycopy-pastesometextfromthistutorialtosavetime:).

Makesurethatatleasttwoorthreeposts(butnotall)havethepublishdateset.Itwillbehelpfullater.

IfyouwanttoknowmoreaboutDjangoadmin,youshouldcheckDjango'sdocumentation:https://docs.djangoproject.com/en/1.9/ref/contrib/admin/

Thisisprobablyagoodmomenttograbacoffee(ortea)orsomethingtoeattore-energiseyourself.YoucreatedyourfirstDjangomodel-youdeservealittletimeout!

Djangoadmin

63

Deploy!Thefollowingchaptercanbesometimesabithardtogetthrough.Persistandfinishit;deploymentisanimportantpartofthewebsitedevelopmentprocess.Thischapterisplacedinthemiddleofthetutorialsothatyourmentorcanhelpwiththeslightlytrickierprocessofgettingyourwebsiteonline.Thismeansyoucanstillfinishthetutorialonyourownifyourunoutoftime.

Untilnow,yourwebsitewasonlyavailableonyourcomputer.Nowyouwilllearnhowtodeployit!DeployingistheprocessofpublishingyourapplicationontheInternetsopeoplecanfinallygoandseeyourapp:).

Asyoulearned,awebsitehastobelocatedonaserver.Therearealotofserverprovidersavailableontheinternet.Wewilluseonethathasarelativelysimpledeploymentprocess:PythonAnywhere.PythonAnywhereisfreeforsmallapplicationsthatdon'thavetoomanyvisitorssoit'lldefinitelybeenoughforyounow.

Theotherexternalservicewe'llbeusingisGitHub,whichisacodehostingservice.Thereareothersoutthere,butalmostallprogrammershaveaGitHubaccountthesedays,andnowsowillyou!

Thesethreeplaceswillbeimportanttoyou.Yourlocalcomputerwillbetheplacewhereyoudodevelopmentandtesting.Whenyou'rehappywiththechanges,youwillplaceacopyofyourprogramonGitHub.YourwebsitewillbeonPythonAnywhereandyouwillupdateitbygettinganewcopyofyourcodefromGitHub.

GitGitisa"versioncontrolsystem"usedbyalotofprogrammers.Thissoftwarecantrackchangestofilesovertimesothatyoucanrecallspecificversionslater.Abitlikethe"trackchanges"featureinMicrosoftWord,butmuchmorepowerful.

InstallingGitIfyoualreadydidtheInstallationsteps,noneedtodothisagain-youcanskiptothenextsectionandstartcreatingyourGitrepository.

Windows

YoucandownloadGitfromgit-scm.com.Youcanhit"next"onallstepsexceptforone;inthefifthstepentitled"AdjustingyourPATHenvironment",choose"UseGitandoptionalUnixtoolsfromtheWindowsCommandPrompt"(thebottomoption).Otherthanthat,thedefaultsarefine.CheckoutWindows-style,commitUnix-stylelineendingsisgood.

MacOSDownloadGitfromgit-scm.comandjustfollowtheinstructions.

LinuxIfitisn'tinstalledalready,gitshouldbeavailableviayourpackagemanager,sotry:

DebianorUbuntucommand-line

$sudoapt-getinstallgit

Deploy!

64

Fedora(upto21)

command-line

$sudoyuminstallgit

Fedora(22+)

command-line

$sudodnfinstallgit

openSUSE

command-line

$sudozypperinstallgit

StartingourGitrepositoryGittrackschangestoaparticularsetoffilesinwhat'scalledacoderepository(or"repo"forshort).Let'sstartoneforourproject.Openupyourconsoleandrunthesecommands,inthedjangogirlsdirectory:

Checkyourcurrentworkingdirectorywithapwd(OSX/Linux)orcd(Windows)commandbeforeinitializingtherepository.Youshouldbeinthedjangogirlsfolder.

command-line

$gitinit

InitializedemptyGitrepositoryin~/djangogirls/.git/

$gitconfig--globaluser.name"YourName"

$gitconfig--globaluser.emailyou@example.com

Initializingthegitrepositoryissomethingweonlyneedtodoonceperproject(andyouwon'thavetore-entertheusernameandemailagainever).

Gitwilltrackchangestoallthefilesandfoldersinthisdirectory,buttherearesomefileswewantittoignore.Wedothisbycreatingafilecalled.gitignoreinthebasedirectory.Openupyoureditorandcreateanewfilewiththefollowingcontents:

.gitignore

*.pyc

__pycache__

myvenv

db.sqlite3

/static

.DS_Store

Andsaveitas.gitignoreinthe"djangogirls"folder.

Deploy!

65

Thedotatthebeginningofthefilenameisimportant!Ifyou'rehavinganydifficultycreatingit(Macsdon'tlikeyoutocreatefilesthatbeginwithadotviatheFinder,forexample),thenusethe"SaveAs"featureinyoureditor,it'sbulletproof.

NoteOneofthefilesyouspecifiedinyour.gitignorefileisdb.sqlite3.Thatfileisyourlocaldatabase,wherealloryourpostsarestored.Wedon'twanttoaddthistoyourrepository,becauseyourwebsiteonPythonAnywhereisgoingtobeusingadifferentdatabase.ThatdatabasecouldbeSQLite,likeyourdevelopmentmachine,butusually,youwilluseonecalledMySQLwhichcandealwithalotmoresitevisitorsthanSQLite.Eitherway,byignoringyourSQLitedatabasefortheGitHubcopy,itmeansthatallofthepostsyoucreatedsofararegoingtostayandonlybeavailablelocally,butyou'regonnahavetoaddthemagainonproduction.Youshouldthinkofyourlocaldatabaseasagoodplaygroundwhereyoucantestdifferentthingsandnotbeafraidthatyou'regoingtodeleteyourrealpostsfromyourblog.

It'sagoodideatouseagitstatuscommandbeforegitaddorwheneveryoufindyourselfunsureofwhathaschanged.Thiswillhelpstopanysurprisesfromhappening,suchaswrongfilesbeingaddedorcommited.Thegitstatuscommandreturnsinformationaboutanyuntracked/modifed/stagedfiles,branchstatus,andmuchmore.Theoutputshouldbesimilarto:

command-line

$gitstatus

Onbranchmaster

Initialcommit

Untrackedfiles:

(use"gitadd<file>..."toincludeinwhatwillbecommitted)

.gitignore

blog/

manage.py

mysite/

nothingaddedtocommitbutuntrackedfilespresent(use"gitadd"totrack)

Andfinallywesaveourchanges.Gotoyourconsoleandrunthesecommands:

command-line

$gitadd--all.

$gitcommit-m"MyDjangoGirlsapp,firstcommit"

[...]

13fileschanged,200insertions(+)

createmode100644.gitignore

[...]

createmode100644mysite/wsgi.py

PushingourcodetoGitHubGotoGitHub.comandsignupforanew,freeuseraccount.(Ifyoualreadydidthatintheworkshopprep,thatisgreat!)

Then,createanewrepository,givingitthename"my-first-blog".Leavethe"initialisewithaREADME"tickboxun-checked,leavethe.gitignoreoptionblank(we'vedonethatmanually)andleavetheLicenseasNone.

Deploy!

66

Thenamemy-first-blogisimportant--youcouldchoosesomethingelse,butit'sgoingtooccurlotsoftimesintheinstructionsbelow,andyou'dhavetosubstituteiteachtime.It'sprobablyeasiertojuststickwiththenamemy-first-blog.

Onthenextscreen,you'llbeshownyourrepo'scloneURL.Choosethe"HTTPS"version,copyit,andwe'llpasteitintotheterminalshortly:

NowweneedtohookuptheGitrepositoryonyourcomputertotheoneuponGitHub.

Typethefollowingintoyourconsole(Replace<your-github-username>withtheusernameyouenteredwhenyoucreatedyourGitHubaccount,butwithouttheangle-brackets):

command-line

Deploy!

67

$gitremoteaddoriginhttps://github.com/<your-github-username>/my-first-blog.git

$gitpush-uoriginmaster

EnteryourGitHubusernameandpasswordandyoushouldseesomethinglikethis:

command-line

Usernamefor'https://github.com':hjwp

Passwordfor'https://hjwp@github.com':

Countingobjects:6,done.

Writingobjects:100%(6/6),200bytes|0bytes/s,done.

Total3(delta0),reused0(delta0)

Tohttps://github.com/hjwp/my-first-blog.git

*[newbranch]master->master

Branchmastersetuptotrackremotebranchmasterfromorigin.

YourcodeisnowonGitHub.Goandcheckitout!You'llfindit'sinfinecompany-Django,theDjangoGirlsTutorial,andmanyothergreatopensourcesoftwareprojectsalsohosttheircodeonGitHub:)

SettingupourblogonPythonAnywhereYoumighthavealreadycreatedaPythonAnywhereaccountearlierduringtheinstallsteps-ifso,noneedtodoitagain.

Nextit'stimetosignupforafree"Beginner"accountonPythonAnywhere.

www.pythonanywhere.com

Whenchoosingyourusernamehere,bearinmindthatyourblog'sURLwilltaketheformyourusername.pythonanywhere.com,sochooseeitheryourownnickname,oranameforwhatyourblogisallabout.

PullingourcodedownonPythonAnywhereWhenyou'vesignedupforPythonAnywhere,you'llbetakentoyourdashboardor"Consoles"page.Choosetheoptiontostarta"Bash"console--that'sthePythonAnywhereversionofaconsole,justliketheoneonyourcomputer.

PythonAnywhereisbasedonLinux,soifyou'reonWindows,theconsolewilllookalittledifferentfromtheoneonyourcomputer.

Let'spulldownourcodefromGitHubandontoPythonAnywherebycreatinga"clone"ofourrepo.TypethefollowingintotheconsoleonPythonAnywhere(don'tforgettouseyourGitHubusernameinplaceof<your-github-username>):

PythonAnywherecommand-line

$gitclonehttps://github.com/<your-github-username>/my-first-blog.git

ThiswillpulldownacopyofyourcodeontoPythonAnywhere.Checkitoutbytypingtreemy-first-blog:

PythonAnywherecommand-line

Deploy!

68

$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

CreatingavirtualenvonPythonAnywhereJustlikeyoudidonyourowncomputer,youcancreateavirtualenvonPythonAnywhere.IntheBashconsole,type:

PythonAnywherecommand-line

$cdmy-first-blog

$virtualenv--python=python3.5myvenv

Runningvirtualenvwithinterpreter/usr/bin/python3.5

[...]

Installingsetuptools,pip...done.

$sourcemyvenv/bin/activate

(myvenv)$pipinstalldjango~=1.9.0

Collectingdjango

[...]

Successfullyinstalleddjango-1.9

Thepipinstallstepcantakeacoupleofminutes.Patience,patience!Butifittakesmorethan5minutes,somethingiswrong.Askyourcoach.

CreatingthedatabaseonPythonAnywhere

Here'sanotherthingthat'sdifferentbetweenyourowncomputerandtheserver:itusesadifferentdatabase.Sotheuseraccountsandpostscanbedifferentontheserverandonyourcomputer.

Wecaninitialisethedatabaseontheserverjustlikewedidtheoneonyourowncomputer,withmigrateandcreatesuperuser:

PythonAnywherecommand-line

(mvenv)$pythonmanage.pymigrate

Operationstoperform:

[...]

Applyingsessions.0001_initial...OK

(mvenv)$pythonmanage.pycreatesuperuser

Publishingourblogasawebapp

Deploy!

69

NowourcodeisonPythonAnywhere,ourvirtualenvisready,andthedatabaseisinitialised.We'rereadytopublishitasawebapp!

ClickbacktothePythonAnywheredashboardbyclickingonitslogo,andgoclickontheWebtab.Finally,hitAddanewwebapp.

Afterconfirmingyourdomainname,choosemanualconfiguration(NBnotthe"Django"option)inthedialog.NextchoosePython3.5,andclickNexttofinishthewizard.

Makesureyouchoosethe"Manualconfiguration"option,notthe"Django"one.We'retoocoolforthedefaultPythonAnywhereDjangosetup;-)

SettingthevirtualenvYou'llbetakentothePythonAnywhereconfigscreenforyourwebapp,whichiswhereyou'llneedtogowheneveryouwanttomakechangestotheappontheserver.

Inthe"Virtualenv"section,clicktheredtextthatsays"Enterthepathtoavirtualenv",andenter:/home/<your-PythonAnywhere-username>/my-first-blog/myvenv/.Clicktheblueboxwiththecheckmarktosavethepathbeforemovingon.

SubstituteyourownPythonAnywhereusernameasappropriate.Ifyoumakeamistake,PythonAnywherewillshowyoualittlewarning.

ConfiguringtheWSGIfile

Djangoworksusingthe"WSGIprotocol",astandardforservingwebsitesusingPython,whichPythonAnywheresupports.ThewayweconfigurePythonAnywheretorecogniseourDjangoblogisbyeditingaWSGIconfigurationfile.

Clickonthe"WSGIconfigurationfile"link(inthe"Code"sectionnearthetopofthepage--it'llbenamedsomethinglike/var/www/<your-PythonAnywhere-username>_pythonanywhere_com_wsgi.py),andyou'llbetakentoaneditor.

Deleteallthecontentsandreplacethemwithsomethinglikethis:

<your-username>_pythonanywhere_com_wsgi.py

Deploy!

70

importos

importsys

path='/home/<your-PythonAnywhere-username>/my-first-blog'#useyourownPythonAnywhereusernamehere

ifpathnotinsys.path:

sys.path.append(path)

os.environ['DJANGO_SETTINGS_MODULE']='mysite.settings'

fromdjango.core.wsgiimportget_wsgi_application

fromdjango.contrib.staticfiles.handlersimportStaticFilesHandler

application=StaticFilesHandler(get_wsgi_application())

Don'tforgettosubstituteinyourownPythonAnywhereusernamewhereitsays<your-PythonAnywhere-username>NoteInlinefour,wemakesurePythonanywhereknowshowtofindourapplication.Itisveryimportantthatthispathnameiscorrect,andespeciallythattherearenoextraspaceshere.Otherwiseyouwillseean"ImportError"intheerrorlog.

Thisfile'sjobistotellPythonAnywherewhereourwebapplivesandwhattheDjangosettingsfile'snameis.

TheStaticFilesHandlerisfordealingwithourCSS.Thisistakencareofautomaticallyforyouduringlocaldevelopmentbytherunservercommand.We'llfindoutabitmoreaboutstaticfileslaterinthetutorial,whenweedittheCSSforoursite.

HitSaveandthengobacktotheWebtab.

We'realldone!HitthebiggreenReloadbuttonandyou'llbeabletogoviewyourapplication.You'llfindalinktoitatthetopofthepage.

DebuggingtipsIfyouseeanerrorwhenyoutrytovisityoursite,thefirstplacetolookforsomedebugginginfoisinyourerrorlog.You'llfindalinktothisonthePythonAnywhereWebtab.Seeifthereareanyerrormessagesinthere;themostrecentonesareatthebottom.Commonproblemsinclude:

Forgettingoneofthestepswedidintheconsole:creatingthevirtualenv,activatingit,installingDjangointoit,migratingthedatabase.

MakingamistakeinthevirtualenvpathontheWebtab--therewillusuallybealittlerederrormessageonthere,ifthereisaproblem.

MakingamistakeintheWSGIconfigurationfile--didyougetthepathtoyourmy-first-blogfolderright?

DidyoupickthesameversionofPythonforyourvirtualenvasyoudidforyourwebapp?Bothshouldbe3.5.

TherearesomegeneraldebuggingtipsonthePythonAnywherewiki.

Andremember,yourcoachisheretohelp!

Youarelive!Thedefaultpageforyoursiteshouldsay"WelcometoDjango",justlikeitdoesonyourlocalcomputer.Tryadding/admin/totheendoftheURL,andyou'llbetakentotheadminsite.Loginwiththeusernameandpassword,andyou'llseeyoucanaddnewPostsontheserver.

Onceyouhaveafewpostscreated,youcangobacktoyourlocalsetup(notPythonAnywhere).Fromhereyoushouldworkonyourlocalsetuptomakechanges.ThisisacommonworkflowinWebdevelopment(makechangeslocally,pushthosechangestoGitHub,pullyourchangesdowntoyourliveWebserver).Thisallowsyoutoworkandexperimentwithout

Deploy!

71

breakingyourliveWebsite.Prettycool,huh?

GiveyourselfaHUGEpatontheback!Serverdeploymentsareoneofthetrickiestpartsofwebdevelopmentanditoftentakespeopleseveraldaysbeforetheygetthemworking.Butyou'vegotyoursitelive,ontherealInternet,justlikethat!

Deploy!

72

DjangoURLsWe'reabouttobuildourfirstwebpage:ahomepageforyourblog!Butfirst,let'slearnalittlebitaboutDjangourls.

WhatisaURL?AURLissimplyawebaddress.YoucanseeaURLeverytimeyouvisitawebsite-itisvisibleinyourbrowser'saddressbar(yes!127.0.0.1:8000isaURL!Andhttps://djangogirls.orgisalsoaURL):

EverypageontheInternetneedsitsownURL.ThiswayyourapplicationknowswhatitshouldshowtoauserwhoopensaURL.InDjangoweusesomethingcalledURLconf(URLconfiguration).URLconfisasetofpatternsthatDjangowilltrytomatchwiththereceivedURLtofindthecorrectview.

HowdoURLsworkinDjango?Let'sopenupthemysite/urls.pyfileinyourcodeeditorofchoiceandseewhatitlookslike:

mysite/urls.py

"""mysiteURLConfiguration

[...]

"""

fromdjango.conf.urlsimporturl

fromdjango.contribimportadmin

urlpatterns=[

url(r'^admin/',admin.site.urls),

]

Asyoucansee,Djangoalreadyputsomethinghereforus.

Linesbetweentriplequotes('''or""")arecalleddocstrings-youcanwritethematthetopofafile,classormethodtodescribewhatitdoes.Theywon'tberunbyPython.

TheadminURL,whichyouvisitedinpreviouschapterisalreadyhere:

mysite/urls.py

url(r'^admin/',admin.site.urls),

ItmeansthatforeveryURLthatstartswithadmin/Djangowillfindacorrespondingview.Inthiscasewe'reincludingalotofadminURLssoitisn'tallpackedintothissmallfile--it'smorereadableandcleaner.

Djangourls

73

RegexDoyouwonderhowDjangomatchesURLstoviews?Well,thispartistricky.Djangousesregex,shortfor"regularexpressions".Regexhasalot(alot!)ofrulesthatformasearchpattern.Sinceregexesareanadvancedtopic,wewillnotgoindetailoverhowtheywork.

Ifyoustillwishtounderstandhowwecreatedthepatterns,hereisanexampleoftheprocess-wewillonlyneedalimitedsubsetoftherulestoexpressthepatternwearelookingfor,namely:

^forbeginningofthetext

$forendoftext

\dforadigit

+toindicatethatthepreviousitemshouldberepeatedatleastonce

()tocapturepartofthepattern

Anythingelseintheurldefinitionwillbetakenliterally.

Nowimagineyouhaveawebsitewiththeaddresslikethat:http://www.mysite.com/post/12345/,where12345isthenumberofyourpost.

Writingseparateviewsforallthepostnumberswouldbereallyannoying.Withregularexpressionwecancreateapatternthatwillmatchtheurlandextractthenumberforus: ̂ post/(\d+)/$.Let'sbreakitdownpiecebypiecetoseewhatwearedoinghere:

^post/istellingDjangototakeanythingthathaspost/atthebeginningoftheurl(rightafter ̂ )(\d+)meansthattherewillbeanumber(oneormoredigits)andthatwewantthenumbercapturedandextracted/tellsdjangothatanother/charactershouldfollow$thenindicatestheendoftheURLmeaningthatonlystringsendingwiththe/willmatchthispattern

YourfirstDjangourl!TimetocreateourfirstURL!Wewant'http://127.0.0.1:8000/'tobeahomepageofourbloganddisplayalistofposts.

Wealsowanttokeepthemysite/urls.pyfileclean,sowewillimporturlsfromourblogapplicationtothemainmysite/urls.pyfile.

Goahead,addalinethatwillimportblog.urlsintothemainurl('').Notethatweareusingtheincludefunctionheresoyouwillneedtoaddthattotheimportonthefirstlineofthefile.

Yourmysite/urls.pyfileshouldnowlooklikethis:

mysite/urls.py

fromdjango.conf.urlsimportinclude,url

fromdjango.contribimportadmin

urlpatterns=[

url(r'^admin/',admin.site.urls),

url(r'',include('blog.urls')),

]

Djangowillnowredirecteverythingthatcomesinto'http://127.0.0.1:8000/'toblog.urlsandlookforfurtherinstructionsthere.

WhenwritingregularexpressionsinPythonitisalwaysdonewithrinfrontofthestring.ThisisahelpfulhintforPythonthatthestringmaycontainspecialcharactersthatarenotmeantforPythonitself,butfortheregularexpressioninstead.

blog.urls

Djangourls

74

Createanewblog/urls.pyemptyfile.Allright!Addthesetwofirstlines:

blog/urls.py

fromdjango.conf.urlsimporturl

from.importviews

Herewe'reimportingDjango'sfunctionurlandallofourviewsfromblogapplication(wedon'thaveanyyet,butwewillgettothatinaminute!)

Afterthat,wecanaddourfirstURLpattern:

blog/urls.py

urlpatterns=[

url(r'^$',views.post_list,name='post_list'),

]

Asyoucansee,we'renowassigningaviewcalledpost_listto ̂ $URL.Thisregularexpressionwillmatch ̂ (abeginning)followedby$(anend)-soonlyanemptystringwillmatch.That'scorrect,becauseinDjangoURLresolvers,'http://127.0.0.1:8000/'isnotapartoftheURL.ThispatternwilltellDjangothatviews.post_lististherightplacetogoifsomeoneentersyourwebsiteatthe'http://127.0.0.1:8000/'address.

Thelastpartname='post_list'isthenameoftheURLthatwillbeusedtoidentifytheview.Thiscanbethesameasthenameoftheviewbutitcanalsobesomethingcompletelydifferent.WewillbeusingthenamedURLslaterintheprojectsoitisimportanttonameeachURLintheapp.WeshouldalsotrytokeepthenamesofURLsuniqueandeasytoremember.

Ifyoutrytovisithttp://127.0.0.1:8000/now,thenyou'llfindsomesortof'webpagenotavailable'message.Thisisbecausetheserver(remembertypingrunserver?)isnolongerrunning.Takealookatyourserverconsolewindowtofindoutwhy.

Yourconsoleisshowinganerrorbutdon'tworry—they'reactuallyprettyuseful:

It'stellingyouthatthereisnoattribute'post_list'.That'sthenameoftheviewthatDjangoistryingtofindanduse,butwehaven'tcreatedityet.Atthisstageyour/admin/willalsonotwork.Noworries,wewillgetthere.

IfyouwanttoknowmoreaboutDjangoURLconfs,lookattheofficialdocumentation:https://docs.djangoproject.com/en/1.9/topics/http/urls/

Djangourls

75

Djangoviews-timetocreate!Timetogetridofthebugwecreatedinthelastchapter:)

Aviewisaplacewhereweputthe"logic"ofourapplication.Itwillrequestinformationfromthemodelyoucreatedbeforeandpassittoatemplate.We'llcreateatemplateinthenextchapter.ViewsarejustPythonfunctionsthatarealittlebitmorecomplicatedthantheoneswewroteintheIntroductiontoPythonchapter.

Viewsareplacedintheviews.pyfile.Wewilladdourviewstotheblog/views.pyfile.

blog/views.pyOK,let'sopenupthisfileandseewhat'sinthere:

blog/views.py

fromdjango.shortcutsimportrender

#Createyourviewshere.

Nottoomuchstuffhereyet.

Rememberthatlinesstartingwith#arecommentsandthoselineswon'tberunbyPython.

Thesimplestviewcanlooklikethis.

blog/views.py

defpost_list(request):

returnrender(request,'blog/post_list.html',{})

Asyoucansee,wecreatedafunction(def)calledpost_listthattakesrequestandreturnafunctionrenderthatwillrender(puttogether)ourtemplateblog/post_list.html.

Savethefile,gotohttp://127.0.0.1:8000/andseewhatwehavegot.

Anothererror!Readwhat'sgoingonnow:

Thisshowsthattheserverisrunningagain,atleast,butitstilldoesn'tlookright,doesit?Don'tworry,it'sjustanerrorpage,nothingtobescaredof!Justliketheerrormessagesintheconsole,theseareactuallyprettyuseful.YoucanreadthattheTemplateDoesNotExist.Let'sfixthisbugandcreateatemplateinthenextchapter!

Djangoviews-timetocreate!

76

LearnmoreaboutDjangoviewsbyreadingtheofficialdocumentation:https://docs.djangoproject.com/en/1.9/topics/http/views/

Djangoviews-timetocreate!

77

IntroductiontoHTMLWhat'satemplate,youmayask?

Atemplateisafilethatwecanre-usetopresentdifferentinformationinaconsistentformat-forexample,youcoulduseatemplatetohelpyouwritealetter,becausealthougheachlettermightcontainadifferentmessageandbeaddressedtoadifferentperson,theywillsharethesameformat.

ADjangotemplate'sformatisdescribedinalanguagecalledHTML(that'stheHTMLwementionedinthefirstchapterHowtheInternetworks).

WhatisHTML?HTMLisasimplecodethatisinterpretedbyyourwebbrowser-suchasChrome,FirefoxorSafari-todisplayawebpagefortheuser.

HTMLstandsfor"HyperTextMarkupLanguage".HyperTextmeansit'satypeoftextthatsupportshyperlinksbetweenpages.Markupmeanswehavetakenadocumentandmarkeditupwithcodetotellsomething(inthiscase,abrowser)howtointerpretthepage.HTMLcodeisbuiltwithtags,eachonestartingwith<andendingwith>.Thesetagsrepresentmarkupelements.

Yourfirsttemplate!Creatingatemplatemeanscreatingatemplatefile.Everythingisafile,right?Youhaveprobablynoticedthisalready.

Templatesaresavedinblog/templates/blogdirectory.Sofirstcreateadirectorycalledtemplatesinsideyourblogdirectory.Thencreateanotherdirectorycalledbloginsideyourtemplatesdirectory:

blog

└───templates

└───blog

(Youmightwonderwhyweneedtwodirectoriesbothcalledblog-asyouwilldiscoverlater,thisissimplyausefulnamingconventionthatmakeslifeeasierwhenthingsstarttogetmorecomplicated.)

Andnowcreateapost_list.htmlfile(justleaveitblankfornow)insidetheblog/templates/blogdirectory.

Seehowyourwebsitelooksnow:http://127.0.0.1:8000/

IfyoustillhaveanerrorTemplateDoesNotExist,trytorestartyourserver.Gointocommandline,stoptheserverbypressingCtrl+C(ControlandCbuttonstogether)andstartitagainbyrunningapythonmanage.pyrunservercommand.

IntroductiontoHTML

78

Noerroranymore!Congratulations:)However,yourwebsiteisn'tactuallypublishinganythingexceptanemptypage,becauseyourtemplateisemptytoo.Weneedtofixthat.

Addthefollowingtoyourtemplatefile:

blog/templates/blog/post_list.html

<html>

<p>Hithere!</p>

<p>Itworks!</p>

</html>

Sohowdoesyourwebsitelooknow?Clicktofindout:http://127.0.0.1:8000/

Itworked!Niceworkthere:)

Themostbasictag,<html>,isalwaysthebeginningofanywebpageand</html>isalwaystheend.Asyoucansee,thewholecontentofthewebsitegoesbetweenthebeginningtag<html>andclosingtag</html><p>isatagforparagraphelements;</p>closeseachparagraph

Head&bodyEachHTMLpageisalsodividedintotwoelements:headandbody.

headisanelementthatcontainsinformationaboutthedocumentthatisnotdisplayedonthescreen.

bodyisanelementthatcontainseverythingelsethatisdisplayedaspartofthewebpage.

Weuse<head>totellthebrowserabouttheconfigurationofthepage,and<body>totellitwhat'sactuallyonthepage.

Forexample,youcanputawebpagetitleelementinsidethe<head>,likethis:

blog/templates/blog/post_list.html

IntroductiontoHTML

79

<html>

<head>

<title>Ola'sblog</title>

</head>

<body>

<p>Hithere!</p>

<p>Itworks!</p>

</body>

</html>

Savethefileandrefreshyourpage.

Noticehowthebrowserhasunderstoodthat"Ola'sblog"isthetitleofyourpage?Ithasinterpreted<title>Ola'sblog</title>andplacedthetextinthetitlebarofyourbrowser(itwillalsobeusedforbookmarksandsoon).

Probablyyouhavealsonoticedthateachopeningtagismatchedbyaclosingtag,witha/,andthatelementsarenested(i.e.youcan'tcloseaparticulartaguntilalltheonesthatwereinsideithavebeenclosedtoo).

It'slikeputtingthingsintoboxes.Youhaveonebigbox,<html></html>;insideitthereis<body></body>,andthatcontainsstillsmallerboxes:<p></p>.

Youneedtofollowtheserulesofclosingtags,andofnestingelements-ifyoudon't,thebrowsermaynotbeabletointerpretthemproperlyandyourpagewilldisplayincorrectly.

CustomizeyourtemplateYoucannowhavealittlefunandtrytocustomizeyourtemplate!Hereareafewusefultagsforthat:

<h1>Aheading</h1>-foryourmostimportantheading<h2>Asub-heading</h2>foraheadingatthenextlevel<h3>Asub-sub-heading</h3>...andsoon,upto<h6><p>Aparagraphoftext</p>

<em>text</em>emphasizesyourtext<strong>text</strong>stronglyemphasizesyourtext<br/>goestoanotherline(youcan'tputanythinginsidebr)<ahref="https://djangogirls.org">link</a>createsalink<ul><li>firstitem</li><li>seconditem</li></ul>makesalist,justlikethisone!<div></div>definesasectionofthepage

Here'sanexampleofafulltemplate:

blog/templates/blog/post_list.html

IntroductiontoHTML

80

<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>

We'vecreatedthreedivsectionshere.

Thefirstdivelementcontainsthetitleofourblog-it'saheadingandalinkAnothertwodivelementscontainourblogpostswithapublisheddate,h2withaposttitlethatisclickableandtwops(paragraph)oftext,oneforthedateandoneforourblogpost.

Itgivesusthiseffect:

Yaaay!Butsofar,ourtemplateonlyeverdisplaysexactlythesameinformation-whereasearlierweweretalkingabouttemplatesasallowingustodisplaydifferentinformationinthesameformat.

IntroductiontoHTML

81

WhatwereallywanttodoisdisplayrealpostsaddedinourDjangoadmin-andthat'swherewe'regoingnext.

Onemorething:deploy!It'dbegoodtoseeallthisoutandliveontheInternet,right?Let'sdoanotherPythonAnywheredeploy:

Commit,andpushyourcodeuptoGithub

Firstoff,let'sseewhatfileshavechangedsincewelastdeployed(runthesecommandslocally,notonPythonAnywhere):

command-line

$gitstatus

Makesureyou'reinthedjangogirlsdirectoryandlet'stellgittoincludeallthechangeswithinthisdirectory:

command-line

$gitadd--all.

--allmeansthatgitwillalsorecognizeifyou'vedeletedfiles(bydefault,itonlyrecognizesnew/modifiedfiles).Alsoremember(fromchapter3)that.meansthecurrentdirectory.

Beforeweuploadallthefiles,let'scheckwhatgitwillbeuploading(allthefilesthatgitwilluploadshouldnowappearingreen):

command-line

$gitstatus

We'realmostthere,nowit'stimetotellittosavethischangeinitshistory.We'regoingtogiveita"commitmessage"wherewedescribewhatwe'vechanged.Youcantypeanythingyou'dlikeatthisstage,butit'shelpfultotypesomethingdescriptivesothatyoucanrememberwhatyou'vedoneinthefuture.

command-line

$gitcommit-m"ChangedtheHTMLforthesite."

Makesureyouusedoublequotesaroundthecommitmessage.

Oncewe'vedonethat,weupload(push)ourchangesuptoGithub:

command-line

$gitpush

PullyournewcodedowntoPythonAnywhere,andreloadyourwebapp

OpenupthePythonAnywhereconsolespageandgotoyourBashconsole(orstartanewone).Then,run:

command-line

$cd~/my-first-blog

$gitpull

[...]

IntroductiontoHTML

82

Andwatchyourcodegetdownloaded.Ifyouwanttocheckthatit'sarrived,youcanhopovertotheFilestabandviewyourcodeonPythonAnywhere.

Finally,hoponovertotheWebtabandhitReloadonyourwebapp.

Yourupdateshouldbelive!Goaheadandrefreshyourwebsiteinthebrowser.Changesshouldbevisible:)

IntroductiontoHTML

83

DjangoORMandQuerySetsInthischapteryou'lllearnhowDjangoconnectstothedatabaseandstoresdatainit.Let'sdivein!

WhatisaQuerySet?AQuerySetis,inessence,alistofobjectsofagivenModel.QuerySetallowsyoutoreadthedatafromthedatabase,filteritandorderit.

It'seasiesttolearnbyexample.Let'strythis,shallwe?

DjangoshellOpenupyourlocalconsole(notonPythonAnywhere)andtypethiscommand:

command-line

(myvenv)~/djangogirls$pythonmanage.pyshell

Theeffectshouldbelikethis:

command-line

(InteractiveConsole)

>>>

You'renowinDjango'sinteractiveconsole.It'sjustlikePythonpromptbutwithsomeadditionalDjangomagic:).YoucanuseallthePythoncommandsheretoo,ofcourse.

AllobjectsLet'strytodisplayallofourpostsfirst.Youcandothatwiththefollowingcommand:

command-line

>>>Post.objects.all()

Traceback(mostrecentcalllast):

File"<console>",line1,in<module>

NameError:name'Post'isnotdefined

Oops!Anerrorshowedup.IttellsusthatthereisnoPost.It'scorrect--weforgottoimportitfirst!

command-line

>>>fromblog.modelsimportPost

Thisissimple:weimportmodelPostfromblog.models.Let'strydisplayingallpostsagain:

command-line

>>>Post.objects.all()

[<Post:myposttitle>,<Post:anotherposttitle>]

DjangoORM(Querysets)

84

It'salistofthepostswecreatedearlier!WecreatedthesepostsusingtheDjangoadmininterface.But,nowwewanttocreatenewpostsusingPython,sohowdowedothat?

Createobject

ThisishowyoucreateanewPostobjectindatabase:

command-line

>>>Post.objects.create(author=me,title='Sampletitle',text='Test')

Butwehaveonemissingingredienthere:me.WeneedtopassaninstanceofUsermodelasanauthor.Howtodothat?

Let'simportUsermodelfirst:

command-line

>>>fromdjango.contrib.auth.modelsimportUser

Whatusersdowehaveinourdatabase?Trythis:

command-line

>>>User.objects.all()

[<User:ola>]

It'sthesuperuserwecreatedearlier!Let'sgetaninstanceoftheusernow:

command-line

me=User.objects.get(username='ola')

Asyoucansee,wenowgetaUserwithausernamethatequalsto'ola'.Neat!Ofcourse,youhavetoadjustittoyourusername.

Nowwecanfinallycreateourpost:

command-line

>>>Post.objects.create(author=me,title='Sampletitle',text='Test')

Hurray!Wannacheckifitworked?

command-line

>>>Post.objects.all()

[<Post:myposttitle>,<Post:anotherposttitle>,<Post:Sampletitle>]

Thereitis,onemorepostinthelist!

Addmoreposts

Youcannowhavealittlefunandaddmorepoststoseehowitworks.Add2-3moreandgoaheadtothenextpart.

Filterobjects

DjangoORM(Querysets)

85

AbigpartofQuerySetsisanabilitytofilterthem.Let'ssay,wewanttofindallpostsUserolaauthored.WewillusefilterinsteadofallinPost.objects.all().Inparentheseswewillstatewhatcondition(s)ablogpostneedstomeettoendupinourqueryset.Inoursituationitisauthorthatisequaltome.ThewaytowriteitinDjangois:author=me.Nowourpieceofcodelookslikethis:

command-line

>>>Post.objects.filter(author=me)

[<Post:Sampletitle>,<Post:Postnumber2>,<Post:My3rdpost!>,<Post:4thtitleofpost>]

Ormaybewewanttoseeallthepoststhatcontainaword'title'inthetitlefield?

command-line

>>>Post.objects.filter(title__contains='title')

[<Post:Sampletitle>,<Post:4thtitleofpost>]

Therearetwounderscorecharacters(_)betweentitleandcontains.Django'sORMusesthisruletoseparatefieldnames("title")andoperationsorfilters("contains").Ifyouonlyuseoneunderscore,you'llgetanerrorlike"FieldError:Cannotresolvekeywordtitle_contains".

Youcanalsogetalistofallpublishedposts.Wedoitbyfilteringallthepoststhathavepublished_datesetinthepast:

command-line

>>>fromdjango.utilsimporttimezone

>>>Post.objects.filter(published_date__lte=timezone.now())

[]

Unfortunately,thepostweaddedfromthePythonconsoleisnotpublishedyet.Wecanchangethat!Firstgetaninstanceofapostwewanttopublish:

command-line

>>>post=Post.objects.get(title="Sampletitle")

Andthenpublishitwithourpublishmethod!

command-line

>>>post.publish()

Nowtrytogetlistofpublishedpostsagain(presstheuparrowbutton3timesandhitenter):

command-line

>>>Post.objects.filter(published_date__lte=timezone.now())

[<Post:Sampletitle>]

Orderingobjects

QuerySetsalsoallowyoutoorderthelistofobjects.Let'strytoorderthembycreated_datefield:

command-line

>>>Post.objects.order_by('created_date')

[<Post:Sampletitle>,<Post:Postnumber2>,<Post:My3rdpost!>,<Post:4thtitleofpost>]

DjangoORM(Querysets)

86

Wecanalsoreversetheorderingbyadding-atthebeginning:

command-line

>>>Post.objects.order_by('-created_date')

[<Post:4thtitleofpost>,<Post:My3rdpost!>,<Post:Postnumber2>,<Post:Sampletitle>]

ChainingQuerySets

YoucanalsocombineQuerySetsbychainingthemtogether:

>>>Post.objects.filter(published_date__lte=timezone.now()).order_by('published_date')

Thisisreallypowerfulandletsyouwritequitecomplexqueries.

Cool!You'renowreadyforthenextpart!Toclosetheshell,typethis:

command-line

>>>exit()

$

DjangoORM(Querysets)

87

DynamicdataintemplatesWehavedifferentpiecesinplace:thePostmodelisdefinedinmodels.py,wehavepost_listinviews.pyandthetemplateadded.ButhowwillweactuallymakeourpostsappearinourHTMLtemplate?Becausethatiswhatwewanttodo.Takesomecontent(modelssavedinthedatabase)anddisplayitnicelyinourtemplate,right?

Thisisexactlywhatviewsaresupposedtodo:connectmodelsandtemplates.Inourpost_listviewwewillneedtotakemodelswewanttodisplayandpassthemtothetemplate.Inaviewwedecidewhat(model)willbedisplayedinatemplate.

OK,sohowwillweachieveit?

Weneedtoopenourblog/views.py.Sofarpost_listviewlookslikethis:

blog/views.py

fromdjango.shortcutsimportrender

defpost_list(request):

returnrender(request,'blog/post_list.html',{})

Rememberwhenwetalkedaboutincludingcodewrittenindifferentfiles?Nowitisthemomentwhenwehavetoincludethemodelwehavewritteninmodels.py.Wewilladdthislinefrom.modelsimportPostlikethis:

blog/views.py

fromdjango.shortcutsimportrender

from.modelsimportPost

Thedotbeforemodelsmeanscurrentdirectoryorcurrentapplication.Bothviews.pyandmodels.pyareinthesamedirectory.Thismeanswecanuse.andthenameofthefile(without.py).Thenweimportthenameofthemodel(Post).

Butwhat'snext?TotakeactualblogpostsfromPostmodelweneedsomethingcalledQuerySet.

QuerySetYoushouldalreadybefamiliarwithhowQuerySetswork.WetalkedaboutitinDjangoORM(QuerySets)chapter.

Sonowwewantpublishedblogpostssortedbypublished_date,right?WealreadydidthatinQuerySetschapter!

blog/views.py

Post.objects.filter(published_date__lte=timezone.now()).order_by('published_date')

Nowweputthispieceofcodeinsidetheblog/views.pyfilebyaddingittothefunctiondefpost_list(request):

blog/views.py

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',{})

Dynamicdataintemplates

88

PleasenotethatwecreateavariableforourQuerySet:posts.TreatthisasthenameofourQuerySet.Fromnowonwecanrefertoitbythisname.

Also,thecodeusesthetimezone.now()function,soweneedtoaddanimportfortimezone.

ThelastmissingpartispassingthepostsQuerySettothetemplate.Don'tworrywewillcoverhowtodisplayitinanextchapter.

Intherenderfunctionwealreadyhaveparameterwithrequest(soeverythingwereceivefromtheuserviatheInternet)andatemplatefile'blog/post_list.html'.Thelastparameter,whichlookslikethis:{}isaplaceinwhichwecanaddsomethingsforthetemplatetouse.Weneedtogivethemnames(wewillstickto'posts'rightnow:)).Itshouldlooklikethis:{'posts':posts}.Pleasenotethatthepartbefore:isastring;youneedtowrapitwithquotes''.

Sofinallyourblog/views.pyfileshouldlooklikethis:

blog/views.py

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})

That'sit!TimetogobacktoourtemplateanddisplaythisQuerySet!

WanttoreadalittlebitmoreaboutQuerySetsinDjango?Youshouldlookhere:https://docs.djangoproject.com/en/1.9/ref/models/querysets/

Dynamicdataintemplates

89

DjangotemplatesTimetodisplaysomedata!Djangogivesussomehelpfulbuilt-intemplatetagsforthat.

Whataretemplatetags?Yousee,inHTML,youcan'treallywritePythoncode,becausebrowsersdon'tunderstandit.TheyonlyknowHTML.WeknowthatHTMLisratherstatic,whilePythonismuchmoredynamic.

DjangotemplatetagsallowustotransferPython-likethingsintoHTML,soyoucanbuilddynamicwebsitesfasterandeasier.Yikes!

DisplaypostlisttemplateInthepreviouschapterwegaveourtemplatealistofpostsinthepostsvariable.NowwewilldisplayitinHTML.

ToprintavariableinDjangotemplates,weusedoublecurlybracketswiththevariable'snameinside,likethis:

blog/templates/blog/post_list.html

{{posts}}

Trythisinyourblog/templates/blog/post_list.htmltemplate.Replaceeverythingfromthesecond<div>tothethird</div>with{{posts}}.Savethefile,andrefreshthepagetoseetheresults:

Asyoucansee,allwe'vegotisthis:

blog/templates/blog/post_list.html

[<Post:Mysecondpost>,<Post:Myfirstpost>]

ThismeansthatDjangounderstandsitasalistofobjects.RememberfromIntroductiontoPythonhowwecandisplaylists?Yes,withforloops!InaDjangotemplateyoudothemlikethis:

blog/templates/blog/post_list.html

{%forpostinposts%}

{{post}}

{%endfor%}

Trythisinyourtemplate.

Djangotemplates

90

Itworks!ButwewantthemtobedisplayedlikethestaticpostswecreatedearlierintheIntroductiontoHTMLchapter.YoucanmixHTMLandtemplatetags.Ourbodywilllooklikethis:

blog/templates/blog/post_list.html

<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%}

Everythingyouputbetween{%for%}and{%endfor%}willberepeatedforeachobjectinthelist.Refreshyourpage:

Haveyounoticedthatweusedaslightlydifferentnotationthistime{{post.title}}or{{post.text}}?WeareaccessingdataineachofthefieldsdefinedinourPostmodel.Alsothe|linebreaksbrispipingtheposts'textthroughafiltertoconvertline-breaksintoparagraphs.

Djangotemplates

91

OnemorethingIt'dbegoodtoseeifyourwebsitewillstillbeworkingonthepublicInternet,right?Let'strydeployingtoPythonAnywhereagain.Here'sarecapofthesteps...

First,pushyourcodetoGithub

command-line

$gitstatus

[...]

$gitadd--all.

$gitstatus

[...]

$gitcommit-m"Modifiedtemplatestodisplaypostsfromdatabase."

[...]

$gitpush

Then,logbackintoPythonAnywhereandgotoyourBashconsole(orstartanewone),andrun:

command-line

$cdmy-first-blog

$gitpull

[...]

Finally,hoponovertotheWebtabandhitReloadonyourwebapp.Yourupdateshouldbelive!IftheblogpostsonyourPythonAnywheresitedon'tmatchthepostsappearingonthebloghostedonyourlocalserver-that'sOK.ThedatabasesonyourlocalcomputerandPythonAnywheredon'tsyncwiththerestofyourfiles.

Congrats!NowgoaheadandtryaddinganewpostinyourDjangoadmin(remembertoaddpublished_date!)MakesureyouareintheDjangoadminforyourpythonanywheresite,https://yourname.pythonanywhere.com/admin.Thenrefreshyourpagetoseeifthepostappearsthere.

Workslikeacharm?We'reproud!Stepawayfromyourcomputerforabit,youhaveearnedabreak.:)

Djangotemplates

92

CSS-makeitpretty!Ourblogstilllooksprettyugly,right?Timetomakeitnice!WewilluseCSSforthat.

WhatisCSS?CascadingStyleSheets(CSS)isalanguageusedfordescribingthelookandformattingofawebsitewritteninmarkuplanguage(likeHTML).Treatitasmake-upforourwebpage;).

Butwedon'twanttostartfromscratchagain,right?Oncemore,we'llusesomethingthatprogrammersreleasedontheInternetforfree.Youknow,reinventingthewheelisnofun.

Let'suseBootstrap!BootstrapisoneofthemostpopularHTMLandCSSframeworksfordevelopingbeautifulwebsites:https://getbootstrap.com/

ItwaswrittenbyprogrammerswhoworkedforTwitter.Nowit'sdevelopedbyvolunteersfromallovertheworld!

InstallBootstrapToinstallBootstrap,youneedtoaddthistoyour<head>inyour.htmlfile:

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">

Thisdoesn'taddanyfilestoyourproject.Itjustpointstofilesthatexistontheinternet.Justgoahead,openyourwebsiteandrefreshthepage.Hereitis!

Lookingniceralready!

StaticfilesinDjango

CSS-makeitpretty

93

Finallywewilltakeacloserlookatthesethingswe'vebeencallingstaticfiles.StaticfilesareallyourCSSandimages.Theircontentdoesn'tdependontherequestcontextandwillbethesameforeveryuser.

WheretoputstaticfilesforDjango

Djangoalreadyknowswheretofindthestaticfilesforthebuilt-in"admin"app.Nowwejustneedtoaddsomestaticfilesforourownapp,blog.

Wedothatbycreatingafoldercalledstaticinsidetheblogapp:

djangogirls

├──blog

│├──migrations

│└──static

└──mysite

Djangowillautomaticallyfindanyfolderscalled"static"insideanyofyourapps'folders.Then,itwillbeabletousetheircontentsasstaticfiles.

YourfirstCSSfile!Let'screateaCSSfilenow,toaddyourownstyletoyourweb-page.Createanewdirectorycalledcssinsideyourstaticdirectory.Thencreateanewfilecalledblog.cssinsidethiscssdirectory.Ready?

djangogirls

└───blog

└───static

└───css

└───blog.css

TimetowritesomeCSS!Openuptheblog/static/css/blog.cssfileinyourcodeeditor.

Wewon'tbegoingtoodeepintocustomizingandlearningaboutCSShere.It'sprettyeasyandyoucanlearnitonyourownafterthisworkshop.Thereisarecommendationforafreecoursetolearnmoreattheendofthispage.

Butlet'sdoatleastalittle.Maybewecouldchangethecolorofourheader?Tounderstandcolors,computersusespecialcodes.Thesecodesstartwith#followedby6letters(A-F)andnumbers(0-9).Forexample,thecodeforblueis#0000FF.Youcanfindthecolorcodesformanycolorshere:http://www.colorpicker.com/.Youmayalsousepredefinedcolors,suchasredandgreen.

Inyourblog/static/css/blog.cssfileyoushouldaddthefollowingcode:

blog/static/css/blog.css

h1a{

color:#FCA205;

}

h1aisaCSSSelector.Thismeanswe'reapplyingourstylestoanyaelementinsideofanh1element.Sowhenwehavesomethinglike:<h1><ahref="">link</a></h1>theh1astylewillapply.Inthiscase,we'retellingittochangeitscolorto#FCA205,whichisorange.Ofcourse,youcanputyourowncolorhere!

InaCSSfilewedeterminestylesforelementsintheHTMLfile.Thefirstwayweidentifyelementsiswiththeelementname.YoumightremembertheseastagsfromtheHTMLsection.Thingslikea,h1,andbodyareallexamplesofelementnames.Wealsoidentifyelementsbytheattributeclassortheattributeid.Classandidarenamesyougivetheelementbyyourself.Classesdefinegroupsofelements,andidspointtospecificelements.Forexample,youcouldidentifythefollowingtagbyusingthetagnamea,theclassexternal_link,ortheidlink_to_wiki_page:

CSS-makeitpretty

94

<ahref="https://en.wikipedia.org/wiki/Django"class="external_link"id="link_to_wiki_page">

ReadaboutCSSSelectorsinw3schools.

Then,weneedtoalsotellourHTMLtemplatethatweaddedsomeCSS.Opentheblog/templates/blog/post_list.htmlfileandaddthislineattheverybeginningofit:

blog/templates/blog/post_list.html

{%loadstaticfiles%}

We'rejustloadingstaticfileshere:).Betweenthe<head>and</head>,afterthelinkstotheBootstrapCSSfilesaddthisline:

blog/templates/blog/post_list.html

<linkrel="stylesheet"href="{%static'css/blog.css'%}">

Thebrowserreadsthefilesintheorderthey'regiven,soweneedtomakesurethisisintherightplace.OtherwisethecodeinourfilemayoverridecodeinBootstrapfiles.WejusttoldourtemplatewhereourCSSfileislocated.

Yourfileshouldnowlooklikethis:

blog/templates/blog/post_list.html

{%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,savethefileandrefreshthesite!

CSS-makeitpretty

95

Nicework!Maybewewouldalsoliketogiveourwebsitealittleairandincreasethemarginontheleftside?Let'strythis!

blog/static/css/blog.css

body{

padding-left:15px;

}

AddthistoyourCSS,savethefileandseehowitworks!

Maybewecancustomizethefontinourheader?Pastethisintoyour<head>inblog/templates/blog/post_list.htmlfile:

blog/templates/blog/post_list.html

<linkhref="//fonts.googleapis.com/css?family=Lobster&subset=latin,latin-ext"rel="stylesheet"type="text/css">

Asbefore,checktheorderandplacebeforethelinktoblog/static/css/blog.css.ThislinewillimportafontcalledLobsterfromGoogleFonts(https://www.google.com/fonts).

Findtheh1adeclarationblock(thecodebetweenbraces{and})intheCSSfileblog/static/css/blog.css.Nowaddthelinefont-family:'Lobster';betweenthebraces,andrefreshthepage:

blog/static/css/blog.css

CSS-makeitpretty

96

h1a{

color:#FCA205;

font-family:'Lobster';

}

Great!

Asmentionedabove,CSShasaconceptofclasses.TheseallowyoutonameapartoftheHTMLcodeandapplystylesonlytothispart,withoutaffectingotherparts.Thiscanbesuperhelpful!Maybeyouhavetwodivsthataredoingsomethingdifferent(likeyourheaderandyourpost).Aclasscanhelpyoumakethemlookdifferent.

GoaheadandnamesomepartsoftheHTMLcode.Addaclasscalledpage-headertoyourdivthatcontainsyourheader,likethis:

blog/templates/blog/post_list.html

<divclass="page-header">

<h1><ahref="/">DjangoGirlsBlog</a></h1>

</div>

Andnowaddaclassposttoyourdivcontainingablogpost.

blog/templates/blog/post_list.html

<divclass="post">

<p>published:{{post.published_date}}</p>

<h1><ahref="">{{post.title}}</a></h1>

<p>{{post.text|linebreaksbr}}</p>

</div>

Wewillnowadddeclarationblockstodifferentselectors.Selectorsstartingwith.relatetoclasses.TherearemanygreattutorialsandexplanationsaboutCSSontheWebtohelpyouunderstandthefollowingcode.Fornow,justcopyandpasteitintoyourblog/static/css/blog.cssfile:

blog/static/css/blog.css

CSS-makeitpretty

97

.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{

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;

}

ThensurroundtheHTMLcodewhichdisplaysthepostswithdeclarationsofclasses.Replacethis:

blog/templates/blog/post_list.html

{%forpostinposts%}

<divclass="post">

<p>published:{{post.published_date}}</p>

<h1><ahref="">{{post.title}}</a></h1>

<p>{{post.text|linebreaksbr}}</p>

</div>

{%endfor%}

intheblog/templates/blog/post_list.htmlwiththis:

blog/templates/blog/post_list.html

CSS-makeitpretty

98

<divclass="contentcontainer">

<divclass="row">

<divclass="col-md-8">

{%forpostinposts%}

<divclass="post">

<divclass="date">

<p>published:{{post.published_date}}</p>

</div>

<h1><ahref="">{{post.title}}</a></h1>

<p>{{post.text|linebreaksbr}}</p>

</div>

{%endfor%}

</div>

</div>

</div>

Savethosefilesandrefreshyourwebsite.

Woohoo!Looksawesome,right?LookatthecodewejustpastedtofindtheplaceswhereweaddedclassesintheHTMLandusedthemintheCSS.Wherewouldyoumakethechangeifyouwantedthedatetobeturquoise?

Don'tbeafraidtotinkerwiththisCSSalittlebitandtrytochangesomethings.PlayingwiththeCSScanhelpyouunderstandwhatthedifferentthingsaredoing.Ifyoubreaksomething,don'tworry,youcanalwaysundoit!

WereallyrecommendtakingthisfreeonlineCodeacademyHTML&CSScourse.ItcanhelpyoulearnallaboutmakingyourwebsitesprettierwithCSS.

Readyforthenextchapter?!:)

CSS-makeitpretty

99

TemplateextendingAnothernicethingDjangohasforyouistemplateextending.Whatdoesthismean?ItmeansthatyoucanusethesamepartsofyourHTMLfordifferentpagesofyourwebsite.

Templateshelpwhenyouwanttousethesameinformation/layoutinmorethanoneplace.Youdon'thavetorepeatyourselfineveryfile.Andifyouwanttochangesomething,youdon'thavetodoitineverytemplate,justonce!

CreatebasetemplateAbasetemplateisthemostbasictemplatethatyouextendoneverypageofyourwebsite.

Let'screateabase.htmlfileinblog/templates/blog/:

blog

└───templates

└───blog

base.html

post_list.html

Thenopenitupandcopyeverythingfrompost_list.htmltobase.htmlfile,likethis:

blog/templates/blog/base.html

{%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>

Theninbase.html,replaceyourwhole<body>(everythingbetween<body>and</body>)withthis:

blog/templates/blog/base.html

Templateextending

100

<body>

<divclass="page-header">

<h1><ahref="/">DjangoGirlsBlog</a></h1>

</div>

<divclass="contentcontainer">

<divclass="row">

<divclass="col-md-8">

{%blockcontent%}

{%endblock%}

</div>

</div>

</div>

</body>

Youmightnoticethisreplacedeverythingfrom{%forpostinposts%}to{%endfor%}with:

blog/templates/blog/base.html

{%blockcontent%}

{%endblock%}

Butwhy?Youjustcreatedablock!Youusedthetemplatetag{%block%}tomakeanareathatwillhaveHTMLinsertedinit.ThatHTMLwillcomefromanothertemplatesthatextendsthistemplate(base.html).Wewillshowyouhowtodothisinamoment.

Nowsavebase.html,andopenyourblog/templates/blog/post_list.htmlagain.You'regoingtoremoveeverythingabove{%forpostinposts%}andbelow{%endfor%}.Whenyou'redonethefilewilllooklikethis:

blog/templates/blog/post_list.html

{%forpostinposts%}

<divclass="post">

<divclass="date">

{{post.published_date}}

</div>

<h1><ahref="">{{post.title}}</a></h1>

<p>{{post.text|linebreaksbr}}</p>

</div>

{%endfor%}

Wewanttousethisaspartofourtemplateforallthecontentblocks.Timetoaddblocktagstothisfile!

Youwantyourblocktagtomatchthetaginyourbase.htmlfile.Youalsowantittoincludeallthecodethatbelongsinyourcontentblocks.Todothat,puteverythingbetween{%blockcontent%}and{%endblockcontent%}.Likethis:

blog/templates/blog/post_list.html

{%blockcontent%}

{%forpostinposts%}

<divclass="post">

<divclass="date">

{{post.published_date}}

</div>

<h1><ahref="">{{post.title}}</a></h1>

<p>{{post.text|linebreaksbr}}</p>

</div>

{%endfor%}

{%endblock%}

Onlyonethingleft.Weneedtoconnectthesetwotemplatestogether.Thisiswhatextendingtemplatesisallabout!We'lldothisbyaddinganextendstagtothebeginningofthefile.Likethis:

blog/templates/blog/post_list.html

Templateextending

101

{%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%}

{%endblock%}

That'sit!Checkifyourwebsiteisstillworkingproperly:)

IfyouhaveanerrorTemplateDoesNotExistthatsaysthatthereisnoblog/base.htmlfileandyouhaverunserverrunningintheconsole,trytostopit(bypressingCtrl+C-ControlandCbuttonstogether)andrestartitbyrunningapythonmanage.pyrunservercommand.

Templateextending

102

ExtendyourapplicationWe'vealreadycompletedallthedifferentstepsnecessaryforthecreationofourwebsite:weknowhowtowriteamodel,url,viewandtemplate.Wealsoknowhowtomakeourwebsitepretty.

Timetopractice!

Thefirstthingweneedinourblogis,obviously,apagetodisplayonepost,right?

WealreadyhaveaPostmodel,sowedon'tneedtoaddanythingtomodels.py.

Createatemplatelinktoapost'sdetailWewillstartwithaddingalinkinsideblog/templates/blog/post_list.htmlfile.Sofaritshouldlooklike:

blog/templates/blog/post_list.html

{%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%}

Wewanttohavealinkfromapost'stitleinthepostlisttothepost'sdetailpage.Let'schange<h1><ahref="">{{post.title}}</a></h1>sothatitlinkstothepost'sdetailpage:

blog/templates/blog/post_list.html

<h1><ahref="{%url'post_detail'pk=post.pk%}">{{post.title}}</a></h1>

Timetoexplainthemysterious{%url'post_detail'pk=post.pk%}.Asyoumightsuspect,the{%%}notationmeansthatweareusingDjangotemplatetags.ThistimewewilluseonethatwillcreateaURLforus!

blog.views.post_detailisapathtoapost_detailviewwewanttocreate.Pleasenote:blogisthenameofourapplication(thedirectoryblog),viewsisfromthenameoftheviews.pyfileandthelastbit-post_detail-isthenameoftheview.

Nowwhenwegoto:http://127.0.0.1:8000/wewillhaveanerror(asexpected,sincewedon'thaveaURLoraviewforpost_detail).Itwilllooklikethis:

Extendyourapplication

103

CreateaURLtoapost'sdetailLet'screateaURLinurls.pyforourpost_detailview!

Wewantourfirstpost'sdetailtobedisplayedatthisURL:http://127.0.0.1:8000/post/1/

Let'smakeaURLintheblog/urls.pyfiletopointDjangotoaviewnamedpost_detail,thatwillshowanentireblogpost.Addthelineurl(r'^post/(?P<pk>\d+)/$',views.post_detail,name='post_detail'),totheblog/urls.pyfile.Thefileshouldlooklikethis:

blog/urls.py

fromdjango.conf.urlsimporturl

from.importviews

urlpatterns=[

url(r'^$',views.post_list,name='post_list'),

url(r'^post/(?P<pk>\d+)/$',views.post_detail,name='post_detail'),

]

Thispart ̂ post/(?P<pk>\d+)/$looksscary,butnoworries-wewillexplainitforyou:

itstartswith ̂ again--"thebeginning"post/onlymeansthatafterthebeginning,theURLshouldcontainthewordpostand/.Sofarsogood.(?P<pk>\d+)-thispartistrickier.ItmeansthatDjangowilltakeeverythingthatyouplacehereandtransferittoaviewasavariablecalledpk.\dalsotellsusthatitcanonlybeadigit,notaletter(soeverythingbetween0and9).+meansthatthereneedstobeoneormoredigitsthere.Sosomethinglikehttp://127.0.0.1:8000/post//isnotvalid,buthttp://127.0.0.1:8000/post/1234567890/isperfectlyok!/-thenweneed/again$-"theend"!

Thatmeansifyouenterhttp://127.0.0.1:8000/post/5/intoyourbrowser,Djangowillunderstandthatyouarelookingforaviewcalledpost_detailandtransfertheinformationthatpkequals5tothatview.

pkisshortcutforprimarykey.ThisnameisoftenusedinDjangoprojects.Butyoucannameyourvariableasyoulike(remember:lowercaseand_insteadofwhitespaces!).Forexampleinsteadof(?P<pk>\d+)wecouldhavevariablepost_id,sothisbitwouldlooklike:(?P<post_id>\d+).

Ok,we'veaddedanewURLpatterntoblog/urls.py!Let'srefreshthepage:http://127.0.0.1:8000/Boom!Theserverhasstoppedrunningagain.Havealookattheconsole-asexpected,there'syetanothererror!

Extendyourapplication

104

Doyourememberwhatthenextstepis?Ofcourse:addingaview!

Addapost'sdetailviewThistimeourviewisgivenanextraparameterpk.Ourviewneedstocatchit,right?Sowewilldefineourfunctionasdefpost_detail(request,pk):.Notethatweneedtouseexactlythesamenameastheonewespecifiedinurls(pk).Omittingthisvariableisincorrectandwillresultinanerror!

Now,wewanttogetoneandonlyoneblogpost.Todothiswecanusequerysetslikethis:

blog/views.py

Post.objects.get(pk=pk)

Butthiscodehasaproblem.IfthereisnoPostwithgivenprimarykey(pk)wewillhaveasuperuglyerror!

Wedon'twantthat!But,ofcourse,Djangocomeswithsomethingthatwillhandlethatforus:get_object_or_404.IncasethereisnoPostwiththegivenpkitwilldisplaymuchnicerpage(calledPageNotFound404page).

Extendyourapplication

105

ThegoodnewsisthatyoucanactuallycreateyourownPagenotfoundpageandmakeitasprettyasyouwant.Butit'snotsuperimportantrightnow,sowewillskipit.

Ok,timetoaddaviewtoourviews.pyfile!

Weshouldopenblog/views.pyandaddthefollowingcode:

blog/views.py

fromdjango.shortcutsimportrender,get_object_or_404

Nearotherfromlines.Andattheendofthefilewewilladdourview:

blog/views.py

defpost_detail(request,pk):

post=get_object_or_404(Post,pk=pk)

returnrender(request,'blog/post_detail.html',{'post':post})

Yes.Itistimetorefreshthepage:http://127.0.0.1:8000/

Extendyourapplication

106

Itworked!Butwhathappenswhenyouclickalinkinblogposttitle?

Ohno!Anothererror!Butwealreadyknowhowtodealwithit,right?Weneedtoaddatemplate!

CreateatemplateforpostdetailWewillcreateafileinblog/templates/blogcalledpost_detail.html.

Itwilllooklikethis:

blog/templates/blog/post_detail.html

Extendyourapplication

107

{%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%}

Onceagainweareextendingbase.html.Inthecontentblockwewanttodisplayapost'spublished_date(ifitexists),titleandtext.Butweshoulddiscusssomeimportantthings,right?

{%if...%}...{%endif%}isatemplatetagwecanusewhenwewanttochecksomething(rememberif...else..fromIntroductiontoPythonchapter?).Inthisscenariowewanttocheckifapost'spublished_dateisnotempty.

Ok,wecanrefreshourpageandseeifTemplateDoesNotExistisgonenow.

Yay!Itworks!

Onemorething:deploytime!It'dbegoodtoseeifyourwebsitewillstillbeworkingonPythonAnywhere,right?Let'strydeployingagain.

command-line

Extendyourapplication

108

$gitstatus

$gitadd--all.

$gitstatus

$gitcommit-m"AddedviewandtemplatefordetailedblogpostaswellasCSSforthesite."

$gitpush

Then,inaPythonAnywhereBashconsole:

command-line

$cdmy-first-blog

$gitpull

[...]

Finally,hoponovertotheWebtabandhitReload.

Andthatshouldbeit!Congrats:)

Extendyourapplication

109

DjangoFormsThefinalthingwewanttodoonourwebsiteiscreateanicewaytoaddandeditblogposts.Django'sadminiscool,butitisratherhardtocustomizeandmakepretty.Withformswewillhaveabsolutepoweroverourinterface-wecandoalmostanythingwecanimagine!

ThenicethingaboutDjangoformsisthatwecaneitherdefineonefromscratchorcreateaModelFormwhichwillsavetheresultoftheformtothemodel.

Thisisexactlywhatwewanttodo:wewillcreateaformforourPostmodel.

LikeeveryimportantpartofDjango,formshavetheirownfile:forms.py.

Weneedtocreateafilewiththisnameintheblogdirectory.

blog

└──forms.py

Ok,let'sopenitandtypethefollowingcode:

blog/forms.py

fromdjangoimportforms

from.modelsimportPost

classPostForm(forms.ModelForm):

classMeta:

model=Post

fields=('title','text',)

WeneedtoimportDjangoformsfirst(fromdjangoimportforms)and,obviously,ourPostmodel(from.modelsimportPost).

PostForm,asyouprobablysuspect,isthenameofourform.WeneedtotellDjango,thatthisformisaModelForm(soDjangowilldosomemagicforus)-forms.ModelFormisresponsibleforthat.

Next,wehaveclassMeta,wherewetellDjangowhichmodelshouldbeusedtocreatethisform(model=Post).

Finally,wecansaywhichfield(s)shouldendupinourform.Inthisscenariowewantonlytitleandtexttobeexposed-authorshouldbethepersonwhoiscurrentlyloggedin(you!)andcreated_dateshouldbeautomaticallysetwhenwecreateapost(i.einthecode),right?

Andthat'sit!Allweneedtodonowisusetheforminaviewanddisplayitinatemplate.

Soonceagainwewillcreate:alinktothepage,aURL,aviewandatemplate.

LinktoapagewiththeformIt'stimetoopenblog/templates/blog/base.html.Wewilladdalinkindivnamedpage-header:

blog/templates/blog/base.html

<ahref="{%url'post_new'%}"class="top-menu"><spanclass="glyphiconglyphicon-plus"></span></a>

Notethatwewanttocallournewviewpost_new.Theclass"glyphiconglyphicon-plus"isprovidedbythebootstrapthemeweareusing,andwilldisplayaplussignforus.

DjangoForms

110

Afteraddingtheline,yourhtmlfileshouldnowlooklikethis:

blog/templates/blog/base.html

{%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'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>

Aftersavingandrefreshingthepagehttp://127.0.0.1:8000youwillobviouslyseeafamiliarNoReverseMatcherror,right?

URLWeopenblog/urls.pyandaddaline:

blog/urls.py

url(r'^post/new/$',views.post_new,name='post_new'),

Andthefinalcodewilllooklikethis:

blog/urls.py

fromdjango.conf.urlsimporturl

from.importviews

urlpatterns=[

url(r'^$',views.post_list,name='post_list'),

url(r'^post/(?P<pk>\d+)/$',views.post_detail,name='post_detail'),

url(r'^post/new/$',views.post_new,name='post_new'),

]

Afterrefreshingthesite,weseeanAttributeError,sincewedon'thavepost_newviewimplemented.Let'sadditrightnow.

post_newviewTimetoopentheblog/views.pyfileandaddthefollowinglineswiththerestofthefromrows:

blog/views.py

DjangoForms

111

from.formsimportPostForm

andourview:

blog/views.py

defpost_new(request):

form=PostForm()

returnrender(request,'blog/post_edit.html',{'form':form})

TocreateanewPostform,weneedtocallPostForm()andpassittothetemplate.Wewillgobacktothisview,butfornow,let'screatequicklyatemplatefortheform.

TemplateWeneedtocreateafilepost_edit.htmlintheblog/templates/blogdirectory.Tomakeaformworkweneedseveralthings:

wehavetodisplaytheform.Wecandothatforexamplewithasimple{%raw%}{{form.as_p}}{%endraw%}.thelineaboveneedstobewrappedwithanHTMLformtag:<formmethod="POST">...</form>weneedaSavebutton.WedothatwithanHTMLbutton:<buttontype="submit">Save</button>andfinallyjustaftertheopening<form...>tagweneedtoadd{%raw%}{%csrf_token%}{%endraw%}.Thisisveryimportant,sinceitmakesyourformssecure!Djangowillcomplainifyouforgetaboutthisbitifyoutrytosavetheform:

Ok,solet'sseehowtheHTMLinpost_edit.htmlshouldlook:

blog/templates/blog/post_edit.html

{%extends'blog/base.html'%}

{%blockcontent%}

<h1>Newpost</h1>

<formmethod="POST"class="post-form">{%csrf_token%}

{{form.as_p}}

<buttontype="submit"class="savebtnbtn-default">Save</button>

</form>

{%endblock%}

Timetorefresh!Yay!Yourformisdisplayed!

DjangoForms

112

But,waitaminute!Whenyoutypesomethingintitleandtextfieldsandtrytosaveit-whatwillhappen?

Nothing!Weareonceagainonthesamepageandourtextisgone...andnonewpostisadded.Sowhatwentwrong?

Theansweris:nothing.Weneedtodoalittlebitmoreworkinourview.

SavingtheformOpenblog/views.pyonceagain.Currentlyallwehaveinthepost_newviewis:

blog/views.py

defpost_new(request):

form=PostForm()

returnrender(request,'blog/post_edit.html',{'form':form})

Whenwesubmittheform,wearebroughtbacktothesameview,butthistimewehavesomemoredatainrequest,morespecificallyinrequest.POST(thenaminghasnothingtodowithablog"post",it'stodowiththefactthatwe're"posting"data).RememberthatintheHTMLfileour<form>definitionhadthevariablemethod="POST"?Allthefieldsfromtheformarenowinrequest.POST.YoushouldnotrenamePOSTtoanythingelse(theonlyothervalidvalueformethodisGET,butwehavenotimetoexplainwhatthedifferenceis).

Soinourviewwehavetwoseparatesituationstohandle.First:whenweaccessthepageforthefirsttimeandwewantablankform.Second:whenwegobacktotheviewwithallform'sdatawejusttyped.Soweneedtoaddacondition(wewilluseifforthat).

blog/views.py

DjangoForms

113

ifrequest.method=="POST":

[...]

else:

form=PostForm()

It'stimetofillinthedots[...].IfmethodisPOSTthenwewanttoconstructthePostFormwithdatafromtheform,right?Wewilldothatwith:

blog/views.py

form=PostForm(request.POST)

Easy!Nextthingistocheckiftheformiscorrect(allrequiredfieldsaresetandnoincorrectvalueswillbesaved).Wedothatwithform.is_valid().

Wecheckiftheformisvalidandifso,wecansaveit!

blog/views.py

ifform.is_valid():

post=form.save(commit=False)

post.author=request.user

post.published_date=timezone.now()

post.save()

Basically,wehavetwothingshere:wesavetheformwithform.saveandweaddanauthor(sincetherewasnoauthorfieldinthePostFormandthisfieldisrequired!).commit=Falsemeansthatwedon'twanttosavePostmodelyet-wewanttoaddauthorfirst.Mostofthetimeyouwilluseform.save(),withoutcommit=False,butinthiscase,weneedtodothat.post.save()willpreservechanges(addingauthor)andanewblogpostiscreated!

Finally,itwouldbeawesomeifwecanimmediatelygotopost_detailpagefornewlycreatedblogpost,right?Todothatweneedonemoreimport:

blog/views.py

fromdjango.shortcutsimportredirect

Additattheverybeginningofyourfile.Andnowwecansay:gotopost_detailpageforanewlycreatedpost.

blog/views.py

returnredirect('post_detail',pk=post.pk)

post_detailisthenameoftheviewwewanttogoto.Rememberthatthisviewrequiresapkvariable?Topassittotheviewsweusepk=post.pk,wherepostisthenewlycreatedblogpost!

Ok,wetalkedalot,butweprobablywanttoseewhatthewholeviewlookslikenow,right?

blog/views.py

DjangoForms

114

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('post_detail',pk=post.pk)

else:

form=PostForm()

returnrender(request,'blog/post_edit.html',{'form':form})

Let'sseeifitworks.Gotothepagehttp://127.0.0.1:8000/post/new/,addatitleandtext,saveit...andvoilà!Thenewblogpostisaddedandweareredirectedtopost_detailpage!

Youmighthavenoticedthatwearesettingpublishdatebeforesavingthepost.Lateron,wewillintroduceapublishbuttoninDjangoGirlsTutorial:Extensions.

Thatisawesome!

AswehaverecentlyusedtheDjangoadmininterfacethesystemcurrentlythinksweareloggedin.Thereareafewsituationsthatcouldleadtousbeingloggedout(closingthebrowser,restartingtheDBetc.).Ifyoufindthatyouaregettingerrorscreatingapostreferringtoalackofaloggedinuser,headtotheadminpagehttp://127.0.0.1:8000/adminandloginagain.Thiswillfixtheissuetemporarily.ThereisapermanentfixawaitingyouintheHomework:addsecuritytoyourwebsite!chapterafterthemaintutorial.

FormvalidationNow,wewillshowyouhowcoolDjangoformsare.Ablogpostneedstohavetitleandtextfields.InourPostmodelwedidnotsay(asopposedtopublished_date)thatthesefieldsarenotrequired,soDjango,bydefault,expectsthemtobeset.

Trytosavetheformwithouttitleandtext.Guess,whatwillhappen!

DjangoForms

115

Djangoistakingcareofvalidatingthatallthefieldsinourformarecorrect.Isn'titawesome?

EditformNowweknowhowtoaddanewform.Butwhatifwewanttoeditanexistingone?Itisverysimilartowhatwejustdid.Let'screatesomeimportantthingsquickly(ifyoudon'tunderstandsomething,youshouldaskyourcoachorlookatthepreviouschapters,sincewecoveredallthesestepsalready).

Openblog/templates/blog/post_detail.htmlandaddthisline:

blog/templates/blog/post_detail.html

<aclass="btnbtn-default"href="{%url'post_edit'pk=post.pk%}"><spanclass="glyphiconglyphicon-pencil"></span></a

>

sothatthetemplatewilllooklike:

blog/templates/blog/post_detail.html

DjangoForms

116

{%extends'blog/base.html'%}

{%blockcontent%}

<divclass="post">

{%ifpost.published_date%}

<divclass="date">

{{post.published_date}}

</div>

{%endif%}

<aclass="btnbtn-default"href="{%url'post_edit'pk=post.pk%}"><spanclass="glyphiconglyphicon-pencil"></

span></a>

<h1>{{post.title}}</h1>

<p>{{post.text|linebreaksbr}}</p>

</div>

{%endblock%}

Inblog/urls.pyweaddthisline:

blog/urls.py

url(r'^post/(?P<pk>\d+)/edit/$',views.post_edit,name='post_edit'),

Wewillreusethetemplateblog/templates/blog/post_edit.html,sothelastmissingthingisaview.

Let'sopenablog/views.pyandaddattheveryendofthefile:

blog/views.py

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('post_detail',pk=post.pk)

else:

form=PostForm(instance=post)

returnrender(request,'blog/post_edit.html',{'form':form})

Thislooksalmostexactlythesameasourpost_newview,right?Butnotentirely.Firstthing:wepassanextrapkparameterfromurls.Next:wegetthePostmodelwewanttoeditwithget_object_or_404(Post,pk=pk)andthen,whenwecreateaformwepassthispostasaninstancebothwhenwesavetheform:

blog/views.py

form=PostForm(request.POST,instance=post)

andwhenwejustopenedaformwiththisposttoedit:

blog/views.py

form=PostForm(instance=post)

Ok,let'stestifitworks!Let'sgotopost_detailpage.Thereshouldbeaneditbuttoninthetop-rightcorner:

DjangoForms

117

Whenyouclickityouwillseetheformwithourblogpost:

Feelfreetochangethetitleorthetextandsavechanges!

Congratulations!Yourapplicationisgettingmoreandmorecomplete!

IfyouneedmoreinformationaboutDjangoformsyoushouldreadthedocumentation:https://docs.djangoproject.com/en/1.9/topics/forms/

DjangoForms

118

SecurityBeingabletocreatenewpostsjustbyclickingalinkisawesome!But,rightnow,anyonethatvisitsyoursitewillbeabletopostanewblogpostandthat'sprobablynotsomethingyouwant.Let'smakeitsothebuttonshowsupforyoubutnotforanyoneelse.

Inblog/templates/blog/base.html,findourpage-headerdivandtheanchortagyouputinthereearlier.Itshouldlooklikethis:

blog/templates/blog/base.html

<ahref="{%url'post_new'%}"class="top-menu"><spanclass="glyphiconglyphicon-plus"></span></a>

We'regoingtoaddanother{%if%}tagtothiswhichwillmakethelinkonlyshowupforusersthatareloggedintotheadmin.Rightnow,that'sjustyou!Changethe<a>tagtolooklikethis:

blog/templates/blog/base.html

{%ifuser.is_authenticated%}

<ahref="{%url'post_new'%}"class="top-menu"><spanclass="glyphiconglyphicon-plus"></span></a>

{%endif%}

This{%if%}willcausethelinktoonlybesenttothebrowseriftheuserrequestingthepageisloggedin.Thisdoesn'tprotectthecreationofnewpostscompletely,butit'sagoodfirststep.We'llcovermoresecurityintheextensionlessons.

Remembertheediticonwejustaddedtoourdetailpage?Wealsowanttoaddthesamechangethere,sootherpeoplewon'tbeabletoeditexistingposts.

Openblog/templates/blog/post_detail.htmlandfind:

blog/templates/blog/post_detail.html

<aclass="btnbtn-default"href="{%url'post_edit'pk=post.pk%}"><spanclass="glyphiconglyphicon-pencil"></span></a

>

Changeitto:

blog/templates/blog/post_detail.html

{%ifuser.is_authenticated%}

<aclass="btnbtn-default"href="{%url'post_edit'pk=post.pk%}"><spanclass="glyphiconglyphicon-pencil"></sp

an></a>

{%endif%}

Sinceyou'relikelyloggedin,ifyourefreshthepage,youwon'tseeanythingdifferent.Loadthepageinanewbrowseroranincognitowindow,though,andyou'llseethatthelinkdoesn'tshowup,andtheicondoesn'tdisplayeither!

Onemorething:deploytime!Let'sseeifallthisworksonPythonAnywhere.Timeforanotherdeploy!

First,commityournewcode,andpushituptoGithub

command-line

DjangoForms

119

$gitstatus

$gitadd--all.

$gitstatus

$gitcommit-m"Addedviewstocreate/editblogpostinsidethesite."

$gitpush

Then,inaPythonAnywhereBashconsole:

command-line

$cdmy-first-blog

$gitpull

[...]

Finally,hoponovertotheWebtabandhitReload.

Andthatshouldbeit!Congrats:)

DjangoForms

120

What'snext?Congratulateyourself!You'retotallyawesome.We'reproud!<3

Whattodonow?

Takeabreakandrelax.Youhavejustdonesomethingreallyhuge.

Afterthatmakesureto:

FollowDjangoGirlsonFacebookorTwittertostayuptodate

Canyourecommendanyfurtherresources?Yes!First,goaheadandtryourotherbook,calledDjangoGirlsTutorial:Extensions.

Lateron,youcantrytheresourceslistedbelow.They'reallveryrecommended!

Django'sofficialtutorialNewCodertutorialsCodeAcademyPythoncourseCodeAcademyHTML&CSScourseDjangoCarrotstutorialLearnPythonTheHardWaybookGettingStartedWithDjangovideolessonsTwoScoopsofDjango:BestPracticesforDjango1.8bookHelloWebApp:LearnHowtoBuildaWebApp

What'snext?

121

top related