Upload
others
View
6
Download
0
Embed Size (px)
Citation preview
1.1
1.2
1.3
1.4
1.5
1.6
1.7
1.8
1.9
1.10
1.11
1.12
1.13
1.14
1.15
1.16
1.17
1.18
1.19
1.20
1.21
1.22
1.23
1.24
TableofContentsIntroduction
Installation
HowtheInternetworks
Introductiontocommandline
Pythoninstallation
Codeeditor
IntroductiontoPython
WhatisDjango?
Djangoinstallation
YourfirstDjangoproject!
Djangomodels
Djangoadmin
Deploy!
Djangourls
Djangoviews-timetocreate!
IntroductiontoHTML
DjangoORM(Querysets)
Dynamicdataintemplates
Djangotemplates
CSS-makeitpretty
Templateextending
Extendyourapplication
DjangoForms
What'snext?
2
DjangoGirlsTutorial
ThisworkislicensedundertheCreativeCommonsAttribution-ShareAlike4.0InternationalLicense.Toviewacopyofthislicense,visithttps://creativecommons.org/licenses/by-sa/4.0/
IntroductionHaveyoueverfeltthattheworldismoreandmoreabouttechnologyandyouaresomehowleftbehind?Haveyoueverwonderedhowtocreateawebsitebuthaveneverhadenoughmotivationtostart?Haveyoueverthoughtthatthesoftwareworldistoocomplicatedforyoutoeventrydoingsomethingonyourown?
Well,wehavegoodnewsforyou!Programmingisnotashardasitseemsandwewanttoshowyouhowfunitcanbe.
Thistutorialwillnotmagicallyturnyouintoaprogrammer.Ifyouwanttobegoodatit,youneedmonthsorevenyearsoflearningandpractice.Butwewanttoshowyouthatprogrammingorcreatingwebsitesisnotascomplicatedasitseems.Wewilltrytoexplaindifferentbitsandpiecesaswellaswecan,soyouwillnotfeelintimidatedbytechnology.
Wehopethatwe'llbeabletomakeyoulovetechnologyasmuchaswedo!
Whatwillyoulearnduringthetutorial?Onceyou'vefinishedthetutorial,youwillhaveasimple,workingwebapplication:yourownblog.Wewillshowyouhowtoputitonline,sootherswillseeyourwork!
Itwill(moreorless)looklikethis:
Introduction
3
Ifyouworkwiththetutorialonyourownanddon'thaveacoachwhowillhelpyouincaseofanyproblem,wehavea
chatsystemforyou: .Weaskedourcoachesandpreviousattendeestobetherefromtimetotimeandhelpotherswiththetutorial!Don'tbeafraidtoaskyourquestionthere!
OK,let'sstartatthebeginning…
FollowingthetutorialathomeItisamazingtotakepartinaDjangoGirlsworkshop,butweareawarethatitisnotalwayspossibletoattendone.Thisiswhyweencourageyoutotryfollowingthistutorialathome.Forreadersathomewearecurrentlypreparingvideosthatwillmakeiteasiertofollowthetutorialonyourown.Itisstillaworkinprogress,butmoreandmorethingswillbecoveredsoonattheCodingisforgirlsYouTubechannel.
Ineverychapteralreadycovered,thereisalinkthatpointstothecorrectvideo.
AboutandcontributingThistutorialismaintainedbyDjangoGirls.Ifyoufindanymistakesorwanttoupdatethetutorialpleasefollowthecontributingguidelines.
Wouldyouliketohelpustranslatethetutorialtootherlanguages?
Introduction
4
Currently,translationsarebeingkeptoncrowdin.complatformat:
https://crowdin.com/project/django-girls-tutorial
Ifyourlanguageisnotlistedoncrowdin,pleaseopenanewissueinformingusofthelanguagesowecanaddit.
Introduction
5
Ifyou'redoingthetutorialathomeIfyou'redoingthetutorialathome,notatoneoftheDjangoGirlsevents,youcancompletelyskipthischapternowandgostraighttotheHowtheInternetworks?chapter.
Thisisbecausewecoverthesethingsinthewholetutorialanyway,andthisisjustanadditionalpagethatgathersalloftheinstallationinstructionsinoneplace.TheDjangoGirlseventincludesone"Installationevening"whereweinstalleverythingsowedon'tneedtobotherwithitduringtheworkshop,sothisisusefulforus.
Ifyoufindituseful,youcanfollowthroughthischaptertoo.Butifyouwanttostartlearningthingsbeforeinstallingabunchofstuffonyourcomputer,skipthischapterandwewillexplaintheinstallationparttoyoulateron.
Goodluck!
InstallationIntheworkshopyouwillbebuildingablog,andthereareafewsetuptasksinthetutorialwhichwouldbegoodtoworkthroughbeforehandsothatyouarereadytostartcodingontheday.
Chromebooksetup(ifyou'reusingone)Youcanskiprightoverthissectionifyou'renotusingaChromebook.Ifyouare,yourinstallationexperiencewillbealittledifferent.Youcanignoretherestoftheinstallationinstructions.
Cloud9
Cloud9isatoolthatgivesyouacodeeditorandaccesstoacomputerrunningontheinternetwhereyoucaninstall,write,andrunsoftware.Forthedurationofthetutorial,Cloud9willactasyourlocalmachine.You'llstillberunningcommandsinaterminalinterfacejustlikeyourclassmatesonOSX,Ubuntu,orWindows,butyourterminalwillbeconnectedtoacomputerrunningsomewhereelsethatCloud9setsupforyou.
1. InstallCloud9fromtheChromewebstore2. Gotoc9.io3. Signupforanaccount4. ClickCreateaNewWorkspace5. Nameitdjango-girls6. SelecttheBlank(secondfromtherightonthebottomrowwithorangelogo)
Nowyoushouldseeaninterfacewithasidebar,abigmainwindowwithsometext,andasmallwindowatthebottomthatlookssomethinglike:
Cloud9
yourusername:~/workspace$
Thisbottomareaisyourterminal,whereyouwillgivethecomputerCloud9haspreparedforyouinstructions.Youcanresizethatwindowtomakeitabitbigger.
VirtualEnvironment
Installation
6
Avirtualenvironment(alsocalledavirtualenv)islikeaprivateboxwecanstuffusefulcomputercodeintoforaprojectwe'reworkingon.Weusethemtokeepthevariousbitsofcodewewantforourvariousprojectsseparatesothingsdon'tgetmixedupbetweenprojects.
InyourterminalatthebottomoftheCloud9interface,runthefollowing:
Cloud9
sudoaptinstallpython3.5-venv
Ifthisstilldoesn'twork,askyourcoachforsomehelp.
Next,run:
Cloud9
mkdirdjangogirls
cddjangogirls
python3.5-mvenvmyvenv
sourcemyvenv/bin/activate
pipinstalldjango~=1.9.0
(notethatonthelastlineweuseatildefollowedbyanequalsign:~=).
Github
MakeaGithubaccount.
PythonAnywhere
TheDjangoGirlstutorialincludesasectiononwhatiscalledDeployment,whichistheprocessoftakingthecodethatpowersyournewwebapplicationandmovingittoapubliclyaccessiblecomputer(calledaserver)sootherpeoplecanseeyourwork.
ThispartisalittleoddwhendoingthetutorialonaChromebooksincewe'realreadyusingacomputerthatisontheinternet(asopposedto,say,alaptop).However,it'sstilluseful,aswecanthinkofourCloud9workspaceasaplaceorour"inprogress"workandPythonAnywhereasaplacetoshowoffourstuffasitbecomesmorecomplete.
Thus,signupforanewPythonAnywhereaccountatwww.pythonanywhere.com.
InstallPythonForreadersathome:thischapteriscoveredintheInstallingPython&CodeEditorvideo.
ThissectionisbasedonatutorialbyGeekGirlsCarrots(https://github.com/ggcarrots/django-carrots)
DjangoiswritteninPython.WeneedPythontodoanythinginDjango.Let'sstartbyinstallingit!WewantyoutoinstallPython3.5,soifyouhaveanyearlierversion,youwillneedtoupgradeit.
WindowsYoucandownloadPythonforWindowsfromthewebsitehttps://www.python.org/downloads/release/python-351/.Afterdownloadingthe*.msifile,youshouldrunit(double-clickonit)andfollowtheinstructionsthere.Itisimportanttorememberthepath(thedirectory)whereyouinstalledPython.Itwillbeneededlater!
Onethingtowatchoutfor:onthesecondscreenoftheinstallationwizard,marked"Customize",makesureyouscrolldowntothe"Addpython.exetothePath"optionandselect"Willbeinstalledonlocalharddrive",asshownhere:
Installation
7
Inupcomingsteps,you'llbeusingtheWindowsCommandLine(whichwe'llalsotellyouabout).Fornow,ifyouneedtotypeinsomecommands,gotoStartmenu→AllPrograms→Accessories→CommandPrompt.(OnnewerversionsofWindows,youmighthavetosearchfor"CommandPrompt"sinceit'ssometimeshidden.)
Linux
ItisverylikelythatyoualreadyhavePythoninstalledoutofthebox.Tocheckifyouhaveitinstalled(andwhichversionitis),openaconsoleandtypethefollowingcommand:
command-line
$python3--version
Python3.5.1
Ifyouhaveadifferent'microversion'ofPythoninstalled,e.g.3.5.0,thenyoudon'thavetoupgrade.Ifyoudon'thavePythoninstalled,orifyouwantadifferentversion,youcaninstallitasfollows:
DebianorUbuntu
Typethiscommandintoyourconsole:
command-line
$sudoapt-getinstallpython3.5
Fedora(upto21)
Usethiscommandinyourconsole:
command-line
Installation
8
$sudoyuminstallpython3
Fedora(22+)Usethiscommandinyourconsole:
command-line
$sudodnfinstallpython3
openSUSE
Usethiscommandinyourconsole:
command-line
$sudozypperinstallpython3
OSXBeforeyouinstallPythononOSX,youshouldensureyourMacsettingsallowinstallingpackagesthataren'tfromtheAppStore.GotoSystemPreferences(it'sintheApplicationsfolder),click"Security&Privacy,"andthenthe"General"tab.Ifyour"Allowappsdownloadedfrom:"issetto"MacAppStore,"changeitto"MacAppStoreandidentifieddevelopers."
Youneedtogotothewebsitehttps://www.python.org/downloads/release/python-351/anddownloadthePythoninstaller:
DownloadtheMacOSX64-bit/32-bitinstallerfile,Doubleclickpython-3.5.1-macosx10.6.pkgtoruntheinstaller.
VerifytheinstallationwassuccessfulbyopeningtheTerminalapplicationandrunningthepython3command:
command-line
$python3--version
Python3.5.1
Ifyouhaveanydoubts,orifsomethingwentwrongandyouhavenoideawhattodonext,pleaseaskyourcoach!Sometimesthingsdon'tgosmoothlyandit'sbettertoaskforhelpfromsomeonewithmoreexperience.
SetupvirtualenvandinstallDjangoPartofthissectionisbasedontutorialsbyGeekGirlsCarrots(https://github.com/ggcarrots/django-carrots).
Partofthissectionisbasedonthedjango-marcadortutoriallicensedundertheCreativeCommonsAttribution-ShareAlike4.0InternationalLicense.Thedjango-marcadortutorialiscopyrightedbyMarkusZapke-Gründemannetal.
Virtualenvironment
Installation
9
BeforeweinstallDjangowewillgetyoutoinstallanextremelyusefultooltohelpkeepyourcodingenvironmenttidyonyourcomputer.It'spossibletoskipthisstep,butit'shighlyrecommended.Startingwiththebestpossiblesetupwillsaveyoualotoftroubleinthefuture!
So,let'screateavirtualenvironment(alsocalledavirtualenv).VirtualenvwillisolateyourPython/Djangosetuponaper-projectbasis.Thismeansthatanychangesyoumaketoonewebsitewon'taffectanyothersyou'realsodeveloping.Neat,right?
Allyouneedtodoisfindadirectoryinwhichyouwanttocreatethevirtualenv;yourhomedirectory,forexample.OnWindowsitmightlooklikeC:\Users\Name\(whereNameisthenameofyourlogin).
NOTE:OnWindows,makesurethatthisdirectorydoesnotcontainaccentedorspecialcharacters;ifyourusernamecontainsaccentedcharacters,useadifferentdirectory,forexampleC:\djangogirls.
Forthistutorialwewillbeusinganewdirectorydjangogirlsfromyourhomedirectory:
command-line
$mkdirdjangogirls
$cddjangogirls
Wewillmakeavirtualenvcalledmyvenv.Thegeneralcommandwillbeintheformat:
command-line
$python3-mvenvmyvenv
Windows
Tocreateanewvirtualenv,youneedtoopentheconsole(wetoldyouaboutthatafewchaptersago–remember?)andrunC:\Python35\python-mvenvmyvenv.Itwilllooklikethis:
command-line
C:\Users\Name\djangogirls>C:\Python35\python-mvenvmyvenv
whereC:\Python35\pythonisthedirectoryinwhichyoupreviouslyinstalledPythonandmyvenvisthenameofyourvirtualenv.Youcanuseanyothername,butsticktolowercaseandusenospaces,accentsorspecialcharacters.Itisalsogoodideatokeepthenameshort–you'llbereferencingitalot!
LinuxandOSX
CreatingavirtualenvonbothLinuxandOSXisassimpleasrunningpython3-mvenvmyvenv.Itwilllooklikethis:
command-line
$python3-mvenvmyvenv
myvenvisthenameofyourvirtualenv.Youcanuseanyothername,butsticktolowercaseandusenospaces.Itisalsogoodideatokeepthenameshortasyou'llbereferencingitalot!
Installation
10
NOTE:OnsomeversionsofDebian/Ubuntuyoumayreceivethefollowingerror:
command-line
Thevirtualenvironmentwasnotcreatedsuccessfullybecauseensurepipisnotavailable.OnDebian/Ubuntusys
tems,youneedtoinstallthepython3-venvpackageusingthefollowingcommand.
apt-getinstallpython3-venv
Youmayneedtousesudowiththatcommand.Afterinstallingthepython3-venvpackage,recreateyourvirtual
environment.
Inthiscase,followtheinstructionsaboveandinstallthepython3-venvpackage:
command-line
$sudoapt-getinstallpython3-venv
NOTE:OnsomeversionsofDebian/Ubuntuinitiatingthevirtualenvironmentlikethiscurrentlygivesthefollowingerror:
command-line
Error:Command'['/home/eddie/Slask/tmp/venv/bin/python3','-Im','ensurepip','--upgrade','--default-pip']'
returnednon-zeroexitstatus1
Togetaroundthis,usethevirtualenvcommandinstead.
command-line
$sudoapt-getinstallpython-virtualenv
$virtualenv--python=python3.5myvenv
NOTE:Ifyougetanerrorlike
command-line
E:Unabletolocatepackagepython3-venv
theninsteadrun:
command-line
sudoaptinstallpython3.5-venv
WorkingwithvirtualenvThecommandabovewillcreateadirectorycalledmyvenv(orwhatevernameyouchose)thatcontainsourvirtualenvironment(basicallyabunchofdirectoryandfiles).
WindowsStartyourvirtualenvironmentbyrunning:
command-line
C:\Users\Name\djangogirls>myvenv\Scripts\activate
Installation
11
NOTE:onWindows10youmightgetanerrorintheWindowsPowerShellsaysexecutionofscriptsisdisabledonthissystem.InthosecasesopenanotherWindowsPowerShellandRunasAdministratortrydoingthisbeforecontinue:
command-line
C:\WINDOWS\system32>Set-ExecutionPolicy-ExecutionPolicyRemoteSigned
ExecutionPolicyChange
Theexecutionpolicyhelpsprotectyoufromscriptsthatyoudonottrust.Changingtheexecutionpolicym
ightexposeyoutothesecurityrisksdescribedintheabout_Execution_Policieshelptopicathttp://go.micros
oft.com/fwlink/?LinkID=135170.Doyouwanttochangetheexecutionpolicy?[Y]Yes[A]YestoAll[N]No[L
]NotoAll[S]Suspend[?]Help(defaultis"N"):A
LinuxandOSX
Startyourvirtualenvironmentbyrunning:
command-line
$sourcemyvenv/bin/activate
Remembertoreplacemyvenvwithyourchosenvirtualenvname!
NOTE:sometimessourcemightnotbeavailable.Inthosecasestrydoingthisinstead:
command-line
$.myvenv/bin/activate
Youwillknowthatyouhavevirtualenvstartedwhenyouseethatthepromptinyourconsoleisprefixedwith(myvenv).
Whenworkingwithinavirtualenvironment,pythonwillautomaticallyrefertothecorrectversionsoyoucanusepythoninsteadofpython3.
OK,wehaveallimportantdependenciesinplace.WecanfinallyinstallDjango!
InstallingDjangoNowthatyouhaveyourvirtualenvstarted,youcaninstallDjango.
Beforewedothat,weshouldmakesurewehavethelatestversionofpip,thesoftwarethatweusetoinstallDjango.Intheconsole,runpipinstall--upgradepip.
Thenrunpipinstalldjango~=1.9.0(notethatweuseatildefollowedbyanequalsign:~=)toinstallDjango.
command-line
(myvenv)~$pipinstalldjango~=1.9.0
Downloading/unpackingdjango==1.9
Installingcollectedpackages:django
Successfullyinstalleddjango
Cleaningup...
onWindows
Installation
12
IfyougetanerrorwhencallingpiponWindowsplatform,pleasecheckifyourprojectpathnamecontainsspaces,accentsorspecialcharacters(forexample,C:\Users\UserName\djangogirls).Ifitdoes,pleaseconsiderusinganotherplacewithoutspaces,accentsorspecialcharacters(suggestion:C:\djangogirls).Createanewvirtualenvinthenewdirectory,thendeletetheoldoneandtrytheabovecommandagain.(Movingthevirtualenvdirectorywon'tworksincevirtualenvusesabsolutepaths.)
onWindows8andWindows10
YourcommandlinemightfreezeafterwhenyoutrytoinstallDjango.Ifthishappens,insteadoftheabovecommanduse:
command-line
C:\Users\Name\djangogirls>python-mpipinstalldjango~=1.9.0
onLinux
IfyougetanerrorwhencallingpiponUbuntu12.04pleaserunpython-mpipinstall-U--force-reinstallpiptofixthepipinstallationinthevirtualenv.
That'sit!You'renow(finally)readytocreateaDjangoapplication!
InstallacodeeditorTherearealotofdifferenteditorsanditlargelyboilsdowntopersonalpreference.MostPythonprogrammersusecomplexbutextremelypowerfulIDEs(IntegratedDevelopmentEnvironments),suchasPyCharm.Asabeginner,however,that'sprobablylesssuitable;ourrecommendationsareequallypowerful,butalotsimpler.
Oursuggestionsarebelow,butfeelfreetoaskyourcoachwhattheirpreferencesare–it'llbeeasiertogethelpfromthem.
GeditGeditisanopen-source,freeeditor,availableforalloperatingsystems.
Downloadithere
SublimeText2SublimeTextisaverypopulareditorwithafreeevaluationperiod.It'seasytoinstallanduse,andit'savailableforalloperatingsystems.
Downloadithere
AtomAtomisanextremelynewcodeeditorcreatedbyGitHub.It'sfree,open-source,easytoinstallandeasytouse.It'savailableforWindows,OSXandLinux.
Downloadithere
Whyareweinstallingacodeeditor?Youmightbewonderingwhyweareinstallingthisspecialcodeeditorsoftware,ratherthanusingsomethinglikeWordorNotepad.
Installation
13
Thefirstreasonisthatcodeneedstobeplaintext,andtheproblemwithprogramslikeWordandTexteditisthattheydon'tactuallyproduceplaintext,theyproducerichtext(withfontsandformatting),usingcustomformatslikeRTF(RichTextFormat).
Thesecondreasonisthatcodeeditorsarespecialisedforeditingcode,sotheycanprovidehelpfulfeatureslikehighlightingcodewithcolouraccordingtoitsmeaning,orautomaticallyclosingquotesforyou.
We'llseeallthisinactionlater.Soon,you'llcometothinkofyourtrustyoldcodeeditorasoneofyourfavouritetools.:)
InstallGitWindows
YoucandownloadGitfromgit-scm.com.Youcanhit"next"onallstepsexceptforone;inthefifthstepentitled"AdjustingyourPATHenvironment",choose"UseGitandoptionalUnixtoolsfromtheWindowsCommandPrompt"(thebottomoption).Otherthanthat,thedefaultsarefine.CheckoutWindows-style,commitUnix-stylelineendingsisgood.
MacOS
DownloadGitfromgit-scm.comandjustfollowtheinstructions.
Linux
Ifitisn'tinstalledalready,gitshouldbeavailableviayourpackagemanager,sotry:
DebianorUbuntu
command-line
$sudoapt-getinstallgit
Fedora(upto21)
command-line
$sudoyuminstallgit
Fedora(22+)
command-line
$sudodnfinstallgit
openSUSE
command-line
$sudozypperinstallgit
CreateaGitHubaccountGotoGitHub.comandsignupforanew,freeuseraccount.
Installation
14
CreateaPythonAnywhereaccountNextit'stimetosignupforafree"Beginner"accountonPythonAnywhere.
www.pythonanywhere.com
Whenchoosingyourusernamehere,bearinmindthatyourblog'sURLwilltaketheformyourusername.pythonanywhere.com,sochooseeitheryourownnickname,oranameforwhatyourblogisallabout.
StartreadingCongratulations,youareallsetupandreadytogo!Ifyoustillhavesometimebeforetheworkshop,itwouldbeusefultostartreadingafewofthebeginningchapters:
Howtheinternetworks
Introductiontothecommandline
IntroductiontoPython
WhatisDjango?
Enjoytheworkshop!Whenyoubegintheworkshop,you'llbeabletogostraighttoYourfirstDjangoproject!becauseyoualreadycoveredthematerialintheearlierchapters.
Installation
15
HowtheInternetworksForreadersathome:thischapteriscoveredintheHowtheInternetWorksvideo.
Thischapterisinspiredbythetalk"HowtheInternetworks"byJessicaMcKellar(http://web.mit.edu/jesstess/www/).
WebetyouusetheInterneteveryday.Butdoyouactuallyknowwhathappenswhenyoutypeanaddresslikehttps://djangogirls.orgintoyourbrowserandpressenter?
Thefirstthingyouneedtounderstandisthatawebsiteisjustabunchoffilessavedonaharddisk.Justlikeyourmovies,music,orpictures.However,thereisonepartthatisuniqueforwebsites:theyincludecomputercodecalledHTML.
Ifyou'renotfamiliarwithprogrammingitcanbehardtograspHTMLatfirst,butyourwebbrowsers(likeChrome,Safari,Firefox,etc.)loveit.Webbrowsersaredesignedtounderstandthiscode,followitsinstructions,andpresentthesefilesthatyourwebsiteismadeof,exactlythewayyouwant.
Aswitheveryfile,weneedtostoreHTMLfilessomewhereonaharddisk.FortheInternet,weusespecial,powerfulcomputerscalledservers.Theydon'thaveascreen,mouseorakeyboard,becausetheirmainpurposeistostoredataandserveit.That'swhythey'recalledservers–becausetheyserveyoudata.
OK,butyouwanttoknowhowtheInternetlooks,right?
Wedrewyouapicture!Itlookslikethis:
Lookslikeamess,right?Infactitisanetworkofconnectedmachines(theabove-mentionedservers).Hundredsofthousandsofmachines!Many,manykilometersofcablesaroundtheworld!YoucanvisitaSubmarineCableMapwebsite(http://submarinecablemap.com)toseehowcomplicatedthenetis.Hereisascreenshotfromthewebsite:
HowtheInternetworks
16
Itisfascinating,isn'tit?Butobviously,itisnotpossibletohaveawirebetweeneverymachineconnectedtotheInternet.So,toreachamachine(forexample,theonewherehttps://djangogirls.orgissaved)weneedtopassarequestthroughmany,manydifferentmachines.
Itlookslikethis:
HowtheInternetworks
17
Imaginethatwhenyoutypehttps://djangogirls.org,yousendaletterthatsays:"DearDjangoGirls,Iwanttoseethedjangogirls.orgwebsite.Sendittome,please!"
Yourlettergoestothepostofficeclosesttoyou.Thenitgoestoanotherthatisabitnearertoyouraddressee,thentoanother,andanotheruntilitisdeliveredatitsdestination.Theonlyuniquethingisthatifyousendmanyletters(datapackets)tothesameplace,theycouldgothroughtotallydifferentpostoffices(routers).Thisdependsonhowtheyaredistributedateachoffice.
HowtheInternetworks
18
Yes,itisassimpleasthat.Yousendmessagesandyouexpectsomeresponse.Ofcourse,insteadofpaperandpenyouusebytesofdata,buttheideaisthesame!
Insteadofaddresseswithastreetname,city,zipcodeandcountryname,weuseIPaddresses.YourcomputerfirstaskstheDNS(DomainNameSystem)totranslatedjangogirls.orgintoanIPaddress.Itworksalittlebitlikeold-fashionedphonebookswhereyoucanlookupthenameofthepersonyouwanttocontactandfindtheirphonenumberandaddress.
Whenyousendaletter,itneedstohavecertainfeaturestobedeliveredcorrectly:anaddress,astamp,etc.Youalsousealanguagethatthereceiverunderstands,right?Thesameappliestothedatapacketsyousendtoseeawebsite.WeuseaprotocolcalledHTTP(HypertextTransferProtocol).
So,basically,whenyouhaveawebsite,youneedtohaveaserver(machine)whereitlives.Whentheserverreceivesanincomingrequest(inaletter),itsendsbackyourwebsite(inanotherletter).
SincethisisaDjangotutorial,youmightaskwhatDjangodoes.Whenyousendaresponse,youdon'talwayswanttosendthesamethingtoeverybody.Itissomuchbetterifyourlettersarepersonalized,especiallyforthepersonthathasjustwrittentoyou,right?Djangohelpsyouwithcreatingthesepersonalized,interestingletters.:)
Enoughtalk–timetocreate!
HowtheInternetworks
19
Introductiontothecommand-lineinterfaceForreadersathome:thischapteriscoveredintheYournewfriend:CommandLinevideo.
It'sexciting,right?!You'llwriteyourfirstlineofcodeinjustafewminutes!:)
Letusintroduceyoutoyourfirstnewfriend:thecommandline!
Thefollowingstepswillshowyouhowtousetheblackwindowallhackersuse.Itmightlookabitscaryatfirstbutreallyit'sjustapromptwaitingforcommandsfromyou.
Pleasenotethatthroughoutthisbookweusetheterms'directory'and'folder'interchangeablybuttheyareoneandthesamething.
Whatisthecommandline?Thewindow,whichisusuallycalledthecommandlineorcommand-lineinterface,isatext-basedapplicationforviewing,handling,andmanipulatingfilesonyourcomputer.It'smuchlikeWindowsExplorerorFinderontheMac,butwithoutthegraphicalinterface.Othernamesforthecommandlineare:cmd,CLI,prompt,consoleorterminal.
Openthecommand-lineinterfaceTostartsomeexperimentsweneedtoopenourcommand-lineinterfacefirst.
Windows
GotoStartmenu→AllPrograms→Accessories→CommandPrompt.
MacOSX
Applications→Utilities→Terminal.
Linux
It'sprobablyunderApplications→Accessories→Terminal,butthatmaydependonyoursystem.Ifit'snotthere,justGoogleit.:)
PromptYounowshouldseeawhiteorblackwindowthatiswaitingforyourcommands.
Ifyou'reonMacorLinux,youprobablysee$,justlikethis:
command-line
$
OnWindows,it'sa>sign,likethis:
command-line
>
Introductiontocommandline
20
Eachcommandwillbeprependedbythissignandonespace,butyoudon'thavetotypeit.Yourcomputerwilldoitforyou.:)
Justasmallnote:inyourcasetheremaybesomethinglikeC:\Users\ola>orOlas-MacBook-Air:~ola$beforethepromptsign,andthisis100%OK.
Thepartuptoandincludingthe$orthe>iscalledthecommandlineprompt,orpromptforshort.Itpromptsyoutoinputsomethingthere.
Inthetutorial,whenwewantyoutotypeinacommand,wewillincludethe$or>,andoccasionallymoretotheleft.Youcanignoretheleftpartandjusttypeinthecommandwhichstartsaftertheprompt.
Yourfirstcommand(YAY!)Let'sstartwithsomethingsimple.Typethiscommand:
command-line
$whoami
or
command-line
>whoami
Andthenhitenter.Thisisourresult:
command-line
$whoami
olasitarska
Asyoucansee,thecomputerhasjustprintedyourusername.Neat,huh?:)
Trytotypeeachcommand;donotcopy-paste.You'llremembermorethisway!
BasicsEachoperatingsystemhasaslightlydifferentsetofcommandsforthecommandline,somakesuretofollowinstructionsforyouroperatingsystem.Let'strythis,shallwe?
CurrentdirectoryIt'dbenicetoknowwherearewenow,right?Let'ssee.Typethiscommandandhitenter:
command-line
$pwd
/Users/olasitarska
Ifyou'reonWindows:
command-line
Introductiontocommandline
21
>cd
C:\Users\olasitarska
You'llprobablyseesomethingsimilaronyourmachine.Onceyouopenthecommandlineyouusuallystartatyouruser'shomedirectory.
Note:'pwd'standsfor'printworkingdirectory'.
Listfilesanddirectories
Sowhat'sinit?It'dbecooltofindout.Let'ssee:
command-line
$ls
Applications
Desktop
Downloads
Music
...
Windows:
command-line
>dir
DirectoryofC:\Users\olasitarska
05/08/201407:28PM<DIR>Applications
05/08/201407:28PM<DIR>Desktop
05/08/201407:28PM<DIR>Downloads
05/08/201407:28PM<DIR>Music
...
ChangecurrentdirectoryNow,let'sgotoourDesktopdirectory:
command-line
$cdDesktop
Windows:
command-line
>cdDesktop
Checkifit'sreallychanged:
command-line
$pwd
/Users/olasitarska/Desktop
Windows:
command-line
Introductiontocommandline
22
>cd
C:\Users\olasitarska\Desktop
Hereitis!
PROtip:ifyoutypecdDandthenhittabonyourkeyboard,thecommandlinewillautomaticallyfillintherestofthenamesoyoucannavigatefaster.Ifthereismorethanonefolderstartingwith"D",hitthetabbuttontwicetogetalistofoptions.
Createdirectory
Howaboutcreatingapracticedirectoryonyourdesktop?Youcandoitthisway:
command-line
$mkdirpractice
Windows:
command-line
>mkdirpractice
Thislittlecommandwillcreateafolderwiththenamepracticeonyourdesktop.Youcancheckifit'stherejustbylookingonyourDesktoporbyrunningalsordircommand!Tryit.:)
PROtip:Ifyoudon'twanttotypethesamecommandsoverandover,trypressingtheuparrowanddownarrowonyourkeyboardtocyclethroughrecentlyusedcommands.
Exercise!Asmallchallengeforyou:inyournewlycreatedpracticedirectory,createadirectorycalledtest.(Usethecdandmkdircommands.)
Solution:command-line
$cdpractice
$mkdirtest
$ls
test
Windows:
command-line
>cdpractice
>mkdirtest
>dir
05/08/201407:28PM<DIR>test
Congrats!:)
Introductiontocommandline
23
Cleanup
Wedon'twanttoleaveamess,solet'sremoveeverythingwediduntilthatpoint.
First,weneedtogetbacktoDesktop:
command-line
$cd..
Windows:
command-line
>cd..
Using..withthecdcommandwillchangeyourcurrentdirectorytotheparentdirectory(thatis,thedirectorythatcontainsyourcurrentdirectory).
Checkwhereyouare:
command-line
$pwd
/Users/olasitarska/Desktop
Windows:
command-line
>cd
C:\Users\olasitarska\Desktop
Nowtimetodeletethepracticedirectory:
Attention:Deletingfilesusingdel,rmdirorrmisirrecoverable,meaningthedeletedfileswillbegoneforever!Sobeverycarefulwiththiscommand.
command-line
$rm-rpractice
Windows:
command-line
>rmdir/Spractice
practice,Areyousure<Y/N>?Y
Done!Tobesureit'sactuallydeleted,let'scheckit:
command-line
$ls
Windows:
command-line
Introductiontocommandline
24
>dir
ExitThat'sitfornow!Youcansafelyclosethecommandlinenow.Let'sdoitthehackerway,alright?:)
command-line
$exit
Windows:
command-line
>exit
Cool,huh?:)
SummaryHereisasummaryofsomeusefulcommands:
Command(Windows)
Command(MacOS/Linux) Description Example
exit exit closethewindow exit
cd cd changedirectory cdtest
dir ls listdirectories/files dir
copy cp copyfile copyc:\test\test.txtc:\windows\test.txt
move mv movefile movec:\test\test.txtc:\windows\test.txt
mkdir mkdir createanewdirectory mkdirtestdirectory
rmdir(ordel) rm deleteafile delc:\test\test.txt
rmdir\S rm-r deleteadirectory rm-rtestdirectory
Thesearejustaveryfewofthecommandsyoucanruninyourcommandline,butyou'renotgoingtouseanythingmorethanthattoday.
Ifyou'recurious,ss64.comcontainsacompletereferenceofcommandsforalloperatingsystems.
Ready?Let'sdiveintoPython!
Introductiontocommandline
25
Let’sstartwithPythonWe'refinallyhere!
Butfirst,letustellyouwhatPythonis.Pythonisaverypopularprogramminglanguagethatcanbeusedforcreatingwebsites,games,scientificsoftware,graphics,andmuch,muchmore.
Pythonoriginatedinthelate1980sanditsmaingoalistobereadablebyhumanbeings(notonlymachines!).Thisiswhyitlooksmuchsimplerthanotherprogramminglanguages.Thismakesiteasytolearn,butdon'tworry–Pythonisalsoreallypowerful!
PythoninstallationIfyou'reusingaChromebook,skipthischapterandmakesureyoufollowtheChromebookSetupinstructions.
NoteIfyoualreadyworkedthroughtheInstallationsteps,there'snoneedtodothisagain–youcanskipstraightaheadtothenextchapter!
Forreadersathome:thischapteriscoveredintheInstallingPython&CodeEditorvideo.
ThissectionisbasedonatutorialbyGeekGirlsCarrots(https://github.com/ggcarrots/django-carrots)
DjangoiswritteninPython.WeneedPythontodoanythinginDjango.Let'sstartbyinstallingit!WewantyoutoinstallPython3.5,soifyouhaveanyearlierversion,youwillneedtoupgradeit.
WindowsYoucandownloadPythonforWindowsfromthewebsitehttps://www.python.org/downloads/release/python-351/.Afterdownloadingthe*.msifile,youshouldrunit(double-clickonit)andfollowtheinstructionsthere.Itisimportanttorememberthepath(thedirectory)whereyouinstalledPython.Itwillbeneededlater!
Onethingtowatchoutfor:onthesecondscreenoftheinstallationwizard,marked"Customize",makesureyouscrolldowntothe"Addpython.exetothePath"optionandselect"Willbeinstalledonlocalharddrive",asshownhere:
Pythoninstallation
26
Inupcomingsteps,you'llbeusingtheWindowsCommandLine(whichwe'llalsotellyouabout).Fornow,ifyouneedtotypeinsomecommands,gotoStartmenu→AllPrograms→Accessories→CommandPrompt.(OnnewerversionsofWindows,youmighthavetosearchfor"CommandPrompt"sinceit'ssometimeshidden.)
Linux
ItisverylikelythatyoualreadyhavePythoninstalledoutofthebox.Tocheckifyouhaveitinstalled(andwhichversionitis),openaconsoleandtypethefollowingcommand:
command-line
$python3--version
Python3.5.1
Ifyouhaveadifferent'microversion'ofPythoninstalled,e.g.3.5.0,thenyoudon'thavetoupgrade.Ifyoudon'thavePythoninstalled,orifyouwantadifferentversion,youcaninstallitasfollows:
DebianorUbuntu
Typethiscommandintoyourconsole:
command-line
$sudoapt-getinstallpython3.5
Fedora(upto21)
Usethiscommandinyourconsole:
command-line
Pythoninstallation
27
$sudoyuminstallpython3
Fedora(22+)Usethiscommandinyourconsole:
command-line
$sudodnfinstallpython3
openSUSE
Usethiscommandinyourconsole:
command-line
$sudozypperinstallpython3
OSXBeforeyouinstallPythononOSX,youshouldensureyourMacsettingsallowinstallingpackagesthataren'tfromtheAppStore.GotoSystemPreferences(it'sintheApplicationsfolder),click"Security&Privacy,"andthenthe"General"tab.Ifyour"Allowappsdownloadedfrom:"issetto"MacAppStore,"changeitto"MacAppStoreandidentifieddevelopers."
Youneedtogotothewebsitehttps://www.python.org/downloads/release/python-351/anddownloadthePythoninstaller:
DownloadtheMacOSX64-bit/32-bitinstallerfile,Doubleclickpython-3.5.1-macosx10.6.pkgtoruntheinstaller.
VerifytheinstallationwassuccessfulbyopeningtheTerminalapplicationandrunningthepython3command:
command-line
$python3--version
Python3.5.1
Ifyouhaveanydoubts,orifsomethingwentwrongandyouhavenoideawhattodonext,pleaseaskyourcoach!Sometimesthingsdon'tgosmoothlyandit'sbettertoaskforhelpfromsomeonewithmoreexperience.
Pythoninstallation
28
CodeeditorForreadersathome:thischapteriscoveredintheInstallingPython&CodeEditorvideo.
You'reabouttowriteyourfirstlineofcode,soit'stimetodownloadacodeeditor!
Ifyou'reusingaChromebook,skipthischapterandmakesureyoufollowtheChromebookSetupinstructions.
NoteYoumighthavedonethisearlierintheInstallationchapter–ifso,youcanskiprightaheadtothenextchapter!
Therearealotofdifferenteditorsanditlargelyboilsdowntopersonalpreference.MostPythonprogrammersusecomplexbutextremelypowerfulIDEs(IntegratedDevelopmentEnvironments),suchasPyCharm.Asabeginner,however,that'sprobablylesssuitable;ourrecommendationsareequallypowerful,butalotsimpler.
Oursuggestionsarebelow,butfeelfreetoaskyourcoachwhattheirpreferencesare–it'llbeeasiertogethelpfromthem.
GeditGeditisanopen-source,freeeditor,availableforalloperatingsystems.
Downloadithere
SublimeText2SublimeTextisaverypopulareditorwithafreeevaluationperiod.It'seasytoinstallanduse,andit'savailableforalloperatingsystems.
Downloadithere
AtomAtomisanextremelynewcodeeditorcreatedbyGitHub.It'sfree,open-source,easytoinstallandeasytouse.It'savailableforWindows,OSXandLinux.
Downloadithere
Whyareweinstallingacodeeditor?Youmightbewonderingwhyweareinstallingthisspecialcodeeditorsoftware,ratherthanusingsomethinglikeWordorNotepad.
Thefirstreasonisthatcodeneedstobeplaintext,andtheproblemwithprogramslikeWordandTexteditisthattheydon'tactuallyproduceplaintext,theyproducerichtext(withfontsandformatting),usingcustomformatslikeRTF(RichTextFormat).
Thesecondreasonisthatcodeeditorsarespecialisedforeditingcode,sotheycanprovidehelpfulfeatureslikehighlightingcodewithcolouraccordingtoitsmeaning,orautomaticallyclosingquotesforyou.
We'llseeallthisinactionlater.Soon,you'llcometothinkofyourtrustyoldcodeeditorasoneofyourfavouritetools.:)
Codeeditor
29
Codeeditor
30
IntroductiontoPythonPartofthischapterisbasedontutorialsbyGeekGirlsCarrots(https://github.com/ggcarrots/django-carrots).
Let'swritesomecode!
PythonpromptForreadersathome:thispartiscoveredinthePythonBasics:Integers,Strings,Lists,VariablesandErrorsvideo.
TostartplayingwithPython,weneedtoopenupacommandlineonyourcomputer.Youshouldalreadyknowhowtodothat–youlearneditintheIntrotoCommandLinechapter.
Onceyou'reready,followtheinstructionsbelow.
WewanttoopenupaPythonconsole,sotypeinpythononWindowsorpython3onMacOS/Linuxandhitenter.
command-line
$python3
Python3.5.1(...)
Type"help","copyright","credits"or"license"formoreinformation.
>>>
YourfirstPythoncommand!AfterrunningthePythoncommand,thepromptchangedto>>>.ForusthismeansthatfornowwemayonlyusecommandsinthePythonlanguage.Youdon'thavetotypein>>>–Pythonwilldothatforyou.
IfyouwanttoexitthePythonconsoleatanypoint,justtypeexit()orusetheshortcutCtrl+ZforWindowsandCtrl+DforMac/Linux.Thenyouwon'tsee>>>anylonger.
Fornow,wedon'twanttoexitthePythonconsole.Wewanttolearnmoreaboutit.Let'sstartwithsomethingreallysimple.Forexample,trytypingsomemath,like2+3andhitenter.
command-line
>>>2+3
5
Nice!Seehowtheanswerpoppedout?Pythonknowsmath!Youcouldtryothercommandslike:
4*5
5-1
40/2
Havefunwiththisforalittlewhileandthengetbackhere.:)
Asyoucansee,Pythonisagreatcalculator.Ifyou'rewonderingwhatelseyoucando…
StringsHowaboutyourname?Typeyourfirstnameinquoteslikethis:
command-line
IntroductiontoPython
31
>>>"Ola"
'Ola'
You'venowcreatedyourfirststring!It'sasequenceofcharactersthatcanbeprocessedbyacomputer.Thestringmustalwaysbeginandendwiththesamecharacter.Thismaybesingle(')ordouble(")quotes(thereisnodifference!)ThequotestellPythonthatwhat'sinsideofthemisastring.
Stringscanbestrungtogether.Trythis:
command-line
>>>"Hithere"+"Ola"
'HithereOla'
Youcanalsomultiplystringswithanumber:
command-line
>>>"Ola"*3
'OlaOlaOla'
Ifyouneedtoputanapostropheinsideyourstring,youhavetwowaystodoit.
Usingdoublequotes:
command-line
>>>"Runnin'downthehill"
"Runnin'downthehill"
orescapingtheapostrophewithabackslash(\):
command-line
>>>'Runnin\'downthehill'
"Runnin'downthehill"
Nice,huh?Toseeyournameinuppercaseletters,simplytype:
command-line
>>>"Ola".upper()
'OLA'
Youjustusedtheuppermethodonyourstring!Amethod(likeupper())isasequenceofinstructionsthatPythonhastoperformonagivenobject("Ola")onceyoucallit.
Ifyouwanttoknowthenumberofletterscontainedinyourname,thereisafunctionforthattoo!
command-line
>>>len("Ola")
3
Wonderwhysometimesyoucallfunctionswitha.attheendofastring(like"Ola".upper())andsometimesyoufirstcallafunctionandplacethestringinparentheses?Well,insomecases,functionsbelongtoobjects,likeupper(),whichcanonlybeperformedonstrings.Inthiscase,wecallthefunctionamethod.Othertimes,functionsdon'tbelongtoanything
IntroductiontoPython
32
specificandcanbeusedondifferenttypesofobjects,justlikelen().That'swhywe'regiving"Ola"asaparametertothelenfunction.
Summary
OK,enoughofstrings.Sofaryou'velearnedabout:
theprompt–typingcommands(code)intothePythonpromptresultsinanswersinPythonnumbersandstrings–inPythonnumbersareusedformathandstringsfortextobjectsoperators–like+and\*,combinevaluestoproduceanewonefunctions–likeupper()andlen(),performactionsonobjects.
Thesearethebasicsofeveryprogramminglanguageyoulearn.Readyforsomethingharder?Webetyouare!
ErrorsLet'strysomethingnew.Canwegetthelengthofanumberthesamewaywecouldfindoutthelengthofourname?Typeinlen(304023)andhitenter:
command-line
>>>len(304023)
Traceback(mostrecentcalllast):
File"<stdin>",line1,in<module>
TypeError:objectoftype'int'hasnolen()
Wegotourfirsterror!Itsaysthatobjectsoftype"int"(integers,wholenumbers)havenolength.Sowhatcanwedonow?Maybewecanwriteournumberasastring?Stringshavealength,right?
command-line
>>>len(str(304023))
6
Itworked!Weusedthestrfunctioninsideofthelenfunction.str()convertseverythingtostrings.
ThestrfunctionconvertsthingsintostringsTheintfunctionconvertsthingsintointegers
Important:wecanconvertnumbersintotext,butwecan'tnecessarilyconverttextintonumbers–whatwouldint('hello')beanyway?
VariablesAnimportantconceptinprogrammingisvariables.Avariableisnothingmorethananameforsomethingsoyoucanuseitlater.Programmersusethesevariablestostoredata,maketheircodemorereadableandsotheydon'thavetokeeprememberingwhatthingsare.
Let'ssaywewanttocreateanewvariablecalledname:
command-line
>>>name="Ola"
Yousee?It'seasy!It'ssimply:nameequalsOla.
IntroductiontoPython
33
Asyou'venoticed,yourprogramdidn'treturnanythinglikeitdidbefore.Sohowdoweknowthatthevariableactuallyexists?Simplyenternameandhitenter:
command-line
>>>name
'Ola'
Yippee!Yourfirstvariable!:)Youcanalwayschangewhatitrefersto:
command-line
>>>name="Sonja"
>>>name
'Sonja'
Youcanuseitinfunctionstoo:
command-line
>>>len(name)
5
Awesome,right?Ofcourse,variablescanbeanything–numberstoo!Trythis:
command-line
>>>a=4
>>>b=6
>>>a*b
24
Butwhatifweusedthewrongname?Canyouguesswhatwouldhappen?Let'stry!
command-line
>>>city="Tokyo"
>>>ctiy
Traceback(mostrecentcalllast):
File"<stdin>",line1,in<module>
NameError:name'ctiy'isnotdefined
Anerror!Asyoucansee,PythonhasdifferenttypesoferrorsandthisoneiscalledaNameError.Pythonwillgiveyouthiserrorifyoutrytouseavariablethathasn'tbeendefinedyet.Ifyouencounterthiserrorlater,checkyourcodetoseeifyou'vemistypedanynames.
Playwiththisforawhileandseewhatyoucando!
TheprintfunctionTrythis:
command-line
>>>name='Maria'
>>>name
'Maria'
>>>print(name)
Maria
IntroductiontoPython
34
Whenyoujusttypename,thePythoninterpreterrespondswiththestringrepresentationofthevariable'name',whichisthelettersM-a-r-i-a,surroundedbysinglequotes,''.Whenyousayprint(name),Pythonwill"print"thecontentsofthevariabletothescreen,withoutthequotes,whichisneater.
Aswe'llseelater,print()isalsousefulwhenwewanttoprintthingsfrominsidefunctions,orwhenwewanttoprintthingsonmultiplelines.
ListsBesidestringsandintegers,Pythonhasallsortsofdifferenttypesofobjects.Nowwe'regoingtointroduceonecalledlist.Listsareexactlywhatyouthinktheyare:objectswhicharelistsofotherobjects.:)
Goaheadandcreatealist:
command-line
>>>[]
[]
Yes,thislistisempty.Notveryuseful,right?Let'screatealistoflotterynumbers.Wedon'twanttorepeatourselvesallthetime,sowewillputitinavariable,too:
command-line
>>>lottery=[3,42,12,19,30,59]
Allright,wehavealist!Whatcanwedowithit?Let'sseehowmanylotterynumbersthereareinalist.Doyouhaveanyideawhichfunctionyoushoulduseforthat?Youknowthisalready!
command-line
>>>len(lottery)
6
Yes!len()cangiveyouanumberofobjectsinalist.Handy,right?Maybewewillsortitnow:
command-line
>>>lottery.sort()
Thisdoesn'treturnanything,itjustchangedtheorderinwhichthenumbersappearinthelist.Let'sprintitoutagainandseewhathappened:
command-line
>>>print(lottery)
[3,12,19,30,42,59]
Asyoucansee,thenumbersinyourlistarenowsortedfromthelowesttohighestvalue.Congrats!
Maybewewanttoreversethatorder?Let'sdothat!
command-line
>>>lottery.reverse()
>>>print(lottery)
[59,42,30,19,12,3]
IntroductiontoPython
35
Easy,right?Ifyouwanttoaddsomethingtoyourlist,youcandothisbytypingthiscommand:
command-line
>>>lottery.append(199)
>>>print(lottery)
[59,42,30,19,12,3,199]
Ifyouwanttoshowonlythefirstnumber,youcandothisbyusingindexes.Anindexisthenumberthatsayswhereinalistanitemoccurs.Programmersprefertostartcountingat0,sothefirstobjectinyourlistisatindex0,thenextoneisat1,andsoon.Trythis:
command-line
>>>print(lottery[0])
59
>>>print(lottery[1])
42
Asyoucansee,youcanaccessdifferentobjectsinyourlistbyusingthelist'snameandtheobject'sindexinsideofsquarebrackets.
Todeletesomethingfromyourlistyouwillneedtouseindexesaswelearntaboveandthepop()method.Let'stryanexampleandreinforcewhatwelearntpreviously;wewillbedeletingthefirstnumberofourlist.
command-line
>>>print(lottery)
[59,42,30,19,12,3,199]
>>>print(lottery[0])
59
>>>lottery.pop(0)
>>>print(lottery)
[42,30,19,12,3,199]
Thatworkedlikeacharm!
Forextrafun,trysomeotherindexes:6,7,1000,-1,-6or-1000.Seeifyoucanpredicttheresultbeforetryingthecommand.Dotheresultsmakesense?
YoucanfindalistofallavailablelistmethodsinthischapterofthePythondocumentation:https://docs.python.org/3/tutorial/datastructures.html
DictionariesForreadersathome:thispartiscoveredinthePythonBasics:Dictionariesvideo.
Adictionaryissimilartoalist,butyouaccessvaluesbylookingupakeyinsteadofanumericindex.Akeycanbeanystringornumber.Thesyntaxtodefineanemptydictionaryis:
command-line
>>>{}
{}
Thisshowsthatyoujustcreatedanemptydictionary.Hurray!
Now,trywritingthefollowingcommand(trysubstitutingyourowninformation,too):
command-line
IntroductiontoPython
36
>>>participant={'name':'Ola','country':'Poland','favorite_numbers':[7,42,92]}
Withthiscommand,youjustcreatedavariablenamedparticipantwiththreekey–valuepairs:
Thekeynamepointstothevalue'Ola'(astringobject),countrypointsto'Poland'(anotherstring),andfavorite_numberspointsto[7,42,92](alistwiththreenumbersinit).
Youcancheckthecontentofindividualkeyswiththissyntax:
command-line
>>>print(participant['name'])
Ola
See,it'ssimilartoalist.Butyoudon'tneedtoremembertheindex–justthename.
WhathappensifweaskPythonthevalueofakeythatdoesn'texist?Canyouguess?Let'stryitandsee!
command-line
>>>participant['age']
Traceback(mostrecentcalllast):
File"<stdin>",line1,in<module>
KeyError:'age'
Look,anothererror!ThisoneisaKeyError.Pythonishelpfulandtellsyouthatthekey'age'doesn'texistinthisdictionary.
Whenshouldyouuseadictionaryoralist?Well,that'sagoodpointtoponder.Justhaveasolutioninmindbeforelookingattheanswerinthenextline.
Doyoujustneedanorderedsequenceofitems?Goforalist.Doyouneedtoassociatevalueswithkeys,soyoucanlookthemupefficiently(bykey)lateron?Useadictionary.
Dictionaries,likelists,aremutable,meaningthattheycanbechangedaftertheyarecreated.Youcanaddnewkey–valuepairstoadictionaryafteritiscreated,likethis:
command-line
>>>participant['favorite_language']='Python'
Likelists,usingthelen()methodonthedictionariesreturnsthenumberofkey–valuepairsinthedictionary.Goaheadandtypeinthiscommand:
command-line
>>>len(participant)
4
Ihopeitmakessenseuptonow.:)Readyforsomemorefunwithdictionaries?Readonforsomeamazingthings.
Youcanusethepop()methodtodeleteaniteminthedictionary.Say,ifyouwanttodeletetheentrycorrespondingtothekey'favorite_numbers',justtypeinthefollowingcommand:
command-line
>>>participant.pop('favorite_numbers')
>>>participant
{'country':'Poland','favorite_language':'Python','name':'Ola'}
IntroductiontoPython
37
Asyoucanseefromtheoutput,thekey–valuepaircorrespondingtothe'favorite_numbers'keyhasbeendeleted.
Aswellasthis,youcanalsochangeavalueassociatedwithanalready-createdkeyinthedictionary.Typethis:
command-line
>>>participant['country']='Germany'
>>>participant
{'country':'Germany','favorite_language':'Python','name':'Ola'}
Asyoucansee,thevalueofthekey'country'hasbeenalteredfrom'Poland'to'Germany'.:)Exciting?Hurrah!Youjustlearntanotheramazingthing.
Summary
Awesome!Youknowalotaboutprogrammingnow.Inthislastpartyoulearnedabout:
errors–younowknowhowtoreadandunderstanderrorsthatshowupifPythondoesn'tunderstandacommandyou'vegivenitvariables–namesforobjectsthatallowyoutocodemoreeasilyandtomakeyourcodemorereadablelists–listsofobjectsstoredinaparticularorderdictionaries–objectsstoredaskey–valuepairs
Excitedforthenextpart?:)
ComparethingsForreadersathome:thispartiscoveredinthePythonBasics:Comparisonsvideo.
Abigpartofprogramminginvolvescomparingthings.What'stheeasiestthingtocompare?Numbers,ofcourse.Let'sseehowthatworks:
command-line
>>>5>2
True
>>>3<1
False
>>>5>2*2
True
>>>1==1
True
>>>5!=2
True
WegavePythonsomenumberstocompare.Asyoucansee,notonlycanPythoncomparenumbers,butitcanalsocomparemethodresults.Nice,huh?
Doyouwonderwhyweputtwoequalsigns==nexttoeachothertocompareifnumbersareequal?Weuseasingle=forassigningvaluestovariables.Youalways,alwaysneedtoputtwoofthem–==–ifyouwanttocheckifthingsareequaltoeachother.Wecanalsostatethatthingsareunequaltoeachother.Forthat,weusethesymbol!=,asshownintheexampleabove.
GivePythontwomoretasks:
command-line
IntroductiontoPython
38
>>>6>=12/2
True
>>>3<=2
False
>and<areeasy,butwhatdo>=and<=mean?Readthemlikethis:
x>ymeans:xisgreaterthanyx<ymeans:xislessthanyx<=ymeans:xislessthanorequaltoyx>=ymeans:xisgreaterthanorequaltoy
Awesome!Wannadoonemore?Trythis:
command-line
>>>6>2and2<3
True
>>>3>2and2<1
False
>>>3>2or2<1
True
YoucangivePythonasmanynumberstocompareasyouwant,anditwillgiveyouananswer!Prettysmart,right?
and–ifyouusetheandoperator,bothcomparisonshavetobeTrueinorderforthewholecommandtobeTrueor–ifyouusetheoroperator,onlyoneofthecomparisonshastobeTrueinorderforthewholecommandtobeTrue
Haveyouheardoftheexpression"comparingapplestooranges"?Let'strythePythonequivalent:
command-line
>>>1>'django'
Traceback(mostrecentcalllast):
File"<stdin>",line1,in<module>
TypeError:unorderabletypes:int()>str()
Hereyouseethatjustlikeintheexpression,Pythonisnotabletocompareanumber(int)andastring(str).Instead,itshowsaTypeErrorandtellsusthetwotypescan'tbecomparedtogether.
BooleanIncidentally,youjustlearnedaboutanewtypeofobjectinPython.It'scalledBoolean,anditisprobablytheeasiesttypethereis.
ThereareonlytwoBooleanobjects:
TrueFalse
ButforPythontounderstandthis,youneedtoalwayswriteitas'True'(firstletteruppercased,withtherestoftheletterlowercased).true,TRUE,andtRUEwon'twork–onlyTrueiscorrect.(Thesameappliesto'False'aswell,ofcourse.)
Booleanscanbevariables,too!Seehere:
command-line
IntroductiontoPython
39
>>>a=True
>>>a
True
Youcanalsodoitthisway:
command-line
>>>a=2>5
>>>a
False
PracticeandhavefunwithBooleansbytryingtorunthefollowingcommands:
TrueandTrue
FalseandTrue
Trueor1==1
1!=2
Congrats!Booleansareoneofthecoolestfeaturesinprogramming,andyoujustlearnedhowtousethem!
Saveit!Forreadersathome:thispartiscoveredinthePythonBasics:Savingfilesand"If"statementvideo.
Sofarwe'vebeenwritingallourpythoncodeintheinterpreter,whichlimitsustoenteringonelineofcodeatatime.Normalprogramsaresavedinfilesandexecutedbyourprogramminglanguageinterpreterorcompiler.Sofarwe'vebeenrunningourprogramsonelineatatimeinthePythoninterpreter.We'regoingtoneedmorethanonelineofcodeforthenextfewtasks,sowe'llquicklyneedto:
ExitthePythoninterpreterOpenupourcodeeditorofchoiceSavesomecodeintoanewpythonfileRunit!
ToexitfromthePythoninterpreterthatwe'vebeenusing,simplytypetheexit()function
command-line
>>>exit()
$
Thiswillputyoubackintothecommandprompt.
Earlier,wepickedoutacodeeditorfromthecodeeditorsection.We'llneedtoopentheeditornowandwritesomecodeintoanewfile:
editor
print('Hello,Djangogirls!')
Obviously,you'reaprettyseasonedPythondevelopernow,sofeelfreetowritesomecodethatyou'velearnedtoday.
Nowweneedtosavethefileandgiveitadescriptivename.Let'scallthefilepython_intro.pyandsaveittoyourdesktop.Wecannamethefileanythingwewant,buttheimportantparthereistomakesurethefileendsin.py.The.pyextensiontellsouroperatingsystemthatthisisaPythonexecutablefileandPythoncanrunit.
IntroductiontoPython
40
Youshouldnoticeoneofthecoolestthingaboutcodeeditors:colours!InthePythonconsole,everythingwasthesamecolour;nowyoushouldseethattheprintfunctionisadifferentcolourfromthestring.Thisiscalled"syntaxhighlighting",andit'sareallyusefulfeaturewhencoding.Thecolourofthingswillgiveyouhints,suchasunclosedstringsoratypoinakeywordname(likethedefinafunction,whichwe'llseebelow).Thisisoneofthereasonsweuseacodeeditor.:)
Withthefilesaved,it'stimetorunit!Usingtheskillsyou'velearnedinthecommandlinesection,usetheterminaltochangedirectoriestothedesktop.(Note:Replace<your_name>includingthe<and>withyourusername.)
OnaMac,thecommandwilllooksomethinglikethis:
command-line
$cd/Users/<your_name>/Desktop
OnLinux,itwillbelikethis(theword"Desktop"mightbetranslatedtoyourlocallanguage):
command-line
$cd/home/<your_name>/Desktop
AndonWindows,itwillbelikethis:
command-line
>cdC:\Users\<your_name>\Desktop
Ifyougetstuck,justaskforhelp.
NowusePythontoexecutethecodeinthefilelikethis:
command-line
$python3python_intro.py
Hello,Djangogirls!
Note:onWindows'python3'isnotrecognizedasacommand.Instead,use'python'toexecutethefile:
command-line
>pythonpython_intro.py
Alright!YoujustranyourfirstPythonprogramthatwassavedtoafile.Feelawesome?
Youcannowmoveontoanessentialtoolinprogramming:
If…elif…elseLotsofthingsincodeshouldbeexecutedonlywhengivenconditionsaremet.That'swhyPythonhassomethingcalledifstatements.
Replacethecodeinyourpython_intro.pyfilewiththis:
python_intro.py
if3>2:
IntroductiontoPython
41
Ifweweretosaveandrunthis,we'dseeanerrorlikethis:
command-line
$python3python_intro.py
File"python_intro.py",line2
^
SyntaxError:unexpectedEOFwhileparsing
Pythonexpectsustogivefurtherinstructionstoitwhichareexecutedifthecondition3>2turnsouttobetrue(orTrueforthatmatter).Let’strytomakePythonprint“Itworks!”.Changeyourcodeinyourpython_intro.pyfiletothis:
python_intro.py
if3>2:
print('Itworks!')
Noticehowwe'veindentedthenextlineofcodeby4spaces?WeneedtodothissoPythonknowswhatcodetoruniftheresultistrue.Youcandoonespace,butnearlyallPythonprogrammersdo4tomakethingslookneat.Asingletabwillalsocountas4spaces.
Saveitandgiveitanotherrun:
command-line
$python3python_intro.py
Itworks!
Note:RememberthatonWindows,'python3'isnotrecognizedasacommand.Fromnowon,replace'python3'with'python'toexecutethefile.
Whatifaconditionisn'tTrue?Inpreviousexamples,codewasexecutedonlywhentheconditionswereTrue.ButPythonalsohaselifandelsestatements:
python_intro.py
if5>2:
print('5isindeedgreaterthan2')
else:
print('5isnotgreaterthan2')
Whenthisisrunitwillprintout:
command-line
$python3python_intro.py
5isindeedgreaterthan2
If2wereagreaternumberthan5,thenthesecondcommandwouldbeexecuted.Easy,right?Let'sseehowelifworks:
python_intro.py
IntroductiontoPython
42
name='Sonja'
ifname=='Ola':
print('HeyOla!')
elifname=='Sonja':
print('HeySonja!')
else:
print('Heyanonymous!')
andexecuted:
command-line
$python3python_intro.py
HeySonja!
Seewhathappenedthere?elifletsyouaddextraconditionsthatrunifthepreviousconditionsfail.
Youcanaddasmanyelifstatementsasyoulikeafteryourinitialifstatement.Forexample:
python_intro.py
volume=57
ifvolume<20:
print("It'skindaquiet.")
elif20<=volume<40:
print("It'sniceforbackgroundmusic")
elif40<=volume<60:
print("Perfect,Icanhearallthedetails")
elif60<=volume<80:
print("Niceforparties")
elif80<=volume<100:
print("Abitloud!")
else:
print("Myearsarehurting!:(")
Pythonrunsthrougheachtestinsequenceandprints:
command-line
$python3python_intro.py
Perfect,Icanhearallthedetails
CommentsCommentsarelinesbeginningwith#.Youcanwritewhateveryouwantafterthe#andPythonwillignoreit.Commentscanmakeyourcodeeasierforotherpeopletounderstand.
Let'sseehowthatlooks:
python_intro.py
#Changethevolumeifit'stooloudortooquiet
ifvolume<20orvolume>80:
volume=50
print("That'sbetter!")
Youdon'tneedtowriteacommentforeverylineofcode,buttheyareusefulforexplainingwhyyourcodeisdoingsomething,orprovidingasummarywhenit'sdoingsomethingcomplex.
Summary
IntroductiontoPython
43
Inthelastfewexercisesyoulearnedabout:
comparingthings–inPythonyoucancomparethingsbyusing>,>=,==,<=,<andtheand,oroperatorsBoolean–atypeofobjectthatcanonlyhaveoneoftwovalues:TrueorFalseSavingfiles–storingcodeinfilessoyoucanexecutelargerprograms.if…elif…else–statementsthatallowyoutoexecutecodeonlywhencertainconditionsaremet.comments-linesthatPythonwon'trunwhichletyoudocumentyourcode
Timeforthelastpartofthischapter!
Yourownfunctions!Forreadersathome:thispartiscoveredinthePythonBasics:Functionsvideo.
Rememberfunctionslikelen()thatyoucanexecuteinPython?Well,goodnews–youwilllearnhowtowriteyourownfunctionsnow!
AfunctionisasequenceofinstructionsthatPythonshouldexecute.EachfunctioninPythonstartswiththekeyworddef,isgivenaname,andcanhavesomeparameters.Let'sstartwithaneasyone.Replacethecodeinpython_intro.pywiththefollowing:
python_intro.py
defhi():
print('Hithere!')
print('Howareyou?')
hi()
Okay,ourfirstfunctionisready!
Youmaywonderwhywe'vewrittenthenameofthefunctionatthebottomofthefile.ThisisbecausePythonreadsthefileandexecutesitfromtoptobottom.Soinordertouseourfunction,wehavetore-writeitatthebottom.
Let'srunthisnowandseewhathappens:
command-line
$python3python_intro.py
Hithere!
Howareyou?
Thatwaseasy!Let'sbuildourfirstfunctionwithparameters.Wewillusethepreviousexample–afunctionthatsays'hi'tothepersonrunningit–withaname:
python_intro.py
defhi(name):
Asyoucansee,wenowgaveourfunctionaparameterthatwecalledname:
python_intro.py
IntroductiontoPython
44
defhi(name):
ifname=='Ola':
print('HiOla!')
elifname=='Sonja':
print('HiSonja!')
else:
print('Hianonymous!')
hi()
Remember:Theprintfunctionisindentedfourspaceswithintheifstatement.Thisisbecausethefunctionrunswhentheconditionismet.Let'sseehowitworksnow:
command-line
$python3python_intro.py
Traceback(mostrecentcalllast):
File"python_intro.py",line10,in<module>
hi()
TypeError:hi()missing1requiredpositionalargument:'name'
Oops,anerror.Luckily,Pythongivesusaprettyusefulerrormessage.Ittellsusthatthefunctionhi()(theonewedefined)hasonerequiredargument(calledname)andthatweforgottopassitwhencallingthefunction.Let'sfixitatthebottomofthefile:
python_intro.py
hi("Ola")
Andrunitagain:
command-line
$python3python_intro.py
HiOla!
Andifwechangethename?
python_intro.py
hi("Sonja")
Andrunit:
command-line
$python3python_intro.py
HiSonja!
Now,whatdoyouthinkwillhappenifyouwriteanothernameinthere?(NotOlaorSonja.)Giveitatryandseeifyou'reright.Itshouldprintoutthis:
command-line
Hianonymous!
Thisisawesome,right?Thiswayyoudon'thavetorepeatyourselfeverytimeyouwanttochangethenameofthepersonthefunctionissupposedtogreet.Andthat'sexactlywhyweneedfunctions–youneverwanttorepeatyourcode!
IntroductiontoPython
45
Let'sdosomethingsmarter–therearemorenamesthantwo,andwritingaconditionforeachwouldbehard,right?
python_intro.py
defhi(name):
print('Hi'+name+'!')
hi("Rachel")
Let'scallthecodenow:
command-line
$python3python_intro.py
HiRachel!
Congratulations!Youjustlearnedhowtowritefunctions!:)
LoopsForreadersathome:thispartiscoveredinthePythonBasics:ForLoopvideo.
Thisisthelastpartalready.Thatwasquick,right?:)
Programmersdon'tliketorepeatthemselves.Programmingisallaboutautomatingthings,sowedon'twanttogreeteverypersonbytheirnamemanually,right?That'swhereloopscomeinhandy.
Stillrememberlists?Let'sdoalistofgirls:
python_intro.py
girls=['Rachel','Monica','Phoebe','Ola','You']
Wewanttogreetallofthembytheirname.Wehavethehifunctiontodothat,solet'suseitinaloop:
python_intro.py
fornameingirls:
Theforstatementbehavessimilarlytotheifstatement;codebelowbothoftheseneedtobeindentedfourspaces.
Hereisthefullcodethatwillbeinthefile:
python_intro.py
defhi(name):
print('Hi'+name+'!')
girls=['Rachel','Monica','Phoebe','Ola','You']
fornameingirls:
hi(name)
print('Nextgirl')
Andwhenwerunit:
command-line
IntroductiontoPython
46
$python3python_intro.py
HiRachel!
Nextgirl
HiMonica!
Nextgirl
HiPhoebe!
Nextgirl
HiOla!
Nextgirl
HiYou!
Nextgirl
Asyoucansee,everythingyouputinsideaforstatementwithanindentwillberepeatedforeveryelementofthelistgirls.
Youcanalsouseforonnumbersusingtherangefunction:
python_intro.py
foriinrange(1,6):
print(i)
Whichwouldprint:
command-line
1
2
3
4
5
rangeisafunctionthatcreatesalistofnumbersfollowingoneaftertheother(thesenumbersareprovidedbyyouasparameters).
NotethatthesecondofthesetwonumbersisnotincludedinthelistthatisoutputbyPython(meaningrange(1,6)countsfrom1to5,butdoesnotincludethenumber6).Thatisbecause"range"ishalf-open,andbythatwemeanitincludesthefirstvalue,butnotthelast.
SummaryThat'sit.Youtotallyrock!Thiswasatrickychapter,soyoushouldfeelproudofyourself.We'redefinitelyproudofyouformakingitthisfar!
Youmightwanttobrieflydosomethingelse–stretch,walkaroundforabit,restyoureyes–beforegoingontothenextchapter.:)
IntroductiontoPython
47
IntroductiontoPython
48
WhatisDjango?Django(/ˈdʒæŋɡoʊ/jang-goh)isafreeandopensourcewebapplicationframework,writteninPython.Awebframeworkisasetofcomponentsthathelpsyoutodevelopwebsitesfasterandeasier.
Whenyou'rebuildingawebsite,youalwaysneedasimilarsetofcomponents:awaytohandleuserauthentication(signingup,signingin,signingout),amanagementpanelforyourwebsite,forms,awaytouploadfiles,etc.
Luckilyforyouotherpeoplelongagonoticedthatwebdevelopersfacesimilarproblemswhenbuildinganewsite,sotheyteamedupandcreatedframeworks(Djangoisoneofthem)thatgiveyouready-madecomponentsyoucanuse.
Frameworksexisttosaveyoufromhavingtoreinventthewheelandhelpalleviatesomeoftheoverheadwhenyou’rebuildinganewsite.
Whydoyouneedaframework?TounderstandwhatDjangoactuallyisfor,weneedtotakeacloserlookattheservers.Thefirstthingisthattheserverneedstoknowthatyouwantittoserveyouawebpage.
Imagineamailbox(port)whichismonitoredforincomingletters(requests).Thisisdonebyawebserver.Thewebserverreadstheletter,andsendsaresponsewithawebpage.Butwhenyouwanttosendsomething,youneedtohavesomecontent.AndDjangoissomethingthathelpsyoucreatethecontent.
Whathappenswhensomeonerequestsawebsitefromyourserver?Whenarequestcomestoawebserverit'spassedtoDjangowhichtriestofigureoutwhatactuallyisrequested.Ittakesawebpageaddressfirstandtriestofigureoutwhattodo.ThispartisdonebyDjango'surlresolver(notethatawebsiteaddressiscalledaURL-UniformResourceLocator-sothenameurlresolvermakessense).Itisnotverysmart-ittakesalistofpatternsandtriestomatchtheURL.DjangocheckspatternsfromtoptothebottomandifsomethingismatchedthenDjangopassestherequesttotheassociatedfunction(whichiscalledview).
Imagineamailcarrierwithaletter.Sheiswalkingdownthestreetandcheckseachhousenumberagainsttheoneontheletter.Ifitmatches,sheputstheletterthere.Thisishowtheurlresolverworks!
Intheviewfunctionalltheinterestingthingsaredone:wecanlookatadatabasetolookforsomeinformation.Maybetheuseraskedtochangesomethinginthedata?Likealettersaying"Pleasechangethedescriptionofmyjob."Theviewcancheckifyouareallowedtodothat,thenupdatethejobdescriptionforyouandsendbackamessage:"Done!".ThentheviewgeneratesaresponseandDjangocansendittotheuser'swebbrowser.
Ofcourse,thedescriptionaboveisalittlebitsimplified,butyoudon'tneedtoknowallthetechnicalthingsyet.Havingageneralideaisenough.
Soinsteadofdivingtoomuchintodetails,wewillsimplystartcreatingsomethingwithDjangoandwewilllearnalltheimportantpartsalongtheway!
WhatisDjango?
49
DjangoinstallationIfyou'reusingaChromebook,skipthischapterandmakesureyoufollowtheChromebookSetupinstructions.
NoteIfyoualreadyworkedthroughtheInstallationstepsthenyou'vealreadydonethis-youcangostraighttothenextchapter!
PartofthissectionisbasedontutorialsbyGeekGirlsCarrots(https://github.com/ggcarrots/django-carrots).
Partofthissectionisbasedonthedjango-marcadortutoriallicensedundertheCreativeCommonsAttribution-ShareAlike4.0InternationalLicense.Thedjango-marcadortutorialiscopyrightedbyMarkusZapke-Gründemannetal.
VirtualenvironmentBeforeweinstallDjangowewillgetyoutoinstallanextremelyusefultooltohelpkeepyourcodingenvironmenttidyonyourcomputer.It'spossibletoskipthisstep,butit'shighlyrecommended.Startingwiththebestpossiblesetupwillsaveyoualotoftroubleinthefuture!
So,let'screateavirtualenvironment(alsocalledavirtualenv).VirtualenvwillisolateyourPython/Djangosetuponaper-projectbasis.Thismeansthatanychangesyoumaketoonewebsitewon'taffectanyothersyou'realsodeveloping.Neat,right?
Allyouneedtodoisfindadirectoryinwhichyouwanttocreatethevirtualenv;yourhomedirectory,forexample.OnWindowsitmightlooklikeC:\Users\Name\(whereNameisthenameofyourlogin).
NOTE:OnWindows,makesurethatthisdirectorydoesnotcontainaccentedorspecialcharacters;ifyourusernamecontainsaccentedcharacters,useadifferentdirectory,forexampleC:\djangogirls.
Forthistutorialwewillbeusinganewdirectorydjangogirlsfromyourhomedirectory:
command-line
$mkdirdjangogirls
$cddjangogirls
Wewillmakeavirtualenvcalledmyvenv.Thegeneralcommandwillbeintheformat:
command-line
$python3-mvenvmyvenv
WindowsTocreateanewvirtualenv,youneedtoopentheconsole(wetoldyouaboutthatafewchaptersago–remember?)andrunC:\Python35\python-mvenvmyvenv.Itwilllooklikethis:
command-line
C:\Users\Name\djangogirls>C:\Python35\python-mvenvmyvenv
whereC:\Python35\pythonisthedirectoryinwhichyoupreviouslyinstalledPythonandmyvenvisthenameofyourvirtualenv.Youcanuseanyothername,butsticktolowercaseandusenospaces,accentsorspecialcharacters.Itisalsogoodideatokeepthenameshort–you'llbereferencingitalot!
Djangoinstallation
50
LinuxandOSX
CreatingavirtualenvonbothLinuxandOSXisassimpleasrunningpython3-mvenvmyvenv.Itwilllooklikethis:
command-line
$python3-mvenvmyvenv
myvenvisthenameofyourvirtualenv.Youcanuseanyothername,butsticktolowercaseandusenospaces.Itisalsogoodideatokeepthenameshortasyou'llbereferencingitalot!
NOTE:OnsomeversionsofDebian/Ubuntuyoumayreceivethefollowingerror:
command-line
Thevirtualenvironmentwasnotcreatedsuccessfullybecauseensurepipisnotavailable.OnDebian/Ubuntusys
tems,youneedtoinstallthepython3-venvpackageusingthefollowingcommand.
apt-getinstallpython3-venv
Youmayneedtousesudowiththatcommand.Afterinstallingthepython3-venvpackage,recreateyourvirtual
environment.
Inthiscase,followtheinstructionsaboveandinstallthepython3-venvpackage:
command-line
$sudoapt-getinstallpython3-venv
NOTE:OnsomeversionsofDebian/Ubuntuinitiatingthevirtualenvironmentlikethiscurrentlygivesthefollowingerror:
command-line
Error:Command'['/home/eddie/Slask/tmp/venv/bin/python3','-Im','ensurepip','--upgrade','--default-pip']'
returnednon-zeroexitstatus1
Togetaroundthis,usethevirtualenvcommandinstead.
command-line
$sudoapt-getinstallpython-virtualenv
$virtualenv--python=python3.5myvenv
NOTE:Ifyougetanerrorlike
command-line
E:Unabletolocatepackagepython3-venv
theninsteadrun:
command-line
sudoaptinstallpython3.5-venv
Workingwithvirtualenv
Djangoinstallation
51
Thecommandabovewillcreateadirectorycalledmyvenv(orwhatevernameyouchose)thatcontainsourvirtualenvironment(basicallyabunchofdirectoryandfiles).
Windows
Startyourvirtualenvironmentbyrunning:
command-line
C:\Users\Name\djangogirls>myvenv\Scripts\activate
NOTE:onWindows10youmightgetanerrorintheWindowsPowerShellsaysexecutionofscriptsisdisabledonthissystem.InthosecasesopenanotherWindowsPowerShellandRunasAdministratortrydoingthisbeforecontinue:
command-line
C:\WINDOWS\system32>Set-ExecutionPolicy-ExecutionPolicyRemoteSigned
ExecutionPolicyChange
Theexecutionpolicyhelpsprotectyoufromscriptsthatyoudonottrust.Changingtheexecutionpolicym
ightexposeyoutothesecurityrisksdescribedintheabout_Execution_Policieshelptopicathttp://go.micros
oft.com/fwlink/?LinkID=135170.Doyouwanttochangetheexecutionpolicy?[Y]Yes[A]YestoAll[N]No[L
]NotoAll[S]Suspend[?]Help(defaultis"N"):A
LinuxandOSXStartyourvirtualenvironmentbyrunning:
command-line
$sourcemyvenv/bin/activate
Remembertoreplacemyvenvwithyourchosenvirtualenvname!
NOTE:sometimessourcemightnotbeavailable.Inthosecasestrydoingthisinstead:
command-line
$.myvenv/bin/activate
Youwillknowthatyouhavevirtualenvstartedwhenyouseethatthepromptinyourconsoleisprefixedwith(myvenv).
Whenworkingwithinavirtualenvironment,pythonwillautomaticallyrefertothecorrectversionsoyoucanusepythoninsteadofpython3.
OK,wehaveallimportantdependenciesinplace.WecanfinallyinstallDjango!
InstallingDjangoNowthatyouhaveyourvirtualenvstarted,youcaninstallDjango.
Beforewedothat,weshouldmakesurewehavethelatestversionofpip,thesoftwarethatweusetoinstallDjango.Intheconsole,runpipinstall--upgradepip.
Thenrunpipinstalldjango~=1.9.0(notethatweuseatildefollowedbyanequalsign:~=)toinstallDjango.
command-line
Djangoinstallation
52
(myvenv)~$pipinstalldjango~=1.9.0
Downloading/unpackingdjango==1.9
Installingcollectedpackages:django
Successfullyinstalleddjango
Cleaningup...
onWindows
IfyougetanerrorwhencallingpiponWindowsplatform,pleasecheckifyourprojectpathnamecontainsspaces,accentsorspecialcharacters(forexample,C:\Users\UserName\djangogirls).Ifitdoes,pleaseconsiderusinganotherplacewithoutspaces,accentsorspecialcharacters(suggestion:C:\djangogirls).Createanewvirtualenvinthenewdirectory,thendeletetheoldoneandtrytheabovecommandagain.(Movingthevirtualenvdirectorywon'tworksincevirtualenvusesabsolutepaths.)
onWindows8andWindows10
YourcommandlinemightfreezeafterwhenyoutrytoinstallDjango.Ifthishappens,insteadoftheabovecommanduse:
command-line
C:\Users\Name\djangogirls>python-mpipinstalldjango~=1.9.0
onLinux
IfyougetanerrorwhencallingpiponUbuntu12.04pleaserunpython-mpipinstall-U--force-reinstallpiptofixthepipinstallationinthevirtualenv.
That'sit!You'renow(finally)readytocreateaDjangoapplication!
Djangoinstallation
53
YourfirstDjangoproject!PartofthischapterisbasedontutorialsbyGeekGirlsCarrots(https://github.com/ggcarrots/django-carrots).
Partsofthischapterarebasedonthedjango-marcadortutoriallicensedunderCreativeCommonsAttribution-ShareAlike4.0InternationalLicense.Thedjango-marcadortutorialiscopyrightedbyMarkusZapke-Gründemannetal.
We'regoingtocreateasimpleblog!
ThefirststepistostartanewDjangoproject.Basically,thismeansthatwe'llrunsomescriptsprovidedbyDjangothatwillcreatetheskeletonofaDjangoprojectforus.Thisisjustabunchofdirectoriesandfilesthatwewilluselater.
ThenamesofsomefilesanddirectoriesareveryimportantforDjango.Youshouldnotrenamethefilesthatweareabouttocreate.Movingthemtoadifferentplaceisalsonotagoodidea.Djangoneedstomaintainacertainstructuretobeabletofindimportantthings.
Remembertoruneverythinginthevirtualenv.Ifyoudon'tseeaprefix(myvenv)inyourconsoleyouneedtoactivateyourvirtualenv.WeexplainedhowtodothatintheDjangoinstallationchapterintheWorkingwithvirtualenvpart.Typingmyvenv\Scripts\activateonWindowsorsourcemyvenv/bin/activateonMacOS/Linuxwilldothisforyou.
InyourMacOSorLinuxconsoleyoushouldrunthefollowingcommand;don'tforgettoaddtheperiod(ordot).attheend:
command-line
(myvenv)~/djangogirls$django-adminstartprojectmysite.
OnWindows;don'tforgettoaddtheperiod(ordot).attheend:
command-line
(myvenv)C:\Users\Name\djangogirls>django-admin.pystartprojectmysite.
Theperiod.iscrucialbecauseittellsthescripttoinstallDjangoinyourcurrentdirectory(forwhichtheperiod.isashort-handreference)
NoteWhentypingthecommandsabove,rememberthatyouonlytypethepartwhichstartsdjango-adminordjango-admin.py.The(myvenv)~/djangogirls$and(myvenv)C:\Users\Name\djangogirls>partsshownherearejustexamplesofthepromptthatwillbeinvitingyourinputonyourcommandline.
django-admin.pyisascriptthatwillcreatethedirectoriesandfilesforyou.Youshouldnowhaveadirectorystructurewhichlookslikethis:
djangogirls
├───manage.py
└───mysite
settings.py
urls.py
wsgi.py
__init__.py
manage.pyisascriptthathelpswithmanagementofthesite.Withitwewillbeabletostartawebserveronourcomputerwithoutinstallinganythingelse,amongstotherthings.
Thesettings.pyfilecontainstheconfigurationofyourwebsite.
YourfirstDjangoproject!
54
Rememberwhenwetalkedaboutamailcarriercheckingwheretodeliveraletter?urls.pyfilecontainsalistofpatternsusedbyurlresolver.
Let'signoretheotherfilesfornowaswewon'tchangethem.Theonlythingtorememberisnottodeletethembyaccident!
ChangingsettingsLet'smakesomechangesinmysite/settings.py.Openthefileusingthecodeeditoryouinstalledearlier.
Itwouldbenicetohavethecorrecttimeonourwebsite.Gotothewikipediatimezoneslistandcopyyourrelevanttimezone(TZ).(eg.Europe/Berlin)
Insettings.py,findthelinethatcontainsTIME_ZONEandmodifyittochooseyourowntimezone:
mysite/settings.py
TIME_ZONE='Europe/Berlin'
Modifying"Europe/Berlin"asappropriate
We'llalsoneedtoaddapathforstaticfiles(we'llfindoutallaboutstaticfilesandCSSlaterinthetutorial).Godowntotheendofthefile,andjustunderneaththeSTATIC_URLentry,addanewonecalledSTATIC_ROOT:
mysite/settings.py
STATIC_URL='/static/'
STATIC_ROOT=os.path.join(BASE_DIR,'static')
:Ifyou'reusingaChromebook,addthislineatthebottomofyoursettings.pyfile:MESSAGE_STORAGE='django.contrib.messages.storage.session.SessionStorage'
SetupadatabaseThere'salotofdifferentdatabasesoftwarethatcanstoredataforyoursite.We'llusethedefaultone,sqlite3.
Thisisalreadysetupinthispartofyourmysite/settings.pyfile:
mysite/settings.py
DATABASES={
'default':{
'ENGINE':'django.db.backends.sqlite3',
'NAME':os.path.join(BASE_DIR,'db.sqlite3'),
}
}
Tocreateadatabaseforourblog,let'srunthefollowingintheconsole:pythonmanage.pymigrate(weneedtobeinthedjangogirlsdirectorythatcontainsthemanage.pyfile).Ifthatgoeswell,youshouldseesomethinglikethis:
command-line
YourfirstDjangoproject!
55
(myvenv)~/djangogirls$pythonmanage.pymigrate
Operationstoperform:
Applyallmigrations:auth,admin,contenttypes,sessions
Runningmigrations:
Renderingmodelstates...DONE
Applyingcontenttypes.0001_initial...OK
Applyingauth.0001_initial...OK
Applyingadmin.0001_initial...OK
Applyingadmin.0002_logentry_remove_auto_add...OK
Applyingcontenttypes.0002_remove_content_type_name...OK
Applyingauth.0002_alter_permission_name_max_length...OK
Applyingauth.0003_alter_user_email_max_length...OK
Applyingauth.0004_alter_user_username_opts...OK
Applyingauth.0005_alter_user_last_login_null...OK
Applyingauth.0006_require_contenttypes_0002...OK
Applyingauth.0007_alter_validators_add_error_messages...OK
Applyingsessions.0001_initial...OK
Andwe'redone!Timetostartthewebserverandseeifourwebsiteisworking!
StartingthewebserverYouneedtobeinthedirectorythatcontainsthemanage.pyfile(thedjangogirlsdirectory).Intheconsole,wecanstartthewebserverbyrunningpythonmanage.pyrunserver:
command-line
(myvenv)~/djangogirls$pythonmanage.pyrunserver
IfyouareonaChromebook,usethiscommandinstead:
Cloud9
(myvenv)~/djangogirls$pythonmanage.pyrunserver0.0.0.0:8080
IfyouareonWindowsandthisfailswithUnicodeDecodeError,usethiscommandinstead:
command-line
(myvenv)~/djangogirls$pythonmanage.pyrunserver0:8000
Nowallyouneedtodoischeckthatyourwebsiteisrunning.Openyourbrowser(Firefox,Chrome,Safari,InternetExplorerorwhateveryouuse)andentertheaddress:
browser
http://127.0.0.1:8000/
Ifyou'reusingaChromebook,you'llalwaysvisityourtestserverbyaccessing:
browser
https://django-girls-<yourcloud9username>.c9users.io
Congratulations!You'vejustcreatedyourfirstwebsiteandrunitusingawebserver!Isn'tthatawesome?
YourfirstDjangoproject!
56
Whilethewebserverisrunning,youwon'tseeanewcommandlineprompttoenteradditonalcommands.Theterminalwillacceptnewtextbutwillnotexecutenewcommands.Thisisbecausethewebservercontinuouslyrunsinordertolistenforincomingrequests.
WereviewedhowwebserversworkintheHowtheInternetworkschapter.
Totypeadditionalcommandswhilethewebserverisrunning,openanewterminalwindowandactivateyourvirtualenv.Tostopthewebserver,switchbacktothewindowinwhichit'srunningandpressCTRL+C-ControlandCbuttonstogether(onWindows,youmighthavetopressCtrl+Break).
Readyforthenextstep?It'stimetocreatesomecontent!
YourfirstDjangoproject!
57
DjangomodelsWhatwewanttocreatenowissomethingthatwillstoreallthepostsinourblog.Buttobeabletodothatweneedtotalkalittlebitaboutthingscalledobjects.
ObjectsThereisaconceptinprogrammingcalledObject-orientedprogramming.Theideaisthatinsteadofwritingeverythingasaboringsequenceofprogramminginstructionswecanmodelthingsanddefinehowtheyinteractwitheachother.
Sowhatisanobject?Itisacollectionofpropertiesandactions.Itsoundsweird,butwewillgiveyouanexample.
IfwewanttomodelacatwewillcreateanobjectCatthathassomepropertiessuchas:color,age,mood(likegood,bad,orsleepy;)),andowner(thatisaPersonobjectormaybe,incaseofastraycat,thispropertyisempty).
ThentheCathassomeactions:purr,scratch,orfeed(inwhichcase,wewillgivethecatsomeCatFood,whichcouldbeaseparateobjectwithproperties,liketaste).
Cat
--------
color
age
mood
owner
purr()
scratch()
feed(cat_food)
CatFood
--------
taste
Sobasicallytheideaistodescriberealthingsincodewithproperties(calledobjectproperties)andactions(calledmethods).
Howwillwemodelblogpoststhen?Wewanttobuildablog,right?
Weneedtoanswerthequestion:Whatisablogpost?Whatpropertiesshouldithave?
Well,forsureourblogpostneedssometextwithitscontentandatitle,right?Itwouldbealsonicetoknowwhowroteit-soweneedanauthor.Finally,wewanttoknowwhenthepostwascreatedandpublished.
Post
--------
title
text
author
created_date
published_date
Whatkindofthingscouldbedonewithablogpost?Itwouldbenicetohavesomemethodthatpublishesthepost,right?
Sowewillneedapublishmethod.
Sincewealreadyknowwhatwewanttoachieve,let'sstartmodelingitinDjango!
Djangomodel
Djangomodels
58
Knowingwhatanobjectis,wecancreateaDjangomodelforourblogpost.
AmodelinDjangoisaspecialkindofobject-itissavedinthedatabase.Adatabaseisacollectionofdata.Thisisaplaceinwhichyouwillstoreinformationaboutusers,yourblogposts,etc.WewillbeusingaSQLitedatabasetostoreourdata.ThisisthedefaultDjangodatabaseadapter--it'llbeenoughforusrightnow.
Youcanthinkofamodelinthedatabaseasaspreadsheetwithcolumns(fields)androws(data).
CreatinganapplicationTokeepeverythingtidy,wewillcreateaseparateapplicationinsideourproject.Itisverynicetohaveeverythingorganizedfromtheverybeginning.Tocreateanapplicationweneedtorunthefollowingcommandintheconsole(fromdjangogirlsdirectorywheremanage.pyfileis):
command-line
(myvenv)~/djangogirls$pythonmanage.pystartappblog
Youwillnoticethatanewblogdirectoryiscreatedanditcontainsanumberoffilesnow.Ourdirectoriesandfilesinourprojectshouldlooklikethis:
djangogirls
├──blog
│├──__init__.py
│├──admin.py
│├──apps.py
│├──migrations
││└──__init__.py
│├──models.py
│├──tests.py
│└──views.py
├──db.sqlite3
├──manage.py
└──mysite
├──__init__.py
├──settings.py
├──urls.py
└──wsgi.py
AftercreatinganapplicationwealsoneedtotellDjangothatitshoulduseit.Wedothatinthefilemysite/settings.py.WeneedtofindINSTALLED_APPSandaddalinecontaining'blog',justabove).Sothefinalproductshouldlooklikethis:
mysite/settings.py
INSTALLED_APPS=(
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'blog',
)
Creatingablogpostmodel
Intheblog/models.pyfilewedefineallobjectscalledModels-thisisaplaceinwhichwewilldefineourblogpost.
Let'sopenblog/models.py,removeeverythingfromitandwritecodelikethis:
blog/models.py
Djangomodels
59
fromdjango.dbimportmodels
fromdjango.utilsimporttimezone
classPost(models.Model):
author=models.ForeignKey('auth.User')
title=models.CharField(max_length=200)
text=models.TextField()
created_date=models.DateTimeField(
default=timezone.now)
published_date=models.DateTimeField(
blank=True,null=True)
defpublish(self):
self.published_date=timezone.now()
self.save()
def__str__(self):
returnself.title
Double-checkthatyouusetwounderscorecharacters(_)oneachsideofstr.ThisconventionisusedfrequentlyinPythonandsometimeswealsocallthem"dunder"(shortfor"double-underscore").
Itlooksscary,right?Butnoworrieswewillexplainwhattheselinesmean!
Alllinesstartingwithfromorimportarelinesthataddsomebitsfromotherfiles.Soinsteadofcopyingandpastingthesamethingsineveryfile,wecanincludesomepartswithfrom...import....
classPost(models.Model):-thislinedefinesourmodel(itisanobject).
classisaspecialkeywordthatindicatesthatwearedefininganobject.Postisthenameofourmodel.Wecangiveitadifferentname(butwemustavoidspecialcharactersandwhitespaces).Alwaysstartaclassnamewithanuppercaseletter.models.ModelmeansthatthePostisaDjangoModel,soDjangoknowsthatitshouldbesavedinthedatabase.
Nowwedefinethepropertiesweweretalkingabout:title,text,created_date,published_dateandauthor.Todothatweneedtodefineatypeofeachfield(Isittext?Anumber?Adate?Arelationtoanotherobject,likeaUser?).
models.CharField-thisishowyoudefinetextwithalimitednumberofcharacters.models.TextField-thisisforlongtextwithoutalimit.Soundsidealforblogpostcontent,right?models.DateTimeField-thisisadateandtime.models.ForeignKey-thisisalinktoanothermodel.
Wewillnotexplaineverybitofcodeheresinceitwouldtaketoomuchtime.YoushouldtakealookatDjango'sdocumentationifyouwanttoknowmoreaboutModelfieldsandhowtodefinethingsotherthanthosedescribedabove(https://docs.djangoproject.com/en/1.9/ref/models/fields/#field-types).
Whataboutdefpublish(self):?Itisexactlythepublishmethodweweretalkingaboutbefore.defmeansthatthisisafunction/methodandpublishisthenameofthemethod.Youcanchangethenameofthemethod,ifyouwant.Thenamingruleisthatweuselowercaseandunderscoresinsteadofwhitespaces.Forexample,amethodthatcalculatesaveragepricecouldbecalledcalculate_average_price.
Methodsoftenreturnsomething.Thereisanexampleofthatinthe__str__method.Inthisscenario,whenwecall__str__()wewillgetatext(string)withaPosttitle.
Alsonoticethatbothdefpublish(self):,anddef__str__(self):areindentedinsideourclass.BecausePythonissensitivetowhitespace,weneedtoindentourmethodsinsidetheclass.Otherwise,themethodswon'tbelongtotheclass,andyoucangetsomeunexpectedbehavior.
Ifsomethingisstillnotclearaboutmodels,feelfreetoaskyourcoach!Weknowitiscomplicated,especiallywhenyoulearnwhatobjectsandfunctionsareatthesametime.Buthopefullyitlooksslightlylessmagicforyounow!
Djangomodels
60
Createtablesformodelsinyourdatabase
Thelaststephereistoaddournewmodeltoourdatabase.FirstwehavetomakeDjangoknowthatwehavesomechangesinourmodel(wehavejustcreatedit!).Gotoyourconsolewindowandtypepythonmanage.pymakemigrationsblog.Itwilllooklikethis:
command-line
(myvenv)~/djangogirls$pythonmanage.pymakemigrationsblog
Migrationsfor'blog':
0001_initial.py:
-CreatemodelPost
Djangopreparedforusamigrationfilethatwehavetoapplynowtoourdatabase.Typepythonmanage.pymigrateblogandtheoutputshouldbe:
command-line
(myvenv)~/djangogirls$pythonmanage.pymigrateblog
Operationstoperform:
Applyallmigrations:blog
Runningmigrations:
Renderingmodelstates...DONE
Applyingblog.0001_initial...OK
Hurray!OurPostmodelisnowinourdatabase!Itwouldbenicetoseeit,right?JumptothenextchaptertoseewhatyourPostlookslike!
Djangomodels
61
DjangoadminToadd,editanddeletepostswe'vejustmodeled,wewilluseDjangoadmin.
Let'sopentheblog/admin.pyfileandreplaceitscontentwiththis:
blog/admin.py
fromdjango.contribimportadmin
from.modelsimportPost
admin.site.register(Post)
Asyoucansee,weimport(include)thePostmodeldefinedinthepreviouschapter.Tomakeourmodelvisibleontheadminpage,weneedtoregisterthemodelwithadmin.site.register(Post).
OK,timetolookatourPostmodel.Remembertorunpythonmanage.pyrunserverintheconsoletorunthewebserver.Gotothebrowserandtypetheaddresshttp://127.0.0.1:8000/admin/Youwillseealoginpagelikethis:
Tologin,youneedtocreateasuperuser-auserwhichhascontrolovereverythingonthesite.Gobacktothecommand-lineandtypepythonmanage.pycreatesuperuser,andpressenter.
Remember,towritenewcommandswhilethewebserverisrunning,openanewterminalwindowandactivateyourvirtualenv.WereviewedhowtowritenewcommandsintheYourfirstDjangoproject!chapter,intheStartingthewebserversection.
Whenprompted,typeyourusername(lowercase,nospaces),emailaddress,andpassword.Don'tworrythatyoucan'tseethepasswordyou'retypingin-that'showit'ssupposedtobe.Justtypeitinandpressentertocontinue.Theoutputshouldlooklikethis(whereusernameandemailshouldbeyourownones):
command-line
(myvenv)~/djangogirls$pythonmanage.pycreatesuperuser
Username:admin
Emailaddress:[email protected]
Password:
Password(again):
Superusercreatedsuccessfully.
Djangoadmin
62
Returntoyourbrowser.Loginwiththesuperuser'scredentialsyouchose;youshouldseetheDjangoadmindashboard.
GotoPostsandexperimentalittlebitwithit.Addfiveorsixblogposts.Don'tworryaboutthecontent-youcansimplycopy-pastesometextfromthistutorialtosavetime:).
Makesurethatatleasttwoorthreeposts(butnotall)havethepublishdateset.Itwillbehelpfullater.
IfyouwanttoknowmoreaboutDjangoadmin,youshouldcheckDjango'sdocumentation:https://docs.djangoproject.com/en/1.9/ref/contrib/admin/
Thisisprobablyagoodmomenttograbacoffee(ortea)orsomethingtoeattore-energiseyourself.YoucreatedyourfirstDjangomodel-youdeservealittletimeout!
Djangoadmin
63
Deploy!Thefollowingchaptercanbesometimesabithardtogetthrough.Persistandfinishit;deploymentisanimportantpartofthewebsitedevelopmentprocess.Thischapterisplacedinthemiddleofthetutorialsothatyourmentorcanhelpwiththeslightlytrickierprocessofgettingyourwebsiteonline.Thismeansyoucanstillfinishthetutorialonyourownifyourunoutoftime.
Untilnow,yourwebsitewasonlyavailableonyourcomputer.Nowyouwilllearnhowtodeployit!DeployingistheprocessofpublishingyourapplicationontheInternetsopeoplecanfinallygoandseeyourapp:).
Asyoulearned,awebsitehastobelocatedonaserver.Therearealotofserverprovidersavailableontheinternet.Wewilluseonethathasarelativelysimpledeploymentprocess:PythonAnywhere.PythonAnywhereisfreeforsmallapplicationsthatdon'thavetoomanyvisitorssoit'lldefinitelybeenoughforyounow.
Theotherexternalservicewe'llbeusingisGitHub,whichisacodehostingservice.Thereareothersoutthere,butalmostallprogrammershaveaGitHubaccountthesedays,andnowsowillyou!
Thesethreeplaceswillbeimportanttoyou.Yourlocalcomputerwillbetheplacewhereyoudodevelopmentandtesting.Whenyou'rehappywiththechanges,youwillplaceacopyofyourprogramonGitHub.YourwebsitewillbeonPythonAnywhereandyouwillupdateitbygettinganewcopyofyourcodefromGitHub.
GitGitisa"versioncontrolsystem"usedbyalotofprogrammers.Thissoftwarecantrackchangestofilesovertimesothatyoucanrecallspecificversionslater.Abitlikethe"trackchanges"featureinMicrosoftWord,butmuchmorepowerful.
InstallingGitIfyoualreadydidtheInstallationsteps,noneedtodothisagain-youcanskiptothenextsectionandstartcreatingyourGitrepository.
Windows
YoucandownloadGitfromgit-scm.com.Youcanhit"next"onallstepsexceptforone;inthefifthstepentitled"AdjustingyourPATHenvironment",choose"UseGitandoptionalUnixtoolsfromtheWindowsCommandPrompt"(thebottomoption).Otherthanthat,thedefaultsarefine.CheckoutWindows-style,commitUnix-stylelineendingsisgood.
MacOSDownloadGitfromgit-scm.comandjustfollowtheinstructions.
LinuxIfitisn'tinstalledalready,gitshouldbeavailableviayourpackagemanager,sotry:
DebianorUbuntucommand-line
$sudoapt-getinstallgit
Deploy!
64
Fedora(upto21)
command-line
$sudoyuminstallgit
Fedora(22+)
command-line
$sudodnfinstallgit
openSUSE
command-line
$sudozypperinstallgit
StartingourGitrepositoryGittrackschangestoaparticularsetoffilesinwhat'scalledacoderepository(or"repo"forshort).Let'sstartoneforourproject.Openupyourconsoleandrunthesecommands,inthedjangogirlsdirectory:
Checkyourcurrentworkingdirectorywithapwd(OSX/Linux)orcd(Windows)commandbeforeinitializingtherepository.Youshouldbeinthedjangogirlsfolder.
command-line
$gitinit
InitializedemptyGitrepositoryin~/djangogirls/.git/
$gitconfig--globaluser.name"YourName"
Initializingthegitrepositoryissomethingweonlyneedtodoonceperproject(andyouwon'thavetore-entertheusernameandemailagainever).
Gitwilltrackchangestoallthefilesandfoldersinthisdirectory,buttherearesomefileswewantittoignore.Wedothisbycreatingafilecalled.gitignoreinthebasedirectory.Openupyoureditorandcreateanewfilewiththefollowingcontents:
.gitignore
*.pyc
__pycache__
myvenv
db.sqlite3
/static
.DS_Store
Andsaveitas.gitignoreinthe"djangogirls"folder.
Deploy!
65
Thedotatthebeginningofthefilenameisimportant!Ifyou'rehavinganydifficultycreatingit(Macsdon'tlikeyoutocreatefilesthatbeginwithadotviatheFinder,forexample),thenusethe"SaveAs"featureinyoureditor,it'sbulletproof.
NoteOneofthefilesyouspecifiedinyour.gitignorefileisdb.sqlite3.Thatfileisyourlocaldatabase,wherealloryourpostsarestored.Wedon'twanttoaddthistoyourrepository,becauseyourwebsiteonPythonAnywhereisgoingtobeusingadifferentdatabase.ThatdatabasecouldbeSQLite,likeyourdevelopmentmachine,butusually,youwilluseonecalledMySQLwhichcandealwithalotmoresitevisitorsthanSQLite.Eitherway,byignoringyourSQLitedatabasefortheGitHubcopy,itmeansthatallofthepostsyoucreatedsofararegoingtostayandonlybeavailablelocally,butyou'regonnahavetoaddthemagainonproduction.Youshouldthinkofyourlocaldatabaseasagoodplaygroundwhereyoucantestdifferentthingsandnotbeafraidthatyou'regoingtodeleteyourrealpostsfromyourblog.
It'sagoodideatouseagitstatuscommandbeforegitaddorwheneveryoufindyourselfunsureofwhathaschanged.Thiswillhelpstopanysurprisesfromhappening,suchaswrongfilesbeingaddedorcommited.Thegitstatuscommandreturnsinformationaboutanyuntracked/modifed/stagedfiles,branchstatus,andmuchmore.Theoutputshouldbesimilarto:
command-line
$gitstatus
Onbranchmaster
Initialcommit
Untrackedfiles:
(use"gitadd<file>..."toincludeinwhatwillbecommitted)
.gitignore
blog/
manage.py
mysite/
nothingaddedtocommitbutuntrackedfilespresent(use"gitadd"totrack)
Andfinallywesaveourchanges.Gotoyourconsoleandrunthesecommands:
command-line
$gitadd--all.
$gitcommit-m"MyDjangoGirlsapp,firstcommit"
[...]
13fileschanged,200insertions(+)
createmode100644.gitignore
[...]
createmode100644mysite/wsgi.py
PushingourcodetoGitHubGotoGitHub.comandsignupforanew,freeuseraccount.(Ifyoualreadydidthatintheworkshopprep,thatisgreat!)
Then,createanewrepository,givingitthename"my-first-blog".Leavethe"initialisewithaREADME"tickboxun-checked,leavethe.gitignoreoptionblank(we'vedonethatmanually)andleavetheLicenseasNone.
Deploy!
66
Thenamemy-first-blogisimportant--youcouldchoosesomethingelse,butit'sgoingtooccurlotsoftimesintheinstructionsbelow,andyou'dhavetosubstituteiteachtime.It'sprobablyeasiertojuststickwiththenamemy-first-blog.
Onthenextscreen,you'llbeshownyourrepo'scloneURL.Choosethe"HTTPS"version,copyit,andwe'llpasteitintotheterminalshortly:
NowweneedtohookuptheGitrepositoryonyourcomputertotheoneuponGitHub.
Typethefollowingintoyourconsole(Replace<your-github-username>withtheusernameyouenteredwhenyoucreatedyourGitHubaccount,butwithouttheangle-brackets):
command-line
Deploy!
67
$gitremoteaddoriginhttps://github.com/<your-github-username>/my-first-blog.git
$gitpush-uoriginmaster
EnteryourGitHubusernameandpasswordandyoushouldseesomethinglikethis:
command-line
Usernamefor'https://github.com':hjwp
Passwordfor'https://[email protected]':
Countingobjects:6,done.
Writingobjects:100%(6/6),200bytes|0bytes/s,done.
Total3(delta0),reused0(delta0)
Tohttps://github.com/hjwp/my-first-blog.git
*[newbranch]master->master
Branchmastersetuptotrackremotebranchmasterfromorigin.
YourcodeisnowonGitHub.Goandcheckitout!You'llfindit'sinfinecompany-Django,theDjangoGirlsTutorial,andmanyothergreatopensourcesoftwareprojectsalsohosttheircodeonGitHub:)
SettingupourblogonPythonAnywhereYoumighthavealreadycreatedaPythonAnywhereaccountearlierduringtheinstallsteps-ifso,noneedtodoitagain.
Nextit'stimetosignupforafree"Beginner"accountonPythonAnywhere.
www.pythonanywhere.com
Whenchoosingyourusernamehere,bearinmindthatyourblog'sURLwilltaketheformyourusername.pythonanywhere.com,sochooseeitheryourownnickname,oranameforwhatyourblogisallabout.
PullingourcodedownonPythonAnywhereWhenyou'vesignedupforPythonAnywhere,you'llbetakentoyourdashboardor"Consoles"page.Choosetheoptiontostarta"Bash"console--that'sthePythonAnywhereversionofaconsole,justliketheoneonyourcomputer.
PythonAnywhereisbasedonLinux,soifyou'reonWindows,theconsolewilllookalittledifferentfromtheoneonyourcomputer.
Let'spulldownourcodefromGitHubandontoPythonAnywherebycreatinga"clone"ofourrepo.TypethefollowingintotheconsoleonPythonAnywhere(don'tforgettouseyourGitHubusernameinplaceof<your-github-username>):
PythonAnywherecommand-line
$gitclonehttps://github.com/<your-github-username>/my-first-blog.git
ThiswillpulldownacopyofyourcodeontoPythonAnywhere.Checkitoutbytypingtreemy-first-blog:
PythonAnywherecommand-line
Deploy!
68
$treemy-first-blog
my-first-blog/
├──blog
│├──__init__.py
│├──admin.py
│├──migrations
││├──0001_initial.py
││└──__init__.py
│├──models.py
│├──tests.py
│└──views.py
├──manage.py
└──mysite
├──__init__.py
├──settings.py
├──urls.py
└──wsgi.py
CreatingavirtualenvonPythonAnywhereJustlikeyoudidonyourowncomputer,youcancreateavirtualenvonPythonAnywhere.IntheBashconsole,type:
PythonAnywherecommand-line
$cdmy-first-blog
$virtualenv--python=python3.5myvenv
Runningvirtualenvwithinterpreter/usr/bin/python3.5
[...]
Installingsetuptools,pip...done.
$sourcemyvenv/bin/activate
(myvenv)$pipinstalldjango~=1.9.0
Collectingdjango
[...]
Successfullyinstalleddjango-1.9
Thepipinstallstepcantakeacoupleofminutes.Patience,patience!Butifittakesmorethan5minutes,somethingiswrong.Askyourcoach.
CreatingthedatabaseonPythonAnywhere
Here'sanotherthingthat'sdifferentbetweenyourowncomputerandtheserver:itusesadifferentdatabase.Sotheuseraccountsandpostscanbedifferentontheserverandonyourcomputer.
Wecaninitialisethedatabaseontheserverjustlikewedidtheoneonyourowncomputer,withmigrateandcreatesuperuser:
PythonAnywherecommand-line
(mvenv)$pythonmanage.pymigrate
Operationstoperform:
[...]
Applyingsessions.0001_initial...OK
(mvenv)$pythonmanage.pycreatesuperuser
Publishingourblogasawebapp
Deploy!
69
NowourcodeisonPythonAnywhere,ourvirtualenvisready,andthedatabaseisinitialised.We'rereadytopublishitasawebapp!
ClickbacktothePythonAnywheredashboardbyclickingonitslogo,andgoclickontheWebtab.Finally,hitAddanewwebapp.
Afterconfirmingyourdomainname,choosemanualconfiguration(NBnotthe"Django"option)inthedialog.NextchoosePython3.5,andclickNexttofinishthewizard.
Makesureyouchoosethe"Manualconfiguration"option,notthe"Django"one.We'retoocoolforthedefaultPythonAnywhereDjangosetup;-)
SettingthevirtualenvYou'llbetakentothePythonAnywhereconfigscreenforyourwebapp,whichiswhereyou'llneedtogowheneveryouwanttomakechangestotheappontheserver.
Inthe"Virtualenv"section,clicktheredtextthatsays"Enterthepathtoavirtualenv",andenter:/home/<your-PythonAnywhere-username>/my-first-blog/myvenv/.Clicktheblueboxwiththecheckmarktosavethepathbeforemovingon.
SubstituteyourownPythonAnywhereusernameasappropriate.Ifyoumakeamistake,PythonAnywherewillshowyoualittlewarning.
ConfiguringtheWSGIfile
Djangoworksusingthe"WSGIprotocol",astandardforservingwebsitesusingPython,whichPythonAnywheresupports.ThewayweconfigurePythonAnywheretorecogniseourDjangoblogisbyeditingaWSGIconfigurationfile.
Clickonthe"WSGIconfigurationfile"link(inthe"Code"sectionnearthetopofthepage--it'llbenamedsomethinglike/var/www/<your-PythonAnywhere-username>_pythonanywhere_com_wsgi.py),andyou'llbetakentoaneditor.
Deleteallthecontentsandreplacethemwithsomethinglikethis:
<your-username>_pythonanywhere_com_wsgi.py
Deploy!
70
importos
importsys
path='/home/<your-PythonAnywhere-username>/my-first-blog'#useyourownPythonAnywhereusernamehere
ifpathnotinsys.path:
sys.path.append(path)
os.environ['DJANGO_SETTINGS_MODULE']='mysite.settings'
fromdjango.core.wsgiimportget_wsgi_application
fromdjango.contrib.staticfiles.handlersimportStaticFilesHandler
application=StaticFilesHandler(get_wsgi_application())
Don'tforgettosubstituteinyourownPythonAnywhereusernamewhereitsays<your-PythonAnywhere-username>NoteInlinefour,wemakesurePythonanywhereknowshowtofindourapplication.Itisveryimportantthatthispathnameiscorrect,andespeciallythattherearenoextraspaceshere.Otherwiseyouwillseean"ImportError"intheerrorlog.
Thisfile'sjobistotellPythonAnywherewhereourwebapplivesandwhattheDjangosettingsfile'snameis.
TheStaticFilesHandlerisfordealingwithourCSS.Thisistakencareofautomaticallyforyouduringlocaldevelopmentbytherunservercommand.We'llfindoutabitmoreaboutstaticfileslaterinthetutorial,whenweedittheCSSforoursite.
HitSaveandthengobacktotheWebtab.
We'realldone!HitthebiggreenReloadbuttonandyou'llbeabletogoviewyourapplication.You'llfindalinktoitatthetopofthepage.
DebuggingtipsIfyouseeanerrorwhenyoutrytovisityoursite,thefirstplacetolookforsomedebugginginfoisinyourerrorlog.You'llfindalinktothisonthePythonAnywhereWebtab.Seeifthereareanyerrormessagesinthere;themostrecentonesareatthebottom.Commonproblemsinclude:
Forgettingoneofthestepswedidintheconsole:creatingthevirtualenv,activatingit,installingDjangointoit,migratingthedatabase.
MakingamistakeinthevirtualenvpathontheWebtab--therewillusuallybealittlerederrormessageonthere,ifthereisaproblem.
MakingamistakeintheWSGIconfigurationfile--didyougetthepathtoyourmy-first-blogfolderright?
DidyoupickthesameversionofPythonforyourvirtualenvasyoudidforyourwebapp?Bothshouldbe3.5.
TherearesomegeneraldebuggingtipsonthePythonAnywherewiki.
Andremember,yourcoachisheretohelp!
Youarelive!Thedefaultpageforyoursiteshouldsay"WelcometoDjango",justlikeitdoesonyourlocalcomputer.Tryadding/admin/totheendoftheURL,andyou'llbetakentotheadminsite.Loginwiththeusernameandpassword,andyou'llseeyoucanaddnewPostsontheserver.
Onceyouhaveafewpostscreated,youcangobacktoyourlocalsetup(notPythonAnywhere).Fromhereyoushouldworkonyourlocalsetuptomakechanges.ThisisacommonworkflowinWebdevelopment(makechangeslocally,pushthosechangestoGitHub,pullyourchangesdowntoyourliveWebserver).Thisallowsyoutoworkandexperimentwithout
Deploy!
71
breakingyourliveWebsite.Prettycool,huh?
GiveyourselfaHUGEpatontheback!Serverdeploymentsareoneofthetrickiestpartsofwebdevelopmentanditoftentakespeopleseveraldaysbeforetheygetthemworking.Butyou'vegotyoursitelive,ontherealInternet,justlikethat!
Deploy!
72
DjangoURLsWe'reabouttobuildourfirstwebpage:ahomepageforyourblog!Butfirst,let'slearnalittlebitaboutDjangourls.
WhatisaURL?AURLissimplyawebaddress.YoucanseeaURLeverytimeyouvisitawebsite-itisvisibleinyourbrowser'saddressbar(yes!127.0.0.1:8000isaURL!Andhttps://djangogirls.orgisalsoaURL):
EverypageontheInternetneedsitsownURL.ThiswayyourapplicationknowswhatitshouldshowtoauserwhoopensaURL.InDjangoweusesomethingcalledURLconf(URLconfiguration).URLconfisasetofpatternsthatDjangowilltrytomatchwiththereceivedURLtofindthecorrectview.
HowdoURLsworkinDjango?Let'sopenupthemysite/urls.pyfileinyourcodeeditorofchoiceandseewhatitlookslike:
mysite/urls.py
"""mysiteURLConfiguration
[...]
"""
fromdjango.conf.urlsimporturl
fromdjango.contribimportadmin
urlpatterns=[
url(r'^admin/',admin.site.urls),
]
Asyoucansee,Djangoalreadyputsomethinghereforus.
Linesbetweentriplequotes('''or""")arecalleddocstrings-youcanwritethematthetopofafile,classormethodtodescribewhatitdoes.Theywon'tberunbyPython.
TheadminURL,whichyouvisitedinpreviouschapterisalreadyhere:
mysite/urls.py
url(r'^admin/',admin.site.urls),
ItmeansthatforeveryURLthatstartswithadmin/Djangowillfindacorrespondingview.Inthiscasewe'reincludingalotofadminURLssoitisn'tallpackedintothissmallfile--it'smorereadableandcleaner.
Djangourls
73
RegexDoyouwonderhowDjangomatchesURLstoviews?Well,thispartistricky.Djangousesregex,shortfor"regularexpressions".Regexhasalot(alot!)ofrulesthatformasearchpattern.Sinceregexesareanadvancedtopic,wewillnotgoindetailoverhowtheywork.
Ifyoustillwishtounderstandhowwecreatedthepatterns,hereisanexampleoftheprocess-wewillonlyneedalimitedsubsetoftherulestoexpressthepatternwearelookingfor,namely:
^forbeginningofthetext
$forendoftext
\dforadigit
+toindicatethatthepreviousitemshouldberepeatedatleastonce
()tocapturepartofthepattern
Anythingelseintheurldefinitionwillbetakenliterally.
Nowimagineyouhaveawebsitewiththeaddresslikethat:http://www.mysite.com/post/12345/,where12345isthenumberofyourpost.
Writingseparateviewsforallthepostnumberswouldbereallyannoying.Withregularexpressionwecancreateapatternthatwillmatchtheurlandextractthenumberforus: ̂ post/(\d+)/$.Let'sbreakitdownpiecebypiecetoseewhatwearedoinghere:
^post/istellingDjangototakeanythingthathaspost/atthebeginningoftheurl(rightafter ̂ )(\d+)meansthattherewillbeanumber(oneormoredigits)andthatwewantthenumbercapturedandextracted/tellsdjangothatanother/charactershouldfollow$thenindicatestheendoftheURLmeaningthatonlystringsendingwiththe/willmatchthispattern
YourfirstDjangourl!TimetocreateourfirstURL!Wewant'http://127.0.0.1:8000/'tobeahomepageofourbloganddisplayalistofposts.
Wealsowanttokeepthemysite/urls.pyfileclean,sowewillimporturlsfromourblogapplicationtothemainmysite/urls.pyfile.
Goahead,addalinethatwillimportblog.urlsintothemainurl('').Notethatweareusingtheincludefunctionheresoyouwillneedtoaddthattotheimportonthefirstlineofthefile.
Yourmysite/urls.pyfileshouldnowlooklikethis:
mysite/urls.py
fromdjango.conf.urlsimportinclude,url
fromdjango.contribimportadmin
urlpatterns=[
url(r'^admin/',admin.site.urls),
url(r'',include('blog.urls')),
]
Djangowillnowredirecteverythingthatcomesinto'http://127.0.0.1:8000/'toblog.urlsandlookforfurtherinstructionsthere.
WhenwritingregularexpressionsinPythonitisalwaysdonewithrinfrontofthestring.ThisisahelpfulhintforPythonthatthestringmaycontainspecialcharactersthatarenotmeantforPythonitself,butfortheregularexpressioninstead.
blog.urls
Djangourls
74
Createanewblog/urls.pyemptyfile.Allright!Addthesetwofirstlines:
blog/urls.py
fromdjango.conf.urlsimporturl
from.importviews
Herewe'reimportingDjango'sfunctionurlandallofourviewsfromblogapplication(wedon'thaveanyyet,butwewillgettothatinaminute!)
Afterthat,wecanaddourfirstURLpattern:
blog/urls.py
urlpatterns=[
url(r'^$',views.post_list,name='post_list'),
]
Asyoucansee,we'renowassigningaviewcalledpost_listto ̂ $URL.Thisregularexpressionwillmatch ̂ (abeginning)followedby$(anend)-soonlyanemptystringwillmatch.That'scorrect,becauseinDjangoURLresolvers,'http://127.0.0.1:8000/'isnotapartoftheURL.ThispatternwilltellDjangothatviews.post_lististherightplacetogoifsomeoneentersyourwebsiteatthe'http://127.0.0.1:8000/'address.
Thelastpartname='post_list'isthenameoftheURLthatwillbeusedtoidentifytheview.Thiscanbethesameasthenameoftheviewbutitcanalsobesomethingcompletelydifferent.WewillbeusingthenamedURLslaterintheprojectsoitisimportanttonameeachURLintheapp.WeshouldalsotrytokeepthenamesofURLsuniqueandeasytoremember.
Ifyoutrytovisithttp://127.0.0.1:8000/now,thenyou'llfindsomesortof'webpagenotavailable'message.Thisisbecausetheserver(remembertypingrunserver?)isnolongerrunning.Takealookatyourserverconsolewindowtofindoutwhy.
Yourconsoleisshowinganerrorbutdon'tworry—they'reactuallyprettyuseful:
It'stellingyouthatthereisnoattribute'post_list'.That'sthenameoftheviewthatDjangoistryingtofindanduse,butwehaven'tcreatedityet.Atthisstageyour/admin/willalsonotwork.Noworries,wewillgetthere.
IfyouwanttoknowmoreaboutDjangoURLconfs,lookattheofficialdocumentation:https://docs.djangoproject.com/en/1.9/topics/http/urls/
Djangourls
75
Djangoviews-timetocreate!Timetogetridofthebugwecreatedinthelastchapter:)
Aviewisaplacewhereweputthe"logic"ofourapplication.Itwillrequestinformationfromthemodelyoucreatedbeforeandpassittoatemplate.We'llcreateatemplateinthenextchapter.ViewsarejustPythonfunctionsthatarealittlebitmorecomplicatedthantheoneswewroteintheIntroductiontoPythonchapter.
Viewsareplacedintheviews.pyfile.Wewilladdourviewstotheblog/views.pyfile.
blog/views.pyOK,let'sopenupthisfileandseewhat'sinthere:
blog/views.py
fromdjango.shortcutsimportrender
#Createyourviewshere.
Nottoomuchstuffhereyet.
Rememberthatlinesstartingwith#arecommentsandthoselineswon'tberunbyPython.
Thesimplestviewcanlooklikethis.
blog/views.py
defpost_list(request):
returnrender(request,'blog/post_list.html',{})
Asyoucansee,wecreatedafunction(def)calledpost_listthattakesrequestandreturnafunctionrenderthatwillrender(puttogether)ourtemplateblog/post_list.html.
Savethefile,gotohttp://127.0.0.1:8000/andseewhatwehavegot.
Anothererror!Readwhat'sgoingonnow:
Thisshowsthattheserverisrunningagain,atleast,butitstilldoesn'tlookright,doesit?Don'tworry,it'sjustanerrorpage,nothingtobescaredof!Justliketheerrormessagesintheconsole,theseareactuallyprettyuseful.YoucanreadthattheTemplateDoesNotExist.Let'sfixthisbugandcreateatemplateinthenextchapter!
Djangoviews-timetocreate!
76
LearnmoreaboutDjangoviewsbyreadingtheofficialdocumentation:https://docs.djangoproject.com/en/1.9/topics/http/views/
Djangoviews-timetocreate!
77
IntroductiontoHTMLWhat'satemplate,youmayask?
Atemplateisafilethatwecanre-usetopresentdifferentinformationinaconsistentformat-forexample,youcoulduseatemplatetohelpyouwritealetter,becausealthougheachlettermightcontainadifferentmessageandbeaddressedtoadifferentperson,theywillsharethesameformat.
ADjangotemplate'sformatisdescribedinalanguagecalledHTML(that'stheHTMLwementionedinthefirstchapterHowtheInternetworks).
WhatisHTML?HTMLisasimplecodethatisinterpretedbyyourwebbrowser-suchasChrome,FirefoxorSafari-todisplayawebpagefortheuser.
HTMLstandsfor"HyperTextMarkupLanguage".HyperTextmeansit'satypeoftextthatsupportshyperlinksbetweenpages.Markupmeanswehavetakenadocumentandmarkeditupwithcodetotellsomething(inthiscase,abrowser)howtointerpretthepage.HTMLcodeisbuiltwithtags,eachonestartingwith<andendingwith>.Thesetagsrepresentmarkupelements.
Yourfirsttemplate!Creatingatemplatemeanscreatingatemplatefile.Everythingisafile,right?Youhaveprobablynoticedthisalready.
Templatesaresavedinblog/templates/blogdirectory.Sofirstcreateadirectorycalledtemplatesinsideyourblogdirectory.Thencreateanotherdirectorycalledbloginsideyourtemplatesdirectory:
blog
└───templates
└───blog
(Youmightwonderwhyweneedtwodirectoriesbothcalledblog-asyouwilldiscoverlater,thisissimplyausefulnamingconventionthatmakeslifeeasierwhenthingsstarttogetmorecomplicated.)
Andnowcreateapost_list.htmlfile(justleaveitblankfornow)insidetheblog/templates/blogdirectory.
Seehowyourwebsitelooksnow:http://127.0.0.1:8000/
IfyoustillhaveanerrorTemplateDoesNotExist,trytorestartyourserver.Gointocommandline,stoptheserverbypressingCtrl+C(ControlandCbuttonstogether)andstartitagainbyrunningapythonmanage.pyrunservercommand.
IntroductiontoHTML
78
Noerroranymore!Congratulations:)However,yourwebsiteisn'tactuallypublishinganythingexceptanemptypage,becauseyourtemplateisemptytoo.Weneedtofixthat.
Addthefollowingtoyourtemplatefile:
blog/templates/blog/post_list.html
<html>
<p>Hithere!</p>
<p>Itworks!</p>
</html>
Sohowdoesyourwebsitelooknow?Clicktofindout:http://127.0.0.1:8000/
Itworked!Niceworkthere:)
Themostbasictag,<html>,isalwaysthebeginningofanywebpageand</html>isalwaystheend.Asyoucansee,thewholecontentofthewebsitegoesbetweenthebeginningtag<html>andclosingtag</html><p>isatagforparagraphelements;</p>closeseachparagraph
Head&bodyEachHTMLpageisalsodividedintotwoelements:headandbody.
headisanelementthatcontainsinformationaboutthedocumentthatisnotdisplayedonthescreen.
bodyisanelementthatcontainseverythingelsethatisdisplayedaspartofthewebpage.
Weuse<head>totellthebrowserabouttheconfigurationofthepage,and<body>totellitwhat'sactuallyonthepage.
Forexample,youcanputawebpagetitleelementinsidethe<head>,likethis:
blog/templates/blog/post_list.html
IntroductiontoHTML
79
<html>
<head>
<title>Ola'sblog</title>
</head>
<body>
<p>Hithere!</p>
<p>Itworks!</p>
</body>
</html>
Savethefileandrefreshyourpage.
Noticehowthebrowserhasunderstoodthat"Ola'sblog"isthetitleofyourpage?Ithasinterpreted<title>Ola'sblog</title>andplacedthetextinthetitlebarofyourbrowser(itwillalsobeusedforbookmarksandsoon).
Probablyyouhavealsonoticedthateachopeningtagismatchedbyaclosingtag,witha/,andthatelementsarenested(i.e.youcan'tcloseaparticulartaguntilalltheonesthatwereinsideithavebeenclosedtoo).
It'slikeputtingthingsintoboxes.Youhaveonebigbox,<html></html>;insideitthereis<body></body>,andthatcontainsstillsmallerboxes:<p></p>.
Youneedtofollowtheserulesofclosingtags,andofnestingelements-ifyoudon't,thebrowsermaynotbeabletointerpretthemproperlyandyourpagewilldisplayincorrectly.
CustomizeyourtemplateYoucannowhavealittlefunandtrytocustomizeyourtemplate!Hereareafewusefultagsforthat:
<h1>Aheading</h1>-foryourmostimportantheading<h2>Asub-heading</h2>foraheadingatthenextlevel<h3>Asub-sub-heading</h3>...andsoon,upto<h6><p>Aparagraphoftext</p>
<em>text</em>emphasizesyourtext<strong>text</strong>stronglyemphasizesyourtext<br/>goestoanotherline(youcan'tputanythinginsidebr)<ahref="https://djangogirls.org">link</a>createsalink<ul><li>firstitem</li><li>seconditem</li></ul>makesalist,justlikethisone!<div></div>definesasectionofthepage
Here'sanexampleofafulltemplate:
blog/templates/blog/post_list.html
IntroductiontoHTML
80
<html>
<head>
<title>DjangoGirlsblog</title>
</head>
<body>
<div>
<h1><ahref="">DjangoGirlsBlog</a></h1>
</div>
<div>
<p>published:14.06.2014,12:14</p>
<h2><ahref="">Myfirstpost</a></h2>
<p>Aeneaneuleoquam.Pellentesqueornaresemlaciniaquamvenenatisvestibulum.Donecidelitnonmipo
rtagravidaategetmetus.Fuscedapibus,tellusaccursuscommodo,tortormauriscondimentumnibh,utfermentummass
ajustositametrisus.</p>
</div>
<div>
<p>published:14.06.2014,12:14</p>
<h2><ahref="">Mysecondpost</a></h2>
<p>Aeneaneuleoquam.Pellentesqueornaresemlaciniaquamvenenatisvestibulum.Donecidelitnonmipo
rtagravidaategetmetus.Fuscedapibus,tellusaccursuscommodo,tortormauriscondimentumnibh,utf.</p>
</div>
</body>
</html>
We'vecreatedthreedivsectionshere.
Thefirstdivelementcontainsthetitleofourblog-it'saheadingandalinkAnothertwodivelementscontainourblogpostswithapublisheddate,h2withaposttitlethatisclickableandtwops(paragraph)oftext,oneforthedateandoneforourblogpost.
Itgivesusthiseffect:
Yaaay!Butsofar,ourtemplateonlyeverdisplaysexactlythesameinformation-whereasearlierweweretalkingabouttemplatesasallowingustodisplaydifferentinformationinthesameformat.
IntroductiontoHTML
81
WhatwereallywanttodoisdisplayrealpostsaddedinourDjangoadmin-andthat'swherewe'regoingnext.
Onemorething:deploy!It'dbegoodtoseeallthisoutandliveontheInternet,right?Let'sdoanotherPythonAnywheredeploy:
Commit,andpushyourcodeuptoGithub
Firstoff,let'sseewhatfileshavechangedsincewelastdeployed(runthesecommandslocally,notonPythonAnywhere):
command-line
$gitstatus
Makesureyou'reinthedjangogirlsdirectoryandlet'stellgittoincludeallthechangeswithinthisdirectory:
command-line
$gitadd--all.
--allmeansthatgitwillalsorecognizeifyou'vedeletedfiles(bydefault,itonlyrecognizesnew/modifiedfiles).Alsoremember(fromchapter3)that.meansthecurrentdirectory.
Beforeweuploadallthefiles,let'scheckwhatgitwillbeuploading(allthefilesthatgitwilluploadshouldnowappearingreen):
command-line
$gitstatus
We'realmostthere,nowit'stimetotellittosavethischangeinitshistory.We'regoingtogiveita"commitmessage"wherewedescribewhatwe'vechanged.Youcantypeanythingyou'dlikeatthisstage,butit'shelpfultotypesomethingdescriptivesothatyoucanrememberwhatyou'vedoneinthefuture.
command-line
$gitcommit-m"ChangedtheHTMLforthesite."
Makesureyouusedoublequotesaroundthecommitmessage.
Oncewe'vedonethat,weupload(push)ourchangesuptoGithub:
command-line
$gitpush
PullyournewcodedowntoPythonAnywhere,andreloadyourwebapp
OpenupthePythonAnywhereconsolespageandgotoyourBashconsole(orstartanewone).Then,run:
command-line
$cd~/my-first-blog
$gitpull
[...]
IntroductiontoHTML
82
Andwatchyourcodegetdownloaded.Ifyouwanttocheckthatit'sarrived,youcanhopovertotheFilestabandviewyourcodeonPythonAnywhere.
Finally,hoponovertotheWebtabandhitReloadonyourwebapp.
Yourupdateshouldbelive!Goaheadandrefreshyourwebsiteinthebrowser.Changesshouldbevisible:)
IntroductiontoHTML
83
DjangoORMandQuerySetsInthischapteryou'lllearnhowDjangoconnectstothedatabaseandstoresdatainit.Let'sdivein!
WhatisaQuerySet?AQuerySetis,inessence,alistofobjectsofagivenModel.QuerySetallowsyoutoreadthedatafromthedatabase,filteritandorderit.
It'seasiesttolearnbyexample.Let'strythis,shallwe?
DjangoshellOpenupyourlocalconsole(notonPythonAnywhere)andtypethiscommand:
command-line
(myvenv)~/djangogirls$pythonmanage.pyshell
Theeffectshouldbelikethis:
command-line
(InteractiveConsole)
>>>
You'renowinDjango'sinteractiveconsole.It'sjustlikePythonpromptbutwithsomeadditionalDjangomagic:).YoucanuseallthePythoncommandsheretoo,ofcourse.
AllobjectsLet'strytodisplayallofourpostsfirst.Youcandothatwiththefollowingcommand:
command-line
>>>Post.objects.all()
Traceback(mostrecentcalllast):
File"<console>",line1,in<module>
NameError:name'Post'isnotdefined
Oops!Anerrorshowedup.IttellsusthatthereisnoPost.It'scorrect--weforgottoimportitfirst!
command-line
>>>fromblog.modelsimportPost
Thisissimple:weimportmodelPostfromblog.models.Let'strydisplayingallpostsagain:
command-line
>>>Post.objects.all()
[<Post:myposttitle>,<Post:anotherposttitle>]
DjangoORM(Querysets)
84
It'salistofthepostswecreatedearlier!WecreatedthesepostsusingtheDjangoadmininterface.But,nowwewanttocreatenewpostsusingPython,sohowdowedothat?
Createobject
ThisishowyoucreateanewPostobjectindatabase:
command-line
>>>Post.objects.create(author=me,title='Sampletitle',text='Test')
Butwehaveonemissingingredienthere:me.WeneedtopassaninstanceofUsermodelasanauthor.Howtodothat?
Let'simportUsermodelfirst:
command-line
>>>fromdjango.contrib.auth.modelsimportUser
Whatusersdowehaveinourdatabase?Trythis:
command-line
>>>User.objects.all()
[<User:ola>]
It'sthesuperuserwecreatedearlier!Let'sgetaninstanceoftheusernow:
command-line
me=User.objects.get(username='ola')
Asyoucansee,wenowgetaUserwithausernamethatequalsto'ola'.Neat!Ofcourse,youhavetoadjustittoyourusername.
Nowwecanfinallycreateourpost:
command-line
>>>Post.objects.create(author=me,title='Sampletitle',text='Test')
Hurray!Wannacheckifitworked?
command-line
>>>Post.objects.all()
[<Post:myposttitle>,<Post:anotherposttitle>,<Post:Sampletitle>]
Thereitis,onemorepostinthelist!
Addmoreposts
Youcannowhavealittlefunandaddmorepoststoseehowitworks.Add2-3moreandgoaheadtothenextpart.
Filterobjects
DjangoORM(Querysets)
85
AbigpartofQuerySetsisanabilitytofilterthem.Let'ssay,wewanttofindallpostsUserolaauthored.WewillusefilterinsteadofallinPost.objects.all().Inparentheseswewillstatewhatcondition(s)ablogpostneedstomeettoendupinourqueryset.Inoursituationitisauthorthatisequaltome.ThewaytowriteitinDjangois:author=me.Nowourpieceofcodelookslikethis:
command-line
>>>Post.objects.filter(author=me)
[<Post:Sampletitle>,<Post:Postnumber2>,<Post:My3rdpost!>,<Post:4thtitleofpost>]
Ormaybewewanttoseeallthepoststhatcontainaword'title'inthetitlefield?
command-line
>>>Post.objects.filter(title__contains='title')
[<Post:Sampletitle>,<Post:4thtitleofpost>]
Therearetwounderscorecharacters(_)betweentitleandcontains.Django'sORMusesthisruletoseparatefieldnames("title")andoperationsorfilters("contains").Ifyouonlyuseoneunderscore,you'llgetanerrorlike"FieldError:Cannotresolvekeywordtitle_contains".
Youcanalsogetalistofallpublishedposts.Wedoitbyfilteringallthepoststhathavepublished_datesetinthepast:
command-line
>>>fromdjango.utilsimporttimezone
>>>Post.objects.filter(published_date__lte=timezone.now())
[]
Unfortunately,thepostweaddedfromthePythonconsoleisnotpublishedyet.Wecanchangethat!Firstgetaninstanceofapostwewanttopublish:
command-line
>>>post=Post.objects.get(title="Sampletitle")
Andthenpublishitwithourpublishmethod!
command-line
>>>post.publish()
Nowtrytogetlistofpublishedpostsagain(presstheuparrowbutton3timesandhitenter):
command-line
>>>Post.objects.filter(published_date__lte=timezone.now())
[<Post:Sampletitle>]
Orderingobjects
QuerySetsalsoallowyoutoorderthelistofobjects.Let'strytoorderthembycreated_datefield:
command-line
>>>Post.objects.order_by('created_date')
[<Post:Sampletitle>,<Post:Postnumber2>,<Post:My3rdpost!>,<Post:4thtitleofpost>]
DjangoORM(Querysets)
86
Wecanalsoreversetheorderingbyadding-atthebeginning:
command-line
>>>Post.objects.order_by('-created_date')
[<Post:4thtitleofpost>,<Post:My3rdpost!>,<Post:Postnumber2>,<Post:Sampletitle>]
ChainingQuerySets
YoucanalsocombineQuerySetsbychainingthemtogether:
>>>Post.objects.filter(published_date__lte=timezone.now()).order_by('published_date')
Thisisreallypowerfulandletsyouwritequitecomplexqueries.
Cool!You'renowreadyforthenextpart!Toclosetheshell,typethis:
command-line
>>>exit()
$
DjangoORM(Querysets)
87
DynamicdataintemplatesWehavedifferentpiecesinplace:thePostmodelisdefinedinmodels.py,wehavepost_listinviews.pyandthetemplateadded.ButhowwillweactuallymakeourpostsappearinourHTMLtemplate?Becausethatiswhatwewanttodo.Takesomecontent(modelssavedinthedatabase)anddisplayitnicelyinourtemplate,right?
Thisisexactlywhatviewsaresupposedtodo:connectmodelsandtemplates.Inourpost_listviewwewillneedtotakemodelswewanttodisplayandpassthemtothetemplate.Inaviewwedecidewhat(model)willbedisplayedinatemplate.
OK,sohowwillweachieveit?
Weneedtoopenourblog/views.py.Sofarpost_listviewlookslikethis:
blog/views.py
fromdjango.shortcutsimportrender
defpost_list(request):
returnrender(request,'blog/post_list.html',{})
Rememberwhenwetalkedaboutincludingcodewrittenindifferentfiles?Nowitisthemomentwhenwehavetoincludethemodelwehavewritteninmodels.py.Wewilladdthislinefrom.modelsimportPostlikethis:
blog/views.py
fromdjango.shortcutsimportrender
from.modelsimportPost
Thedotbeforemodelsmeanscurrentdirectoryorcurrentapplication.Bothviews.pyandmodels.pyareinthesamedirectory.Thismeanswecanuse.andthenameofthefile(without.py).Thenweimportthenameofthemodel(Post).
Butwhat'snext?TotakeactualblogpostsfromPostmodelweneedsomethingcalledQuerySet.
QuerySetYoushouldalreadybefamiliarwithhowQuerySetswork.WetalkedaboutitinDjangoORM(QuerySets)chapter.
Sonowwewantpublishedblogpostssortedbypublished_date,right?WealreadydidthatinQuerySetschapter!
blog/views.py
Post.objects.filter(published_date__lte=timezone.now()).order_by('published_date')
Nowweputthispieceofcodeinsidetheblog/views.pyfilebyaddingittothefunctiondefpost_list(request):
blog/views.py
fromdjango.shortcutsimportrender
fromdjango.utilsimporttimezone
from.modelsimportPost
defpost_list(request):
posts=Post.objects.filter(published_date__lte=timezone.now()).order_by('published_date')
returnrender(request,'blog/post_list.html',{})
Dynamicdataintemplates
88
PleasenotethatwecreateavariableforourQuerySet:posts.TreatthisasthenameofourQuerySet.Fromnowonwecanrefertoitbythisname.
Also,thecodeusesthetimezone.now()function,soweneedtoaddanimportfortimezone.
ThelastmissingpartispassingthepostsQuerySettothetemplate.Don'tworrywewillcoverhowtodisplayitinanextchapter.
Intherenderfunctionwealreadyhaveparameterwithrequest(soeverythingwereceivefromtheuserviatheInternet)andatemplatefile'blog/post_list.html'.Thelastparameter,whichlookslikethis:{}isaplaceinwhichwecanaddsomethingsforthetemplatetouse.Weneedtogivethemnames(wewillstickto'posts'rightnow:)).Itshouldlooklikethis:{'posts':posts}.Pleasenotethatthepartbefore:isastring;youneedtowrapitwithquotes''.
Sofinallyourblog/views.pyfileshouldlooklikethis:
blog/views.py
fromdjango.shortcutsimportrender
fromdjango.utilsimporttimezone
from.modelsimportPost
defpost_list(request):
posts=Post.objects.filter(published_date__lte=timezone.now()).order_by('published_date')
returnrender(request,'blog/post_list.html',{'posts':posts})
That'sit!TimetogobacktoourtemplateanddisplaythisQuerySet!
WanttoreadalittlebitmoreaboutQuerySetsinDjango?Youshouldlookhere:https://docs.djangoproject.com/en/1.9/ref/models/querysets/
Dynamicdataintemplates
89
DjangotemplatesTimetodisplaysomedata!Djangogivesussomehelpfulbuilt-intemplatetagsforthat.
Whataretemplatetags?Yousee,inHTML,youcan'treallywritePythoncode,becausebrowsersdon'tunderstandit.TheyonlyknowHTML.WeknowthatHTMLisratherstatic,whilePythonismuchmoredynamic.
DjangotemplatetagsallowustotransferPython-likethingsintoHTML,soyoucanbuilddynamicwebsitesfasterandeasier.Yikes!
DisplaypostlisttemplateInthepreviouschapterwegaveourtemplatealistofpostsinthepostsvariable.NowwewilldisplayitinHTML.
ToprintavariableinDjangotemplates,weusedoublecurlybracketswiththevariable'snameinside,likethis:
blog/templates/blog/post_list.html
{{posts}}
Trythisinyourblog/templates/blog/post_list.htmltemplate.Replaceeverythingfromthesecond<div>tothethird</div>with{{posts}}.Savethefile,andrefreshthepagetoseetheresults:
Asyoucansee,allwe'vegotisthis:
blog/templates/blog/post_list.html
[<Post:Mysecondpost>,<Post:Myfirstpost>]
ThismeansthatDjangounderstandsitasalistofobjects.RememberfromIntroductiontoPythonhowwecandisplaylists?Yes,withforloops!InaDjangotemplateyoudothemlikethis:
blog/templates/blog/post_list.html
{%forpostinposts%}
{{post}}
{%endfor%}
Trythisinyourtemplate.
Djangotemplates
90
Itworks!ButwewantthemtobedisplayedlikethestaticpostswecreatedearlierintheIntroductiontoHTMLchapter.YoucanmixHTMLandtemplatetags.Ourbodywilllooklikethis:
blog/templates/blog/post_list.html
<div>
<h1><ahref="/">DjangoGirlsBlog</a></h1>
</div>
{%forpostinposts%}
<div>
<p>published:{{post.published_date}}</p>
<h1><ahref="">{{post.title}}</a></h1>
<p>{{post.text|linebreaksbr}}</p>
</div>
{%endfor%}
Everythingyouputbetween{%for%}and{%endfor%}willberepeatedforeachobjectinthelist.Refreshyourpage:
Haveyounoticedthatweusedaslightlydifferentnotationthistime{{post.title}}or{{post.text}}?WeareaccessingdataineachofthefieldsdefinedinourPostmodel.Alsothe|linebreaksbrispipingtheposts'textthroughafiltertoconvertline-breaksintoparagraphs.
Djangotemplates
91
OnemorethingIt'dbegoodtoseeifyourwebsitewillstillbeworkingonthepublicInternet,right?Let'strydeployingtoPythonAnywhereagain.Here'sarecapofthesteps...
First,pushyourcodetoGithub
command-line
$gitstatus
[...]
$gitadd--all.
$gitstatus
[...]
$gitcommit-m"Modifiedtemplatestodisplaypostsfromdatabase."
[...]
$gitpush
Then,logbackintoPythonAnywhereandgotoyourBashconsole(orstartanewone),andrun:
command-line
$cdmy-first-blog
$gitpull
[...]
Finally,hoponovertotheWebtabandhitReloadonyourwebapp.Yourupdateshouldbelive!IftheblogpostsonyourPythonAnywheresitedon'tmatchthepostsappearingonthebloghostedonyourlocalserver-that'sOK.ThedatabasesonyourlocalcomputerandPythonAnywheredon'tsyncwiththerestofyourfiles.
Congrats!NowgoaheadandtryaddinganewpostinyourDjangoadmin(remembertoaddpublished_date!)MakesureyouareintheDjangoadminforyourpythonanywheresite,https://yourname.pythonanywhere.com/admin.Thenrefreshyourpagetoseeifthepostappearsthere.
Workslikeacharm?We'reproud!Stepawayfromyourcomputerforabit,youhaveearnedabreak.:)
Djangotemplates
92
CSS-makeitpretty!Ourblogstilllooksprettyugly,right?Timetomakeitnice!WewilluseCSSforthat.
WhatisCSS?CascadingStyleSheets(CSS)isalanguageusedfordescribingthelookandformattingofawebsitewritteninmarkuplanguage(likeHTML).Treatitasmake-upforourwebpage;).
Butwedon'twanttostartfromscratchagain,right?Oncemore,we'llusesomethingthatprogrammersreleasedontheInternetforfree.Youknow,reinventingthewheelisnofun.
Let'suseBootstrap!BootstrapisoneofthemostpopularHTMLandCSSframeworksfordevelopingbeautifulwebsites:https://getbootstrap.com/
ItwaswrittenbyprogrammerswhoworkedforTwitter.Nowit'sdevelopedbyvolunteersfromallovertheworld!
InstallBootstrapToinstallBootstrap,youneedtoaddthistoyour<head>inyour.htmlfile:
blog/templates/blog/post_list.html
<linkrel="stylesheet"href="//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css">
<linkrel="stylesheet"href="//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap-theme.min.css">
Thisdoesn'taddanyfilestoyourproject.Itjustpointstofilesthatexistontheinternet.Justgoahead,openyourwebsiteandrefreshthepage.Hereitis!
Lookingniceralready!
StaticfilesinDjango
CSS-makeitpretty
93
Finallywewilltakeacloserlookatthesethingswe'vebeencallingstaticfiles.StaticfilesareallyourCSSandimages.Theircontentdoesn'tdependontherequestcontextandwillbethesameforeveryuser.
WheretoputstaticfilesforDjango
Djangoalreadyknowswheretofindthestaticfilesforthebuilt-in"admin"app.Nowwejustneedtoaddsomestaticfilesforourownapp,blog.
Wedothatbycreatingafoldercalledstaticinsidetheblogapp:
djangogirls
├──blog
│├──migrations
│└──static
└──mysite
Djangowillautomaticallyfindanyfolderscalled"static"insideanyofyourapps'folders.Then,itwillbeabletousetheircontentsasstaticfiles.
YourfirstCSSfile!Let'screateaCSSfilenow,toaddyourownstyletoyourweb-page.Createanewdirectorycalledcssinsideyourstaticdirectory.Thencreateanewfilecalledblog.cssinsidethiscssdirectory.Ready?
djangogirls
└───blog
└───static
└───css
└───blog.css
TimetowritesomeCSS!Openuptheblog/static/css/blog.cssfileinyourcodeeditor.
Wewon'tbegoingtoodeepintocustomizingandlearningaboutCSShere.It'sprettyeasyandyoucanlearnitonyourownafterthisworkshop.Thereisarecommendationforafreecoursetolearnmoreattheendofthispage.
Butlet'sdoatleastalittle.Maybewecouldchangethecolorofourheader?Tounderstandcolors,computersusespecialcodes.Thesecodesstartwith#followedby6letters(A-F)andnumbers(0-9).Forexample,thecodeforblueis#0000FF.Youcanfindthecolorcodesformanycolorshere:http://www.colorpicker.com/.Youmayalsousepredefinedcolors,suchasredandgreen.
Inyourblog/static/css/blog.cssfileyoushouldaddthefollowingcode:
blog/static/css/blog.css
h1a{
color:#FCA205;
}
h1aisaCSSSelector.Thismeanswe'reapplyingourstylestoanyaelementinsideofanh1element.Sowhenwehavesomethinglike:<h1><ahref="">link</a></h1>theh1astylewillapply.Inthiscase,we'retellingittochangeitscolorto#FCA205,whichisorange.Ofcourse,youcanputyourowncolorhere!
InaCSSfilewedeterminestylesforelementsintheHTMLfile.Thefirstwayweidentifyelementsiswiththeelementname.YoumightremembertheseastagsfromtheHTMLsection.Thingslikea,h1,andbodyareallexamplesofelementnames.Wealsoidentifyelementsbytheattributeclassortheattributeid.Classandidarenamesyougivetheelementbyyourself.Classesdefinegroupsofelements,andidspointtospecificelements.Forexample,youcouldidentifythefollowingtagbyusingthetagnamea,theclassexternal_link,ortheidlink_to_wiki_page:
CSS-makeitpretty
94
<ahref="https://en.wikipedia.org/wiki/Django"class="external_link"id="link_to_wiki_page">
ReadaboutCSSSelectorsinw3schools.
Then,weneedtoalsotellourHTMLtemplatethatweaddedsomeCSS.Opentheblog/templates/blog/post_list.htmlfileandaddthislineattheverybeginningofit:
blog/templates/blog/post_list.html
{%loadstaticfiles%}
We'rejustloadingstaticfileshere:).Betweenthe<head>and</head>,afterthelinkstotheBootstrapCSSfilesaddthisline:
blog/templates/blog/post_list.html
<linkrel="stylesheet"href="{%static'css/blog.css'%}">
Thebrowserreadsthefilesintheorderthey'regiven,soweneedtomakesurethisisintherightplace.OtherwisethecodeinourfilemayoverridecodeinBootstrapfiles.WejusttoldourtemplatewhereourCSSfileislocated.
Yourfileshouldnowlooklikethis:
blog/templates/blog/post_list.html
{%loadstaticfiles%}
<html>
<head>
<title>DjangoGirlsblog</title>
<linkrel="stylesheet"href="//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css">
<linkrel="stylesheet"href="//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap-theme.min.css">
<linkrel="stylesheet"href="{%static'css/blog.css'%}">
</head>
<body>
<div>
<h1><ahref="/">DjangoGirlsBlog</a></h1>
</div>
{%forpostinposts%}
<div>
<p>published:{{post.published_date}}</p>
<h1><ahref="">{{post.title}}</a></h1>
<p>{{post.text|linebreaksbr}}</p>
</div>
{%endfor%}
</body>
</html>
OK,savethefileandrefreshthesite!
CSS-makeitpretty
95
Nicework!Maybewewouldalsoliketogiveourwebsitealittleairandincreasethemarginontheleftside?Let'strythis!
blog/static/css/blog.css
body{
padding-left:15px;
}
AddthistoyourCSS,savethefileandseehowitworks!
Maybewecancustomizethefontinourheader?Pastethisintoyour<head>inblog/templates/blog/post_list.htmlfile:
blog/templates/blog/post_list.html
<linkhref="//fonts.googleapis.com/css?family=Lobster&subset=latin,latin-ext"rel="stylesheet"type="text/css">
Asbefore,checktheorderandplacebeforethelinktoblog/static/css/blog.css.ThislinewillimportafontcalledLobsterfromGoogleFonts(https://www.google.com/fonts).
Findtheh1adeclarationblock(thecodebetweenbraces{and})intheCSSfileblog/static/css/blog.css.Nowaddthelinefont-family:'Lobster';betweenthebraces,andrefreshthepage:
blog/static/css/blog.css
CSS-makeitpretty
96
h1a{
color:#FCA205;
font-family:'Lobster';
}
Great!
Asmentionedabove,CSShasaconceptofclasses.TheseallowyoutonameapartoftheHTMLcodeandapplystylesonlytothispart,withoutaffectingotherparts.Thiscanbesuperhelpful!Maybeyouhavetwodivsthataredoingsomethingdifferent(likeyourheaderandyourpost).Aclasscanhelpyoumakethemlookdifferent.
GoaheadandnamesomepartsoftheHTMLcode.Addaclasscalledpage-headertoyourdivthatcontainsyourheader,likethis:
blog/templates/blog/post_list.html
<divclass="page-header">
<h1><ahref="/">DjangoGirlsBlog</a></h1>
</div>
Andnowaddaclassposttoyourdivcontainingablogpost.
blog/templates/blog/post_list.html
<divclass="post">
<p>published:{{post.published_date}}</p>
<h1><ahref="">{{post.title}}</a></h1>
<p>{{post.text|linebreaksbr}}</p>
</div>
Wewillnowadddeclarationblockstodifferentselectors.Selectorsstartingwith.relatetoclasses.TherearemanygreattutorialsandexplanationsaboutCSSontheWebtohelpyouunderstandthefollowingcode.Fornow,justcopyandpasteitintoyourblog/static/css/blog.cssfile:
blog/static/css/blog.css
CSS-makeitpretty
97
.page-header{
background-color:#ff9400;
margin-top:0;
padding:20px20px20px40px;
}
.page-headerh1,.page-headerh1a,.page-headerh1a:visited,.page-headerh1a:active{
color:#ffffff;
font-size:36pt;
text-decoration:none;
}
.content{
margin-left:40px;
}
h1,h2,h3,h4{
font-family:'Lobster',cursive;
}
.date{
color:#828282;
}
.save{
float:right;
}
.post-formtextarea,.post-forminput{
width:100%;
}
.top-menu,.top-menu:hover,.top-menu:visited{
color:#ffffff;
float:right;
font-size:26pt;
margin-right:20px;
}
.post{
margin-bottom:70px;
}
.posth1a,.posth1a:visited{
color:#000000;
}
ThensurroundtheHTMLcodewhichdisplaysthepostswithdeclarationsofclasses.Replacethis:
blog/templates/blog/post_list.html
{%forpostinposts%}
<divclass="post">
<p>published:{{post.published_date}}</p>
<h1><ahref="">{{post.title}}</a></h1>
<p>{{post.text|linebreaksbr}}</p>
</div>
{%endfor%}
intheblog/templates/blog/post_list.htmlwiththis:
blog/templates/blog/post_list.html
CSS-makeitpretty
98
<divclass="contentcontainer">
<divclass="row">
<divclass="col-md-8">
{%forpostinposts%}
<divclass="post">
<divclass="date">
<p>published:{{post.published_date}}</p>
</div>
<h1><ahref="">{{post.title}}</a></h1>
<p>{{post.text|linebreaksbr}}</p>
</div>
{%endfor%}
</div>
</div>
</div>
Savethosefilesandrefreshyourwebsite.
Woohoo!Looksawesome,right?LookatthecodewejustpastedtofindtheplaceswhereweaddedclassesintheHTMLandusedthemintheCSS.Wherewouldyoumakethechangeifyouwantedthedatetobeturquoise?
Don'tbeafraidtotinkerwiththisCSSalittlebitandtrytochangesomethings.PlayingwiththeCSScanhelpyouunderstandwhatthedifferentthingsaredoing.Ifyoubreaksomething,don'tworry,youcanalwaysundoit!
WereallyrecommendtakingthisfreeonlineCodeacademyHTML&CSScourse.ItcanhelpyoulearnallaboutmakingyourwebsitesprettierwithCSS.
Readyforthenextchapter?!:)
CSS-makeitpretty
99
TemplateextendingAnothernicethingDjangohasforyouistemplateextending.Whatdoesthismean?ItmeansthatyoucanusethesamepartsofyourHTMLfordifferentpagesofyourwebsite.
Templateshelpwhenyouwanttousethesameinformation/layoutinmorethanoneplace.Youdon'thavetorepeatyourselfineveryfile.Andifyouwanttochangesomething,youdon'thavetodoitineverytemplate,justonce!
CreatebasetemplateAbasetemplateisthemostbasictemplatethatyouextendoneverypageofyourwebsite.
Let'screateabase.htmlfileinblog/templates/blog/:
blog
└───templates
└───blog
base.html
post_list.html
Thenopenitupandcopyeverythingfrompost_list.htmltobase.htmlfile,likethis:
blog/templates/blog/base.html
{%loadstaticfiles%}
<html>
<head>
<title>DjangoGirlsblog</title>
<linkrel="stylesheet"href="//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css">
<linkrel="stylesheet"href="//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap-theme.min.css">
<linkhref='//fonts.googleapis.com/css?family=Lobster&subset=latin,latin-ext'rel='stylesheet'type='text/css'
>
<linkrel="stylesheet"href="{%static'css/blog.css'%}">
</head>
<body>
<divclass="page-header">
<h1><ahref="/">DjangoGirlsBlog</a></h1>
</div>
<divclass="contentcontainer">
<divclass="row">
<divclass="col-md-8">
{%forpostinposts%}
<divclass="post">
<divclass="date">
{{post.published_date}}
</div>
<h1><ahref="">{{post.title}}</a></h1>
<p>{{post.text|linebreaksbr}}</p>
</div>
{%endfor%}
</div>
</div>
</div>
</body>
</html>
Theninbase.html,replaceyourwhole<body>(everythingbetween<body>and</body>)withthis:
blog/templates/blog/base.html
Templateextending
100
<body>
<divclass="page-header">
<h1><ahref="/">DjangoGirlsBlog</a></h1>
</div>
<divclass="contentcontainer">
<divclass="row">
<divclass="col-md-8">
{%blockcontent%}
{%endblock%}
</div>
</div>
</div>
</body>
Youmightnoticethisreplacedeverythingfrom{%forpostinposts%}to{%endfor%}with:
blog/templates/blog/base.html
{%blockcontent%}
{%endblock%}
Butwhy?Youjustcreatedablock!Youusedthetemplatetag{%block%}tomakeanareathatwillhaveHTMLinsertedinit.ThatHTMLwillcomefromanothertemplatesthatextendsthistemplate(base.html).Wewillshowyouhowtodothisinamoment.
Nowsavebase.html,andopenyourblog/templates/blog/post_list.htmlagain.You'regoingtoremoveeverythingabove{%forpostinposts%}andbelow{%endfor%}.Whenyou'redonethefilewilllooklikethis:
blog/templates/blog/post_list.html
{%forpostinposts%}
<divclass="post">
<divclass="date">
{{post.published_date}}
</div>
<h1><ahref="">{{post.title}}</a></h1>
<p>{{post.text|linebreaksbr}}</p>
</div>
{%endfor%}
Wewanttousethisaspartofourtemplateforallthecontentblocks.Timetoaddblocktagstothisfile!
Youwantyourblocktagtomatchthetaginyourbase.htmlfile.Youalsowantittoincludeallthecodethatbelongsinyourcontentblocks.Todothat,puteverythingbetween{%blockcontent%}and{%endblockcontent%}.Likethis:
blog/templates/blog/post_list.html
{%blockcontent%}
{%forpostinposts%}
<divclass="post">
<divclass="date">
{{post.published_date}}
</div>
<h1><ahref="">{{post.title}}</a></h1>
<p>{{post.text|linebreaksbr}}</p>
</div>
{%endfor%}
{%endblock%}
Onlyonethingleft.Weneedtoconnectthesetwotemplatestogether.Thisiswhatextendingtemplatesisallabout!We'lldothisbyaddinganextendstagtothebeginningofthefile.Likethis:
blog/templates/blog/post_list.html
Templateextending
101
{%extends'blog/base.html'%}
{%blockcontent%}
{%forpostinposts%}
<divclass="post">
<divclass="date">
{{post.published_date}}
</div>
<h1><ahref="">{{post.title}}</a></h1>
<p>{{post.text|linebreaksbr}}</p>
</div>
{%endfor%}
{%endblock%}
That'sit!Checkifyourwebsiteisstillworkingproperly:)
IfyouhaveanerrorTemplateDoesNotExistthatsaysthatthereisnoblog/base.htmlfileandyouhaverunserverrunningintheconsole,trytostopit(bypressingCtrl+C-ControlandCbuttonstogether)andrestartitbyrunningapythonmanage.pyrunservercommand.
Templateextending
102
ExtendyourapplicationWe'vealreadycompletedallthedifferentstepsnecessaryforthecreationofourwebsite:weknowhowtowriteamodel,url,viewandtemplate.Wealsoknowhowtomakeourwebsitepretty.
Timetopractice!
Thefirstthingweneedinourblogis,obviously,apagetodisplayonepost,right?
WealreadyhaveaPostmodel,sowedon'tneedtoaddanythingtomodels.py.
Createatemplatelinktoapost'sdetailWewillstartwithaddingalinkinsideblog/templates/blog/post_list.htmlfile.Sofaritshouldlooklike:
blog/templates/blog/post_list.html
{%extends'blog/base.html'%}
{%blockcontent%}
{%forpostinposts%}
<divclass="post">
<divclass="date">
{{post.published_date}}
</div>
<h1><ahref="">{{post.title}}</a></h1>
<p>{{post.text|linebreaksbr}}</p>
</div>
{%endfor%}
{%endblockcontent%}
Wewanttohavealinkfromapost'stitleinthepostlisttothepost'sdetailpage.Let'schange<h1><ahref="">{{post.title}}</a></h1>sothatitlinkstothepost'sdetailpage:
blog/templates/blog/post_list.html
<h1><ahref="{%url'post_detail'pk=post.pk%}">{{post.title}}</a></h1>
Timetoexplainthemysterious{%url'post_detail'pk=post.pk%}.Asyoumightsuspect,the{%%}notationmeansthatweareusingDjangotemplatetags.ThistimewewilluseonethatwillcreateaURLforus!
blog.views.post_detailisapathtoapost_detailviewwewanttocreate.Pleasenote:blogisthenameofourapplication(thedirectoryblog),viewsisfromthenameoftheviews.pyfileandthelastbit-post_detail-isthenameoftheview.
Nowwhenwegoto:http://127.0.0.1:8000/wewillhaveanerror(asexpected,sincewedon'thaveaURLoraviewforpost_detail).Itwilllooklikethis:
Extendyourapplication
103
CreateaURLtoapost'sdetailLet'screateaURLinurls.pyforourpost_detailview!
Wewantourfirstpost'sdetailtobedisplayedatthisURL:http://127.0.0.1:8000/post/1/
Let'smakeaURLintheblog/urls.pyfiletopointDjangotoaviewnamedpost_detail,thatwillshowanentireblogpost.Addthelineurl(r'^post/(?P<pk>\d+)/$',views.post_detail,name='post_detail'),totheblog/urls.pyfile.Thefileshouldlooklikethis:
blog/urls.py
fromdjango.conf.urlsimporturl
from.importviews
urlpatterns=[
url(r'^$',views.post_list,name='post_list'),
url(r'^post/(?P<pk>\d+)/$',views.post_detail,name='post_detail'),
]
Thispart ̂ post/(?P<pk>\d+)/$looksscary,butnoworries-wewillexplainitforyou:
itstartswith ̂ again--"thebeginning"post/onlymeansthatafterthebeginning,theURLshouldcontainthewordpostand/.Sofarsogood.(?P<pk>\d+)-thispartistrickier.ItmeansthatDjangowilltakeeverythingthatyouplacehereandtransferittoaviewasavariablecalledpk.\dalsotellsusthatitcanonlybeadigit,notaletter(soeverythingbetween0and9).+meansthatthereneedstobeoneormoredigitsthere.Sosomethinglikehttp://127.0.0.1:8000/post//isnotvalid,buthttp://127.0.0.1:8000/post/1234567890/isperfectlyok!/-thenweneed/again$-"theend"!
Thatmeansifyouenterhttp://127.0.0.1:8000/post/5/intoyourbrowser,Djangowillunderstandthatyouarelookingforaviewcalledpost_detailandtransfertheinformationthatpkequals5tothatview.
pkisshortcutforprimarykey.ThisnameisoftenusedinDjangoprojects.Butyoucannameyourvariableasyoulike(remember:lowercaseand_insteadofwhitespaces!).Forexampleinsteadof(?P<pk>\d+)wecouldhavevariablepost_id,sothisbitwouldlooklike:(?P<post_id>\d+).
Ok,we'veaddedanewURLpatterntoblog/urls.py!Let'srefreshthepage:http://127.0.0.1:8000/Boom!Theserverhasstoppedrunningagain.Havealookattheconsole-asexpected,there'syetanothererror!
Extendyourapplication
104
Doyourememberwhatthenextstepis?Ofcourse:addingaview!
Addapost'sdetailviewThistimeourviewisgivenanextraparameterpk.Ourviewneedstocatchit,right?Sowewilldefineourfunctionasdefpost_detail(request,pk):.Notethatweneedtouseexactlythesamenameastheonewespecifiedinurls(pk).Omittingthisvariableisincorrectandwillresultinanerror!
Now,wewanttogetoneandonlyoneblogpost.Todothiswecanusequerysetslikethis:
blog/views.py
Post.objects.get(pk=pk)
Butthiscodehasaproblem.IfthereisnoPostwithgivenprimarykey(pk)wewillhaveasuperuglyerror!
Wedon'twantthat!But,ofcourse,Djangocomeswithsomethingthatwillhandlethatforus:get_object_or_404.IncasethereisnoPostwiththegivenpkitwilldisplaymuchnicerpage(calledPageNotFound404page).
Extendyourapplication
105
ThegoodnewsisthatyoucanactuallycreateyourownPagenotfoundpageandmakeitasprettyasyouwant.Butit'snotsuperimportantrightnow,sowewillskipit.
Ok,timetoaddaviewtoourviews.pyfile!
Weshouldopenblog/views.pyandaddthefollowingcode:
blog/views.py
fromdjango.shortcutsimportrender,get_object_or_404
Nearotherfromlines.Andattheendofthefilewewilladdourview:
blog/views.py
defpost_detail(request,pk):
post=get_object_or_404(Post,pk=pk)
returnrender(request,'blog/post_detail.html',{'post':post})
Yes.Itistimetorefreshthepage:http://127.0.0.1:8000/
Extendyourapplication
106
Itworked!Butwhathappenswhenyouclickalinkinblogposttitle?
Ohno!Anothererror!Butwealreadyknowhowtodealwithit,right?Weneedtoaddatemplate!
CreateatemplateforpostdetailWewillcreateafileinblog/templates/blogcalledpost_detail.html.
Itwilllooklikethis:
blog/templates/blog/post_detail.html
Extendyourapplication
107
{%extends'blog/base.html'%}
{%blockcontent%}
<divclass="post">
{%ifpost.published_date%}
<divclass="date">
{{post.published_date}}
</div>
{%endif%}
<h1>{{post.title}}</h1>
<p>{{post.text|linebreaksbr}}</p>
</div>
{%endblock%}
Onceagainweareextendingbase.html.Inthecontentblockwewanttodisplayapost'spublished_date(ifitexists),titleandtext.Butweshoulddiscusssomeimportantthings,right?
{%if...%}...{%endif%}isatemplatetagwecanusewhenwewanttochecksomething(rememberif...else..fromIntroductiontoPythonchapter?).Inthisscenariowewanttocheckifapost'spublished_dateisnotempty.
Ok,wecanrefreshourpageandseeifTemplateDoesNotExistisgonenow.
Yay!Itworks!
Onemorething:deploytime!It'dbegoodtoseeifyourwebsitewillstillbeworkingonPythonAnywhere,right?Let'strydeployingagain.
command-line
Extendyourapplication
108
$gitstatus
$gitadd--all.
$gitstatus
$gitcommit-m"AddedviewandtemplatefordetailedblogpostaswellasCSSforthesite."
$gitpush
Then,inaPythonAnywhereBashconsole:
command-line
$cdmy-first-blog
$gitpull
[...]
Finally,hoponovertotheWebtabandhitReload.
Andthatshouldbeit!Congrats:)
Extendyourapplication
109
DjangoFormsThefinalthingwewanttodoonourwebsiteiscreateanicewaytoaddandeditblogposts.Django'sadminiscool,butitisratherhardtocustomizeandmakepretty.Withformswewillhaveabsolutepoweroverourinterface-wecandoalmostanythingwecanimagine!
ThenicethingaboutDjangoformsisthatwecaneitherdefineonefromscratchorcreateaModelFormwhichwillsavetheresultoftheformtothemodel.
Thisisexactlywhatwewanttodo:wewillcreateaformforourPostmodel.
LikeeveryimportantpartofDjango,formshavetheirownfile:forms.py.
Weneedtocreateafilewiththisnameintheblogdirectory.
blog
└──forms.py
Ok,let'sopenitandtypethefollowingcode:
blog/forms.py
fromdjangoimportforms
from.modelsimportPost
classPostForm(forms.ModelForm):
classMeta:
model=Post
fields=('title','text',)
WeneedtoimportDjangoformsfirst(fromdjangoimportforms)and,obviously,ourPostmodel(from.modelsimportPost).
PostForm,asyouprobablysuspect,isthenameofourform.WeneedtotellDjango,thatthisformisaModelForm(soDjangowilldosomemagicforus)-forms.ModelFormisresponsibleforthat.
Next,wehaveclassMeta,wherewetellDjangowhichmodelshouldbeusedtocreatethisform(model=Post).
Finally,wecansaywhichfield(s)shouldendupinourform.Inthisscenariowewantonlytitleandtexttobeexposed-authorshouldbethepersonwhoiscurrentlyloggedin(you!)andcreated_dateshouldbeautomaticallysetwhenwecreateapost(i.einthecode),right?
Andthat'sit!Allweneedtodonowisusetheforminaviewanddisplayitinatemplate.
Soonceagainwewillcreate:alinktothepage,aURL,aviewandatemplate.
LinktoapagewiththeformIt'stimetoopenblog/templates/blog/base.html.Wewilladdalinkindivnamedpage-header:
blog/templates/blog/base.html
<ahref="{%url'post_new'%}"class="top-menu"><spanclass="glyphiconglyphicon-plus"></span></a>
Notethatwewanttocallournewviewpost_new.Theclass"glyphiconglyphicon-plus"isprovidedbythebootstrapthemeweareusing,andwilldisplayaplussignforus.
DjangoForms
110
Afteraddingtheline,yourhtmlfileshouldnowlooklikethis:
blog/templates/blog/base.html
{%loadstaticfiles%}
<html>
<head>
<title>DjangoGirlsblog</title>
<linkrel="stylesheet"href="//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css">
<linkrel="stylesheet"href="//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap-theme.min.css">
<linkhref='//fonts.googleapis.com/css?family=Lobster&subset=latin,latin-ext'rel='stylesheet'type='text/css'
>
<linkrel="stylesheet"href="{%static'css/blog.css'%}">
</head>
<body>
<divclass="page-header">
<ahref="{%url'post_new'%}"class="top-menu"><spanclass="glyphiconglyphicon-plus"></span></a>
<h1><ahref="/">DjangoGirlsBlog</a></h1>
</div>
<divclass="contentcontainer">
<divclass="row">
<divclass="col-md-8">
{%blockcontent%}
{%endblock%}
</div>
</div>
</div>
</body>
</html>
Aftersavingandrefreshingthepagehttp://127.0.0.1:8000youwillobviouslyseeafamiliarNoReverseMatcherror,right?
URLWeopenblog/urls.pyandaddaline:
blog/urls.py
url(r'^post/new/$',views.post_new,name='post_new'),
Andthefinalcodewilllooklikethis:
blog/urls.py
fromdjango.conf.urlsimporturl
from.importviews
urlpatterns=[
url(r'^$',views.post_list,name='post_list'),
url(r'^post/(?P<pk>\d+)/$',views.post_detail,name='post_detail'),
url(r'^post/new/$',views.post_new,name='post_new'),
]
Afterrefreshingthesite,weseeanAttributeError,sincewedon'thavepost_newviewimplemented.Let'sadditrightnow.
post_newviewTimetoopentheblog/views.pyfileandaddthefollowinglineswiththerestofthefromrows:
blog/views.py
DjangoForms
111
from.formsimportPostForm
andourview:
blog/views.py
defpost_new(request):
form=PostForm()
returnrender(request,'blog/post_edit.html',{'form':form})
TocreateanewPostform,weneedtocallPostForm()andpassittothetemplate.Wewillgobacktothisview,butfornow,let'screatequicklyatemplatefortheform.
TemplateWeneedtocreateafilepost_edit.htmlintheblog/templates/blogdirectory.Tomakeaformworkweneedseveralthings:
wehavetodisplaytheform.Wecandothatforexamplewithasimple{%raw%}{{form.as_p}}{%endraw%}.thelineaboveneedstobewrappedwithanHTMLformtag:<formmethod="POST">...</form>weneedaSavebutton.WedothatwithanHTMLbutton:<buttontype="submit">Save</button>andfinallyjustaftertheopening<form...>tagweneedtoadd{%raw%}{%csrf_token%}{%endraw%}.Thisisveryimportant,sinceitmakesyourformssecure!Djangowillcomplainifyouforgetaboutthisbitifyoutrytosavetheform:
Ok,solet'sseehowtheHTMLinpost_edit.htmlshouldlook:
blog/templates/blog/post_edit.html
{%extends'blog/base.html'%}
{%blockcontent%}
<h1>Newpost</h1>
<formmethod="POST"class="post-form">{%csrf_token%}
{{form.as_p}}
<buttontype="submit"class="savebtnbtn-default">Save</button>
</form>
{%endblock%}
Timetorefresh!Yay!Yourformisdisplayed!
DjangoForms
112
But,waitaminute!Whenyoutypesomethingintitleandtextfieldsandtrytosaveit-whatwillhappen?
Nothing!Weareonceagainonthesamepageandourtextisgone...andnonewpostisadded.Sowhatwentwrong?
Theansweris:nothing.Weneedtodoalittlebitmoreworkinourview.
SavingtheformOpenblog/views.pyonceagain.Currentlyallwehaveinthepost_newviewis:
blog/views.py
defpost_new(request):
form=PostForm()
returnrender(request,'blog/post_edit.html',{'form':form})
Whenwesubmittheform,wearebroughtbacktothesameview,butthistimewehavesomemoredatainrequest,morespecificallyinrequest.POST(thenaminghasnothingtodowithablog"post",it'stodowiththefactthatwe're"posting"data).RememberthatintheHTMLfileour<form>definitionhadthevariablemethod="POST"?Allthefieldsfromtheformarenowinrequest.POST.YoushouldnotrenamePOSTtoanythingelse(theonlyothervalidvalueformethodisGET,butwehavenotimetoexplainwhatthedifferenceis).
Soinourviewwehavetwoseparatesituationstohandle.First:whenweaccessthepageforthefirsttimeandwewantablankform.Second:whenwegobacktotheviewwithallform'sdatawejusttyped.Soweneedtoaddacondition(wewilluseifforthat).
blog/views.py
DjangoForms
113
ifrequest.method=="POST":
[...]
else:
form=PostForm()
It'stimetofillinthedots[...].IfmethodisPOSTthenwewanttoconstructthePostFormwithdatafromtheform,right?Wewilldothatwith:
blog/views.py
form=PostForm(request.POST)
Easy!Nextthingistocheckiftheformiscorrect(allrequiredfieldsaresetandnoincorrectvalueswillbesaved).Wedothatwithform.is_valid().
Wecheckiftheformisvalidandifso,wecansaveit!
blog/views.py
ifform.is_valid():
post=form.save(commit=False)
post.author=request.user
post.published_date=timezone.now()
post.save()
Basically,wehavetwothingshere:wesavetheformwithform.saveandweaddanauthor(sincetherewasnoauthorfieldinthePostFormandthisfieldisrequired!).commit=Falsemeansthatwedon'twanttosavePostmodelyet-wewanttoaddauthorfirst.Mostofthetimeyouwilluseform.save(),withoutcommit=False,butinthiscase,weneedtodothat.post.save()willpreservechanges(addingauthor)andanewblogpostiscreated!
Finally,itwouldbeawesomeifwecanimmediatelygotopost_detailpagefornewlycreatedblogpost,right?Todothatweneedonemoreimport:
blog/views.py
fromdjango.shortcutsimportredirect
Additattheverybeginningofyourfile.Andnowwecansay:gotopost_detailpageforanewlycreatedpost.
blog/views.py
returnredirect('post_detail',pk=post.pk)
post_detailisthenameoftheviewwewanttogoto.Rememberthatthisviewrequiresapkvariable?Topassittotheviewsweusepk=post.pk,wherepostisthenewlycreatedblogpost!
Ok,wetalkedalot,butweprobablywanttoseewhatthewholeviewlookslikenow,right?
blog/views.py
DjangoForms
114
defpost_new(request):
ifrequest.method=="POST":
form=PostForm(request.POST)
ifform.is_valid():
post=form.save(commit=False)
post.author=request.user
post.published_date=timezone.now()
post.save()
returnredirect('post_detail',pk=post.pk)
else:
form=PostForm()
returnrender(request,'blog/post_edit.html',{'form':form})
Let'sseeifitworks.Gotothepagehttp://127.0.0.1:8000/post/new/,addatitleandtext,saveit...andvoilà!Thenewblogpostisaddedandweareredirectedtopost_detailpage!
Youmighthavenoticedthatwearesettingpublishdatebeforesavingthepost.Lateron,wewillintroduceapublishbuttoninDjangoGirlsTutorial:Extensions.
Thatisawesome!
AswehaverecentlyusedtheDjangoadmininterfacethesystemcurrentlythinksweareloggedin.Thereareafewsituationsthatcouldleadtousbeingloggedout(closingthebrowser,restartingtheDBetc.).Ifyoufindthatyouaregettingerrorscreatingapostreferringtoalackofaloggedinuser,headtotheadminpagehttp://127.0.0.1:8000/adminandloginagain.Thiswillfixtheissuetemporarily.ThereisapermanentfixawaitingyouintheHomework:addsecuritytoyourwebsite!chapterafterthemaintutorial.
FormvalidationNow,wewillshowyouhowcoolDjangoformsare.Ablogpostneedstohavetitleandtextfields.InourPostmodelwedidnotsay(asopposedtopublished_date)thatthesefieldsarenotrequired,soDjango,bydefault,expectsthemtobeset.
Trytosavetheformwithouttitleandtext.Guess,whatwillhappen!
DjangoForms
115
Djangoistakingcareofvalidatingthatallthefieldsinourformarecorrect.Isn'titawesome?
EditformNowweknowhowtoaddanewform.Butwhatifwewanttoeditanexistingone?Itisverysimilartowhatwejustdid.Let'screatesomeimportantthingsquickly(ifyoudon'tunderstandsomething,youshouldaskyourcoachorlookatthepreviouschapters,sincewecoveredallthesestepsalready).
Openblog/templates/blog/post_detail.htmlandaddthisline:
blog/templates/blog/post_detail.html
<aclass="btnbtn-default"href="{%url'post_edit'pk=post.pk%}"><spanclass="glyphiconglyphicon-pencil"></span></a
>
sothatthetemplatewilllooklike:
blog/templates/blog/post_detail.html
DjangoForms
116
{%extends'blog/base.html'%}
{%blockcontent%}
<divclass="post">
{%ifpost.published_date%}
<divclass="date">
{{post.published_date}}
</div>
{%endif%}
<aclass="btnbtn-default"href="{%url'post_edit'pk=post.pk%}"><spanclass="glyphiconglyphicon-pencil"></
span></a>
<h1>{{post.title}}</h1>
<p>{{post.text|linebreaksbr}}</p>
</div>
{%endblock%}
Inblog/urls.pyweaddthisline:
blog/urls.py
url(r'^post/(?P<pk>\d+)/edit/$',views.post_edit,name='post_edit'),
Wewillreusethetemplateblog/templates/blog/post_edit.html,sothelastmissingthingisaview.
Let'sopenablog/views.pyandaddattheveryendofthefile:
blog/views.py
defpost_edit(request,pk):
post=get_object_or_404(Post,pk=pk)
ifrequest.method=="POST":
form=PostForm(request.POST,instance=post)
ifform.is_valid():
post=form.save(commit=False)
post.author=request.user
post.published_date=timezone.now()
post.save()
returnredirect('post_detail',pk=post.pk)
else:
form=PostForm(instance=post)
returnrender(request,'blog/post_edit.html',{'form':form})
Thislooksalmostexactlythesameasourpost_newview,right?Butnotentirely.Firstthing:wepassanextrapkparameterfromurls.Next:wegetthePostmodelwewanttoeditwithget_object_or_404(Post,pk=pk)andthen,whenwecreateaformwepassthispostasaninstancebothwhenwesavetheform:
blog/views.py
form=PostForm(request.POST,instance=post)
andwhenwejustopenedaformwiththisposttoedit:
blog/views.py
form=PostForm(instance=post)
Ok,let'stestifitworks!Let'sgotopost_detailpage.Thereshouldbeaneditbuttoninthetop-rightcorner:
DjangoForms
117
Whenyouclickityouwillseetheformwithourblogpost:
Feelfreetochangethetitleorthetextandsavechanges!
Congratulations!Yourapplicationisgettingmoreandmorecomplete!
IfyouneedmoreinformationaboutDjangoformsyoushouldreadthedocumentation:https://docs.djangoproject.com/en/1.9/topics/forms/
DjangoForms
118
SecurityBeingabletocreatenewpostsjustbyclickingalinkisawesome!But,rightnow,anyonethatvisitsyoursitewillbeabletopostanewblogpostandthat'sprobablynotsomethingyouwant.Let'smakeitsothebuttonshowsupforyoubutnotforanyoneelse.
Inblog/templates/blog/base.html,findourpage-headerdivandtheanchortagyouputinthereearlier.Itshouldlooklikethis:
blog/templates/blog/base.html
<ahref="{%url'post_new'%}"class="top-menu"><spanclass="glyphiconglyphicon-plus"></span></a>
We'regoingtoaddanother{%if%}tagtothiswhichwillmakethelinkonlyshowupforusersthatareloggedintotheadmin.Rightnow,that'sjustyou!Changethe<a>tagtolooklikethis:
blog/templates/blog/base.html
{%ifuser.is_authenticated%}
<ahref="{%url'post_new'%}"class="top-menu"><spanclass="glyphiconglyphicon-plus"></span></a>
{%endif%}
This{%if%}willcausethelinktoonlybesenttothebrowseriftheuserrequestingthepageisloggedin.Thisdoesn'tprotectthecreationofnewpostscompletely,butit'sagoodfirststep.We'llcovermoresecurityintheextensionlessons.
Remembertheediticonwejustaddedtoourdetailpage?Wealsowanttoaddthesamechangethere,sootherpeoplewon'tbeabletoeditexistingposts.
Openblog/templates/blog/post_detail.htmlandfind:
blog/templates/blog/post_detail.html
<aclass="btnbtn-default"href="{%url'post_edit'pk=post.pk%}"><spanclass="glyphiconglyphicon-pencil"></span></a
>
Changeitto:
blog/templates/blog/post_detail.html
{%ifuser.is_authenticated%}
<aclass="btnbtn-default"href="{%url'post_edit'pk=post.pk%}"><spanclass="glyphiconglyphicon-pencil"></sp
an></a>
{%endif%}
Sinceyou'relikelyloggedin,ifyourefreshthepage,youwon'tseeanythingdifferent.Loadthepageinanewbrowseroranincognitowindow,though,andyou'llseethatthelinkdoesn'tshowup,andtheicondoesn'tdisplayeither!
Onemorething:deploytime!Let'sseeifallthisworksonPythonAnywhere.Timeforanotherdeploy!
First,commityournewcode,andpushituptoGithub
command-line
DjangoForms
119
$gitstatus
$gitadd--all.
$gitstatus
$gitcommit-m"Addedviewstocreate/editblogpostinsidethesite."
$gitpush
Then,inaPythonAnywhereBashconsole:
command-line
$cdmy-first-blog
$gitpull
[...]
Finally,hoponovertotheWebtabandhitReload.
Andthatshouldbeit!Congrats:)
DjangoForms
120
What'snext?Congratulateyourself!You'retotallyawesome.We'reproud!<3
Whattodonow?
Takeabreakandrelax.Youhavejustdonesomethingreallyhuge.
Afterthatmakesureto:
FollowDjangoGirlsonFacebookorTwittertostayuptodate
Canyourecommendanyfurtherresources?Yes!First,goaheadandtryourotherbook,calledDjangoGirlsTutorial:Extensions.
Lateron,youcantrytheresourceslistedbelow.They'reallveryrecommended!
Django'sofficialtutorialNewCodertutorialsCodeAcademyPythoncourseCodeAcademyHTML&CSScourseDjangoCarrotstutorialLearnPythonTheHardWaybookGettingStartedWithDjangovideolessonsTwoScoopsofDjango:BestPracticesforDjango1.8bookHelloWebApp:LearnHowtoBuildaWebApp
What'snext?
121