table of contents - amazon web services€¦ · table of contents introduction installation...
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
1.25
TableofContentsIntroduction
Installation
Installation(chromebook)
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/
WelcomeWelcometotheDjangoGirlsTutorial!Wearehappytoseeyouhere:)Inthistutorial,wewilltakeyouonajourneyunderthehoodofwebtechnologies,offeringyouaglimpseofallthebitsandpiecesthatneedtocometogethertomakethewebworkasweknowit.
Aswithallunknownthings,thisisgoingtobeanadventure-butnoworries,sinceyoualreadyworkedupthecouragetobehere,you'llbejustfine:)
IntroductionHaveyoueverfeltthattheworldismoreandmoreabouttechnologytowhichyoucannot(yet)relate?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,we
haveachatsystemforyou: .Weaskedourcoachesandpreviousattendeestobetherefromtimetotimeandhelpotherswiththetutorial!Don'tbeafraidtoaskyourquestionthere!
OK,let'sstartatthebeginning…
FollowingthetutorialathomeItisamazingtotakepartinaDjangoGirlsworkshop,butweareawarethatitisnotalwayspossibletoattendone.Thisiswhyweencourageyoutotryfollowingthistutorialathome.Forreadersathomewearecurrentlypreparingvideosthatwillmakeiteasiertofollowthetutorialonyourown.Itisstillaworkinprogress,butmoreandmorethingswillbecoveredsoonattheCodingisforgirlsYouTubechannel.
Ineverychapteralreadycovered,thereisalinkthatpointstothecorrectvideo.
AboutandcontributingThistutorialismaintainedbyDjangoGirls.Ifyoufindanymistakesorwanttoupdatethetutorialpleasefollowthecontributingguidelines.
Introduction
4
Wouldyouliketohelpustranslatethetutorialtootherlanguages?Currently,translationsarebeingkeptoncrowdin.complatformat:
https://crowdin.com/project/django-girls-tutorial
Ifyourlanguageisnotlistedoncrowdin,pleaseopenanewissueinformingusofthelanguagesowecanaddit.
Introduction
5
Ifyou'redoingthetutorialathomeIfyou'redoingthetutorialathome,notatoneoftheDjangoGirlsevents,youcancompletelyskipthischapternowandgostraighttotheHowtheInternetworkschapter.
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,andasmallwindowatthebottomthatlookssomethinglikethis:
Cloud9
yourusername:~/workspace$
Thisbottomareaisyourterminal,whereyouwillgivethecomputerCloud9haspreparedforyouinstructions.Youcanresizethatwindowtomakeitabitbigger.
VirtualEnvironment
Installation
6
Avirtualenvironment(alsocalledavirtualenv)islikeaprivateboxwecanstuffusefulcomputercodeintoforaprojectwe'reworkingon.Weusethemtokeepthevariousbitsofcodewewantforourvariousprojectsseparatesothingsdon'tgetmixedupbetweenprojects.
InyourterminalatthebottomoftheCloud9interface,runthefollowing:
Cloud9
sudoaptupdatesudoaptinstallpython3.6-venv
Ifthisstilldoesn'twork,askyourcoachforsomehelp.
Next,run:
Cloud9
mkdirdjangogirlscddjangogirlspython3.6-mvenvmyvenvsourcemyvenv/bin/activatepipinstalldjango~=1.11.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.6,soifyouhaveanyearlierversion,youwillneedtoupgradeit.
InstallPython:WindowsFirstcheckwhetheryourcomputerisrunninga32-bitversionora64-bitversionofWindows,bypressingtheWindowskey+Pause/BreakkeywhichwillopenyourSysteminfo,andlookatthe"Systemtype"line.YoucandownloadPythonforWindowsfromthewebsitehttps://www.python.org/downloads/windows/.Clickonthe"Latest
Installation
7
Python3Release-Pythonx.x.x"link.Ifyourcomputerisrunninga64-bitversionofWindows,downloadtheWindowsx86-64executableinstaller.Otherwise,downloadtheWindowsx86executableinstaller.Afterdownloadingtheinstaller,youshouldrunit(double-clickonit)andfollowtheinstructionsthere.
Onethingtowatchoutfor:Duringtheinstallationyouwillnoticeawindowmarked"Setup".Makesureyoutickthe"AddPython3.6toPATH"checkboxandclickon"InstallNow",asshownhere:
Inupcomingsteps,you'llbeusingtheWindowsCommandLine(whichwe'llalsotellyouabout).Fornow,ifyouneedtotypeinsomecommands,gotoStartmenu→WindowsSystem→CommandPrompt.YoucanalsoholdintheWindowskeyandpressthe"R"-keyuntilthe"Run"windowpopsup.ToopentheCommandLine,type"cmd"andpressenterinthe"Run"window.(OnnewerversionsofWindows,youmighthavetosearchfor"CommandPrompt"sinceit'ssometimeshidden.)
Note:ifyouareusinganolderversionofWindows(7,Vista,oranyolderversion)andthePython3.6.xinstallerfailswithanerror,youcantryeither:
Installation
8
1. installallWindowsUpdatesandtrytoinstallPython3.6again;or2. installanolderversionofPython,e.g.,3.4.6.
IfyouinstallanolderversionofPython,theinstallationscreenmaylookabitdifferentthanshownabove.Makesureyouscrolldowntosee"Addpython.exetoPath",thenclickthebuttonontheleftandpick"Willbeinstalledonlocalharddrive":
InstallPython:OSXNoteBeforeyouinstallPythononOSX,youshouldensureyourMacsettingsallowinstallingpackagesthataren'tfromtheAppStore.GotoSystemPreferences(it'sintheApplicationsfolder),click"Security&Privacy,"andthenthe"General"tab.Ifyour"Allowappsdownloadedfrom:"issetto"MacAppStore,"changeitto"MacAppStoreandidentifieddevelopers."
Youneedtogotothewebsitehttps://www.python.org/downloads/release/python-361/anddownloadthePythoninstaller:
DownloadtheMacOSX64-bit/32-bitinstallerfile,Doubleclickpython-3.6.1-macosx10.6.pkgtoruntheinstaller.
InstallPython:LinuxItisverylikelythatyoualreadyhavePythoninstalledoutofthebox.Tocheckifyouhaveitinstalled(andwhichversionitis),openaconsoleandtypethefollowingcommand:
command-line
$python3--versionPython3.6.1
Ifyouhaveadifferent'microversion'ofPythoninstalled,e.g.3.6.0,thenyoudon'thavetoupgrade.Ifyoudon'thavePythoninstalled,orifyouwantadifferentversion,youcaninstallitasfollows:
Installation
9
InstallPython:DebianorUbuntuTypethiscommandintoyourconsole:
command-line
$sudoapt-getinstallpython3.6
InstallPython:FedoraUsethiscommandinyourconsole:
command-line
$sudodnfinstallpython3
Ifyou'reonolderFedoraversionsyoumightgetanerrorthatthecommanddnfisnotfound.Inthatcaseyouneedtouseyuminstead.
InstallPython:openSUSEUsethiscommandinyourconsole:
command-line
$sudozypperinstallpython3
Verifytheinstallationwassuccessfulbyopeningacommandpromptandrunningthepython3command:
command-line
$python3--versionPython3.6.1
NOTE:Ifyou'reonWindowsandyougetanerrormessagethatpython3wasn'tfound,tryusingpython(withoutthe3)andcheckifitstillmightbeaversionofPython3.6.
Ifyouhaveanydoubts,orifsomethingwentwrongandyouhavenoideawhattodonext,pleaseaskyourcoach!Sometimesthingsdon'tgosmoothlyandit'sbettertoaskforhelpfromsomeonewithmoreexperience.
SetupvirtualenvandinstallDjangoPartofthissectionisbasedontutorialsbyGeekGirlsCarrots(https://github.com/ggcarrots/django-carrots).
Partofthissectionisbasedonthedjango-marcadortutoriallicensedundertheCreativeCommonsAttribution-ShareAlike4.0InternationalLicense.Thedjango-marcadortutorialiscopyrightedbyMarkusZapke-Gründemannetal.
VirtualenvironmentBeforeweinstallDjangowewillgetyoutoinstallanextremelyusefultooltohelpkeepyourcodingenvironmenttidyonyourcomputer.It'spossibletoskipthisstep,butit'shighlyrecommended.Startingwiththebestpossiblesetupwillsaveyoualotoftroubleinthefuture!
Installation
10
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
Virtualenvironment:WindowsTocreateanewvirtualenv,youneedtoopenthecommandpromptandrunpython-mvenvmyvenv.Itwilllooklikethis:
command-line
C:\Users\Name\djangogirls>python-mvenvmyvenv
Wheremyvenvisthenameofyourvirtualenv.Youcanuseanyothername,butsticktolowercaseandusenospaces,accentsorspecialcharacters.Itisalsogoodideatokeepthenameshort–you'llbereferencingitalot!
Virtualenvironment:LinuxandOSXCreatingavirtualenvonbothLinuxandOSXisassimpleasrunningpython3-mvenvmyvenv.Itwilllooklikethis:
command-line
$python3-mvenvmyvenv
myvenvisthenameofyourvirtualenv.Youcanuseanyothername,butsticktolowercaseandusenospaces.Itisalsogoodideatokeepthenameshortasyou'llbereferencingitalot!
NOTE:OnsomeversionsofDebian/Ubuntuyoumayreceivethefollowingerror:
command-line
Thevirtualenvironmentwasnotcreatedsuccessfullybecauseensurepipisnotavailable.OnDebian/Ubuntusystems,youneedtoinstallthepython3-venvpackageusingthefollowingcommand.apt-getinstallpython3-venvYoumayneedtousesudowiththatcommand.Afterinstallingthepython3-venvpackage,recreateyourvirtualenvironment.
Inthiscase,followtheinstructionsaboveandinstallthepython3-venvpackage:
command-line
Installation
11
$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.6myvenv
NOTE:Ifyougetanerrorlike
command-line
E:Unabletolocatepackagepython3-venv
theninsteadrun:
command-line
sudoaptinstallpython3.6-venv
WorkingwithvirtualenvThecommandabovewillcreateadirectorycalledmyvenv(orwhatevernameyouchose)thatcontainsourvirtualenvironment(basicallyabunchofdirectoryandfiles).
Workingwithvirtualenv:WindowsStartyourvirtualenvironmentbyrunning:
command-line
C:\Users\Name\djangogirls>myvenv\Scripts\activate
NOTE:onWindows10youmightgetanerrorintheWindowsPowerShellthatsaysexecutionofscriptsisdisabledonthissystem.Inthiscase,openanotherWindowsPowerShellwiththe"RunasAdministrator"option.Thentrytypingthefollowingcommandbeforestartingyourvirtualenvironment:
command-line
C:\WINDOWS\system32>Set-ExecutionPolicy-ExecutionPolicyRemoteSignedExecutionPolicyChangeTheexecutionpolicyhelpsprotectyoufromscriptsthatyoudonottrust.Changingtheexecutionpolicymightexposeyoutothesecurityrisksdescribedintheabout_Execution_Policieshelptopicathttp://go.microsoft.com/fwlink/?LinkID=135170.Doyouwanttochangetheexecutionpolicy?[Y]Yes[A]YestoAll[N]No[L]NotoAll[S]Suspend[?]Help(defaultis"N"):A
Installation
12
Workingwithvirtualenv: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:
command-line
(myvenv)~$pipinstall--upgradepip
Thenrunpipinstalldjango~=1.11.0(notethatweuseatildefollowedbyanequalsign:~=)toinstallDjango.
command-line
(myvenv)~$pipinstalldjango~=1.11.0Collectingdjango~=1.11.0DownloadingDjango-1.11.3-py2.py3-none-any.whl(6.8MB)Installingcollectedpackages:djangoSuccessfullyinstalleddjango-1.11.3
InstallingDjango:WindowsIfyougetanerrorwhencallingpiponWindowsplatform,pleasecheckifyourprojectpathnamecontainsspaces,accentsorspecialcharacters(forexample,C:\Users\UserName\djangogirls).Ifitdoes,pleaseconsiderusinganotherplacewithoutspaces,accentsorspecialcharacters(suggestion:C:\djangogirls).Createanewvirtualenvinthenewdirectory,thendeletetheoldoneandtrytheabovecommandagain.(Movingthevirtualenvdirectorywon'tworksincevirtualenvusesabsolutepaths.)
InstallingDjango:Windows8andWindows10YourcommandlinemightfreezeafterwhenyoutrytoinstallDjango.Ifthishappens,insteadoftheabovecommanduse:
command-line
Installation
13
C:\Users\Name\djangogirls>python-mpipinstalldjango~=1.11.0
InstallingDjango:LinuxIfyougetanerrorwhencallingpiponUbuntu12.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
SublimeText3SublimeTextisaverypopulareditorwithafreeevaluationperiod.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).
Thesecondreasonisthatcodeeditorsarespecializedforeditingcode,sotheycanprovidehelpfulfeatureslikehighlightingcodewithcoloraccordingtoitsmeaning,orautomaticallyclosingquotesforyou.
We'llseeallthisinactionlater.Soon,you'llcometothinkofyourtrustyoldcodeeditorasoneofyourfavoritetools.:)
Installation
14
InstallGitGitisa"versioncontrolsystem"usedbyalotofprogrammers.Thissoftwarecantrackchangestofilesovertimesothatyoucanrecallspecificversionslater.Abitlikethe"trackchanges"featureinMicrosoftWord,butmuchmorepowerful.
InstallingGitInstallingGit:WindowsYoucandownloadGitfromgit-scm.com.Youcanhit"next"onallstepsexceptforone;inthefifthstepentitled"AdjustingyourPATHenvironment",choose"UseGitandoptionalUnixtoolsfromtheWindowsCommandPrompt"(thebottomoption).Otherthanthat,thedefaultsarefine.CheckoutWindows-style,commitUnix-stylelineendingsisgood.
Donotforgettorestartthecommandpromptorpowershellaftertheinstallationfinishedsuccessfully.
InstallingGit:OSXDownloadGitfromgit-scm.comandjustfollowtheinstructions.
NoteIfyouarerunningOSX10.6,10.7,or10.8,youwillneedtoinstalltheversionofgitfromhere:GitinstallerforOSXSnowLeopard
InstallingGit:DebianorUbuntu
command-line
$sudoapt-getinstallgit
InstallingGit:Fedora
command-line
$sudodnfinstallgit
InstallingGit:openSUSE
command-line
$sudozypperinstallgit
CreateaGitHubaccountGotoGitHub.comandsignupforanew,freeuseraccount.
CreateaPythonAnywhereaccountNextit'stimetosignupforafree"Beginner"accountonPythonAnywhere.
www.pythonanywhere.com
Installation
15
NoteWhenchoosingyourusernamehere,bearinmindthatyourblog'sURLwilltaketheformyourusername.pythonanywhere.com,sochooseeitheryourownnickname,oranameforwhatyourblogisallabout.
StartreadingCongratulations,youareallsetupandreadytogo!Ifyoustillhavesometimebeforetheworkshop,itwouldbeusefultostartreadingafewofthebeginningchapters:
Howtheinternetworks
Introductiontothecommandline
IntroductiontoPython
WhatisDjango?
Enjoytheworkshop!Whenyoubegintheworkshop,you'llbeabletogostraighttoYourfirstDjangoproject!becauseyoualreadycoveredthematerialintheearlierchapters.
Installation
16
ChromebooksetupIfyoualreadyworkedthroughtheInstallationsteps,noneedtodothisagain–youcanskipstraightaheadtoIntroductiontoPython.
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,andasmallwindowatthebottomthatlookssomethinglikethis:
Cloud9
yourusername:~/workspace$
Thisbottomareaisyourterminal,whereyouwillgivethecomputerCloud9haspreparedforyouinstructions.Youcanresizethatwindowtomakeitabitbigger.
VirtualEnvironment
Avirtualenvironment(alsocalledavirtualenv)islikeaprivateboxwecanstuffusefulcomputercodeintoforaprojectwe'reworkingon.Weusethemtokeepthevariousbitsofcodewewantforourvariousprojectsseparatesothingsdon'tgetmixedupbetweenprojects.
InyourterminalatthebottomoftheCloud9interface,runthefollowing:
Cloud9
sudoaptupdatesudoaptinstallpython3.6-venv
Ifthisstilldoesn'twork,askyourcoachforsomehelp.
Next,run:
Cloud9
mkdirdjangogirlscddjangogirls
Installation(chromebook)
17
python3.6-mvenvmyvenvsourcemyvenv/bin/activatepipinstalldjango~=1.11.0
(notethatonthelastlineweuseatildefollowedbyanequalsign:~=).
Github
MakeaGithubaccount.
PythonAnywhere
TheDjangoGirlstutorialincludesasectiononwhatiscalledDeployment,whichistheprocessoftakingthecodethatpowersyournewwebapplicationandmovingittoapubliclyaccessiblecomputer(calledaserver)sootherpeoplecanseeyourwork.
ThispartisalittleoddwhendoingthetutorialonaChromebooksincewe'realreadyusingacomputerthatisontheInternet(asopposedto,say,alaptop).However,it'sstilluseful,aswecanthinkofourCloud9workspaceasaplaceorour"inprogress"workandPythonAnywhereasaplacetoshowoffourstuffasitbecomesmorecomplete.
Thus,signupforanewPythonAnywhereaccountatwww.pythonanywhere.com.
Installation(chromebook)
18
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
19
Itisfascinating,isn'tit?Butobviously,itisnotpossibletohaveawirebetweeneverymachineconnectedtotheInternet.So,toreachamachine(forexample,theonewherehttps://djangogirls.orgissaved)weneedtopassarequestthroughmany,manydifferentmachines.
Itlookslikethis:
HowtheInternetworks
20
Imaginethatwhenyoutypehttps://djangogirls.org,yousendaletterthatsays:"DearDjangoGirls,Iwanttoseethedjangogirls.orgwebsite.Sendittome,please!"
Yourlettergoestothepostofficeclosesttoyou.Thenitgoestoanotherthatisabitnearertoyouraddressee,thentoanother,andanotheruntilitisdeliveredatitsdestination.Theonlyuniquethingisthatifyousendmanyletters(datapackets)tothesameplace,theycouldgothroughtotallydifferentpostoffices(routers).Thisdependsonhowtheyaredistributedateachoffice.
HowtheInternetworks
21
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
22
Introductiontothecommand-lineinterfaceForreadersathome:thischapteriscoveredintheYournewfriend:CommandLinevideo.
It'sexciting,right?!You'llwriteyourfirstlineofcodeinjustafewminutes!:)
Letusintroduceyoutoyourfirstnewfriend:thecommandline!
Thefollowingstepswillshowyouhowtousetheblackwindowallhackersuse.Itmightlookabitscaryatfirstbutreallyit'sjustapromptwaitingforcommandsfromyou.
NotePleasenotethatthroughoutthisbookweusetheterms'directory'and'folder'interchangeablybuttheyareoneandthesamething.
Whatisthecommandline?Thewindow,whichisusuallycalledthecommandlineorcommand-lineinterface,isatext-basedapplicationforviewing,handling,andmanipulatingfilesonyourcomputer.It'smuchlikeWindowsExplorerorFinderontheMac,butwithoutthegraphicalinterface.Othernamesforthecommandlineare:cmd,CLI,prompt,consoleorterminal.
Openthecommand-lineinterfaceTostartsomeexperimentsweneedtoopenourcommand-lineinterfacefirst.
Opening:WindowsGotoStartmenu→WindowsSystem→CommandPrompt.
OnolderversionsofWindows,lookinStartmenu→AllPrograms→Accessories→CommandPrompt.
Opening:OSXGotoApplications→Utilities→Terminal.
Opening:LinuxIt'sprobablyunderApplications→Accessories→Terminal,butthatmaydependonyoursystem.Ifit'snotthere,justGoogleit.:)
PromptYounowshouldseeawhiteorblackwindowthatiswaitingforyourcommands.
Prompt:OSXandLinuxIfyou'reonMacorLinux,youprobablysee$,justlikethis:
command-line
$
Prompt:WindowsOnWindows,it'sa>sign,likethis:
command-line
Introductiontocommandline
23
>
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:
Yourfirstcommand:OSXandLinux
command-line
$whoami
Yourfirstcommand:Windows
command-line
>whoami
Andthenhitenter.Thisisourresult:
command-line
$whoamiolasitarska
Asyoucansee,thecomputerhasjustprintedyourusername.Neat,huh?:)
Trytotypeeachcommand;donotcopy-paste.You'llremembermorethisway!
BasicsEachoperatingsystemhasaslightlydifferentsetofcommandsforthecommandline,somakesuretofollowinstructionsforyouroperatingsystem.Let'strythis,shallwe?
Currentdirectory
It'dbenicetoknowwherearewenow,right?Let'ssee.Typethiscommandandhitenter:
Currentdirectory:OSXandLinux
command-line
Introductiontocommandline
24
$pwd/Users/olasitarska
Note:'pwd'standsfor'printworkingdirectory'.
Currentdirectory:Windows
command-line
>cdC:\Users\olasitarska
Note:'cd'standsfor'changedirectory'.WithpowershellyoucanusepwdjustlikeonLinuxorMacOSX.
You'llprobablyseesomethingsimilaronyourmachine.Onceyouopenthecommandlineyouusuallystartatyouruser'shomedirectory.
Listfilesanddirectories
Sowhat'sinit?It'dbecooltofindout.Let'ssee:
Listfilesanddirectories:OSXandLinux
command-line
$lsApplicationsDesktopDownloadsMusic...
Listfilesanddirectories:Windows
command-line
>dirDirectoryofC:\Users\olasitarska05/08/201407:28PM<DIR>Applications05/08/201407:28PM<DIR>Desktop05/08/201407:28PM<DIR>Downloads05/08/201407:28PM<DIR>Music...
Note:Inpowershellyoucanalsouse'ls'likeonLinuxandMacOSX.
Changecurrentdirectory
Now,let'sgotoourDesktopdirectory:
Changecurrentdirectory:OSXandLinux
command-line
$cdDesktop
Introductiontocommandline
25
Changecurrentdirectory:Windows
command-line
>cdDesktop
Checkifit'sreallychanged:
Checkifchanged:OSXandLinux
command-line
$pwd/Users/olasitarska/Desktop
Checkifchanged:Windows
command-line
>cdC:\Users\olasitarska\Desktop
Hereitis!
PROtip:ifyoutypecdDandthenhittabonyourkeyboard,thecommandlinewillautomaticallyfillintherestofthenamesoyoucannavigatefaster.Ifthereismorethanonefolderstartingwith"D",hitthetabkeytwicetogetalistofoptions.
Createdirectory
Howaboutcreatingapracticedirectoryonyourdesktop?Youcandoitthisway:
Createdirectory:OSXandLinux
command-line
$mkdirpractice
Createdirectory:Windows
command-line
>mkdirpractice
Thislittlecommandwillcreateafolderwiththenamepracticeonyourdesktop.Youcancheckifit'stherejustbylookingonyourDesktoporbyrunningalsordircommand!Tryit.:)
PROtip:Ifyoudon'twanttotypethesamecommandsoverandover,trypressingtheuparrowanddownarrowonyourkeyboardtocyclethroughrecentlyusedcommands.
Exercise!
Introductiontocommandline
26
Asmallchallengeforyou:inyournewlycreatedpracticedirectory,createadirectorycalledtest.(Usethecdandmkdircommands.)
Solution:
Exercisesolution:OSXandLinux
command-line
$cdpractice$mkdirtest$lstest
Exercisesolution:Windows
command-line
>cdpractice>mkdirtest>dir05/08/201407:28PM<DIR>test
Congrats!:)
Cleanup
Wedon'twanttoleaveamess,solet'sremoveeverythingwediduntilthatpoint.
First,weneedtogetbacktoDesktop:
Cleanup:OSXandLinux
command-line
$cd..
Cleanup:Windows
command-line
>cd..
Using..withthecdcommandwillchangeyourcurrentdirectorytotheparentdirectory(thatis,thedirectorythatcontainsyourcurrentdirectory).
Checkwhereyouare:
Checklocation:OSXandLinux
command-line
$pwd/Users/olasitarska/Desktop
Checklocation:Windows
Introductiontocommandline
27
command-line
>cdC:\Users\olasitarska\Desktop
Nowtimetodeletethepracticedirectory:
Attention:Deletingfilesusingdel,rmdirorrmisirrecoverable,meaningthedeletedfileswillbegoneforever!Sobeverycarefulwiththiscommand.
Deletedirectory:WindowsPowershell,OSXandLinux
command-line
$rm-rpractice
Deletedirectory:WindowsCommandPrompt
command-line
>rmdir/Spracticepractice,Areyousure<Y/N>?Y
Done!Tobesureit'sactuallydeleted,let'scheckit:
Checkdeletion:OSXandLinux
command-line
$ls
Checkdeletion:Windows
command-line
>dir
Exit
That'sitfornow!Youcansafelyclosethecommandlinenow.Let'sdoitthehackerway,alright?:)
Exit:OSXandLinux
command-line
$exit
Exit:Windows
command-line
>exit
Cool,huh?:)
Introductiontocommandline
28
SummaryHereisasummaryofsomeusefulcommands:
Command(Windows)
Command(MacOS/Linux) Description Example
exit exit closethewindow exit
cd cd changedirectory cdtest
cd pwd showthecurrentdirectory
cd(Windows)orpwd(MacOS/Linux)
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
29
Let’sstartwithPythonWe'refinallyhere!
Butfirst,letustellyouwhatPythonis.Pythonisaverypopularprogramminglanguagethatcanbeusedforcreatingwebsites,games,scientificsoftware,graphics,andmuch,muchmore.
Pythonoriginatedinthelate1980sanditsmaingoalistobereadablebyhumanbeings(notonlymachines!).Thisiswhyitlooksmuchsimplerthanotherprogramminglanguages.Thismakesiteasytolearn,butdon'tworry–Pythonisalsoreallypowerful!
PythoninstallationNoteIfyou'reusingaChromebook,skipthischapterandmakesureyoufollowtheChromebookSetupinstructions.
NoteIfyoualreadyworkedthroughtheInstallationsteps,there'snoneedtodothisagain–youcanskipstraightaheadtothenextchapter!
Forreadersathome:thischapteriscoveredintheInstallingPython&CodeEditorvideo.
ThissectionisbasedonatutorialbyGeekGirlsCarrots(https://github.com/ggcarrots/django-carrots)
DjangoiswritteninPython.WeneedPythontodoanythinginDjango.Let'sstartbyinstallingit!WewantyoutoinstallPython3.6,soifyouhaveanyearlierversion,youwillneedtoupgradeit.
InstallPython:WindowsFirstcheckwhetheryourcomputerisrunninga32-bitversionora64-bitversionofWindows,bypressingtheWindowskey+Pause/BreakkeywhichwillopenyourSysteminfo,andlookatthe"Systemtype"line.YoucandownloadPythonforWindowsfromthewebsitehttps://www.python.org/downloads/windows/.Clickonthe"LatestPython3Release-Pythonx.x.x"link.Ifyourcomputerisrunninga64-bitversionofWindows,downloadtheWindowsx86-64executableinstaller.Otherwise,downloadtheWindowsx86executableinstaller.Afterdownloadingtheinstaller,youshouldrunit(double-clickonit)andfollowtheinstructionsthere.
Onethingtowatchoutfor:Duringtheinstallationyouwillnoticeawindowmarked"Setup".Makesureyoutickthe"AddPython3.6toPATH"checkboxandclickon"InstallNow",asshownhere:
Pythoninstallation
30
Inupcomingsteps,you'llbeusingtheWindowsCommandLine(whichwe'llalsotellyouabout).Fornow,ifyouneedtotypeinsomecommands,gotoStartmenu→WindowsSystem→CommandPrompt.YoucanalsoholdintheWindowskeyandpressthe"R"-keyuntilthe"Run"windowpopsup.ToopentheCommandLine,type"cmd"andpressenterinthe"Run"window.(OnnewerversionsofWindows,youmighthavetosearchfor"CommandPrompt"sinceit'ssometimeshidden.)
Note:ifyouareusinganolderversionofWindows(7,Vista,oranyolderversion)andthePython3.6.xinstallerfailswithanerror,youcantryeither:
1. installallWindowsUpdatesandtrytoinstallPython3.6again;or2. installanolderversionofPython,e.g.,3.4.6.
IfyouinstallanolderversionofPython,theinstallationscreenmaylookabitdifferentthanshownabove.Makesureyouscrolldowntosee"Addpython.exetoPath",thenclickthebuttonontheleftandpick"Willbeinstalledonlocalharddrive":
Pythoninstallation
31
InstallPython:OSXNoteBeforeyouinstallPythononOSX,youshouldensureyourMacsettingsallowinstallingpackagesthataren'tfromtheAppStore.GotoSystemPreferences(it'sintheApplicationsfolder),click"Security&Privacy,"andthenthe"General"tab.Ifyour"Allowappsdownloadedfrom:"issetto"MacAppStore,"changeitto"MacAppStoreandidentifieddevelopers."
Youneedtogotothewebsitehttps://www.python.org/downloads/release/python-361/anddownloadthePythoninstaller:
DownloadtheMacOSX64-bit/32-bitinstallerfile,Doubleclickpython-3.6.1-macosx10.6.pkgtoruntheinstaller.
InstallPython:LinuxItisverylikelythatyoualreadyhavePythoninstalledoutofthebox.Tocheckifyouhaveitinstalled(andwhichversionitis),openaconsoleandtypethefollowingcommand:
command-line
$python3--versionPython3.6.1
Ifyouhaveadifferent'microversion'ofPythoninstalled,e.g.3.6.0,thenyoudon'thavetoupgrade.Ifyoudon'thavePythoninstalled,orifyouwantadifferentversion,youcaninstallitasfollows:
InstallPython:DebianorUbuntuTypethiscommandintoyourconsole:
command-line
$sudoapt-getinstallpython3.6
Pythoninstallation
32
InstallPython:FedoraUsethiscommandinyourconsole:
command-line
$sudodnfinstallpython3
Ifyou'reonolderFedoraversionsyoumightgetanerrorthatthecommanddnfisnotfound.Inthatcaseyouneedtouseyuminstead.
InstallPython:openSUSEUsethiscommandinyourconsole:
command-line
$sudozypperinstallpython3
Verifytheinstallationwassuccessfulbyopeningacommandpromptandrunningthepython3command:
command-line
$python3--versionPython3.6.1
NOTE:Ifyou'reonWindowsandyougetanerrormessagethatpython3wasn'tfound,tryusingpython(withoutthe3)andcheckifitstillmightbeaversionofPython3.6.
Ifyouhaveanydoubts,orifsomethingwentwrongandyouhavenoideawhattodonext,pleaseaskyourcoach!Sometimesthingsdon'tgosmoothlyandit'sbettertoaskforhelpfromsomeonewithmoreexperience.
Pythoninstallation
33
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
SublimeText3SublimeTextisaverypopulareditorwithafreeevaluationperiod.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).
Thesecondreasonisthatcodeeditorsarespecializedforeditingcode,sotheycanprovidehelpfulfeatureslikehighlightingcodewithcoloraccordingtoitsmeaning,orautomaticallyclosingquotesforyou.
We'llseeallthisinactionlater.Soon,you'llcometothinkofyourtrustyoldcodeeditorasoneofyourfavoritetools.:)
Codeeditor
34
Codeeditor
35
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
$python3Python3.6.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+35
Nice!Seehowtheanswerpoppedout?Pythonknowsmath!Youcouldtryothercommandslike:
4*5
5-1
40/2
Toperformexponentialcalculation,say2tothepower3,wetype:
command-line
>>>2**38
IntroductiontoPython
36
Havefunwiththisforalittlewhileandthengetbackhere.:)
Asyoucansee,Pythonisagreatcalculator.Ifyou'rewonderingwhatelseyoucando…
StringsHowaboutyourname?Typeyourfirstnameinquoteslikethis:
command-line
>>>"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.
IntroductiontoPython
37
Ifyouwanttoknowthenumberofletterscontainedinyourname,thereisafunctionforthattoo!
command-line
>>>len("Ola")3
Wonderwhysometimesyoucallfunctionswitha.attheendofastring(like"Ola".upper())andsometimesyoufirstcallafunctionandplacethestringinparentheses?Well,insomecases,functionsbelongtoobjects,likeupper(),whichcanonlybeperformedonstrings.Inthiscase,wecallthefunctionamethod.Othertimes,functionsdon'tbelongtoanythingspecificandcanbeusedondifferenttypesofobjects,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?
Variables
IntroductiontoPython
38
Animportantconceptinprogrammingisvariables.Avariableisnothingmorethananameforsomethingsoyoucanuseitlater.Programmersusethesevariablestostoredata,maketheircodemorereadableandsotheydon'thavetokeeprememberingwhatthingsare.
Let'ssaywewanttocreateanewvariablecalledname:
command-line
>>>name="Ola"
Yousee?It'seasy!It'ssimply:nameequalsOla.
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*b24
Butwhatifweusedthewrongname?Canyouguesswhatwouldhappen?Let'stry!
command-line
>>>city="Tokyo">>>ctiyTraceback(mostrecentcalllast):File"<stdin>",line1,in<module>NameError:name'ctiy'isnotdefined
Anerror!Asyoucansee,PythonhasdifferenttypesoferrorsandthisoneiscalledaNameError.Pythonwillgiveyouthiserrorifyoutrytouseavariablethathasn'tbeendefinedyet.Ifyouencounterthiserrorlater,checkyourcodetoseeifyou'vemistypedanynames.
IntroductiontoPython
39
Playwiththisforawhileandseewhatyoucando!
TheprintfunctionTrythis:
command-line
>>>name='Maria'>>>name'Maria'>>>print(name)Maria
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()
IntroductiontoPython
40
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]
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.
Todeletesomethingfromyourlistyouwillneedtouseindexesaswelearnedaboveandthepop()method.Let'stryanexampleandreinforcewhatwelearnedpreviously;wewillbedeletingthefirstnumberofourlist.
command-line
>>>print(lottery)[59,42,30,19,12,3,199]>>>print(lottery[0])59>>>lottery.pop(0)59>>>print(lottery)[42,30,19,12,3,199]
Thatworkedlikeacharm!
Forextrafun,trysomeotherindexes:6,7,1000,-1,-6or-1000.Seeifyoucanpredicttheresultbeforetryingthecommand.Dotheresultsmakesense?
IntroductiontoPython
41
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
>>>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.
IntroductiontoPython
42
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')[7,42,92]>>>participant{'country':'Poland','favorite_language':'Python','name':'Ola'}
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!Youjustlearnedanotheramazingthing.
Summary
Awesome!Youknowalotaboutprogrammingnow.Inthislastpartyoulearnedabout:
errors–younowknowhowtoreadandunderstanderrorsthatshowupifPythondoesn'tunderstandacommandyou'vegivenitvariables–namesforobjectsthatallowyoutocodemoreeasilyandtomakeyourcodemorereadablelists–listsofobjectsstoredinaparticularorderdictionaries–objectsstoredaskey–valuepairs
Excitedforthenextpart?:)
ComparethingsForreadersathome:thispartiscoveredinthePythonBasics:Comparisonsvideo.
IntroductiontoPython
43
Abigpartofprogramminginvolvescomparingthings.What'stheeasiestthingtocompare?Numbers,ofcourse.Let'sseehowthatworks:
command-line
>>>5>2True>>>3<1False>>>5>2*2True>>>1==1True>>>5!=2True
WegavePythonsomenumberstocompare.Asyoucansee,notonlycanPythoncomparenumbers,butitcanalsocomparemethodresults.Nice,huh?
Doyouwonderwhyweputtwoequalsigns==nexttoeachothertocompareifnumbersareequal?Weuseasingle=forassigningvaluestovariables.Youalways,alwaysneedtoputtwoofthem–==–ifyouwanttocheckifthingsareequaltoeachother.Wecanalsostatethatthingsareunequaltoeachother.Forthat,weusethesymbol!=,asshownintheexampleabove.
GivePythontwomoretasks:
command-line
>>>6>=12/2True>>>3<=2False
>and<areeasy,butwhatdo>=and<=mean?Readthemlikethis:
x>ymeans:xisgreaterthanyx<ymeans:xislessthanyx<=ymeans:xislessthanorequaltoyx>=ymeans:xisgreaterthanorequaltoy
Awesome!Wannadoonemore?Trythis:
command-line
>>>6>2and2<3True>>>3>2and2<1False>>>3>2or2<1True
YoucangivePythonasmanynumberstocompareasyouwant,anditwillgiveyouananswer!Prettysmart,right?
and–ifyouusetheandoperator,bothcomparisonshavetobeTrueinorderforthewholecommandtobeTrueor–ifyouusetheoroperator,onlyoneofthecomparisonshastobeTrueinorderforthewholecommandtobeTrue
Haveyouheardoftheexpression"comparingapplestooranges"?Let'strythePythonequivalent:
command-line
IntroductiontoPython
44
>>>1>'django'Traceback(mostrecentcalllast):File"<stdin>",line1,in<module>TypeError:'>'notsupportedbetweeninstancesof'int'and'str'
Hereyouseethatjustlikeintheexpression,Pythonisnotabletocompareanumber(int)andastring(str).Instead,itshowsaTypeErrorandtellsusthetwotypescan'tbecomparedtogether.
BooleanIncidentally,youjustlearnedaboutanewtypeofobjectinPython.It'scalledBoolean,anditisprobablytheeasiesttypethereis.
ThereareonlytwoBooleanobjects:
TrueFalse
ButforPythontounderstandthis,youneedtoalwayswriteitas'True'(firstletteruppercase,withtherestoftheletterslowercased).true,TRUE,andtRUEwon'twork–onlyTrueiscorrect.(Thesameappliesto'False'aswell,ofcourse.)
Booleanscanbevariables,too!Seehere:
command-line
>>>a=True>>>aTrue
Youcanalsodoitthisway:
command-line
>>>a=2>5>>>aFalse
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:
IntroductiontoPython
45
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.
NoteYoushouldnoticeoneofthecoolestthingaboutcodeeditors:colors!InthePythonconsole,everythingwasthesamecolor;nowyoushouldseethattheprintfunctionisadifferentcolorfromthestring.Thisiscalled"syntaxhighlighting",andit'sareallyusefulfeaturewhencoding.Thecolorofthingswillgiveyouhints,suchasunclosedstringsoratypoinakeywordname(likethedefinafunction,whichwe'llseebelow).Thisisoneofthereasonsweuseacodeeditor.:)
Withthefilesaved,it'stimetorunit!Usingtheskillsyou'velearnedinthecommandlinesection,usetheterminaltochangedirectoriestothedesktop.
Changedirectory:OSXOnaMac,thecommandwilllooksomethinglikethis:
command-line
$cd~/Desktop
Changedirectory:LinuxOnLinux,itwillbelikethis(theword"Desktop"mightbetranslatedtoyourlocallanguage):
command-line
$cd~/Desktop
Changedirectory:WindowsCommandPromptOnWindowsCommandPrompt,itwillbelikethis:
command-line
>cd%HomePath%\Desktop
IntroductiontoPython
46
Changedirectory:WindowsPowershellAndonWindowsPowershell,itwillbelikethis:
command-line
>cd$Home\Desktop
Ifyougetstuck,justaskforhelp.
NowusePythontoexecutethecodeinthefilelikethis:
command-line
$python3python_intro.pyHello,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:
Ifweweretosaveandrunthis,we'dseeanerrorlikethis:
command-line
$python3python_intro.pyFile"python_intro.py",line2^SyntaxError:unexpectedEOFwhileparsing
Pythonexpectsustogivefurtherinstructionstoitwhichareexecutedifthecondition3>2turnsouttobetrue(orTrueforthatmatter).Let’strytomakePythonprint“Itworks!”.Changeyourcodeinyourpython_intro.pyfiletothis:
python_intro.py
if3>2:print('Itworks!')
IntroductiontoPython
47
Noticehowwe'veindentedthenextlineofcodeby4spaces?WeneedtodothissoPythonknowswhatcodetoruniftheresultistrue.Youcandoonespace,butnearlyallPythonprogrammersdo4tomakethingslookneat.Asingletabwillalsocountas4spaces.
Saveitandgiveitanotherrun:
command-line
$python3python_intro.pyItworks!
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.py5isindeedgreaterthan2
If2wereagreaternumberthan5,thenthesecondcommandwouldbeexecuted.Easy,right?Let'sseehowelifworks:
python_intro.py
name='Sonja'ifname=='Ola':print('HeyOla!')elifname=='Sonja':print('HeySonja!')else:print('Heyanonymous!')
andexecuted:
command-line
$python3python_intro.pyHeySonja!
Seewhathappenedthere?elifletsyouaddextraconditionsthatrunifthepreviousconditionsfail.
Youcanaddasmanyelifstatementsasyoulikeafteryourinitialifstatement.Forexample:
python_intro.py
IntroductiontoPython
48
volume=57ifvolume<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.pyPerfect,Icanhearallthedetails
CommentsCommentsarelinesbeginningwith#.Youcanwritewhateveryouwantafterthe#andPythonwillignoreit.Commentscanmakeyourcodeeasierforotherpeopletounderstand.
Let'sseehowthatlooks:
python_intro.py
#Changethevolumeifit'stooloudortooquietifvolume<20orvolume>80:volume=50print("That'sbetter!")
Youdon'tneedtowriteacommentforeverylineofcode,buttheyareusefulforexplainingwhyyourcodeisdoingsomething,orprovidingasummarywhenit'sdoingsomethingcomplex.
Summary
Inthelastfewexercisesyoulearnedabout:
comparingthings–inPythonyoucancomparethingsbyusing>,>=,==,<=,<andtheand,oroperatorsBoolean–atypeofobjectthatcanonlyhaveoneoftwovalues:TrueorFalseSavingfiles–storingcodeinfilessoyoucanexecutelargerprograms.if…elif…else–statementsthatallowyoutoexecutecodeonlywhencertainconditionsaremet.comments-linesthatPythonwon'trunwhichletyoudocumentyourcode
Timeforthelastpartofthischapter!
Yourownfunctions!Forreadersathome:thispartiscoveredinthePythonBasics:Functionsvideo.
IntroductiontoPython
49
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.pyHithere!Howareyou?
Note:ifitdidn'twork,don'tpanic!Theoutputwillhelpyoutofigurewhy:
IfyougetaNameError,thatprobablymeansyoutypedsomethingwrong,soyoushouldcheckthatyouusedthesamenamewhencreatingthefunctionwithdefhi():andwhencallingitwithhi().IfyougetanIndentationError,checkthatbothoftheprintlineshavethesamewhitespaceatthestartofaline:pythonwantsallthecodeinsidethefunctiontobeneatlyaligned.Ifthere'snooutputatall,checkthatthelasthi()isn'tindented-ifitis,thatlinewillbecomepartofthefunctiontoo,anditwillnevergetrun.
Let'sbuildourfirstfunctionwithparameters.Wewillusethepreviousexample–afunctionthatsays'hi'tothepersonrunningit–withaname:
python_intro.py
defhi(name):
Asyoucansee,wenowgaveourfunctionaparameterthatwecalledname:
python_intro.py
defhi(name):ifname=='Ola':print('HiOla!')elifname=='Sonja':print('HiSonja!')else:print('Hianonymous!')
hi()
IntroductiontoPython
50
Remember:Theprintfunctionisindentedfourspaceswithintheifstatement.Thisisbecausethefunctionrunswhentheconditionismet.Let'sseehowitworksnow:
command-line
$python3python_intro.pyTraceback(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.pyHiOla!
Andifwechangethename?
python_intro.py
hi("Sonja")
Andrunit:
command-line
$python3python_intro.pyHiSonja!
Now,whatdoyouthinkwillhappenifyouwriteanothernameinthere?(NotOlaorSonja.)Giveitatryandseeifyou'reright.Itshouldprintoutthis:
command-line
Hianonymous!
Thisisawesome,right?Thiswayyoudon'thavetorepeatyourselfeverytimeyouwanttochangethenameofthepersonthefunctionissupposedtogreet.Andthat'sexactlywhyweneedfunctions–youneverwanttorepeatyourcode!
Let'sdosomethingsmarter–therearemorenamesthantwo,andwritingaconditionforeachwouldbehard,right?
python_intro.py
defhi(name):print('Hi'+name+'!')
IntroductiontoPython
51
hi("Rachel")
Let'scallthecodenow:
command-line
$python3python_intro.pyHiRachel!
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
$python3python_intro.pyHiRachel!NextgirlHiMonica!NextgirlHiPhoebe!
IntroductiontoPython
52
NextgirlHiOla!NextgirlHiYou!Nextgirl
Asyoucansee,everythingyouputinsideaforstatementwithanindentwillberepeatedforeveryelementofthelistgirls.
Youcanalsouseforonnumbersusingtherangefunction:
python_intro.py
foriinrange(1,6):print(i)
Whichwouldprint:
command-line
12345
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
53
IntroductiontoPython
54
WhatisDjango?Django(/ˈdʒæŋɡoʊ/jang-goh)isafreeandopensourcewebapplicationframework,writteninPython.Awebframeworkisasetofcomponentsthathelpsyoutodevelopwebsitesfasterandeasier.
Whenyou'rebuildingawebsite,youalwaysneedasimilarsetofcomponents:awaytohandleuserauthentication(signingup,signingin,signingout),amanagementpanelforyourwebsite,forms,awaytouploadfiles,etc.
Luckilyforyou,otherpeoplelongagonoticedthatwebdevelopersfacesimilarproblemswhenbuildinganewsite,sotheyteamedupandcreatedframeworks(Djangobeingoneofthem)thatgiveyouready-madecomponentstouse.
Frameworksexisttosaveyoufromhavingtoreinventthewheelandtohelpalleviatesomeoftheoverheadwhenyou’rebuildinganewsite.
Whydoyouneedaframework?TounderstandwhatDjangoisactuallyfor,weneedtotakeacloserlookattheservers.Thefirstthingisthattheserverneedstoknowthatyouwantittoserveyouawebpage.
Imagineamailbox(port)whichismonitoredforincomingletters(requests).Thisisdonebyawebserver.Thewebserverreadstheletterandthensendsaresponsewithawebpage.Butwhenyouwanttosendsomething,youneedtohavesomecontent.AndDjangoissomethingthathelpsyoucreatethecontent.
Whathappenswhensomeonerequestsawebsitefromyourserver?Whenarequestcomestoawebserver,it'spassedtoDjangowhichtriestofigureoutwhatisactuallyrequested.Ittakesawebpageaddressfirstandtriestofigureoutwhattodo.ThispartisdonebyDjango'surlresolver(notethatawebsiteaddressiscalledaURL–UniformResourceLocator–sothenameurlresolvermakessense).Itisnotverysmart–ittakesalistofpatternsandtriestomatchtheURL.Djangocheckspatternsfromtoptobottomandifsomethingismatched,thenDjangopassestherequesttotheassociatedfunction(whichiscalledview).
Imagineamailcarrierwithaletter.Sheiswalkingdownthestreetandcheckseachhousenumberagainsttheoneontheletter.Ifitmatches,sheputstheletterthere.Thisishowtheurlresolverworks!
Intheviewfunction,alltheinterestingthingsaredone:wecanlookatadatabasetolookforsomeinformation.Maybetheuseraskedtochangesomethinginthedata?Likealettersaying,"Pleasechangethedescriptionofmyjob."Theviewcancheckifyouareallowedtodothat,thenupdatethejobdescriptionforyouandsendbackamessage:"Done!"ThentheviewgeneratesaresponseandDjangocansendittotheuser'swebbrowser.
Ofcourse,thedescriptionaboveisalittlebitsimplified,butyoudon'tneedtoknowallthetechnicalthingsyet.Havingageneralideaisenough.
Soinsteadofdivingtoomuchintodetails,wewillsimplystartcreatingsomethingwithDjangoandwewilllearnalltheimportantpartsalongtheway!
WhatisDjango?
55
DjangoinstallationNoteIfyou'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
Virtualenvironment:WindowsTocreateanewvirtualenv,youneedtoopenthecommandpromptandrunpython-mvenvmyvenv.Itwilllooklikethis:
command-line
C:\Users\Name\djangogirls>python-mvenvmyvenv
Wheremyvenvisthenameofyourvirtualenv.Youcanuseanyothername,butsticktolowercaseandusenospaces,accentsorspecialcharacters.Itisalsogoodideatokeepthenameshort–you'llbereferencingitalot!
Djangoinstallation
56
Virtualenvironment:LinuxandOSXCreatingavirtualenvonbothLinuxandOSXisassimpleasrunningpython3-mvenvmyvenv.Itwilllooklikethis:
command-line
$python3-mvenvmyvenv
myvenvisthenameofyourvirtualenv.Youcanuseanyothername,butsticktolowercaseandusenospaces.Itisalsogoodideatokeepthenameshortasyou'llbereferencingitalot!
NOTE:OnsomeversionsofDebian/Ubuntuyoumayreceivethefollowingerror:
command-line
Thevirtualenvironmentwasnotcreatedsuccessfullybecauseensurepipisnotavailable.OnDebian/Ubuntusystems,youneedtoinstallthepython3-venvpackageusingthefollowingcommand.apt-getinstallpython3-venvYoumayneedtousesudowiththatcommand.Afterinstallingthepython3-venvpackage,recreateyourvirtualenvironment.
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.6myvenv
NOTE:Ifyougetanerrorlike
command-line
E:Unabletolocatepackagepython3-venv
theninsteadrun:
command-line
sudoaptinstallpython3.6-venv
Workingwithvirtualenv
Djangoinstallation
57
Thecommandabovewillcreateadirectorycalledmyvenv(orwhatevernameyouchose)thatcontainsourvirtualenvironment(basicallyabunchofdirectoryandfiles).
Workingwithvirtualenv:WindowsStartyourvirtualenvironmentbyrunning:
command-line
C:\Users\Name\djangogirls>myvenv\Scripts\activate
NOTE:onWindows10youmightgetanerrorintheWindowsPowerShellthatsaysexecutionofscriptsisdisabledonthissystem.Inthiscase,openanotherWindowsPowerShellwiththe"RunasAdministrator"option.Thentrytypingthefollowingcommandbeforestartingyourvirtualenvironment:
command-line
C:\WINDOWS\system32>Set-ExecutionPolicy-ExecutionPolicyRemoteSignedExecutionPolicyChangeTheexecutionpolicyhelpsprotectyoufromscriptsthatyoudonottrust.Changingtheexecutionpolicymightexposeyoutothesecurityrisksdescribedintheabout_Execution_Policieshelptopicathttp://go.microsoft.com/fwlink/?LinkID=135170.Doyouwanttochangetheexecutionpolicy?[Y]Yes[A]YestoAll[N]No[L]NotoAll[S]Suspend[?]Help(defaultis"N"):A
Workingwithvirtualenv: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:
command-line
(myvenv)~$pipinstall--upgradepip
Djangoinstallation
58
Thenrunpipinstalldjango~=1.11.0(notethatweuseatildefollowedbyanequalsign:~=)toinstallDjango.
command-line
(myvenv)~$pipinstalldjango~=1.11.0Collectingdjango~=1.11.0DownloadingDjango-1.11.3-py2.py3-none-any.whl(6.8MB)Installingcollectedpackages:djangoSuccessfullyinstalleddjango-1.11.3
InstallingDjango:WindowsIfyougetanerrorwhencallingpiponWindowsplatform,pleasecheckifyourprojectpathnamecontainsspaces,accentsorspecialcharacters(forexample,C:\Users\UserName\djangogirls).Ifitdoes,pleaseconsiderusinganotherplacewithoutspaces,accentsorspecialcharacters(suggestion:C:\djangogirls).Createanewvirtualenvinthenewdirectory,thendeletetheoldoneandtrytheabovecommandagain.(Movingthevirtualenvdirectorywon'tworksincevirtualenvusesabsolutepaths.)
InstallingDjango:Windows8andWindows10YourcommandlinemightfreezeafterwhenyoutrytoinstallDjango.Ifthishappens,insteadoftheabovecommanduse:
command-line
C:\Users\Name\djangogirls>python-mpipinstalldjango~=1.11.0
InstallingDjango:LinuxIfyougetanerrorwhencallingpiponUbuntu12.04pleaserunpython-mpipinstall-U--force-reinstallpiptofixthepipinstallationinthevirtualenv.
That'sit!You'renow(finally)readytocreateaDjangoapplication!
Djangoinstallation
59
YourfirstDjangoproject!PartofthischapterisbasedontutorialsbyGeekGirlsCarrots(https://github.com/ggcarrots/django-carrots).
Partsofthischapterarebasedonthedjango-marcadortutoriallicensedundertheCreativeCommonsAttribution-ShareAlike4.0InternationalLicense.Thedjango-marcadortutorialiscopyrightedbyMarkusZapke-Gründemannetal.
We'regoingtocreateasimpleblog!
ThefirststepistostartanewDjangoproject.Basically,thismeansthatwe'llrunsomescriptsprovidedbyDjangothatwillcreatetheskeletonofaDjangoprojectforus.Thisisjustabunchofdirectoriesandfilesthatwewilluselater.
ThenamesofsomefilesanddirectoriesareveryimportantforDjango.Youshouldnotrenamethefilesthatweareabouttocreate.Movingthemtoadifferentplaceisalsonotagoodidea.Djangoneedstomaintainacertainstructuretobeabletofindimportantthings.
Remembertoruneverythinginthevirtualenv.Ifyoudon'tseeaprefix(myvenv)inyourconsole,youneedtoactivateyourvirtualenv.WeexplainedhowtodothatintheDjangoinstallationchapterintheWorkingwithvirtualenvpart.Typingmyvenv\Scripts\activateonWindowsorsourcemyvenv/bin/activateonMacOSXorLinuxwilldothisforyou.
Createproject:OSXorLinuxInyourMacOSXorLinuxconsole,youshouldrunthefollowingcommand.Don'tforgettoaddtheperiod(ordot).attheend!
command-line
(myvenv)~/djangogirls$django-adminstartprojectmysite.
Theperiod.iscrucialbecauseittellsthescripttoinstallDjangoinyourcurrentdirectory(forwhichtheperiod.isashort-handreference).
NoteWhentypingthecommandabove,rememberthatyouonlytypethepartwhichstartsbydjango-admin.The(myvenv)~/djangogirls$partshownhereisjustexampleofthepromptthatwillbeinvitingyourinputonyourcommandline.
Createproject:WindowsOnWindowsyoushouldrunthefollowingcommand.(Don'tforgettoaddtheperiod(ordot).attheend):
command-line
(myvenv)C:\Users\Name\djangogirls>django-admin.exestartprojectmysite.
Theperiod.iscrucialbecauseittellsthescripttoinstallDjangoinyourcurrentdirectory(forwhichtheperiod.isashort-handreference).
NoteWhentypingthecommandabove,rememberthatyouonlytypethepartwhichstartsbydjango-admin.py.The(myvenv)C:\Users\Name\djangogirls>`partshownhereisjustexampleofthepromptthatwillbeinvitingyourinputonyourcommandline.
django-admin.pyisascriptthatwillcreatethedirectoriesandfilesforyou.Youshouldnowhaveadirectorystructurewhichlookslikethis:
djangogirls
YourfirstDjangoproject!
60
├───manage.py└───mysitesettings.pyurls.pywsgi.py__init__.py
Note:inyourdirectorystructure,youwillalsoseeyourvenvdirectorythatwecreatedbefore.
manage.pyisascriptthathelpswithmanagementofthesite.Withitwewillbeable(amongstotherthings)tostartawebserveronourcomputerwithoutinstallinganythingelse.
Thesettings.pyfilecontainstheconfigurationofyourwebsite.
Rememberwhenwetalkedaboutamailcarriercheckingwheretodeliveraletter?urls.pyfilecontainsalistofpatternsusedbyurlresolver.
Let'signoretheotherfilesfornowaswewon'tchangethem.Theonlythingtorememberisnottodeletethembyaccident!
ChangingsettingsLet'smakesomechangesinmysite/settings.py.Openthefileusingthecodeeditoryouinstalledearlier.
Note:Keepinmindthatsettings.pyisaregularfile,likeanyother.Youcanopenitfrominsidethecodeeditor,usingthe"file->open"menuactions.Thisshouldgetyoutheusualwindowinwhichyoucannavigatetoyoursettings.pyfileandselectit.Alternatively,youcanopenthefilebynavigatingtothedjangogirlsfolderonyourdesktopandright-clickingonit.Then,selectyourcodeeditorfromthelist.Selectingtheeditorisimportantasyoumighthaveotherprogramsinstalledthatcanopenthefilebutwillnotletyoueditit.
Itwouldbenicetohavethecorrecttimeonourwebsite.GotoWikipedia'slistoftimezonesandcopyyourrelevanttimezone(TZ)(e.g.Europe/Berlin).
Insettings.py,findthelinethatcontainsTIME_ZONEandmodifyittochooseyourowntimezone.Forexample:
mysite/settings.py
TIME_ZONE='Europe/Berlin'
Alanguagecodeconsistofthelanguage,e.g.enforenglishordeforgerman,andthecountrycode,e.g.deforgermanyorchforswitzerland.YouwillwanttoaddthisifyouwantthedefaultbuttonsandnotificationsfromDjangotobeinyourlanguage.Soyouwouldhave"Cancel"buttontranslatedintothelanguageyoudefinedhere.Djangocomeswithalotofpreparedtranslations.
Changethelanguagecodebychangingthefollowingline:
mysite/settings.py
LANGUAGE_CODE='de-ch'
We'llalsoneedtoaddapathforstaticfiles.(We'llfindoutallaboutstaticfilesandCSSlaterinthetutorial.)Godowntotheendofthefile,andjustunderneaththeSTATIC_URLentry,addanewonecalledSTATIC_ROOT:
mysite/settings.py
STATIC_URL='/static/'STATIC_ROOT=os.path.join(BASE_DIR,'static')
YourfirstDjangoproject!
61
WhenDEBUGisTrueandALLOWED_HOSTSisempty,thehostisvalidatedagainst['localhost','127.0.0.1','[::1]'].Thiswon'tmatchourhostnameonPythonAnywhereoncewedeployourapplicationsowewillchangethefollowingsetting:
mysite/settings.py
ALLOWED_HOSTS=['127.0.0.1','<your_username>.pythonanywhere.com']
Note:Ifyou'reusingaChromebook,addthislineatthebottomofyoursettings.pyfile:MESSAGE_STORAGE='django.contrib.messages.storage.session.SessionStorage'
Alsoadddjango-girls-<your_username>.c9users.iototheALLOWED_HOSTSifyouareusingcloud9
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
(myvenv)~/djangogirls$pythonmanage.pymigrateOperationstoperform:Applyallmigrations:auth,admin,contenttypes,sessionsRunningmigrations:Renderingmodelstates...DONEApplyingcontenttypes.0001_initial...OKApplyingauth.0001_initial...OKApplyingadmin.0001_initial...OKApplyingadmin.0002_logentry_remove_auto_add...OKApplyingcontenttypes.0002_remove_content_type_name...OKApplyingauth.0002_alter_permission_name_max_length...OKApplyingauth.0003_alter_user_email_max_length...OKApplyingauth.0004_alter_user_username_opts...OKApplyingauth.0005_alter_user_last_login_null...OKApplyingauth.0006_require_contenttypes_0002...OKApplyingauth.0007_alter_validators_add_error_messages...OKApplyingsessions.0001_initial...OK
Andwe'redone!Timetostartthewebserverandseeifourwebsiteisworking!
Startingthewebserver
YourfirstDjangoproject!
62
Youneedtobeinthedirectorythatcontainsthemanage.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)andenterthisaddress:
browser
http://127.0.0.1:8000/
Ifyou'reusingaChromebook,you'llalwaysvisityourtestserverbyaccessing:
browser
https://django-girls-<yourcloud9username>.c9users.io
Congratulations!You'vejustcreatedyourfirstwebsiteandrunitusingawebserver!Isn'tthatawesome?
Whilethewebserverisrunning,youwon'tseeanewcommand-lineprompttoenteradditionalcommands.Theterminalwillacceptnewtextbutwillnotexecutenewcommands.Thisisbecausethewebservercontinuouslyrunsinordertolistenforincomingrequests.
WereviewedhowwebserversworkintheHowtheInternetworkschapter.
Totypeadditionalcommandswhilethewebserverisrunning,openanewterminalwindowandactivateyourvirtualenv.Tostopthewebserver,switchbacktothewindowinwhichit'srunningandpressCTRL+C-ControlandCkeystogether(onWindows,youmighthavetopressCtrl+Break).
Readyforthenextstep?It'stimetocreatesomecontent!
YourfirstDjangoproject!
63
YourfirstDjangoproject!
64
DjangomodelsWhatwewanttocreatenowissomethingthatwillstoreallthepostsinourblog.Buttobeabletodothatweneedtotalkalittlebitaboutthingscalledobjects.
ObjectsThereisaconceptinprogrammingcalledobject-orientedprogramming.Theideaisthatinsteadofwritingeverythingasaboringsequenceofprogramminginstructions,wecanmodelthingsanddefinehowtheyinteractwitheachother.
Sowhatisanobject?Itisacollectionofpropertiesandactions.Itsoundsweird,butwewillgiveyouanexample.
Ifwewanttomodelacat,wewillcreateanobjectCatthathassomepropertiessuchascolor,age,mood(likegood,bad,orsleepy;)),andowner(whichcouldbeassignedaPersonobject–ormaybe,incaseofastraycat,thispropertycouldbeempty).
ThentheCathassomeactions:purr,scratch,orfeed(inwhichcase,wewillgivethecatsomeCatFood,whichcouldbeaseparateobjectwithproperties,liketaste).
Cat--------coloragemoodownerpurr()scratch()feed(cat_food)
CatFood--------taste
Sobasicallytheideaistodescriberealthingsincodewithproperties(calledobjectproperties)andactions(calledmethods).
Howwillwemodelblogpoststhen?Wewanttobuildablog,right?
Weneedtoanswerthequestion:Whatisablogpost?Whatpropertiesshouldithave?
Well,forsureourblogpostneedssometextwithitscontentandatitle,right?Itwouldbealsonicetoknowwhowroteit–soweneedanauthor.Finally,wewanttoknowwhenthepostwascreatedandpublished.
Post--------titletextauthorcreated_datepublished_date
Whatkindofthingscouldbedonewithablogpost?Itwouldbenicetohavesomemethodthatpublishesthepost,right?
Sowewillneedapublishmethod.
Djangomodels
65
Sincewealreadyknowwhatwewanttoachieve,let'sstartmodelingitinDjango!
DjangomodelKnowingwhatanobjectis,wecancreateaDjangomodelforourblogpost.
AmodelinDjangoisaspecialkindofobject–itissavedinthedatabase.Adatabaseisacollectionofdata.Thisisaplaceinwhichyouwillstoreinformationaboutusers,yourblogposts,etc.WewillbeusingaSQLitedatabasetostoreourdata.ThisisthedefaultDjangodatabaseadapter–it'llbeenoughforusrightnow.
Youcanthinkofamodelinthedatabaseasaspreadsheetwithcolumns(fields)androws(data).
Creatinganapplication
Tokeepeverythingtidy,wewillcreateaseparateapplicationinsideourproject.Itisverynicetohaveeverythingorganizedfromtheverybeginning.Tocreateanapplicationweneedtorunthefollowingcommandintheconsole(fromdjangogirlsdirectorywheremanage.pyfileis):
command-line
(myvenv)~/djangogirls$pythonmanage.pystartappblog
Youwillnoticethatanewblogdirectoryiscreatedanditcontainsanumberoffilesnow.Thedirectoriesandfilesinourprojectshouldlooklikethis:
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
Aftercreatinganapplication,wealsoneedtotellDjangothatitshoulduseit.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',]
Djangomodels
66
Creatingablogpostmodel
Intheblog/models.pyfilewedefineallobjectscalledModels–thisisaplaceinwhichwewilldefineourblogpost.
Let'sopenblog/models.py,removeeverythingfromit,andwritecodelikethis:
blog/models.py
fromdjango.dbimportmodelsfromdjango.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?Butdon'tworry–wewillexplainwhattheselinesmean!
Alllinesstartingwithfromorimportarelinesthataddsomebitsfromotherfiles.Soinsteadofcopyingandpastingthesamethingsineveryfile,wecanincludesomepartswithfrom...import....
classPost(models.Model):–thislinedefinesourmodel(itisanobject).
classisaspecialkeywordthatindicatesthatwearedefininganobject.Postisthenameofourmodel.Wecangiveitadifferentname(butwemustavoidspecialcharactersandwhitespace).Alwaysstartaclassnamewithanuppercaseletter.models.ModelmeansthatthePostisaDjangoModel,soDjangoknowsthatitshouldbesavedinthedatabase.
Nowwedefinethepropertiesweweretalkingabout:title,text,created_date,published_dateandauthor.Todothatweneedtodefinethetypeofeachfield(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.11/ref/models/fields/#field-types).
Whataboutdefpublish(self):?Thisisexactlythepublishmethodweweretalkingaboutbefore.defmeansthatthisisafunction/methodandpublishisthenameofthemethod.Youcanchangethenameofthemethodifyouwant.Thenamingruleisthatweuselowercaseandunderscoresinsteadofspaces.Forexample,amethodthatcalculatesaveragepricecouldbecalledcalculate_average_price.
Djangomodels
67
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!
Createtablesformodelsinyourdatabase
Thelaststephereistoaddournewmodeltoourdatabase.FirstwehavetomakeDjangoknowthatwehavesomechangesinourmodel.(Wehavejustcreatedit!)Gotoyourconsolewindowandtypepythonmanage.pymakemigrationsblog.Itwilllooklikethis:
command-line
(myvenv)~/djangogirls$pythonmanage.pymakemigrationsblogMigrationsfor'blog':blog/migrations/0001_initial.py:-CreatemodelPost
Note:Remembertosavethefilesyouedit.Otherwise,yourcomputerwillexecutethepreviousversionwhichmightgiveyouunexpectederrormessages.
Djangopreparedamigrationfileforusthatwenowhavetoapplytoourdatabase.Typepythonmanage.pymigrateblogandtheoutputshouldbeasfollows:
command-line
(myvenv)~/djangogirls$pythonmanage.pymigrateblogOperationstoperform:Applyallmigrations:blogRunningmigrations:Renderingmodelstates...DONEApplyingblog.0001_initial...OK
Hurray!OurPostmodelisnowinourdatabase!Itwouldbenicetoseeit,right?JumptothenextchaptertoseewhatyourPostlookslike!
Djangomodels
68
DjangoadminToadd,editanddeletethepostswe'vejustmodeled,wewilluseDjangoadmin.
Let'sopentheblog/admin.pyfileandreplaceitscontentswiththis:
blog/admin.py
fromdjango.contribimportadminfrom.modelsimportPost
admin.site.register(Post)
Asyoucansee,weimport(include)thePostmodeldefinedinthepreviouschapter.Tomakeourmodelvisibleontheadminpage,weneedtoregisterthemodelwithadmin.site.register(Post).
OK,timetolookatourPostmodel.Remembertorunpythonmanage.pyrunserverintheconsoletorunthewebserver.Gotoyourbrowserandtypetheaddresshttp://127.0.0.1:8000/admin/.Youwillseealoginpagelikethis:
Tologin,youneedtocreateasuperuser-auseraccountthathascontrolovereverythingonthesite.Gobacktothecommandline,typepythonmanage.pycreatesuperuser,andpressenter.
Remember,towritenewcommandswhilethewebserverisrunning,openanewterminalwindowandactivateyourvirtualenv.WereviewedhowtowritenewcommandsintheYourfirstDjangoproject!chapter,intheStartingthewebserversection.
Whenprompted,typeyourusername(lowercase,nospaces),emailaddress,andpassword.Don'tworrythatyoucan'tseethepasswordyou'retypingin–that'showit'ssupposedtobe.Justtypeitinandpressentertocontinue.Theoutputshouldlooklikethis(wheretheusernameandemailshouldbeyourownones):
command-line
(myvenv)~/djangogirls$pythonmanage.pycreatesuperuserUsername:adminEmailaddress:[email protected]:Password(again):
Djangoadmin
69
Superusercreatedsuccessfully.
Returntoyourbrowser.Loginwiththesuperuser'scredentialsyouchose;youshouldseetheDjangoadmindashboard.
GotoPostsandexperimentalittlebitwithit.Addfiveorsixblogposts.Don'tworryaboutthecontent–youcansimplycopy-pastesometextfromthistutorialtosavetime.:)
Makesurethatatleasttwoorthreeposts(butnotall)havethepublishdateset.Itwillbehelpfullater.
IfyouwanttoknowmoreaboutDjangoadmin,youshouldcheckDjango'sdocumentation:https://docs.djangoproject.com/en/1.11/ref/contrib/admin/
Thisisprobablyagoodmomenttograbacoffee(ortea)orsomethingtoeattore-energizeyourself.YoucreatedyourfirstDjangomodel–youdeservealittlebreak!
Djangoadmin
70
Djangoadmin
71
Deploy!NoteThefollowingchaptercanbesometimesabithardtogetthrough.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.
GitNoteIfyoualreadydidtheInstallationsteps,there'snoneedtodothisagain–youcanskiptothenextsectionandstartcreatingyourGitrepository.
Gitisa"versioncontrolsystem"usedbyalotofprogrammers.Thissoftwarecantrackchangestofilesovertimesothatyoucanrecallspecificversionslater.Abitlikethe"trackchanges"featureinMicrosoftWord,butmuchmorepowerful.
InstallingGitInstallingGit:WindowsYoucandownloadGitfromgit-scm.com.Youcanhit"next"onallstepsexceptforone;inthefifthstepentitled"AdjustingyourPATHenvironment",choose"UseGitandoptionalUnixtoolsfromtheWindowsCommandPrompt"(thebottomoption).Otherthanthat,thedefaultsarefine.CheckoutWindows-style,commitUnix-stylelineendingsisgood.
Donotforgettorestartthecommandpromptorpowershellaftertheinstallationfinishedsuccessfully.
InstallingGit:OSXDownloadGitfromgit-scm.comandjustfollowtheinstructions.
NoteIfyouarerunningOSX10.6,10.7,or10.8,youwillneedtoinstalltheversionofgitfromhere:GitinstallerforOSXSnowLeopard
InstallingGit:DebianorUbuntu
command-line
$sudoapt-getinstallgit
Deploy!
72
InstallingGit:Fedora
command-line
$sudodnfinstallgit
InstallingGit:openSUSE
command-line
$sudozypperinstallgit
StartingourGitrepositoryGittrackschangestoaparticularsetoffilesinwhat'scalledacoderepository(or"repo"forshort).Let'sstartoneforourproject.Openupyourconsoleandrunthesecommands,inthedjangogirlsdirectory:
NoteCheckyourcurrentworkingdirectorywithapwd(MacOSX/Linux)orcd(Windows)commandbeforeinitializingtherepository.Youshouldbeinthedjangogirlsfolder.
command-line
$gitinitInitializedemptyGitrepositoryin~/djangogirls/.git/$gitconfig--globaluser.name"YourName"[email protected]
Initializingthegitrepositoryissomethingweneedtodoonlyonceperproject(andyouwon'thavetore-entertheusernameandemaileveragain).
Gitwilltrackchangestoallthefilesandfoldersinthisdirectory,buttherearesomefileswewantittoignore.Wedothisbycreatingafilecalled.gitignoreinthebasedirectory.Openupyoureditorandcreateanewfilewiththefollowingcontents:
.gitignore
*.pyc*~__pycache__myvenvdb.sqlite3/static.DS_Store
Andsaveitas.gitignoreinthe"djangogirls"folder.
NoteThedotatthebeginningofthefilenameisimportant!Ifyou'rehavinganydifficultycreatingit(Macsdon'tlikeyoutocreatefilesthatbeginwithadotviatheFinder,forexample),thenusethe"SaveAs"featureinyoureditor;it'sbulletproof.
NoteOneofthefilesyouspecifiedinyour.gitignorefileisdb.sqlite3.Thatfileisyourlocaldatabase,whereallofyourpostsarestored.Wedon'twanttoaddthistoyourrepositorybecauseyourwebsiteonPythonAnywhereisgoingtobeusingadifferentdatabase.ThatdatabasecouldbeSQLite,likeyourdevelopmentmachine,butusuallyyouwilluseonecalledMySQLwhichcandealwithalotmoresitevisitorsthanSQLite.Eitherway,byignoringyourSQLitedatabasefortheGitHubcopy,itmeansthatalloftheposts
Deploy!
73
youcreatedsofararegoingtostayandonlybeavailablelocally,butyou'regoingtohavetoaddthemagainonproduction.Youshouldthinkofyourlocaldatabaseasagoodplaygroundwhereyoucantestdifferentthingsandnotbeafraidthatyou'regoingtodeleteyourrealpostsfromyourblog.
It'sagoodideatouseagitstatuscommandbeforegitaddorwheneveryoufindyourselfunsureofwhathaschanged.Thiswillhelppreventanysurprisesfromhappening,suchaswrongfilesbeingaddedorcommitted.Thegitstatuscommandreturnsinformationaboutanyuntracked/modified/stagedfiles,thebranchstatus,andmuchmore.Theoutputshouldbesimilartothefollowing:
command-line
$gitstatusOnbranchmaster
Initialcommit
Untrackedfiles:(use"gitadd<file>..."toincludeinwhatwillbecommitted)
.gitignoreblog/manage.pymysite/
nothingaddedtocommitbutuntrackedfilespresent(use"gitadd"totrack)
Andfinallywesaveourchanges.Gotoyourconsoleandrunthesecommands:
command-line
$gitadd--all.$gitcommit-m"MyDjangoGirlsapp,firstcommit"[...]13fileschanged,200insertions(+)createmode100644.gitignore[...]createmode100644mysite/wsgi.py
PushingyourcodetoGitHubGotoGitHub.comandsignupforanew,freeuseraccount.(Ifyoualreadydidthatintheworkshopprep,thatisgreat!)
Then,createanewrepository,givingitthename"my-first-blog".Leavethe"initializewithaREADME"checkboxunchecked,leavethe.gitignoreoptionblank(we'vedonethatmanually)andleavetheLicenseasNone.
Deploy!
74
NoteThenamemy-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!
75
$gitremoteaddoriginhttps://github.com/<your-github-username>/my-first-blog.git$gitpush-uoriginmaster
EnteryourGitHubusernameandpasswordandyoushouldseesomethinglikethis:
command-line
Usernamefor'https://github.com':hjwpPasswordfor'https://[email protected]':Countingobjects:6,done.Writingobjects:100%(6/6),200bytes|0bytes/s,done.Total3(delta0),reused0(delta0)Tohttps://github.com/hjwp/my-first-blog.git*[newbranch]master->masterBranchmastersetuptotrackremotebranchmasterfromorigin.
YourcodeisnowonGitHub.Goandcheckitout!You'llfindit'sinfinecompany–Django,theDjangoGirlsTutorial,andmanyothergreatopensourcesoftwareprojectsalsohosttheircodeonGitHub.:)
SettingupourblogonPythonAnywhereNoteYoumighthavealreadycreatedaPythonAnywhereaccountearlierduringtheinstallsteps–ifso,noneedtodoitagain.
Nextit'stimetosignupforafree"Beginner"accountonPythonAnywhere.
www.pythonanywhere.com
NoteWhenchoosingyourusernamehere,bearinmindthatyourblog'sURLwilltaketheformyourusername.pythonanywhere.com,sochooseeitheryourownnickname,oranameforwhatyourblogisallabout.
PullingourcodedownonPythonAnywhereWhenyou'vesignedupforPythonAnywhere,you'llbetakentoyourdashboardor"Consoles"page.Choosetheoptiontostarta"Bash"console–that'sthePythonAnywhereversionofaconsole,justliketheoneonyourcomputer.
NotePythonAnywhereisbasedonLinux,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:
Deploy!
76
PythonAnywherecommand-line
$treemy-first-blogmy-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
CreatingavirtualenvonPythonAnywhere
Justlikeyoudidonyourowncomputer,youcancreateavirtualenvonPythonAnywhere.IntheBashconsole,type:
PythonAnywherecommand-line
$cdmy-first-blog
$virtualenv--python=python3.6myvenvRunningvirtualenvwithinterpreter/usr/bin/python3.6[...]Installingsetuptools,pip...done.
$sourcemyvenv/bin/activate
(myvenv)$pipinstalldjango~=1.11.0Collectingdjango[...]Successfullyinstalleddjango-1.11.3
NoteThepipinstallstepcantakeacoupleofminutes.Patience,patience!Butifittakesmorethanfiveminutes,somethingiswrong.Askyourcoach.
CreatingthedatabaseonPythonAnywhere
Here'sanotherthingthat'sdifferentbetweenyourowncomputerandtheserver:itusesadifferentdatabase.Sotheuseraccountsandpostscanbedifferentontheserverandonyourcomputer.
Justaswedidonyourowncomputer,werepeatthesteptoinitializethedatabaseontheserver,withmigrateandcreatesuperuser:
PythonAnywherecommand-line
(mvenv)$pythonmanage.pymigrateOperationstoperform:[...]Applyingsessions.0001_initial...OK(mvenv)$pythonmanage.pycreatesuperuser
Deploy!
77
PublishingourblogasawebappNowourcodeisonPythonAnywhere,ourvirtualenvisready,andthedatabaseisinitialized.We'rereadytopublishitasawebapp!
ClickbacktothePythonAnywheredashboardbyclickingonitslogo,andthenclickontheWebtab.Finally,hitAddanewwebapp.
Afterconfirmingyourdomainname,choosemanualconfiguration(N.B.–notthe"Django"option)inthedialog.NextchoosePython3.6,andclickNexttofinishthewizard.
NoteMakesureyouchoosethe"Manualconfiguration"option,notthe"Django"one.We'retoocoolforthedefaultPythonAnywhereDjangosetup.;-)
Settingthevirtualenv
You'llbetakentothePythonAnywhereconfigscreenforyourwebapp,whichiswhereyou'llneedtogowheneveryouwanttomakechangestotheappontheserver.
Inthe"Virtualenv"section,clicktheredtextthatsays"Enterthepathtoavirtualenv",andenter/home/<your-PythonAnywhere-username>/my-first-blog/myvenv/.Clicktheblueboxwiththecheckmarktosavethepathbeforemovingon.
NoteSubstituteyourownPythonAnywhereusernameasappropriate.Ifyoumakeamistake,PythonAnywherewillshowyoualittlewarning.
ConfiguringtheWSGIfile
Djangoworksusingthe"WSGIprotocol",astandardforservingwebsitesusingPython,whichPythonAnywheresupports.ThewayweconfigurePythonAnywheretorecognizeourDjangoblogisbyeditingaWSGIconfigurationfile.
Deploy!
78
Clickonthe"WSGIconfigurationfile"link(inthe"Code"sectionnearthetopofthepage–it'llbenamedsomethinglike/var/www/<your-PythonAnywhere-username>_pythonanywhere_com_wsgi.py),andyou'llbetakentoaneditor.
Deleteallthecontentsandreplacethemwiththefollowing:
<your-username>_pythonanywhere_com_wsgi.py
importosimportsys
path=os.path.expanduser('~/my-first-blog')ifpathnotinsys.path:sys.path.append(path)
os.environ['DJANGO_SETTINGS_MODULE']='mysite.settings'
fromdjango.core.wsgiimportget_wsgi_applicationfromdjango.contrib.staticfiles.handlersimportStaticFilesHandlerapplication=StaticFilesHandler(get_wsgi_application())
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.6.
TherearealsosomegeneraldebuggingtipsonthePythonAnywherewiki.
Andremember,yourcoachisheretohelp!
Youarelive!Thedefaultpageforyoursiteshouldsay"Itworked!",justlikeitdoesonyourlocalcomputer.Tryadding/admin/totheendoftheURL,andyou'llbetakentotheadminsite.Loginwiththeusernameandpassword,andyou'llseeyoucanaddnewPostsontheserver.
Deploy!
79
Onceyouhaveafewpostscreated,youcangobacktoyourlocalsetup(notPythonAnywhere).Fromhereyoushouldworkonyourlocalsetuptomakechanges.Thisisacommonworkflowinwebdevelopment–makechangeslocally,pushthosechangestoGitHub,andpullyourchangesdowntoyourliveWebserver.ThisallowsyoutoworkandexperimentwithoutbreakingyourliveWebsite.Prettycool,huh?
GiveyourselfaHUGEpatontheback!Serverdeploymentsareoneofthetrickiestpartsofwebdevelopmentanditoftentakespeopleseveraldaysbeforetheygetthemworking.Butyou'vegotyoursitelive,ontherealInternet,justlikethat!
Deploy!
80
DjangoURLsWe'reabouttobuildourfirstwebpage:ahomepageforyourblog!Butfirst,let'slearnalittlebitaboutDjangoURLs.
WhatisaURL?AURLissimplyawebaddress.YoucanseeaURLeverytimeyouvisitawebsite–itisvisibleinyourbrowser'saddressbar.(Yes!127.0.0.1:8000isaURL!Andhttps://djangogirls.orgisalsoaURL.)
EverypageontheInternetneedsitsownURL.ThiswayyourapplicationknowswhatitshouldshowtoauserwhoopensthatURL.InDjangoweusesomethingcalledURLconf(URLconfiguration).URLconfisasetofpatternsthatDjangowilltrytomatchwiththerequestedURLtofindthecorrectview.
HowdoURLsworkinDjango?Let'sopenupthemysite/urls.pyfileinyourcodeeditorofchoiceandseewhatitlookslike:
mysite/urls.py
"""mysiteURLConfiguration
[...]"""fromdjango.conf.urlsimporturlfromdjango.contribimportadmin
urlpatterns=[url(r'^admin/',admin.site.urls),]
Asyoucansee,Djangohasalreadyputsomethinghereforus.
Linesbetweentriplequotes('''or""")arecalleddocstrings–youcanwritethematthetopofafile,classormethodtodescribewhatitdoes.Theywon'tberunbyPython.
TheadminURL,whichyouvisitedinpreviouschapter,isalreadyhere:
mysite/urls.py
url(r'^admin/',admin.site.urls),
ThislinemeansthatforeveryURLthatstartswithadmin/,Djangowillfindacorrespondingview.Inthiscasewe'reincludingalotofadminURLssoitisn'tallpackedintothissmallfile–it'smorereadableandcleaner.
Djangourls
81
RegexDoyouwonderhowDjangomatchesURLstoviews?Well,thispartistricky.Djangousesregex,shortfor"regularexpressions".Regexhasalot(alot!)ofrulesthatformasearchpattern.Sinceregexesareanadvancedtopic,wewillnotgoindetailoverhowtheywork.
Ifyoustillwishtounderstandhowwecreatedthepatterns,hereisanexampleoftheprocess–wewillonlyneedalimitedsubsetoftherulestoexpressthepatternwearelookingfor,namely:
forthebeginningofthetext$fortheendofthetext\dforadigit+toindicatethatthepreviousitemshouldberepeatedatleastonce()tocapturepartofthepattern
AnythingelseintheURLdefinitionwillbetakenliterally.
Nowimagineyouhaveawebsitewiththeaddresslikehttp://www.mysite.com/post/12345/,where12345isthenumberofyourpost.
Writingseparateviewsforallthepostnumberswouldbereallyannoying.Withregularexpressions,wecancreateapatternthatwillmatchtheURLandextractthenumberforus: post/(\d+)/$.Let'sbreakthisdownpiecebypiecetoseewhatwearedoinghere:
^post/istellingDjangototakeanythingthathaspost/atthebeginningoftheurl(rightafter )(\d+)meansthattherewillbeanumber(oneormoredigits)andthatwewantthenumbercapturedandextracted/tellsdjangothatanother/charactershouldfollow$thenindicatestheendoftheURLmeaningthatonlystringsendingwiththe/willmatchthispattern
YourfirstDjangoURL!TimetocreateourfirstURL!Wewant'http://127.0.0.1:8000/'tobethehomepageofourblogandtodisplayalistofposts.
Wealsowanttokeepthemysite/urls.pyfileclean,sowewillimportURLsfromourblogapplicationtothemainmysite/urls.pyfile.
Goahead,addalinethatwillimportblog.urls.Notethatweareusingtheincludefunctionheresoyouwillneedtoaddthattotheimportonthefirstlineofthefile.
Yourmysite/urls.pyfileshouldnowlooklikethis:
mysite/urls.py
fromdjango.conf.urlsimportinclude,urlfromdjango.contribimportadmin
urlpatterns=[url(r'^admin/',admin.site.urls),url(r'',include('blog.urls')),]
Djangowillnowredirecteverythingthatcomesinto'http://127.0.0.1:8000/'toblog.urlsandlookforfurtherinstructionsthere.
WritingregularexpressionsinPythonisalwaysdonewithrinfrontofthestring.ThisisahelpfulhintforPythonthatthestringmaycontainspecialcharactersthatarenotmeantforPythonitself,butfortheregularexpressioninstead.
Djangourls
82
blog.urlsCreateanewemptyfilenamedurls.pyintheblogdirectory.Allright!Addthesefirsttwolines:
blog/urls.py
fromdjango.conf.urlsimporturlfrom.importviews
Herewe'reimportingDjango'sfunctionurlandallofourviewsfromtheblogapplication.(Wedon'thaveanyyet,butwewillgettothatinaminute!)
Afterthat,wecanaddourfirstURLpattern:
blog/urls.py
urlpatterns=[url(r'^$',views.post_list,name='post_list'),]
Asyoucansee,we'renowassigningaviewcalledpost_listtothe $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.
Thelastpart,name='post_list',isthenameoftheURLthatwillbeusedtoidentifytheview.Thiscanbethesameasthenameoftheviewbutitcanalsobesomethingcompletelydifferent.WewillbeusingthenamedURLslaterintheproject,soitisimportanttonameeachURLintheapp.WeshouldalsotrytokeepthenamesofURLsuniqueandeasytoremember.
Ifyoutrytovisithttp://127.0.0.1:8000/now,thenyou'llfindsomesortof'webpagenotavailable'message.Thisisbecausetheserver(remembertypingrunserver?)isnolongerrunning.Takealookatyourserverconsolewindowtofindoutwhy.
Yourconsoleisshowinganerror,butdon'tworry–it'sactuallyprettyuseful:It'stellingyouthatthereisnoattribute'post_list'.That'sthenameoftheviewthatDjangoistryingtofindanduse,butwehaven'tcreatedityet.Atthisstageyour/admin/willalsonotwork.Noworries–wewillgetthere.
IfyouwanttoknowmoreaboutDjangoURLconfs,lookattheofficialdocumentation:https://docs.djangoproject.com/en/1.11/topics/http/urls/
Djangourls
83
Djangourls
84
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#arecomments–thismeansthatthoselineswon'tberunbyPython.
Let'screateaviewasthecommentsuggests.Addthefollowingminimalviewbelowit:
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/andseewhatwe'vegot.
Anothererror!Readwhat'sgoingonnow:
Djangoviews–timetocreate!
85
Thisshowsthattheserverisrunningagain,atleast,butitstilldoesn'tlookright,doesit?Don'tworry,it'sjustanerrorpage,nothingtobescaredof!Justliketheerrormessagesintheconsole,theseareactuallyprettyuseful.YoucanreadthattheTemplateDoesNotExist.Let'sfixthisbugandcreateatemplateinthenextchapter!
LearnmoreaboutDjangoviewsbyreadingtheofficialdocumentation:https://docs.djangoproject.com/en/1.11/topics/http/views/
Djangoviews–timetocreate!
86
IntroductiontoHTMLWhat'satemplate,youmayask?
Atemplateisafilethatwecanre-usetopresentdifferentinformationinaconsistentformat–forexample,youcoulduseatemplatetohelpyouwritealetter,becausealthougheachlettermightcontainadifferentmessageandbeaddressedtoadifferentperson,theywillsharethesameformat.
ADjangotemplate'sformatisdescribedinalanguagecalledHTML(that'stheHTMLwementionedinthefirstchapter,HowtheInternetworks).
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(ControlandCkeystogether)andstartitagainbyrunningapythonmanage.pyrunservercommand.
IntroductiontoHTML
87
Noerroranymore!Congratulations:)However,yourwebsiteisn'tactuallypublishinganythingexceptanemptypage,becauseyourtemplateisemptytoo.Weneedtofixthat.
Addthefollowingtoyourtemplatefile:
blog/templates/blog/post_list.html
<html><p>Hithere!</p><p>Itworks!</p></html>
Sohowdoesyourwebsitelooknow?Visitittofindout:http://127.0.0.1:8000/
Itworked!Niceworkthere:)
Themostbasictag,<html>,isalwaysthebeginningofanywebpageand</html>isalwaystheend.Asyoucansee,thewholecontentofthewebsitegoesbetweenthebeginningtag<html>andclosingtag</html><p>isatagforparagraphelements;</p>closeseachparagraph
HeadandbodyEachHTMLpageisalsodividedintotwoelements:headandbody.
headisanelementthatcontainsinformationaboutthedocumentthatisnotdisplayedonthescreen.
bodyisanelementthatcontainseverythingelsethatisdisplayedaspartofthewebpage.
Weuse<head>totellthebrowserabouttheconfigurationofthepage,and<body>totellitwhat'sactuallyonthepage.
IntroductiontoHTML
88
Forexample,youcanputawebpagetitleelementinsidethe<head>,likethis:
blog/templates/blog/post_list.html
<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,copyandpasteitintoblog/templates/blog/post_list.html:
blog/templates/blog/post_list.html
IntroductiontoHTML
89
<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.Donecidelitnonmiportagravidaategetmetus.Fuscedapibus,tellusaccursuscommodo,tortormauriscondimentumnibh,utfermentummassajustositametrisus.</p></div>
<div><p>published:14.06.2014,12:14</p><h2><ahref="">Mysecondpost</a></h2><p>Aeneaneuleoquam.Pellentesqueornaresemlaciniaquamvenenatisvestibulum.Donecidelitnonmiportagravidaategetmetus.Fuscedapibus,tellusaccursuscommodo,tortormauriscondimentumnibh,utf.</p></div></body></html>
We'vecreatedthreedivsectionshere.
Thefirstdivelementcontainsthetitleofourblog–it'saheadingandalinkAnothertwodivelementscontainourblogpostswithapublisheddate,h2withaposttitlethatisclickableandtwops(paragraph)oftext,oneforthedateandoneforourblogpost.
Itgivesusthiseffect:
IntroductiontoHTML
90
Yaaay!Butsofar,ourtemplateonlyeverdisplaysexactlythesameinformation–whereasearlierweweretalkingabouttemplatesasallowingustodisplaydifferentinformationinthesameformat.
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
IntroductiontoHTML
91
OpenupthePythonAnywhereconsolespageandgotoyourBashconsole(orstartanewone).Then,run:
command-line
$cd~/my-first-blog$gitpull[...]
Andwatchyourcodegetdownloaded.Ifyouwanttocheckthatit'sarrived,youcanhopovertotheFilestabandviewyourcodeonPythonAnywhere.
Finally,hoponovertotheWebtabandhitReloadonyourwebapp.
Yourupdateshouldbelive!Goaheadandrefreshyourwebsiteinthebrowser.Changesshouldbevisible.:)
IntroductiontoHTML
92
DjangoORMandQuerySetsInthischapteryou'lllearnhowDjangoconnectstothedatabaseandstoresdatainit.Let'sdivein!
WhatisaQuerySet?AQuerySetis,inessence,alistofobjectsofagivenModel.QuerySetsallowyoutoreadthedatafromthedatabase,filteritandorderit.
It'seasiesttolearnbyexample.Let'strythis,shallwe?
DjangoshellOpenupyourlocalconsole(notonPythonAnywhere)andtypethiscommand:
command-line
(myvenv)~/djangogirls$pythonmanage.pyshell
Theeffectshouldbelikethis:
command-line
(InteractiveConsole)>>>
You'renowinDjango'sinteractiveconsole.It'sjustlikethePythonprompt,butwithsomeadditionalDjangomagic.:)YoucanuseallthePythoncommandsheretoo,ofcourse.
Allobjects
Let'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:weimportthemodelPostfromblog.models.Let'strydisplayingallpostsagain:
command-line
>>>Post.objects.all()<QuerySet[<Post:myposttitle>,<Post:anotherposttitle>]>
DjangoORM(Querysets)
93
Thisisalistofthepostswecreatedearlier!WecreatedthesepostsusingtheDjangoadmininterface.ButnowwewanttocreatenewpostsusingPython,sohowdowedothat?
Createobject
ThisishowyoucreateanewPostobjectindatabase:
command-line
>>>Post.objects.create(author=me,title='Sampletitle',text='Test')
Butwehaveonemissingingredienthere:me.WeneedtopassaninstanceofUsermodelasanauthor.Howdowedothat?
Let'simportUsermodelfirst:
command-line
>>>fromdjango.contrib.auth.modelsimportUser
Whatusersdowehaveinourdatabase?Trythis:
command-line
>>>User.objects.all()<QuerySet[<User:ola>]>
Thisisthesuperuserwecreatedearlier!Let'sgetaninstanceoftheusernow:
command-line
>>>me=User.objects.get(username='ola')
Asyoucansee,wenowgetaUserwithausernamethatequals'ola'.Neat!Ofcourse,youhavetoadjustthislinetouseyourownusername.
Nowwecanfinallycreateourpost:
command-line
>>>Post.objects.create(author=me,title='Sampletitle',text='Test')
Hurray!Wannacheckifitworked?
command-line
>>>Post.objects.all()<QuerySet[<Post:myposttitle>,<Post:anotherposttitle>,<Post:Sampletitle>]>
Thereitis,onemorepostinthelist!
Addmoreposts
DjangoORM(Querysets)
94
Youcannowhavealittlefunandaddmorepoststoseehowitworks.Addtwoorthreemoreandthengoaheadtothenextpart.
Filterobjects
AbigpartofQuerySetsistheabilitytofilterthem.Let'ssaywewanttofindallpoststhatuserolaauthored.WewillusefilterinsteadofallinPost.objects.all().Inparentheseswestatewhatcondition(s)ablogpostneedstomeettoendupinourqueryset.Inourcase,theconditionisthatauthorshouldbeequaltome.ThewaytowriteitinDjangoisauthor=me.Nowourpieceofcodelookslikethis:
command-line
>>>Post.objects.filter(author=me)[<Post:Sampletitle>,<Post:Postnumber2>,<Post:My3rdpost!>,<Post:4thtitleofpost>]
Ormaybewewanttoseeallthepoststhatcontaintheword'title'inthetitlefield?
command-line
>>>Post.objects.filter(title__contains='title')[<Post:Sampletitle>,<Post:4thtitleofpost>]
Therearetwounderscorecharacters(_)betweentitleandcontains.Django'sORMusesthisruletoseparatefieldnames("title")andoperationsorfilters("contains").Ifyouuseonlyoneunderscore,you'llgetanerrorlike"FieldError:Cannotresolvekeywordtitle_contains".
Youcanalsogetalistofallpublishedposts.Wedothisbyfilteringallthepoststhathavepublished_datesetinthepast:
command-line
>>>fromdjango.utilsimporttimezone>>>Post.objects.filter(published_date__lte=timezone.now())[]
Unfortunately,thepostweaddedfromthePythonconsoleisnotpublishedyet.Butwecanchangethat!Firstgetaninstanceofapostwewanttopublish:
command-line
>>>post=Post.objects.get(title="Sampletitle")
Andthenpublishitwithourpublishmethod:
command-line
>>>post.publish()
Nowtrytogetlistofpublishedpostsagain(presstheuparrowkeythreetimesandhitenter):
command-line
>>>Post.objects.filter(published_date__lte=timezone.now())[<Post:Sampletitle>]
DjangoORM(Querysets)
95
Orderingobjects
QuerySetsalsoallowyoutoorderthelistofobjects.Let'strytoorderthembycreated_datefield:
command-line
>>>Post.objects.order_by('created_date')[<Post:Sampletitle>,<Post:Postnumber2>,<Post:My3rdpost!>,<Post:4thtitleofpost>]
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)
96
DynamicdataintemplatesWehavedifferentpiecesinplace:thePostmodelisdefinedinmodels.py,wehavepost_listinviews.pyandthetemplateadded.ButhowwillweactuallymakeourpostsappearinourHTMLtemplate?Becausethatiswhatwewanttodo–takesomecontent(modelssavedinthedatabase)anddisplayitnicelyinourtemplate,right?
Thisisexactlywhatviewsaresupposedtodo:connectmodelsandtemplates.Inourpost_listviewwewillneedtotakethemodelswewanttodisplayandpassthemtothetemplate.Inaviewwedecidewhat(model)willbedisplayedinatemplate.
OK,sohowwillweachievethis?
Weneedtoopenourblog/views.py.Sofarpost_listviewlookslikethis:
blog/views.py
fromdjango.shortcutsimportrender
defpost_list(request):returnrender(request,'blog/post_list.html',{})
Rememberwhenwetalkedaboutincludingcodewrittenindifferentfiles?Nowisthemomentwhenwehavetoincludethemodelwehavewritteninmodels.py.Wewilladdthelinefrom.modelsimportPostlikethis:
blog/views.py
fromdjango.shortcutsimportrenderfrom.modelsimportPost
Thedotbeforemodelsmeanscurrentdirectoryorcurrentapplication.Bothviews.pyandmodels.pyareinthesamedirectory.Thismeanswecanuse.andthenameofthefile(without.py).Thenweimportthenameofthemodel(Post).
Butwhat'snext?TotakeactualblogpostsfromthePostmodelweneedsomethingcalledQuerySet.
QuerySetYoushouldalreadybefamiliarwithhowQuerySetswork.WetalkedabouttheminDjangoORM(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),butdon'tforgettofirstaddfromdjango.utilsimporttimezone:
blog/views.py
fromdjango.shortcutsimportrenderfromdjango.utilsimporttimezonefrom.modelsimportPost
Dynamicdataintemplates
97
defpost_list(request):posts=Post.objects.filter(published_date__lte=timezone.now()).order_by('published_date')returnrender(request,'blog/post_list.html',{})
ThelastmissingpartispassingthepostsQuerySettothetemplatecontext.Don'tworry–wewillcoverhowtodisplayitinalaterchapter.
PleasenotethatwecreateavariableforourQuerySet:posts.TreatthisasthenameofourQuerySet.Fromnowonwecanrefertoitbythisname.
Intherenderfunctionwehaveoneparameterrequest(everythingwereceivefromtheuserviatheInternet)andanothergivingthetemplatefile('blog/post_list.html').Thelastparameter,{},isaplaceinwhichwecanaddsomethingsforthetemplatetouse.Weneedtogivethemnames(wewillstickto'posts'rightnow).:)Itshouldlooklikethis:{'posts':posts}.Pleasenotethatthepartbefore:isastring;youneedtowrapitwithquotes:''.
Sofinallyourblog/views.pyfileshouldlooklikethis:
blog/views.py
fromdjango.shortcutsimportrenderfromdjango.utilsimporttimezonefrom.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.11/ref/models/querysets/
Dynamicdataintemplates
98
DjangotemplatesTimetodisplaysomedata!Djangogivesussomehelpfulbuilt-intemplatetagsforthat.
Whataretemplatetags?Yousee,inHTML,youcan'treallywritePythoncode,becausebrowsersdon'tunderstandit.TheyknowonlyHTML.WeknowthatHTMLisratherstatic,whilePythonismuchmoredynamic.
DjangotemplatetagsallowustotransferPython-likethingsintoHTML,soyoucanbuilddynamicwebsitesfasterandeasier.Cool!
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
<QuerySet[<Post:Mysecondpost>,<Post:Myfirstpost>]>
ThismeansthatDjangounderstandsitasalistofobjects.RememberfromIntroductiontoPythonhowwecandisplaylists?Yes,withforloops!InaDjangotemplateyoudothemlikethis:
blog/templates/blog/post_list.html
{%forpostinposts%}{{post}}{%endfor%}
Djangotemplates
99
Trythisinyourtemplate.
Itworks!ButwewantthepoststobedisplayedlikethestaticpostswecreatedearlierintheIntroductiontoHTMLchapter.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:
Djangotemplates
100
Haveyounoticedthatweusedaslightlydifferentnotationthistime({{post.title}}or{{post.text}})?WeareaccessingdataineachofthefieldsdefinedinourPostmodel.Also,the|linebreaksbrispipingtheposts'textthroughafiltertoconvertline-breaksintoparagraphs.
OnemorethingIt'dbegoodtoseeifyourwebsitewillstillbeworkingonthepublicInternet,right?Let'strydeployingtoPythonAnywhereagain.Here'sarecapofthesteps…
First,pushyourcodetoGithub
command-line
$gitstatus[...]$gitadd--all.$gitstatus[...]$gitcommit-m"Modifiedtemplatestodisplaypostsfromdatabase."[...]$gitpush
Then,logbackintoPythonAnywhereandgotoyourBashconsole(orstartanewone),andrun:
PythonAnywherecommand-line
$cdmy-first-blog$gitpull[...]
Djangotemplates
101
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
102
CSS–makeitpretty!Ourblogstilllooksprettyugly,right?Timetomakeitnice!WewilluseCSSforthat.
WhatisCSS?CascadingStyleSheets(CSS)isalanguageusedfordescribingthelookandformattingofawebsitewritteninamarkuplanguage(likeHTML).Treatitasmake-upforourwebpage.;)
Butwedon'twanttostartfromscratchagain,right?Oncemore,we'llusesomethingthatprogrammersreleasedontheInternetforfree.Reinventingthewheelisnofun,youknow.
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!
CSS–makeitpretty
103
StaticfilesinDjangoFinallywewilltakeacloserlookatthesethingswe'vebeencallingstaticfiles.StaticfilesareallyourCSSandimages.Theircontentdoesn'tdependontherequestcontextandwillbethesameforeveryuser.
WheretoputstaticfilesforDjango
Djangoalreadyknowswheretofindthestaticfilesforthebuilt-in"admin"app.Nowwejustneedtoaddsomestaticfilesforourownapp,blog.
Wedothatbycreatingafoldercalledstaticinsidetheblogapp:
djangogirls├──blog│├──migrations│├──static│└──templates└──mysite
Djangowillautomaticallyfindanyfolderscalled"static"insideanyofyourapps'folders.Thenitwillbeabletousetheircontentsasstaticfiles.
YourfirstCSSfile!Let'screateaCSSfilenow,toaddyourownstyletoyourwebpage.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!
CSS–makeitpretty
104
InaCSSfilewedeterminestylesforelementsintheHTMLfile.Thefirstwayweidentifyelementsiswiththeelementname.YoumightremembertheseastagsfromtheHTMLsection.Thingslikea,h1,andbodyareallexamplesofelementnames.Wealsoidentifyelementsbytheattributeclassortheattributeid.Classandidarenamesyougivetheelementbyyourself.Classesdefinegroupsofelements,andidspointtospecificelements.Forexample,youcouldidentifythefollowingtagbyusingthetagnamea,theclassexternal_link,ortheidlink_to_wiki_page:
<ahref="https://en.wikipedia.org/wiki/Django"class="external_link"id="link_to_wiki_page">
YoucanreadmoreaboutCSSSelectorsatw3schools.
WealsoneedtotellourHTMLtemplatethatweaddedsomeCSS.Opentheblog/templates/blog/post_list.htmlfileandaddthislineattheverybeginningofit:
blog/templates/blog/post_list.html
{%loadstaticfiles%}
We'rejustloadingstaticfileshere.:)Betweenthe<head>and</head>tags,afterthelinkstotheBootstrapCSSfiles,addthisline:
blog/templates/blog/post_list.html
<linkrel="stylesheet"href="{%static'css/blog.css'%}">
Thebrowserreadsthefilesintheorderthey'regiven,soweneedtomakesurethisisintherightplace.OtherwisethecodeinourfilemaybeoverridenbycodeinBootstrapfiles.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
105
Nicework!Maybewewouldalsoliketogiveourwebsitealittleairandincreasethemarginontheleftside?Let'strythis!
blog/static/css/blog.css
body{padding-left:15px;}
AddthattoyourCSS,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).
CSS–makeitpretty
106
Findtheh1adeclarationblock(thecodebetweenbraces{and})intheCSSfileblog/static/css/blog.css.Nowaddthelinefont-family:'Lobster';betweenthebraces,andrefreshthepage:
blog/static/css/blog.css
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.TherearemanygreattutorialsandexplanationsaboutCSSontheWebthatcanhelpyouunderstandthefollowingcode.Fornow,justcopyandpasteitintoyourblog/static/css/blog.cssfile:
CSS–makeitpretty
107
blog/static/css/blog.css
.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
108
<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
109
TemplateextendingAnothernicethingDjangohasforyouistemplateextending.Whatdoesthismean?ItmeansthatyoucanusethesamepartsofyourHTMLfordifferentpagesofyourwebsite.
Templateshelpwhenyouwanttousethesameinformationorlayoutinmorethanoneplace.Youdon'thavetorepeatyourselfineveryfile.Andifyouwanttochangesomething,youdon'thavetodoitineverytemplate,justone!
CreateabasetemplateAbasetemplateisthemostbasictemplatethatyouextendoneverypageofyourwebsite.
Let'screateabase.htmlfileinblog/templates/blog/:
blog└───templates└───blogbase.htmlpost_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
110
<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.ThatHTMLwillcomefromanothertemplatethatextendsthistemplate(base.html).Wewillshowyouhowtodothisinamoment.
Nowsavebase.htmlandopenyourblog/templates/blog/post_list.htmlagain.You'regoingtoremoveeverythingabove{%forpostinposts%}andbelow{%endfor%}.Whenyou'redone,thefilewilllooklikethis:
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{%endblock%}.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%}
Templateextending
111
Onlyonethingleft.Weneedtoconnectthesetwotemplatestogether.Thisiswhatextendingtemplatesisallabout!We'lldothisbyaddinganextendstagtothebeginningofthefile.Likethis:
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%}{%endblock%}
That'sit!Checkifyourwebsiteisstillworkingproperly.:)
IfyougettheerrorTemplateDoesNotExist,thatmeansthatthereisnoblog/base.htmlfileandyouhaverunserverrunningintheconsole.Trytostopit(bypressingCtrl+C–theControlandCkeystogether)andrestartitbyrunningapythonmanage.pyrunservercommand.
Templateextending
112
ExtendyourapplicationWe'vealreadycompletedallthedifferentstepsnecessaryforthecreationofourwebsite:weknowhowtowriteamodel,url,viewandtemplate.Wealsoknowhowtomakeourwebsitepretty.
Timetopractice!
Thefirstthingweneedinourblogis,obviously,apagetodisplayonepost,right?
WealreadyhaveaPostmodel,sowedon'tneedtoaddanythingtomodels.py.
Createatemplatelinktoapost'sdetailWewillstartwithaddingalinkinsideblog/templates/blog/post_list.htmlfile.Sofaritshouldlooklikethis:
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%}{%endblock%}
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!
Thepost_detailpartmeansthatDjangowillbeexpectingaURLinblog/urls.pywithname=post_detail
Andhowaboutpk=post.pk?pkisshortforprimarykey,whichisauniquenameforeachrecordinadatabase.Becausewedidn'tspecifyaprimarykeyinourPostmodel,Djangocreatesoneforus(bydefault,anumberthatincreasesbyoneforeachrecord,i.e.1,2,3)andaddsitasafieldnamedpktoeachofourposts.Weaccesstheprimarykeybywritingpost.pk,thesamewayweaccessotherfields(title,author,etc.)inourPostobject!
Nowwhenwegotohttp://127.0.0.1:8000/wewillhaveanerror(asexpected,sincewedonotyethaveaURLoraviewforpost_detail).Itwilllooklikethis:
Extendyourapplication
113
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.urlsimporturlfrom.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/justmeansthatafterthebeginning,theURLshouldcontainthewordpostanda/.Sofarsogood.(?P<pk>\d+)–thispartistrickier.ItmeansthatDjangowilltakeeverythingthatyouplacehereandtransferittoaviewasavariablecalledpk.(Notethatthismatchesthenamewegavetheprimarykeyvariablebackinblog/templates/blog/post_list.html!)\dalsotellsusthatitcanonlybeadigit,notaletter(soeverythingbetween0and9).+meansthatthereneedstobeoneormoredigitsthere.Sosomethinglikehttp://127.0.0.1:8000/post//isnotvalid,buthttp://127.0.0.1:8000/post/1234567890/isperfectlyOK!/–thenweneeda/again.$–"theend"!
Thatmeansifyouenterhttp://127.0.0.1:8000/post/5/intoyourbrowser,Djangowillunderstandthatyouarelookingforaviewcalledpost_detailandtransfertheinformationthatpkequals5tothatview.
OK,we'veaddedanewURLpatterntoblog/urls.py!Let'srefreshthepage:http://127.0.0.1:8000/Boom!Theserverhasstoppedrunningagain.Havealookattheconsole–asexpected,there'syetanothererror!
Extendyourapplication
114
Doyourememberwhatthenextstepis?Ofcourse:addingaview!
Addapost'sdetailviewThistimeourviewisgivenanextraparameter,pk.Ourviewneedstocatchit,right?Sowewilldefineourfunctionasdefpost_detail(request,pk):.Notethatweneedtouseexactlythesamenameastheonewespecifiedinurls(pk).Omittingthisvariableisincorrectandwillresultinanerror!
Now,wewanttogetoneandonlyoneblogpost.Todothis,wecanusequerysets,likethis:
blog/views.py
Post.objects.get(pk=pk)
Butthiscodehasaproblem.IfthereisnoPostwiththegivenprimarykey(pk)wewillhaveasuperuglyerror!
Wedon'twantthat!But,ofcourse,Djangocomeswithsomethingthatwillhandlethatforus:get_object_or_404.IncasethereisnoPostwiththegivenpk,itwilldisplaymuchnicerpage,thePageNotFound404page.
Extendyourapplication
115
ThegoodnewsisthatyoucanactuallycreateyourownPagenotfoundpageandmakeitasprettyasyouwant.Butit'snotsuperimportantrightnow,sowewillskipit.
OK,timetoaddaviewtoourviews.pyfile!
Inblog/urls.pywecreatedaURLrulenamedpost_detailthatreferstoaviewcalledviews.post_detail.ThismeansthatDjangowillbeexpectingaviewfunctioncalledpost_detailinsideblog/views.py.
Weshouldopenblog/views.pyandaddthefollowingcodeneartheotherfromlines:
blog/views.py
fromdjango.shortcutsimportrender,get_object_or_404
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
116
Itworked!Butwhathappenswhenyouclickalinkinblogposttitle?
Ohno!Anothererror!Butwealreadyknowhowtodealwithit,right?Weneedtoaddatemplate!
CreateatemplateforthepostdetailsWewillcreateafileinblog/templates/blogcalledpost_detail.html.
Extendyourapplication
117
Itwilllooklikethis:
blog/templates/blog/post_detail.html
{%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
118
$gitstatus$gitadd--all.$gitstatus$gitcommit-m"AddedviewandtemplatefordetailedblogpostaswellasCSSforthesite."$gitpush
Then,inaPythonAnywhereBashconsole:
command-line
$cdmy-first-blog$gitpull[...]
Finally,hoponovertotheWebtabandhitReload.
Andthatshouldbeit!Congrats:)
Extendyourapplication
119
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=Postfields=('title','text',)
WeneedtoimportDjangoformsfirst(fromdjangoimportforms)and,obviously,ourPostmodel(from.modelsimportPost).
PostForm,asyouprobablysuspect,isthenameofourform.WeneedtotellDjangothatthisformisaModelForm(soDjangowilldosomemagicforus)–forms.ModelFormisresponsibleforthat.
Next,wehaveclassMeta,wherewetellDjangowhichmodelshouldbeusedtocreatethisform(model=Post).
Finally,wecansaywhichfield(s)shouldendupinourform.Inthisscenariowewantonlytitleandtexttobeexposed–authorshouldbethepersonwhoiscurrentlyloggedin(you!)andcreated_dateshouldbeautomaticallysetwhenwecreateapost(i.e.inthecode),right?
Andthat'sit!Allweneedtodonowisusetheforminaviewanddisplayitinatemplate.
Soonceagainwewillcreatealinktothepage,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>
DjangoForms
120
Notethatwewanttocallournewviewpost_new.Theclass"glyphiconglyphicon-plus"isprovidedbythebootstrapthemeweareusing,andwilldisplayaplussignforus.
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.urlsimporturlfrom.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'thavethepost_newviewimplemented.Let'sadditrightnow.
post_newview
DjangoForms
121
Timetoopentheblog/views.pyfileandaddthefollowinglineswiththerestofthefromrows:
blog/views.py
from.formsimportPostForm
Andthenourview:
blog/views.py
defpost_new(request):form=PostForm()returnrender(request,'blog/post_edit.html',{'form':form})
TocreateanewPostform,weneedtocallPostForm()andpassittothetemplate.Wewillgobacktothisview,butfornow,let'squicklycreateatemplatefortheform.
TemplateWeneedtocreateafilepost_edit.htmlintheblog/templates/blogdirectory.Tomakeaformworkweneedseveralthings:
Wehavetodisplaytheform.Wecandothatwith(forexample)asimple{{form.as_p}}.ThelineaboveneedstobewrappedwithanHTMLformtag:<formmethod="POST">...</form>.WeneedaSavebutton.WedothatwithanHTMLbutton:<buttontype="submit">Save</button>.Andfinally,justaftertheopening<form...>tagweneedtoadd{%csrf_token%}.Thisisveryimportant,sinceitmakesyourformssecure!Ifyouforgetaboutthisbit,Djangowillcomplainwhenyoutrytosavetheform:
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%}
DjangoForms
122
Timetorefresh!Yay!Yourformisdisplayed!
But,waitaminute!Whenyoutypesomethinginthetitleandtextfieldsandtrytosaveit,whatwillhappen?
Nothing!Weareonceagainonthesamepageandourtextisgone…andnonewpostisadded.Sowhatwentwrong?
Theansweris:nothing.Weneedtodoalittlebitmoreworkinourview.
SavingtheformOpenblog/views.pyonceagain.Currentlyallwehaveinthepost_newviewisthefollowing:
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).RememberhowintheHTMLfile,our<form>definitionhadthevariablemethod="POST"?Allthefieldsfromtheformarenowinrequest.POST.YoushouldnotrenamePOSTtoanythingelse(theonlyothervalidvalueformethodisGET,butwehavenotimetoexplainwhatthedifferenceis).
DjangoForms
123
Soinourviewwehavetwoseparatesituationstohandle:first,whenweaccessthepageforthefirsttimeandwewantablankform,andsecond,whenwegobacktotheviewwithallformdatawejusttyped.Soweneedtoaddacondition(wewilluseifforthat):
blog/views.py
ifrequest.method=="POST":[...]else:form=PostForm()
It'stimetofillinthedots[...].IfmethodisPOSTthenwewanttoconstructthePostFormwithdatafromtheform,right?Wewilldothatasfollows:
blog/views.py
form=PostForm(request.POST)
Easy!Thenextthingistocheckiftheformiscorrect(allrequiredfieldsaresetandnoincorrectvalueshavebeensubmitted).Wedothatwithform.is_valid().
Wecheckiftheformisvalidandifso,wecansaveit!
blog/views.py
ifform.is_valid():post=form.save(commit=False)post.author=request.userpost.published_date=timezone.now()post.save()
Basically,wehavetwothingshere:wesavetheformwithform.saveandweaddanauthor(sincetherewasnoauthorfieldinthePostFormandthisfieldisrequired).commit=Falsemeansthatwedon'twanttosavethePostmodelyet–wewanttoaddtheauthorfirst.Mostofthetimeyouwilluseform.save()withoutcommit=False,butinthiscase,weneedtosupplyit.post.save()willpreservechanges(addingtheauthor)andanewblogpostiscreated!
Finally,itwouldbeawesomeifwecouldimmediatelygotothepost_detailpageforournewlycreatedblogpost,right?Todothatweneedonemoreimport:
blog/views.py
fromdjango.shortcutsimportredirect
Additattheverybeginningofyourfile.Andnowwecansay,"gotothepost_detailpageforthenewlycreatedpost":
blog/views.py
returnredirect('post_detail',pk=post.pk)
post_detailisthenameoftheviewwewanttogoto.Rememberthatthisviewrequiresapkvariable?Topassittotheviews,weusepk=post.pk,wherepostisthenewlycreatedblogpost!
OK,we'vetalkedalot,butweprobablywanttoseewhatthewholeviewlookslikenow,right?
blog/views.py
defpost_new(request):
DjangoForms
124
ifrequest.method=="POST":form=PostForm(request.POST)ifform.is_valid():post=form.save(commit=False)post.author=request.userpost.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à!Thenewblogpostisaddedandweareredirectedtothepost_detailpage!
Youmighthavenoticedthatwearesettingthepublishdatebeforesavingthepost.Lateron,wewillintroduceapublishbuttoninDjangoGirlsTutorial:Extensions.
Thatisawesome!
AswehaverecentlyusedtheDjangoadmininterface,thesystemcurrentlythinkswearestillloggedin.Thereareafewsituationsthatcouldleadtousbeingloggedout(closingthebrowser,restartingtheDB,etc.).If,whencreatingapost,youfindthatyouaregettingerrorsreferringtothelackofalogged-inuser,headtotheadminpagehttp://127.0.0.1:8000/adminandloginagain.Thiswillfixtheissuetemporarily.ThereisapermanentfixawaitingyouintheHomework:addsecuritytoyourwebsite!chapterafterthemaintutorial.
FormvalidationNow,wewillshowyouhowcoolDjangoformsare.Ablogpostneedstohavetitleandtextfields.InourPostmodelwedidnotsaythatthesefields(asopposedtopublished_date)arenotrequired,soDjango,bydefault,expectsthemtobeset.
Trytosavetheformwithouttitleandtext.Guesswhatwillhappen!
DjangoForms
125
Djangoistakingcaretovalidatethatallthefieldsinourformarecorrect.Isn'titawesome?
EditformNowweknowhowtoaddanewform.Butwhatifwewanttoeditanexistingone?Thisisverysimilartowhatwejustdid.Let'screatesomeimportantthingsquickly.(Ifyoudon'tunderstandsomething,youshouldaskyourcoachorlookatthepreviouschapters,sincewecoveredallthesestepsalready.)
Openblog/templates/blog/post_detail.htmlandaddtheline
blog/templates/blog/post_detail.html
<aclass="btnbtn-default"href="{%url'post_edit'pk=post.pk%}"><spanclass="glyphiconglyphicon-pencil"></span></a>
sothatthetemplatewilllooklikethis:
blog/templates/blog/post_detail.html
{%extends'blog/base.html'%}
{%blockcontent%}<divclass="post">
DjangoForms
126
{%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'sopenblog/views.pyandaddthisattheveryendofthefile:
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.userpost.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.Forone,wepassanextrapkparameterfromurls.Next,wegetthePostmodelwewanttoeditwithget_object_or_404(Post,pk=pk)andthen,whenwecreateaform,wepassthispostasaninstance,bothwhenwesavetheform…
blog/views.py
form=PostForm(request.POST,instance=post)
…andwhenwe'vejustopenedaformwiththisposttoedit:
blog/views.py
form=PostForm(instance=post)
OK,let'stestifitworks!Let'sgotothepost_detailpage.Thereshouldbeaneditbuttoninthetop-rightcorner:
DjangoForms
127
Whenyouclickityouwillseetheformwithourblogpost:
Feelfreetochangethetitleorthetextandsavethechanges!
Congratulations!Yourapplicationisgettingmoreandmorecomplete!
DjangoForms
128
IfyouneedmoreinformationaboutDjangoforms,youshouldreadthedocumentation:https://docs.djangoproject.com/en/1.11/topics/forms/
SecurityBeingabletocreatenewpostsjustbyclickingalinkisawesome!Butrightnow,anyonewhovisitsyoursitewillbeabletomakeanewblogpost,andthat'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%}tagtothis,whichwillmakethelinkshowuponlyforuserswhoareloggedintotheadmin.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%}willcausethelinktobesenttothebrowseronlyiftheuserrequestingthepageisloggedin.Thisdoesn'tprotectthecreationofnewpostscompletely,butit'sagoodfirststep.We'llcovermoresecurityintheextensionlessons.
Remembertheediticonwejustaddedtoourdetailpage?Wealsowanttoaddthesamechangethere,sootherpeoplewon'tbeabletoeditexistingposts.
Openblog/templates/blog/post_detail.htmlandfindthisline:
blog/templates/blog/post_detail.html
<aclass="btnbtn-default"href="{%url'post_edit'pk=post.pk%}"><spanclass="glyphiconglyphicon-pencil"></span></a>
Changeittothis:
blog/templates/blog/post_detail.html
{%ifuser.is_authenticated%}<aclass="btnbtn-default"href="{%url'post_edit'pk=post.pk%}"><spanclass="glyphiconglyphicon-pencil"></span></a>{%endif%}
Sinceyou'relikelyloggedin,ifyourefreshthepage,youwon'tseeanythingdifferent.Loadthepageinadifferentbrowseroranincognitowindow(called"InPrivate"inWindowsEdge),though,andyou'llseethatthelinkdoesn'tshowup,andtheicondoesn'tdisplayeither!
Onemorething:deploytime!
DjangoForms
129
Let'sseeifallthisworksonPythonAnywhere.Timeforanotherdeploy!
First,commityournewcode,andpushituptoGithub:
command-line
$gitstatus$gitadd--all.$gitstatus$gitcommit-m"Addedviewstocreate/editblogpostinsidethesite."$gitpush
Then,inaPythonAnywhereBashconsole:
command-line
$cdmy-first-blog$gitpull[...]
Finally,hoponovertotheWebtabandhitReload.
Andthatshouldbeit!Congrats:)
DjangoForms
130
What'snext?Congratulateyourself!You'retotallyawesome.We'reproud!<3
Whattodonow?
Takeabreakandrelax.Youhavejustdonesomethingreallyhuge.
Afterthat,makesuretofollowDjangoGirlsonFacebookorTwittertostayuptodate.
Canyourecommendanyfurtherresources?
Yes!First,goaheadandtryourotherbook,calledDjangoGirlsTutorial:Extensions.
Lateron,youcantrytheresourceslistedbelow.They'reallveryrecommended!
Django'sofficialtutorialNewCodertutorialsCodeAcademyPythoncourseCodeAcademyHTML&CSScourseDjangoCarrotstutorialLearnPythonTheHardWaybookGettingStartedWithDjangovideolessonsTwoScoopsofDjango1.11:BestPracticesforDjangoWebFrameworkbookHelloWebApp:LearnHowtoBuildaWebApp
What'snext?
131