Django - The Easy Way: A step-by-step guide on building Django websites, 2nd Edition
Transcript of Django - The Easy Way: A step-by-step guide on building Django websites, 2nd Edition
Django-TheEasyWay(2ndEdition)
Astep-by-stepguideonbuildingDjangowebsites
SamuliNatri
copy2017-2018SamuliNatri
TableofContents
Preface
AboutthisbookWhoisthisbookforWhatthisbookisNOTaboutHowthisbookisorganizedChapters1-7Chapters8-10Chapters11-13Chapters14-16Chapters17-20Chapters21-24Chapters25-26Chapters27-28Chapters29-32
Abouttheauthor
1InstallingPythononWindows11DownloadingandinstallingPython12Usingtheinteractiveprompt13Details131Pythoninterpreter
14Summary
2InstallingPythononmacOS21DownloadingandinstallingPython22Usingtheinteractiveprompt23Details231Pythoninterpreter
24Summary
3InstallingPythononLinux31InstallingPython32Usingtheinteractiveprompt33Details331Pythoninterpreter
34Summary
4CreatingvirtualenvironmentsinWindows41Creatingandactivatingvirtualenvironments42Summary
5CreatingvirtualenvironmentsinmacOS51Creatingandactivatingvirtualenvironments52Summary
6CreatingvirtualenvironmentsinLinux61Creatingandactivatingvirtualenvironments62Summary
7Virtualenvironmentsandpip71Whyusevirtualenvironments72Details721Organizingfolders722Freezingrequirements723Excludingvenvfromtherepository724Usingothertools725Usingpythonvspython3
73Summary
8CreatingaDjangoproject81Setup82CreatinganewProject83Runningthedevelopmentserver84Details85Summary
9CreatingaHelloWorldapp91Setup92Creatingapps93Creatingtemplatefiles94Creatingviews95Addingahomepagepath96Summary
10Examiningtheprojectstructureandapps101Addingfeatureswithapps102Exploringtheprojectstructure103Exploringtheprojectpackage
104Summary
11Workingwithtemplateinheritance111Setup112Creatingabaseapp113Extendingtemplates114Details115Summary
12InstallingBootstrap4theme121Setup122Modifyinganexistingtemplate123Updatingthehomepagetemplate124Details125Summary
13Managingstaticfiles131Setup132Creatingastylesheetfile133Details1331Workingwithstaticfiles1332Usingthestatictag1333Forcingcacherefreshwithversioning
134Summary
14Creatingmodels141Setup142CreatingtheFlowermodel143Listingflowers144Details1441Explainingmodels1442Returningastringrepresentation1443Makingdatabasequeries
145Summary
15Creatingabaseproject151Setup152Addingadescriptionfield153Addingmasonrylikecolumns154Addingafooter155Summary
16Creatingadetailpage161Setup162Addingadetailpagepath163Creatingthedetailview164Creatingthedetailpagetemplate165Creatingslugs166Updatingthepath167Definingget_absolute_url()method168Usingurltag169Details1691CapturingURLvalues1692Usingviewparameters1693Explainingslugs1694ReversingURLS
1610Summary
17Addingcategoryasamany-to-onerelationhip171Setup172Addingcategoryfieldandmodel173Updatingthehomepagetemplate174Details1741Examiningmany-to-onerelationships1742Accessingrelatedobjects
175Summary
18ReferencingtagswithaManyToManyfield181Setup182Addingthetagsfield183Updatingthehomepagetemplate184Summary
19Creatingatagspage191Setup192Addingtagspath193Addingtheslugfield194Creatingthetagsview195Updatinghomepagetemplate196Details1961Doinglookupsacrossrelationships1962Reusingtemplates
197Summary
20Creatingasearchfeature201Setup202Addingasearchform203Updatingtheindexview204Details205Summary
21Workingwithformscreatingitems211Setup212Creatingtheeditform213Creatingtheformclass214Updatingurlpatterns215Creatingtheviewfunction216Addingamenuitem217Details2171Protectingagainstcrosssiterequestforgeries2172Addingformfields2173UsingtheFormclass2174Examiningtheviewfunction
218Summary
22Workingwithformseditingitems221Setup222Addingthepath223Creatingtheeditview224Updatingtheeditlink225Details2251Capturingtheid2252Examiningtheeditview
226Summary
23Workingwithformscustomization231Setup232Addingthedescriptionfield233Details2331Changingfieldorder2332Customizingvalidationerrors
234Summary
24Creatinganddeletingobjects241Setup242Addingthedeletepath243Addingthedeleteview244Updatingthedeletelink245Details246Summary
25AuthenticatinguserswithAllauth251Setup252InstallingAllauth253Creatingtemplatefiles254UpdatingthetemplatesforBootstrap4255Details2551Configurationoptions2552Addingthepaths2553django-widget-tweaks
256Summary
26Authorization261Setup262AddingtheEditorgroup263Creatingatestuser264Usingpermissions265Usingdecorators266Details2661Authenticationvsauthorization2662Controllingaccesswithdecorators
267Summary
27Creatinganimagegallery271Setup272Installingpillow273Configuringmediavariables274AddingImageField275Addingimagestoflowers276Usingthestatichelperfunction277Addingthegrid278Details
279Summary
28Addingimagethumbnails281Setup282InstallingImageKit283Addingthethumbnailfield284Details285Summary
29DeployingonHeroku291Setup292CreatingaHerokuapp293InstallingHerokuCLI2931InstallationinWindows2932InstallationinmacOS2933InstallationinUbuntu2934Authenticatingwithabrowser
294CreatingaProcfile295Updatingthesettingspyfile296Creatingtherepository297Pushingchanges298Updatingthedatabase299Summary
30UsingAmazonAWStoservefiles301Setup302CreatinganAmazonAWSbucket303Settinguppermissions304Updatingsettingspyfile305AddinganimagefieldtothePostmodel306Installingpackages307Summary
31SettingupHerokupipelines311Setup312CreatingaGitHubrepository313Creatingapipeline314Testingdeployment315Addingaproductionapp316Enablingreviewapps
317Usingpullrequests318Deletingthebranch319Summary
32SendingemailswithSendGrid321Creatinganaccount322Summary
Licenses
Preface
ldquoDjango-TheEasyWay(2ndEdition)rdquobookisapracticalstep-by-stepguideonhowtobuildDjangowebsites
DjangoisaPythonbasedopensourcewebdevelopmentframeworkthathasbeenaroundsince2005Itenablesyoutocreatecomplexdatabase-drivenwebsiteswhilekeepingthingsdecoupledanddryThePythonPackageIndex(PyPI)hostsnumerousfreepackagesthatcanbeusedtoextendprojectswithoutre-inventingthewheelDjangoisusedbysomewell-knownsiteslikeInstagramBitbucketandDisqus
Aboutthisbook
ThisbookisaboutlearningtheDjangowebframeworkwithsimplepracticalexamplesItguidesyouthroughallthemainconceptsoneatthetimeWewillworkonmanysmallprojectsratherthanworkingonasinglebigapplicationthroughthebookThishelpsdigestingtheinformationastheprojectshavelessdistractingcodefrompreviouschaptersBytheendofthebookyoushouldhaveasolidunderstandingofhowtobuildanddeployappswithDjango
ThecompletebooksourcecodeisavailableinherehttpssamulitoDjango-The-Easy-Way-Source
WhoisthisbookforThisbookissuitableforbeginnertointermediatelevelwebdevelopersYoudonrsquothavetohaveanyexperiencewithDjangoorbuildingwebapplicationsingeneralWestartwiththeverybasicsandincreasecomplexityaswegoalong
WhatthisbookisNOTaboutWeuseBootstrap4tohaveadecentlookingtestingplaygroundbutotherwisefrontendconceptsarecoveredminimallyThisisnotabookaboutPythonHTMLCSSorJavaScriptBasicknowledgeaboutthosetechnologieswouldbehelpfulbutisnotrequiredforthebookThefocusisontheDjangowebframeworkcoreconceptsanddeploymentpractices
HowthisbookisorganizedThisbookisorganizedin32chaptersthatfocusonkeyconceptsoftheframeworkIrecommendreadingthebookinsequencestartingfromtheverybeginningandworkingyourwaytotheendfromthere
Chapters1-7Chapters1-7coverhowtoinstallPythonandusevirtualenvironments
Chapters8-10
Inchapters8-10wecreateasimpleDjangoprojectandexaminetheprojectstructureldquoHelloworldrdquoprojectintroducesthereadertoviewspathsandtemplates
Chapters11-13Chapters11-13coverhowthetemplateinheritanceworksandhowtointegrateBootstrap4frontendframeworkwithDjangoWealsoapplycustomstyleswithCSS(CascadingStyleSheets)
Chapters14-16Chapters14-16coverhowtousemodelsandinteractwithadatabaseWelearnaboutfiltersandhowtobuildabaseprojectthatcanbeusedasastartingpointforotherprojectsWecreateadetailpageandlearnhowtoworkwithslugsandreverseURLS
Chapters17-20Inchapters17-20welearnhowtocategoriseitemswithaForeignKeyfieldandtagitemswithaManyToManyFieldWedolookupsthroughrelationshipsre-usetemplatesandbuildaminimalisticsearchfeature
Chapters21-24Chapters21-24showhowtocreateformswithModelFormWecustomizetheformsbychangingfieldorderandrendervalidationerrorsmanuallyThe
PythoninteractiveinterpreterisusedtomanipulateobjectsandinteractwithDjango
Chapters25-26Chapters25-26coverhowtocreateacompleteauthenticationsystemwiththeAllauthpackageandhowtothemethedefaultformswithBootstrap4Userauthorizationismanagedwithgroupsanddecorators
Chapters27-28
Chapters27-28Inchapters27-28weuploadimagesandservethemfromalocalmediafolderBootstrap4isusedtocreateagridviewtodisplaytheimagesTheuploadedimagesarecompressedtothumbnailsusingtheImageKitpackage
Chapters29-32Chapters29-32showhowtodeploytoHerokuplatformandservestaticassetsanduser-uploadedfilesfromanAmazonAWSbucketWelearnhowtoestablishcontinuousdeploymentworkflowswithHerokupipelinesandsendemailswithSendGrid
AbouttheauthorSamuliNatrihasbeenasoftwaredevelopersincethe90rsquosHeattendedHelsinki
SamuliNatrihasbeenasoftwaredevelopersincethe90rsquosHeattendedHelsinkiUniversityOfTechnology(ComputerScience)andHelsinkiUniversity(SocialSciences)
Websitehttpssamulinatricom
1InstallingPythononWindows
Thischaptercovers
HowtoinstallPythononWindowsHowtousetheinteractiveinterpretertotestit
11DownloadingandinstallingPythonVisithttpssamulitoPython-DownloadanddownloadtheWindowsinstaller
Runtheinstaller
CheckAddPython37toPATHandclickInstallNow
Lettheinstallerfinnishandcloseit
PressWindowskeyorclicktheiconatthebottomleftcorner
SearchforCommandPromptandopenit
12UsingtheinteractivepromptTypepythoninthecommandpromptandpressenterTheinterpreterisnowininteractivemodewaitingforyourcommands
Letrsquosaddtwovariablestogetherandprintouttheresultwithprint()functionInteractivePythonsession
gtgtgta=1
gtgtgtb=1
gtgtgtc=a+b
gtgtgtprint(c)
2
gtgtgt^Z
ExitthesessionwithCtrl-Zplusreturn
13Details
131PythoninterpreterInterpreterisasoftwarelayerbetweenyourprogramandthecomputerItreadsyourcodeandcarriesouttheinstructionsitcontains
YoucantypeandrunPythoncodedirectlyintheinteractivepromptThisallowsustointeractwithDjangoprojectsusingthecommandline
14Summary
PythoncaneasilybeinstalledonWindowsusingtheofficialinstallerMakesuretoaddPythontothePATHsoyoucanruniteverywhereInterpreterisasoftwarelayerbetweenyourcodeandthecomputerYoucanusetheinteractiveprompttotypeandrunPythoncode
2InstallingPythononmacOS
Thischaptercovers
HowtoinstallPythononmacOSHowtousetheinteractiveinterpretertotestit
21DownloadingandinstallingPythonVisithttpssamulitoPython-DownloadanddownloadthelatestmacOSversion
Runtheinstaller
PressCtrlplusSpaceandsearchforterminal
22UsingtheinteractivepromptTypepython3intheterminalandpressreturnTheinterpreterisnowininteractivemodewaitingforyourcommands
Letrsquosaddtwovariablestogetherandprintouttheresultwithprint()functionInteractivePythonsession
gtgtgta=1
gtgtgtb=1
gtgtgtc=a+b
gtgtgtprint(c)
2
gtgtgt^D
ExitthesessionwithCtrl-D
23Details
231PythoninterpreterInterpreterisasoftwarelayerbetweenyourprogramandthecomputerItreadsyourcodeandcarriesouttheinstructionsitcontains
YoucantypeandrunPythoncodedirectlyintheinteractivepromptThisallowsustointeractwithDjangoprojectsusingthecommandline
24Summary
PythoncaneasilybeinstalledonmacOSusingtheofficialinstallerInterpreterisasoftwarelayerbetweenyourcodeandthecomputerYoucanusetheinteractiveprompttotypeandrunPythoncode
3InstallingPythononLinux
Thischaptercovers
HowtoinstallPythononLinuxHowtousetheinteractiveinterpretertotestit
31InstallingPythonClicktheShowapplicationsiconatthebottomleftcorner
Searchforterminalandclicktheicontoopenit
OpenthePythoninteractivepromptwithpython3command
Ifthepython3commanddoesnrsquotworkinstallitwiththefollowingcommandTerminal
sudoaptinstallpython3
32UsingtheinteractivepromptTypepython3intheterminalandpressenter
TheinterpreterisnowininteractivemodewaitingforyourcommandsLetrsquosaddtwovariablestogetherandprintouttheresultwithprint()function
InteractivePythonsessiongtgtgta=1
gtgtgtb=1
gtgtgtc=a+b
gtgtgtprint(c)
2
ExitthepromptwithCtrl-DplusEnter
33Details
331PythoninterpreterInterpreterisasoftwarelayerbetweenyourprogramandthecomputerItreadsyourcodeandcarriesouttheinstructionsitcontains
YoucantypeandrunPythoncodedirectlyintheinteractivepromptThisallowsustointeractwithDjangoprojectsusingthecommandline
34Summary
Pythoncomespre-installedonallmajorLinuxdistributionsInterpreterisasoftwarelayerbetweenyourcodeandthecomputer
YoucanusetheinteractiveprompttotypeandrunPythoncode
4CreatingvirtualenvironmentsinWindows
Thischaptercovers
HowtocreatevirtualenvironmentsinWindows
41CreatingandactivatingvirtualenvironmentsCreateanewdirectoryfortheprojects
Terminalmkdirprojects
cdprojects
venvcommandcreatesthevirtualenvironmentActivateitwiththeactivatebatscript
Terminalpython-mvenvvenv
venvScriptsactivatebat
The(venv)prefixindicatesthattheenvironmentisactiveTerminal
(venv)CUserssamulprojectsgt
Restofthebookwillmostlybethesameforalloperatingsystems
42Summary
YoucanusethevenvcommandtocreatevirtualenvironmentsMakesuretoactivethevirtualenvironmentbeforeyoustartworkingonaproject
5CreatingvirtualenvironmentsinmacOS
Thischaptercovers
HowtocreatevirtualenvironmentsinmacOS
51CreatingandactivatingvirtualenvironmentsCreateanewdirectoryfortheprojects
Terminalmkdirprojects
cdprojects
venvcommandcreatesthevirtualenvironmentActivateitusingthesourcecommand
Terminalpython3-mvenvvenv
sourcevenvbinactivate
sourcecommandreadsandexecutescommandsfromafile
The(venv)prefixindicatesthattheenvironmentisactiveTerminal
(venv)~
Restofthebookwillmostlybethesameforalloperatingsystems
52Summary
YoucanusethevenvcommandtocreatevirtualenvironmentsMakesuretoactivethevirtualenvironmentbeforeyoustartworkingonaproject
6CreatingvirtualenvironmentsinLinux
Thischaptercovers
HowtocreatevirtualenvironmentsinLinux
61CreatingandactivatingvirtualenvironmentsCreateanewdirectoryfortheprojects
Terminalmkdirprojects
cdprojects
venvcommandcreatesthevirtualenvironmentActivateitusingthesourcecommand
Terminalsudoapt-getinstallpython3-venv
python-mvenvvenv
sourcevenvbinactivate
sourcecommandreadsandexecutescommandsfromafile
The(venv)prefixindicatesthattheenvironmentisactiveTerminal
(venv)samulibox~projects$
Restofthebookwillmostlybethesameforalloperatingsystems
62Summary
YoucanusethevenvcommandtocreatevirtualenvironmentsMakesuretoactivethevirtualenvironmentbeforeyoustartworkingonaproject
7Virtualenvironmentsandpip
Thischaptercovers
WhatarevirtualenvironmentsandwhyyoushouldusethemHowtousepiptomanageprojectpackages
71WhyusevirtualenvironmentsVirtualenvironmentsallowyoutomanageprojectdependenciesinanisolatedmannerYoucanhaveaprojectthatusesDjango10andanotherprojectthatusesDjango20TheformerprojectusesPython2andthelatterPython3Withvirtualenvironmentstheydonrsquotinterferewhicheachother
UpdatesmayintroducechangesthatbreakyourapplicationMaybeyourfavouritepackagedoesnrsquotsupportthenewreleaseoryourowncustomcodeisnotreadyfortheupgradeButatthesametimeyoumightwanttostartanotherprojectusingthenewDjangoreleaseThisiswherevirtualenvironmentscomeinhandy
KeepingallprojectpackagesinoneplacealsomakesiteasiertodeployWecangeneratearequirementslistanduseittoinstallthedependenciesonanotherenvironment
Virtualenvironmentforeachproject
Project1
dbsqlite3
managepy
mysite
venv(WithDjango10+Python2)
Project2
dbsqlite3
managepy
mysite
venv(WithDjango20+Python3)
InthisexampleeachprojecthasitsownPythoninstallationandDjangopackageDjangoisinstalledinthevenvfolderlikeanyotherPythonpackage
72Details
721OrganizingfoldersYoudonrsquothavetoputthevenvfolderinsidetheprojectfolderInfactinthisbookIwilluseonesharedvirtualenvironmentforallprojectsInyourownreal-lifeprojectsIwouldrecommendhavingaseparatevirtualenvironmentforeachproject
ThisishowweorganizetheprojectsinthisbookAllprojectsshareonevirtualenvironment
projects
08-Django-Project
09-Hello-World
venv
722FreezingrequirementsProjectpackagelistcanbestoredinafileusingthepipfreezecommand
Terminalpipfreezegtrequirementstxt
pipisaPythonpackagemanager
Therequirementstxtfilemightlooksomethinglikethisrequirementstxt
Django==213
gunicorn==1990
Pillow==530
psycopg2==275
ThesedependenciescanbeinstalledusingthepipinstallcommandTerminal
pipinstall-rrequirementstxt
ThisinstallationprocesshappensautomaticallywhenwedeployourprojecttotheHerokuplatformJustmakesuretofreezetherequirementsafteryouinstalloruninstallpackages
723ExcludingvenvfromtherepositoryExcludethevenvfolderfromtherepositorywhenusingaversioncontrolsystemThiswillbedemonstratedlaterwhenwearereadytodeploy
724UsingothertoolsThereareothertoolsformanagingvirtualenvironmentslikeVirtualenvwrapperCheckoutthistutorialtolearnmorehttpssamulitoVirtual-Environments
725Usingpythonvspython3Usingavirtualenvironmentallowsustousethepythoncommand(insteadofpython3)forldquoPython3rdquoregardlessofthesystemwidePythonversionIfIdeactivatethevirtualenvironmentandrunpythoninmacOSitwilldefaulttoPython2710inmymachine
Terminal~deactivate
~python
Python2710(defaultOct62017222907)
Somakesuretoactivatetheprojectvirtualenvironmentbeforeyoustartworkingonit
73Summary
VirtualenvironmentsallowyoutomanageprojectdependenciesinanisolatedmannerpipisaPythonpackagemanagerYoucanusethepipfreezecommandtostoreprojectdependencieslistinafile
8CreatingaDjangoproject
Thischaptercovers
HowtocreateanewDjangoprojectHowtousethebuilt-indevelopmentserver
81SetupTerminal
cdprojects
mkdir08-Django-Project
cd08-Django-Project
sourcevenvbinactivate
Youdonrsquothavetoactivatethevirtualenvironmentifitrsquosalreadyactivated
82CreatinganewProjectInstallDjangoandusethestartprojectcommandtocreateanewDjangoproject
Terminalpipinstalldjango
django-adminstartprojectmysite
YoushouldnowhavethiskindoffolderstructureProjectfolderstructure
projects
08-Django-Project
managepy
mysite
venv
bin
include
lib
pip-selfcheckjson
pyvenvcfg
08-Django-ProjectfolderisacontainerforthewholeprojectThemysitefolderinsideitistheprojectPythonpackagethatconnectsyourprojectwithDjango
83RunningthedevelopmentserverUserunservertoruntheserver
Terminalpythonmanagepyrunserver
Visithttp1270018000andyoushouldseethewelcomescreen
84Detailsdjango-adminisacommand-linetoolthathelpsyouwithmanagementtasks
Terminaldjango-adminstartprojectmysite
startprojectcommandcreatestheDjangoprojectstructureldquordquodenotesthatwewanttocreatetheprojectinthecurrentdirectory
Thisalsocreatesthemanagepyfileintheprojectrootmanagepydoesthesamethingasdjango-adminplusittakescareoffewthingsforyouForexamplebeforeyoucanuseDjangoyouneedtotellitwhichsettingspyfiletousemanagepydoesthisbydefininganenvironmentvariablewiththenameldquoDJANGO_SETTINGS_MODULErdquoYoudonrsquothavetoworryaboutthisthoughJustusemanagepyforadministrationtaskslikethis
Terminal
Terminalpythonmanagepymakemigrations
YoumighthavenoticedthatadatabasefilewasgeneratedintheprojectrootBydefaultDjangoisconfiguredtousetheSQLitedatabaseThisisperfectlyfinefordevelopmentpurposesbutforproductionyoushouldconsiderotheralternativesWiththeHerokuplatformweusePostgreSQLdatabase
YoucanignoretheldquoYouhave15unappliedmigration(s)rdquowarningintheterminalWewilldealwithmigrationsanddatabaseslater
85Summary
django-adminisacommand-linetoolforadministrativetasksstartprojectcommandcreatesaDjangoprojectskeletonItrsquosmoreconvenienttousemanagepyinsteadofdjango-adminforadministrativetasksaftertheprojecthasbeencreatedSQLiteisthedefaultdatabaseoptionbutyoushouldnrsquotuseitinaproductionenvironment
9CreatingaHelloWorldapp
Thischaptercovers
HowtocreateappsIntroductiononviewspathsandtemplates
91SetupTerminal
cp-fr08-Django-Project09-Hello-World
cd09-Hello-World
sourcevenvbinactivate
92CreatingappsUsestartappcommandtocreateanewapp
Terminalpythonmanagepystartappmyapp
NowyoushouldhavethiskindoffolderstructureFolderstructure
projects
08-Django-Project
09-Hello-World
dbsqlite3
managepy
myappltnewapp
mysite
venv
EditmysiteappsettingspyfileandaddmyapptotheINSTALLED_APPSlistmysitesettingspy
INSTALLED_APPS=[
djangocontribadmin
djangocontribauth
djangocontribcontenttypes
djangocontribsessions
djangocontribmessages
djangocontribstaticfiles
myapplthere
]
93CreatingtemplatefilesCreateindexhtmlfileinthemyapptemplatesfolderYouhavetocreatethetemplatesandmyappfolderstoo
Folderstructurefortemplates09-Hello-World
dbsqlite3
managepy
myapp
templateslt--here
myapplt--here
indexhtmllt--here
AddthisHTMLmarkupinsidetheindexhtmlfilemyapptemplatesmyappindexhtml
lth1gtHelloworldIwasbroughttoyoubythemyappindexvi
ewlth1gt
94CreatingviewsEditmyappappviewspyfileandaddanindexfunction
myappviewspyfromdjangoshortcutsimportrender
defindex(request)lthere
returnrender(requestmyappindexhtml)
95AddingahomepagepathEditmysiteappurlspyfileaddtheindexpathtotheurlpatternslist
mysiteurlspyfromdjangocontribimportadmin
fromdjangourlsimportpath
frommyappimportviewsasmyapp_viewslthere
urlpatterns=[
path(adminadminsiteurls)
path(myapp_viewsindexname=index)lthere
]
RunthedevelopmentserverTerminal
pythonmanagepyrunserver
Visithttp1270018000andyoushouldseethis
Wewilldeepentheknowledgeabouttemplatesviewsandpathsaswegoalong
96Summary
startappcommandcreatesnewappsDonrsquotforgettoaddtheapptothemysitesettingspyfileINSTALLED_APPSlistapptemplatesappisatypicallocationforapptemplatefilesappviewspyfileisatypicallocationforappviewfunctionsmysiteurlspyfileisatypicallocationforURLpatterns
10Examiningtheprojectstructureandapps
Thischaptercovers
WhatareappsOverviewoftheprojectstructureWhatdoesalltheprojectfilesdo
101AddingfeatureswithappsApplication(app)isaPythonpackagethataddsfeaturestoyourprojectWiththemyappapplicationweaddedasimplehomepageldquofeaturerdquoTheprojectnowhasacustomhomepageratherthanthedefaultwelcomescreen
YoucreatenewappswiththestartappcommandThiscreatestheDjangoappfolderstructure
Terminalpythonmanagepystartappmyapp
ItmakessensetogroupsimilarsetoffeaturesintoappsForexampleyoucouldcreateaforumappthatprovidesaforumfunctionalityinforumormaybeacustomadministrationareainmyadmin
Youcouldpotentiallyre-usetheseappsinotherprojects
ThemysitefolderthatwascreatedwiththestartprojectcommandcanalsobeconsideredanappThisappmakesyourPythonprojectawebproject
YoutypicallyenableappsbyaddingastringtotheINSTALLED_APPSlistinthesettingspyfile
mysitesettingspyINSTALLED_APPS=[
djangocontribadmin
myapplt--here
]
102ExploringtheprojectstructureLetrsquostakeacloserlookatanexampleprojectstructure
Projectfolderstructure09-Hello-Worldlt--Projectroot
dbsqlite3lt--Database
managepylt--Managementtool
myapplt--Customapp
forumlt--Customapp
myadminlt--Customapp
mysitelt--Projectpackage
venvlt--Virtualenvironment(Django+Python)
TheprojectrootcontainsthedatabasemanagepyfileandalltheappsthatarenotinstalledinthevirtualenvironmentDjangopackageandPythonisinstalledinthevenvfolder
HerearethedefaultcontentsfornewappsDefaultfilesforanewapp
myapp
__init__py
__pycache__
adminpy
appspy
migrations
modelspy
templates
testspy
viewspy
__init__pyisusuallyanemptyfilethatmarksthisdirectoryasaPythonpackageNoteinnewerPythonversions(33+)itrsquosnotrequiredtohavethisfilehttpssamulitoPEP-420
__pycache__containsbytecodethatmakestheprogramstartfaster
DjangohasanautomaticadmininterfaceinadminthatyoucanusetomanagecontentYouusuallyregistermodelsintheadminpyfilesothattheyareavailableformanagement
myappadminpyfromdjangocontribimportadmin
frommyappmodelsimportPost
adminsiteregister(Post)
DonrsquotworryaboutthisfornowWewillgetbacktoitwhenwecovermodelsAlsonotethatthedefaultadmininterfaceisintendedforinternalmanagementpurposesYoumightwanttoallowcontentmanagementwithacustomsolutionthatprovidesformstoaddandeditcontentCustomformswillbecoveredlaterinthebook
appspyisusedtoconfiguretheappForexampleyoucouldchangethehuman-readablenamefortheapplikethis
myappappspyfromdjangoappsimportAppConfig
classMyConfig(AppConfig)
verbose_name=ExcellentApp
NowintheadmininterfaceitwouldsayldquoExcellentApprdquoinsteadofldquoMyapprdquo
migrationsfoldercontainsthemigrationfilesfortheappTheseareusedtoapplychangestothedatabaseYoucanthinkofthemigrationsystemasaversioncontrolforthedatabaseschema
modelspyfilestoreinformationaboutthedatayouwanttoworkwithTypicallyeachmodelmapstoadatabasetable
HerersquosanexampleoftheFlowermodelwewilluselatermyappmodelspy
fromdjangodbimportmodels
classFlower(modelsModel)
title=modelsCharField(max_length=255default=)
ThismodelismappedtoadatabasetablecalledFlowerandeachattributelikethetitlefieldismappedtoadatabasefield
PutapptemplatefilesinthetemplatesfolderTemplatesfolder
09-Hello-World
myapp
templates
myapp
indexhtmllttemplatefile
TemplatesallowyoutoseparatethepresentationfromtheapplicationlogicDjangohasitsowntemplatelanguagewhereyoumixstaticHTMLvariables
tagsandfilterstogeneratethefinalHTML
YoutypicallycreateasubfolderforeachappinsidethetemplatesfolderItmightlookabitoddtohaveanothermyappfolderinsidethetemplatesfolderbutinthiswaywedonrsquothavetodoanythingspecialforDjangotodiscoverthetemplateWejusthavetousetherightnamingconventions
Forexampleinthemyappviewspyfileweusedmyappindexhtmlasanargumentfortherenderfunction
myappviewspyfromdjangoshortcutsimportrender
defindex(request)
returnrender(requestmyappindexhtml)here
WiththisparameterDjangorsquostemplateloadingmechanismfindsthecorrecttemplateinmyapptemplatesmyappindexhtml
testspyisatypicalplacefortheapptestingcode
ItrsquosaconventiontoputviewfunctionsintheviewspyfileViewfunctiontakesawebrequestandreturnsawebresponseInourldquohelloworldrdquoexampletheindexviewreturnsHTMLcontentsgeneratedwiththehelpoftheindexhtmltemplate
103ExploringtheprojectpackageLetrsquostakealookattheprojectpackagefiles
Projectpackagefiles09-Hello-World
dbsqlite3
managepy
myapp
mysite
__init__py
__pycache__
settingspylthere
urlspylthere
wsgipylthere
Mostoftheprojectconfigurationhappensinthesettingspyfile
Forexamplethedefaultdatabaseconfigurationlookslikethismysitesettingspy
DATABASES=
default
ENGINEdjangodbbackendssqlite3
NAMEospathjoin(BASE_DIRdbsqlite3)
Thisallowsyoutostartworkingwithadatabaseimmediately
ForPostgreSQLdatabasewewoulddosomethinglikethisPostgreSQLconfigurationexample
DATABASES=
default
ENGINEdjangodbbackendspostgresql_psycopg2
NAMEmysitedb
USERusername
PASSWORDpassword
HOSTlocalhost
PORT
WithHerokuplatformyoudonrsquothavetoconfigurethismanuallythoughbecausethedjango-herokupackagedoesitforyou
urlspyfilecontainsURLpatternsDjangostartsgoingthroughthesepatternswhenuserrequestsapageandstopswhenapatternmatchestherequestedURL
InourldquoHelloworldrdquoexampletheindexviewwillbecalledwhenuservisitsthehomepage
urlspyfromdjangocontribimportadmin
fromdjangourlsimportpath
frommyappimportviewsasmyapp_views
urlpatterns=[
path(adminadminsiteurls)
path(myapp_viewsindexname=index)lthere
]
WSGIisaspecificationthatdealswithinteractionsbetweenwebserversandPythonwebapplicationsThestartprojectcommandsetsupdefaultconfigurationforitinwsgipy
104Summary
startprojectcommandcreatesaprojectskeletonwithallthefilesyouneedtogetstartedProjectpackage(folderwithsettingspyfile)connectsyourPythonprojectwithDjangoYoutypicallyaddfeaturestoyourprojectwithappsstartappcommandcreatesabasicapplicationskeleton
11Workingwithtemplateinheritance
Thischaptercovers
HowtosetupabaseappHowthetemplateinheritanceworks
111SetupTerminal
cp-fr09-Hello-World11-Template-Inheritance
cd11-Template-Inheritance
sourcevenvbinactivate
112CreatingabaseappCreateanewapp
Terminalpythonmanagepystartappbase
YoushouldnowhavethiskindoffolderstructureFolderstructure
11-Template-Inheritance
baseltnewapp
dbsqlite3
managepy
myapp
mysite
EditmysiteappsettingspyfileandaddthebaseapptotheINSTALLED_APPSlist
mysitesettingspyINSTALLED_APPS=[
djangocontribstaticfiles
baselthere
myapp
]
113Extendingtemplates
CreateabasehtmlfileinthebaseapptemplatesfolderTemplatefilelocation
11-Template-Inheritance
base
templateslt--here
baselt--here
basehtmllt--here
Addtheselinestothebasehtmlfilebasetemplatesbasebasehtml
ltDOCTYPEhtmlgt
lthtmllang=engt
ltheadgt
lttitlegtMySitelttitlegt
ltheadgt
ltbodygt
ltdivid=contentgt
blockcontentendblock
ltdivgt
ltbodygt
lthtmlgt
Replacemyappindexhtmlfilecontentswiththeselinesmyapptemplatesmyappindexhtml
extendsbasebasehtml
blockcontent
lth1gtHellofrommyappindexviewlth1gt
endblock
RunthedevelopmentserverTerminal
pythonmanagepyrunserver
Visithttp1270018000toseetheresults
Right-clickthewebpagetoviewthepagesourcePagesource
ltDOCTYPEhtmlgt
lthtmllang=engt
ltheadgt
lttitlegtMySitelttitlegt
ltheadgt
ltbodygt
ltdivid=contentgt
lth1gtHellofrommyappindexviewlth1gt
ltdivgt
ltbodygt
lthtmlgt
114DetailsLetrsquostakeacloserlookonhowthisworks
Parentandchildtemplates11-Template-Inheritance
base
templates
base
basehtmlltparenttemplate
myapp
templates
myapp
indexhtmlltchildtemplate
Withtemplateinheritancewecanhaveabaseldquoskeletonrdquothathasblocksthatchildtemplatescanoverride
Inbasehtmlwedefineacontentblockbasetemplatesbasebasehtml
ltdivid=contentgt
blockcontentendblock
ltdivgt
Inindexhtmlwealsodefineacontentblockmyapptemplatesmyappindexhtml
extendsbasebasehtml
blockcontent
lth1gtHellofrommyappindexviewlth1gt
endblock
Thisblockoverridesthecontentblockinthebasetemplate
extendsbasebasehtmltellsthetemplatingenginethatthistemplateextendsanothertemplateInthiscasetheindexhtmltemplateextendsthe
basehtmltemplate
marksatagTheseprovideseveralkindsoffeatureslikeforloopsandinheritancerelatedfunctionality
NowwedonrsquothavetospecifythecommonboilerplatemarkupforeverypageThisisoneofthebenefitsyouhavewithdynamicsystemslikeDjango
115Summary
YoucancreateabaseapptoholdthingsthatarecommontoallappslikethemainHTMLskeletonTemplateinheritanceallowsyoutodefineblocksthatchildtemplatescanoverride
12InstallingBootstrap4theme
Thischaptercovers
HowtouseBootstrap4withyourtemplates
121SetupTerminal
cp-fr11-Template-Inheritance12-Bootstrap
cd12-Bootstrap
sourcevenvbinactivate
122ModifyinganexistingtemplateVisithttpssamulitoBootstrap-Templateandright-clickthepagetoseeitssourcecodeCopythesourcecodeandreplacethecontentofthebasehtmlfilewithit
Replacethelttitlegtelementwiththisbasetemplatesbasebasehtml
lttitlegtBaseprojectfortheDjango-TheEasyWaybook|
MySitelttitlegt
VisithttpssamulitoBootstrapandcopytheBootstrapCDNCSSlinkthatlookslikethis
Linktocopyltlinkrel=stylesheethref=httpsstackpathbootstrapcdn
combootstrap413cssbootstrapmincssintegrity=sha3
84-MCw98SFnGE8fJT3GXwEOngsV7Zt27NXFoaoApmYm81iuXoPkFOJwJ8E
RdknLPMOcrossorigin=anonymousgt
Replacetheselineswiththecopiedlinkbasetemplatesbasebasehtml
lt--BootstrapcoreCSS--gt
ltlinkhref=distcssbootstrapmincssrel=styleshe
etgt
Replacetheselineshellip
Replacetheselineshellipbasetemplatesbasebasehtml
lt--Customstylesforthistemplate--gt
ltlinkhref=starter-templatecss
hellipwiththisstyleelementbasetemplatesbasebasehtml
ltstylegt
body
padding-top5rem
starter-template
padding3rem15rem
text-aligncenter
ltstylegt
InthenextchapterwelearnhowtoloadstaticfilesanduseaseparatestylesheetfileforCSS
Changethenavbar-brandlinkelementtothisbasetemplatesbasebasehtml
ltaclass=navbar-brandhref=gtMySiteltagt
Replacethenavbar-navmr-autoullistwiththisbasetemplatesbasebasehtml
ltulclass=navbar-navmr-autogt
ltliclass=nav-itemactivegt
ltaclass=nav-linkhref=gtHomeltspanclass=sr-o
nlygt(current)ltspangtltagt
ltligt
ltulgt
Removethissearchformelementbasetemplatesbasebasehtml
ltformclass=form-inlinemy-2my-lg-0gt
ltformgt
Replacethestarter-templatedivcontainercontentshellipbasetemplatesbasebasehtml
ltmainrole=mainclass=containergt
ltdivclass=starter-templategt
lth1gtBootstrapstarter
ltpclass=leadgtUse
ltdivgt
ltmaingtlt--container--gt
hellipwiththecontentblockbasetemplatesbasebasehtml
ltmainrole=mainclass=containergt
ltdivclass=starter-templategt
blockcontentendblocklt--here--gt
ltdivgt
ltmaingtlt--container--gt
Replacethesethreelinesattheendofthebasehtmlfilehellipbasetemplatesbasebasehtml
ltscriptgtwindowjQuery||
ltscriptsrc=assets
ltscriptsrc=distj
hellipwiththePopperjsandjQuerylinksfromtheBootstrapfrontpagebasetemplatesbasebasehtml
ltscriptsrc=httpscdnjscloudflarecoma
ltscriptsrc=httpsstackpathbootstrapcdn
123UpdatingthehomepagetemplateReplacemyappindexhtmltemplatecontentswiththeselines
myapptemplatesmyappindexhtmlextendsbasebasehtml
blockcontent
lth1gtBaseprojectfortheltatarget=_blankhref=httpsl
eanpubcomdjango-the-easy-waygtDjango-TheEasyWaylta
gtbooklth1gt
ltpclass=leadgt
Loremipsumdolorsitametconsecteturadipisicingelit
Accusantiumquiseligendicumquetotamremconsequunturc
onsequaturEstprovidentdolorVelitnihileligendifaci
lisperspiciatisvoluptatumadreiciendismolestiasmolliti
aquisquam
ltpgt
endblock
Visithttp1270018000andyoushouldseesomethinglikethis
InthisimageweareseeingthemobiledevicestylingbecauseIresizedthebrowsertofiteverythingintheimage
124DetailsBootstrapisgreatforprototypinganddemonstrationsbutittendstoresultingenericlookingfrontendsunlessyoumodifyitheavilyIpersonallyliketobuildmythemesfromscratchwithHTMLSASSandJavaScriptThisbookfocusesonDjangocoreconceptssoIwillbecoveringthemingrelatedtopicsminimally
125Summary
ItrsquoseasytostartusingBootstrap4withDjangobymodifyinganexistingtheme
13Managingstaticfiles
Thischaptercovers
HowtoaddaCSSstylesheetfileHowtousethestatictemplatetagHowtoforceCSScacherefresh
131SetupTerminal
cp-fr12-Bootstrap13-Static-Files-CSS
cd13-Static-Files-CSS
sourcevenvbinactivate
132CreatingastylesheetfileCreateastaticbasecsssitecssfileinthebaseappfolderYouhavetocreatethefolderstructuremanually
Stylesheetfilelocationbase
staticlthere
baselthere
csslthere
sitecsslthere
EditbasehtmlfileandcopythecontentsofthestyleelementtothesitecssfileLetrsquosalsoaddabrightredcolorforh1elementssowecanseethattheCSSisworkingThesitecssfileshouldnowlooklikethis
basestaticbasecsssitecssbody
padding-top5rem
starter-template
padding3rem15rem
text-aligncenter
h1
colorred
Replacethestyleelementinthebasehtmltemplatehellipbasetemplatesbasebasehtml
ltstylegt
ltstylegt
hellipwiththislinebasetemplatesbasebasehtml
ltlinkrel=stylesheethref=staticbasecsssitecss
gt
Makesuretoputthislinkelementafterthelinethatloadsthebootstrapmincssfile
Makethestatictagavailableinthetemplatebyusingtheloadtagontopofthebasehtmlfile
basetemplatesbasebasehtmlloadstaticlt--here--gt
ltdoctypehtmlgt
lthtmllang=engt
h1elementsshouldnowbered
Youcannowremovetheredstylingfromthesitecssfile
133Details
1331Workingwithstaticfiles
FileslikeCSSJavaScriptandimagesarereferredasstaticfilesWithimagesImeanstaticassetslikebackgroundimagesnotuser-uploadedfilesWewilldealwithmediafileslaterwhenweallowuserstouploadfiles
ThedjangocontribstaticfilesapphelpsyoumanagethesestaticassetsItrsquosinstalledbydefault
mysitesettingspyINSTALLED_APPS=[
djangocontribstaticfileslthere
base
myapp
]
WiththedevelopmentserverthestaticfileswillbeservedautomaticallyindebugmodeInproductionwewillusethecollectstaticcommandtocollectallstaticfilesinoneplaceTheyarethentypicallyservedwithsomethinglikeNginxfromasinglelocationlikestatic
Mediaandstaticfilesinproductionenvironmentmedia
images
Agapanthus_africanus1jpg
mysite
base
dbsqlite3
managepy
staticlthere
LaterIwillalsoshowyouhowtoservethesefilesfromanAmazonAWSbucket
1332UsingthestatictagloadtagloadstagsandfiltersregisteredinotherlibrariesInthiscaseweuseittoenablethestatictagforthetemplateYouhavetouseloadstaticineverytemplatethatusesthestatictagEveniftheparenttemplatealreadyloadsit
statictaggeneratesabsoluteURLSforthestaticfiles
ThishellipUsingstatictagintemplates
href=staticbasecsssitecss
hellipbecomesthisTheresultingHTML
href=staticbasecsssitecss
Thismightseemunnecessarybecausewecouldjusthard-codethecorrectURLtherestaticbasecsssitecssButwecouldalsobeservingthestaticfilesfromsomeotherURLWithaproperconfigurationthesamestatictagcouldbegeneratingthesekindoflinks
Servingstaticfilesfromexternallocationhttpsstaticmysitecombasecsssitecss
OR
httpsmysites3amazonawscomstaticbasecsssitecss
ChangingthisURLwillbetrivialsincewearenothard-codingitintemplatefiles
Ingeneralyoushouldavoidhard-codingintemplateswhenDjangocangeneratethemarkupforyouThisisespeciallyhelpfulwhenprovidingURLStoviewsandtranslatingpaths
1333ForcingcacherefreshwithversioningYoucanalsovisitthestyleURLdirectlytoseeifthestylefileisservedcorrectly
Visitingthestylesheetpathdirectlystaticbasecsssitecss
IfyouarenotseeingstylingchangesevenifthesitecssseemstobeworkingyourbrowsermightbeservingyoustalecontentfromacacheInChromeyoucandothis
VisitViewgtDevelopergtDeveloperToolsSelectNetworkandDisablecacheKeeptheDeveloperToolsopen
TherearesimilarDevelopertoolsinallmajorbrowsers
YoucanalsoforceCSSrefreshbyaddinganewGETparameterv=2eachtimeyoumakestylingchanges
CSSversioningltlinkrel=stylesheethref=staticbasecsssitecss
v=2gt
BetteryetistoletDjangogenerateahashwithManifestStaticFileStoragehttpssamulitoCSS-Versioning
134Summary
YoucanoverrideBootstrapthemingwithcustomstylesheetsstatictaggeneratesabsoluteURLSforstaticassetslikeCSSandJavaScriptfilesInlocaldevelopmentitrsquosusefultodisablebrowsercachingInproductionenvironmentitrsquosacommontechnictoaddahashtotheCSSlinkpathsothestylesheetisnotloadedfromthevisitorrsquosbrowsercacheStaticfilescanalsobeservedfromanexternallocationlikeAmazonAWSbucket
14Creatingmodels
Thischaptercovers
HowtocreateandusemodelsHowtomakedatabasequeries
141SetupTerminal
cp-fr13-Static-Files-CSS14-Models
cd14-Models
sourcevenvbinactivate
142CreatingtheFlowermodelEditmyappmodelspyfile
myappmodelspy14-Models
myapp
modelspylthere
AddaFlowerclassandatitleattributemyappmodelspy
fromdjangodbimportmodels
classFlower(modelsModel)
title=modelsCharField(max_length=255default=)
EditmyappadminpyfileandregistertheFlowerclassmyappadminpy
fromdjangocontribimportadmin
frommyappmodelsimportFlower
adminsiteregister(Flower)
ApplychangestothedatabaseandcreateasuperuserTerminal
pythonmanagepymakemigrations
pythonmanagepymigrate
pythonmanagepyrunserver
pythonmanagepycreatesuperuser
YoucanuseadminastheusernameandpasswordJustbypassthevalidationTerminal
Bypasspasswordvalidationandcreateuseranyway[yN]y
Superusercreatedsuccessfully
Visithttp1270018000adminandaddafewflowersHerearesomeexamplesfromWikipedia
httpssamulitoAmelanchier-alnifoliahttpssamulitoAmelanchier-asiaticahttpssamulitoAgapanthus
ldquoFlowerobject(n)rdquoisnotverydescriptiverepresentationforaFlowerobjectLetrsquosshowthetitleinstead
Editmodelspyfileandadda__str__methodmyappmodelspy
fromdjangodbimportmodels
classFlower(modelsModel)
title=modelsCharField(max_length=255default=)
def__str__(self)
returnselftitle
Nowwecanseetheactualtitles
143ListingflowersLetrsquoslisttheflowersonthefrontpageEditmyappindexhtmltemplateandreplacethecontentswiththeselines
myapptemplatesmyappindexhtmlextendsbasebasehtml
blockcontent
forflowerinflowers
ltdivclass=cardgt
ltdivclass=card-bodygt
lth5class=card-titlegtflowertitlelth5gt
ltpclass=card-textgtLoremipsumdolorsitametcons
ecteturadipisicingelitltpgt
ltahref=adminmyappflowerfloweridchange
class=card-linkgtEditltagt
ltahref=adminmyappflowerfloweriddelete
class=card-linkgtDeleteltagt
ltdivgt
ltdivgt
endfor
endblock
Editthemyappviewspyfileandreplacethecontentswiththeselinesmyappviewspy
fromdjangoshortcutsimportrender
frommyappmodelsimportFlower
defindex(request)
flowers=Flowerobjectsall()
returnrender(requestmyappindexhtmlflowers
flowers)
Nowthefrontpagelookssomethinglikethis
Fornowtheeditanddeletefunctionalityisprovidedthroughtheadminuserinterface
144Details
1441ExplainingmodelsModelsofferanabstractedwaytointeractwithdataWithDjangorsquosdatabase-accessAPIyoucanuseFlowerobjectsall()togetallFlowersratherthandoingquerieslikeSELECTFROMFlowers
TocreatemodelswesubclassdjangodbmodelsModelmyappmodelspy
fromdjangodbimportmodels
classFlower(modelsModel)
title=modelsCharField(max_length=255default=)
Weimportothermodulestogetaccesstothecodetheycontain
Flowerclassrepresentsadatabasetabletitleattributerepresentsadatabasefield
CharFieldisusedforsmallersizestringsUseTextFieldforlargertexts
Tomakeamodeleditableintheadmininterfaceyouhavetoregisteritaswedidinthemyappadminpyfile
myappadminpyadminsiteregister(Flower)
MakemigrationscommandcreatesthemigrationfilesThesefilesareusuallymovedwithrestofthecodeandappliedinotherenvironments
Terminalpythonmanagepymakemigrations
migratecommandupdatesthedatabaseschemaThiswillcreatetheFlowertableandtitlefield
Terminalpythonmanagepymigrate
createsuperusercommandcreatesthemainadministrationaccountThisuserhasallpermissionsbydefaultMakesuretouseadecentpasswordanduniqueusernameintheproductionserver
Terminalpythonmanagepycreatesuperuser
1442Returningastringrepresentation__str__methodreturnsahuman-readablerepresentationofanobjectInthiscaseweusethetitleattributetocreateit
myappmodelspydef__str__(self)
returnselftitle
YoucouldalsoformatthereturnstringusingmultiplefieldslikethisFormattingtherepresentation
def__str__(self)
returnfTitleselftitleDateselfdate
1443MakingdatabasequeriesNowthatwehavemodelswecaninteractwiththedatabaseusinganAPIFlowerobjectsall()returnsaQuerySetthatcontainsallFlowerobjectsin
thedatabaseFetchobjectsfromadatabase
flowers=Flowerobjectsall()
InthemyappviewspyfilewepasstheflowersQuerySettothetemplateusingflowersflowers
myappviewspydefindex(request)
flowers=Flowerobjectsall()
returnrender(requestmyappindexhtmlflowers
flowers)
Inthetemplateweuseaforlooptogothroughalltheobjectsmyapptemplatesmyappindexpy
forflowerinflowers
flowertitle
endfor
145Summary
Djangorsquosdatabase-accessAPImakesiteasytointeractwithpersistentdataYouhavetoregisteramodelwithadminsiteregister()tomakeitavailableintheadmininterface__str__isusedtocomputeahuman-readablerepresentationofanobjectYoucanseeitinuseintheadmininterfaceYoucanuseaforlooptoiteratethroughaQuerySetintemplates
15Creatingabaseproject
Thischaptercovers
Howtoprepareageneralbaseproject
151SetupTerminal
cp-fr14-Models15-Base-Project
cd15-Models
sourcevenvbinactivate
152AddingadescriptionfieldOpenmyappmodelspyfile
myappmodelspy15-Base-Project
myapp
modelspylthere
Addthedescriptionfieldmyappmodelspy
fromdjangodbimportmodels
classFlower(modelsModel)
title=modelsCharField(max_length=255default=)
description=modelsTextField(default=)lthere
RunmigrationsTerminal
pythonmanagepymakemigrations
pythonmanagepymigrate
Visithttp1270018000adminandadddescriptionsfortheflowersYoucanfindmockdatainherehttpssamulitoLorem
153Addingmasonrylikecolumns
Editmyappindexhtmltemplateandwrapthecardsincard-columnsdivandusethedescriptionattributeforthecardtext
myapptemplatesmyappindexhtmlltdivclass=card-columnsgtlt--here--gt
forflowerinflowers
ltdivclass=cardgt
ltdivclass=card-bodygt
lth5class=card-titlegtflowertitlelth5gt
ltpclass=card-textgtflowerdescription|truncate
chars100ltpgtlt--here--gt
ltdivgt
ltdivgt
endfor
ltdivgt
card-columnsorganizesthecardsinamasonrylikecolumns
truncatecharsfiltertruncatesastringifitrsquoslongerthanthenumberspecifiedItalsoaddsanellipsissequencetotheend
154AddingafooterAddfooterelementtothebasehtmltemplate
basetemplatesbasebasehtml
ltmaingt
ltfooterclass=footergtlt--here--gt
ltdivclass=containergt
ltspanclass=text-mutedgt
Baseprojectfortheltatarget=_blankhref=h
ttpsleanpubcomdjango-the-easy-waygtDjango-TheEasy
Wayltagtbook
ltspangt
ltdivgt
ltfootergt
Editthebaseappsitecssfileandaddstylingforthefooterclassbasestaticbasecsssitecss
footer
text-aligncenter
font-size16px
height60px
line-height60px
Youshouldnowseesomethinglikethis
155Summary
WenowhaveadecentbaseprojecttoworkwithWeusethisforsomeofthechaptersasastartingpointYoumightwanttousethisasabaseforyourownexperimentsBootstrapofferssomehelpfulclasseslikecard-columnsthataccomplishquiteabitwithverylittlemarkupTemplatefiltersallowyoutomanipulatetemplateoutputliketruncatestringsorformatdates
16Creatingadetailpage
Thischaptercovers
HowtoaddadetailpageHowtocreateslugsHowtoreturncanonicalURLSwithget_absolute_url()HowtoreverseURLSHowtousetheurltemplatetag
161SetupTerminal
cp-fr15-Base-Project16-Detail-Page
cd16-Detail-Page
sourcevenvbinactivate
162AddingadetailpagepathEditmysiteappurlspyfileandaddapathtothedetailpage
mysiteurlspyurlpatterns=[
path(adminadminsiteurls)
path(flowerltintidgtmyapp_viewsdetailname=deta
il)lthere
path(myapp_viewsindexname=index)
]
163CreatingthedetailviewEditmyappviewspyfileandaddthedetailfunction
myappviewspyfromdjangoshortcutsimportrenderget_object_or_404lt
here
frommodelsimportFlower
defindex(request)
flowers=Flowerobjectsall()
returnrender(requestmyappindexhtmlflowers
flowers)
defdetail(requestid=None)lthere
flower=get_object_or_404(Flowerid=id)
returnrender(requestmyappdetailhtmlflower
flower)
Makesuretoimportget_object_or_404
164CreatingthedetailpagetemplateCreatedetailhtmlfileinthemyapptemplatesfolder
Detailpagetemplate16-Detail-Page
myapp
templates
myapp
detailhtmllthere
Fillitwiththeselinesmyapptemplatesmyappdetailpy
extendsbasebasehtml
blockcontent
ltdivclass=jumbotrongt
ltdivclass=containergt
lth1class=display-3gtflowertitlelth1gt
ltdivclass=leadgtflowerdescriptionltdivgt
ltdivgt
ltdivgt
ltahref=gtBackltagt
endblock
Visithttp1270018000flower1andyoushouldseethedetailpagejumbotron
165CreatingslugsAccessingindividualflowerswithanidisnotthemostfriendlyapproachLetrsquosaddaSlugFieldtoholdahuman-readablepath
EditmyappmodelspyfileandaddaSlugFieldmyappmodelspy
fromdjangoutilstextimportslugifylthere
fromdjangodbimportmodels
classFlower(modelsModel)
title=modelsCharField(max_length=255default=)
description=modelsTextField(default=)
slug=modelsSlugField(blank=Truedefault=)lthere
def__str__(self)
returnselftitle
defsave(selfargskwargs)lthere
selfslug=slugify(selftitle)
super(Flowerself)save()
Wecreatetheslugusingtheslugify()functioninthesavemethod
Editthedetailfunctioninthemyappviewspyfileandchangeallidoccurrencestoslug
myappviewspydefdetail(requestslug=None)lthere
flower=get_object_or_404(Flowerslug=slug)lthere
returnrender(requestmyappdetailhtmlflower
flower)
166UpdatingthepathEditmysiteappurlspyfileandchangethedetailpath
mysiteurlspypath(flowerltintidgtmyapp_viewsdetailname=detail
)
path(flowerltslugsluggtmyapp_viewsdetailname=detai
l)
RunmigrationsTerminal
pythonmanagepymakemigrations
pythonmanagepymigrate
Editallflowersyouhavecreatedandsavethemoncetogenerateslugs
167Definingget_absolute_url()methodWecanaddaldquoViewonsiterdquolinktotheadminbydefiningaget_absolute_urlmethodEditmyappmodelspyfileandaddthemethodtotheFlowerclass
myappmodelspyfromdjangoutilstextimportslugify
fromdjangodbimportmodels
fromdjangourlsimportreverselthere
classFlower(modelsModel)
def__str__(self)
defsave(selfargskwargs)
defget_absolute_url(self)lthere
returnreverse(detailargs=[str(selfslug)])
EditaFlowerobjectandyouwillseealinkonthetoprightcornerClickittovisittheflowerdetailpage
168UsingurltagEditmyappindexhtmlfileandusetheurltagtolinkthecardtothedetailpage
myapptemplatesmyappindexhtmllth5class=card-titlegtltahref=urldetailflowerslug
gtflowertitleltagtlth5gt
Notemakesurethateachflowerhasaslugbyeditingandsavingthemonce
Visitthefrontpageandclickatitletoseethedetailpage
169Details
1691CapturingURLvaluesYoucanuseanglebracketstocapturevaluesfromtheURLInherewefirstcapturedtheidnumberandthentheslug
mysiteurlspypath(flowerltintidgtmyapp_viewsdetailname=detail
)
path(flowerltslugsluggtmyapp_viewsdetailname=detai
l)
Youcanoptionallyspecifyaconvertertypeintconvertertypeinltintidgtmeansthatthepathmatchesonlyintegers
1692UsingviewparametersInthemyappviewspyfilewespecifyaslugparameterTheslugfromtheURLwillbestoredinthisvariableslug=NonemeansthatthedefaultvalueisNoneifaparameterisnotpassedtothisview
myappviewspydefdetail(requestslug=None)
get_object_or_404returnsldquo404PagenotFoundrdquoerroriftheobjectdoesnrsquotexistOtherwisetheobjectwiththeslugfromtheURLparameterwillbestoredintheflowerobject
myappviewspyflower=get_object_or_404(Flowerslug=slug)
1693ExplainingslugsSlugisashortlabelthatcontainsonlylettersnumbersunderscoresorhyphensItrsquosoftenusedtoofferuser-friendlyURLSldquoproductmacbookrdquoisbetterthanldquoproduct-113zxcrdquoInourappweusethetitlefieldtocreatetheslug
InthemyappmodelspyweaddtheSlugFieldandspecifyblank=Truesothatthefieldcanbeemptyforthesave()methodtorun
myappmodelspyslug=modelsSlugField(blank=Truedefault=)
SlugifyfunctionconvertsstringstoURLslugsYoucanfinditindjangoutilstext
myappmodelspyfromdjangoutilstextimportslugify
Youcanoverridepredefinedmodelmethodslikesave()myappmodelspy
defsave(selfargskwargs)
selfslug=slugify(selftitle)
super(Flowerself)save()
Inthesave()methodwecanmakesomethinghappenwhentheobjectissavedInthiscaseweuseittogenerateaslug
Wehavetocallthesuperclassmethodsuper()sothatthesavemethoddefaultbehaviourwillbeexecutedandtheobjectstoredinthedatabase
argsandkwargsallowyoutocollectargumentsorkeywordargumentsandpassthemtothefunctionThisisaPythonconceptwedonrsquotexploreinthisbook
1694ReversingURLSYoucandefineget_absolute_urlmethodtocalculateacanonicalURLforanobjectInhereweusethereverse()functiontogettheURLtoaflowerobject
myappmodelspydefget_absolute_url(self)
returnreverse(detailargs=[str(selfslug)])
ThereversefunctionissimilartotheurltagthatweusedwiththecardmarkupInherewepassthedetailpathnameldquodetailrdquoandtheslugasaparametertoit
Ifyouhaveapathlikethishellipmysiteurlspy
path(flowermyapp_viewsdetailname=detail)
hellipthenreverse(detail)willgenerateflower
Ifyouhaveapathlikethishellipmysiturlspy
path(flowerltslugsluggtmyapp_viewsdetailname=detai
l)
hellipthenreverse(detailargs=[str(selfslug)])willgenerateapathlikethisfloweramelanchier-asiatica
1610Summary
UseanglebracketswithpathstocaptureURLvaluesflowerltslugsluggtget_object_or_404()triestofetchanobjectbutreturnsaldquoPagenotFoundrdquoerroriftheobjectisnotfoundSlugFieldcanbeusedtostoreauser-friendlypathItrsquosusefultodefinetheget_absolute_url()methodforamodeltohaveaneasyaccesstocanonicalURLSUseurltagorobjectget_absolute_urlintemplatesinsteadofhardcodingURLS
17Addingcategoryasamany-to-onerelationhip
Thischaptercovers
Many-to-onerelationshipswithForeignKeyHowtoaccessrelatedobjects
171SetupTerminal
cp-fr15-Base-Project17-Category-ManyToOne
cd17-Category-ManyToOne
sourcevenvbinactivate
172AddingcategoryfieldandmodelEditmyappmodelspyfileandaddaCategoryclassandacategoryfield
myappmodelspyfromdjangodbimportmodels
classCategory(modelsModel)lthere
title=modelsCharField(max_length=255default=)
def__str__(self)
returnselftitle
classFlower(modelsModel)
title=modelsCharField(max_length=255default=)
description=modelsTextField(default=)
category=modelsForeignKey(Categorynull=Trueon_delet
e=modelsPROTECT)lthere
def__str__(self)
returnselftitle
EditmyappadminpyandregistertheCategorymodelmyappadminpy
fromdjangocontribimportadmin
frommyappmodelsimportFlowerCategorylthere
adminsiteregister(Flower)
adminsiteregister(Category)lthere
RunmigrationsTerminal
pythonmanagepymakemigrations
pythonmanagepymigrate
EdittheflowersandselectacategoryforeachitemYoucancreatethereferencedCategoryobjectwhileyouareeditingtheFlowerobjects
173UpdatingthehomepagetemplateEditthemyappindexhtmltemplatefileandprintoutthecategory
myapptemplatesmyappindexhtmlltpclass=card-textgtflowerdescription|truncatechars
100ltpgt
ltahref=class=card-linkgtflowercategoryltagtlt-
-here--gt
174Details
1741Examiningmany-to-onerelationshipsForeignKeyisamany-to-onerelationship
myappmodelspycategory=modelsForeignKey(Categoryon_delete=modelsPRO
TECTnull=True)
Categoriescanlinktomanyflowersbuteachflowercanhaveareferencetoonlyonecategory
ForeignKeyfieldrequirestwoargumentstherelatedmodelclassandon_deleteoption
TheFlowermodelisrelatedtoCategoryclasssowespecifythatasthefirstargument
on_delete=modelsPROTECTpreventsthedeletionofaCategoryobjectifitrsquosreferencedbyaFlowerobject
Youcandeletecategoriesthatarenotreferencedbyanyflower
null=TruemeansthatanemptyfieldwillbestoredasNULLinthedatabaseThisallowsustoruntheinitialmigrationwithoutspecifyingadefaultvalue
1742AccessingrelatedobjectsYoucanaccessrelatedobjectsthesamewayyouaccessanyattribute
Dotnotation
flowercategory
Ifyouneedtogetallflowersthatlinktoaspecificcategoryyoucanuse_setlikethis
Getrelatedflowerscategoryflower_set
Youcantestthisbyaddingthefollowingcodeinsidethecarddivinthemyappindexhtmlfile
myapptemplatesmyappindexhtmlltdivclass=cardgt
lthrgt
Allflowersintheltstronggtflowercategoryltstron
ggtcategoryltbrgt
forc_flowerinflowercategoryflower_setall
ltahref=class=card-linkgtc_flowerltagtltbrgt
endfor
ltdivgt
Useallinflowercategoryflower_setallsoyouhaveaniterabletoloopthrough
175Summary
ForeignKeyisamany-to-onerelationshipAnotherexamplewouldbeacarmodelthathasaforeignkeyrelationshiptoabrandmodelEachcarobject
canlinktoonlyonebrandobjectlikeldquoAudirdquoorldquoMercedes-BenzrdquobutthebrandscanlinktomanycarobjectsMakesuretoregistertheCategorymodelintheadminpyfilesoyoucancreatethereferencedobjectsontheflyIfyousetnull=TrueforafieldemptyvalueswillbestoredasNULLinthedatabase
18ReferencingtagswithaManyToManyfield
Thischaptercovers
Howtoreferencemultipleitemswithmany-to-manyrelationships
181SetupTerminal
cp-fr15-Base-Project18-Tags-ManyToMany
cd18-Tags-ManyToMany
sourcevenvbinactivate
182AddingthetagsfieldEditmyappmodelspyfileandaddTagmodelandtagsfield
myappmodelspyfromdjangodbimportmodels
classTag(modelsModel)lthere
title=modelsCharField(max_length=255default=)
def__str__(self)
returnselftitle
classFlower(modelsModel)
title=modelsCharField(max_length=255default=)
description=modelsTextField(default=)
tags=modelsManyToManyField(Tag)lthere
def__str__(self)
returnselftitle
EditmyappadminpyfileandregistertheTagmodelmyappadminpy
fromdjangocontribimportadmin
frommyappmodelsimportFlowerTaglthere
adminsiteregister(Flower)
adminsiteregister(Tag)lthere
Runmigrations
RunmigrationsTerminal
pythonmanagepymakemigrations
pythonmanagepymigrate
EditaflowerandaddsometagsMakesuretoselectmorethanonetag
183UpdatingthehomepagetemplateEditthemyappindexhtmltemplatefileandprintoutthetags
myapptemplatesmyappindexhtmlltdivclass=cardgt
lthrgt
fortaginflowertagsall
ltahref=class=card-linkgttagltagt
endfor
ltdivgt
184Summary
ManyToManyrelationshipallowsourflowerstoreferencemanytagsandthetagstoreferencemanyflowers
19Creatingatagspage
Thischaptercovers
HowtocreatealdquotagsrdquopagetodisplaytaggeditemsHowtodolookupsacrossrelationshipsHowtore-usetemplates
191SetupTerminal
cp-fr18-Tags-ManyToMany19-Tags-Page
cd19-Tags-Page
sourcevenvbinactivate
192AddingtagspathEditmysiteurlspyfileandaddapathtothetagspage
mysiteurlspyurlpatterns=[
path(adminadminsiteurls)
path(myapp_viewsindexname=index)
path(tagsltslugsluggtmyapp_viewstagsname=tags
)lthere
]
193AddingtheslugfieldEditmyappmodelspyfileandaddaSlugFieldtotheTagmodel
myappmodelspyfromdjangodbimportmodels
fromdjangoutilstextimportslugifylthere
classTag(modelsModel)
title=modelsCharField(max_length=255default=)
slug=modelsSlugField(blank=Truedefault=)lthere
def__str__(self)
returnselftitle
defsave(selfargskwargs)lthere
selfslug=slugify(selftitle)
super(Tagself)save()
194CreatingthetagsviewEditmyappviewspyfileandaddatagsviewfunction
myappviewspyfromdjangoshortcutsimportrender
frommyappmodelsimportFlower
defindex(request)
flowers=Flowerobjectsall()
returnrender(requestmyappindexhtmlflowers
flowers)
deftags(requestslug=None)lthere
flowers=Flowerobjectsfilter(tags__slug=slug)
returnrender(requestmyappindexhtmlflowers
flowers)
RunmigrationsTerminal
pythonmanagepymakemigrations
pythonmanagepymigrate
VisitadminmyapptagEditandsavethetagobjectstogenerateslugs
195UpdatinghomepagetemplateEditmyappindexhtmlfileanduseurltagstagslugtogeneratethelink
myapptemplatesmyappindexhtmllthrgt
fortaginflowertagsall
ltahref=urltagstagslugclass=card-linkgtt
agltagtlt--here--gt
endfor
Nowthefrontpagetagslinktothetagspage
ClickthetaglinksandyouwillseetheaccordingtagpagetagsrosalesIfyouhaveFlowerstaggedwithldquoRosalesrdquoyouwillonlyseethoseitemsinthispage
196Details
1961DoinglookupsacrossrelationshipsInmyappviewspyfilewefetchobjectsthataretaggedwithaspecifictag
myappviewspydeftags(requestslug=None)
flowers=Flowerobjectsfilter(tags__slug=slug)lthe
re
returnrender(requestmyappindexhtmlflowers
flowers)
WithfilterfunctionyoucanreturnaQuerySetthatmatchlookupparametersInthiscaseourparameteristags__slug=slugThiswillreturnallflowerobjectsthathasareferencetoatagobjectwiththeslugfromtheURLtagsrosaleswouldfetchallflowerstaggedwithldquoRosalesrdquo
DjangohasplentyofotherqueryinteractiontoolsSeehttpssamulitoQuerySet-API
1962ReusingtemplatesYoumighthavenoticedthatweareusingthesamemyappindexhtmlinthefrontpageandinthetagspageReusingtemplateswillsaveyoualotoftimeandmakesiteasiertomakechangesNowifwewanttochangethecardstylingormarkupwecandoitinoneplaceThechangeswillshowupinthefrontpageandinthetagspage
197Summary
Djangooffersabigselectionofmethodslikefilter()tomodifyyourdataqueriesYoucandolookupsthroughrelationshipsusingthedoubleunderscore(__)syntaxtags__slug=slugReusingtemplateswillmakeyourapplookconsistentandeasiertomaintain
20Creatingasearchfeature
Thischaptercovers
HowtocreateasimplesearchfeatureHowtoworkwithGETparameters
201SetupTerminal
cp-fr18-Tags-ManyToMany20-Search
cd20-Search
sourcevenvbinactivate
202AddingasearchformEditbasehtmlfileandaddthefollowingltformgtelementatthebottomoftheltnavgtelement
basetemplatesbasebasehtmlltnavgt
ltformaction=method=getclass=form-inlinemt-2m
t-md-0gt
ltinputid=qname=qvalue=requestGETq
class=form-controlmr-sm-2type=textplaceholder=Searc
haria-label=Searchgt
ltbuttonclass=btnbtn-outline-successmy-2my-sm-0
type=submitgtSearchltbuttongt
ltformgt
ltnavgt
203UpdatingtheindexviewEditthemyappviewspyfileandreplacethecontentswiththeselines
myappviewspy
fromdjangoshortcutsimportrender
frommyappmodelsimportFlower
defindex(request)
q=requestGETget(qNone)
items=
ifqisNoneorqis
flowers=Flowerobjectsall()
elifqisnotNone
flowers=Flowerobjectsfilter(title__contains=q)
returnrender(requestmyappindexhtmlflowers
flowers)
NowyoucansearchtitlesbyprovidingaqGETparameterintheURL
http1270018000q=aga
Weareagainusingthesameindexhtmltemplate
204DetailsWhenauserrequestsapagelikeourfrontpageDjangocreatesanHttpRequestobjectThisobjectcontainsmetadataaboutthatrequestThisincludesallGETparameters
WecanthenaccessthoseparametersinHttpRequestGETInthiscaseweonlysendonetheqparameterThisisthenusedinthemyappindexview
Ifwedonrsquotprovidetheqparameteroritisanemptystringthenallobjectsarefetchedflowers=Flowerobjectsall()
IfqisprovidedwefetchallflowerswherethetitlefieldcontainsthequerystringFlowerobjectsfilter(title__contains=q)
205Summary
BootstrapprovidesagenerictemplatethatyoucanuseforthesearchformHttpRequestobjectcontainsmetadataaboutarequestWecanactonthatdatainsideviewsLikefilteritemsbasedonaGETparameter
21Workingwithformscreatingitems
Thischaptercovers
HowtocreateformswithModelForm
211SetupTerminal
cp-fr15-Base-Project21-Forms-Create
cd21-Forms-Create
sourcevenvbinactivate
212CreatingtheeditformCreateanedithtmlfileinthemyapptemplatesfolder
Templatelocationmyapp
templates
myapp
edithtmllthere
indexhtml
Fillitwiththeselinesmyapptemplatesmyappedithtml
extendsbasebasehtml
blockcontent
ltformaction=method=postgt
csrf_token
ltdivclass=rowjustify-content-centergt
ltdivclass=col-6gt
form
lthrclass=mb-3gt
ltbuttonclass=btnbtn-primarybtn-lgbtn-blockty
pe=submitgtSubmitltbuttongt
ltdivgt
ltdivgt
ltformgt
endblock
Wewillusethistemplatetocreateandeditfloweritems
213CreatingtheformclassCreateformspyfileinthemyappfolder
formspylocationmyapp
adminpy
appspy
formspylthere
Fillitwiththeselinesmyappformspy
fromdjangoimportforms
fromdjangoformsimportModelForm
frommodelsimportFlower
classMyForm(ModelForm)
title=formsCharField(label=Title
widget=formsTextInput(attrs=classform-contr
ol))
classMeta
model=Flower
fields=[title]
214UpdatingurlpatternsEditmysiteappurlspyfileandaddthecreatepath
mysiteurlspyurlpatterns=[
path(adminadminsiteurls)
path(myapp_viewsindexname=index)
path(flowercreatemyapp_viewscreatename=create
)lthere
]
215CreatingtheviewfunctionEditmyappviewspyfileandaddacreateviewbelowtheindexview
myappviewspyfromdjangoshortcutsimportrender
frommodelsimportFlower
fromdjangohttpimportHttpResponseRedirectlthere
fromformsimportMyFormlthere
defindex(request)
defcreate(request)lthere
ifrequestmethod==POST
form=MyForm(requestPOST)
ifformis_valid()
formsave()
returnHttpResponseRedirect()
else
form=MyForm()
returnrender(requestmyappedithtmlformform
)
216AddingamenuitemEditbaseappbasehtmlfileandaddamenulinktotheflowercreationform
basetemplatesbasebasehtmlltulgt
ltligtltagtHomeltagtltligt
ltliclass=nav-itemgtlt--here--gt
ltaclass=nav-linkhref=flowercreategt
CreateFlower
ltagt
ltligt
ltulgt
IremovedunimportantCSSclassesforthebookThecompletemarkupisavailableattheGitHubrepository
Visitflowercreateandcreateaflower
Thenewflowerwillnowshowuponthefrontpage
Notethatthebootstrapclasscard-columnscreatesamasonrylikearrangementnotagrid
217Details
2171ProtectingagainstcrosssiterequestforgeriesInthemyappedithtmlfilewedefineaCSRFtoken
myapptemplatesmyappedithtmlltformaction=method=postgt
csrf_tokenlthere
ltformgt
ThistokenaddsprotectionagainstCrossSiteRequestForgerieswheremaliciouspartiescancausevisitorrsquosbrowsertomakearequesttoyourwebsiteThecookiesinthevisitorbrowsermaketheappthinkthattherequestcamefromanauthorizedsource
UsethetokenonlyinPOSTrequestsYoudonrsquotneeditwithGETrequestsAnyrequestthathasapotentialtochangethesystemshoudbeaPOSTrequestLikewhenweaddflowerstothedatabase
GETrequestsareoftenusedinsituationswherethesystemstateisnotchangedlikewhenwequerydatabasewiththesearchformTheqsearchwordparameterispublicdatawedonrsquotneedtohideYouwanttobeabletosharelinkslikethishttpssamulinatricomsearchq=Django
AlsoyoushouldnrsquotusethetokenwithformsthatpointtoexternalURLSThisintroducesavulnerabilityasthetokenisleakedaction=intheformmeans
thatthePOSTdataissenttothecurrentinternalURL(flowercreate)
2172AddingformfieldsEasiestwaytogenerateHTMLmarkupfortheformfieldsistousetheformtemplatevariable
myapptemplatesmyappedithtmlltdivclass=col-6gt
form
ltdivgt
ThiswillproducethefollowingHTMLGeneratedHTML
ltdivclass=col-6gt
ltlabelfor=id_titlegtTitleltlabelgt
ltinputtype=textname=titlemaxlength=255class=
form-controlrequired=id=id_titlegt
ltdivgt
2173UsingtheFormclassFormclassrepresentsaformItdescribesaforminasimilarwaytheFlowermodeldescribeshowfieldsmaptodatabasefieldsWithformsthefieldsmaptoHTMLelements
ModelFormisahelperclassthatcreatesthatFormclassfromaModelmyappformspy
classMyForm(ModelForm)
title=formsCharField(label=Title
widget=formsTextInput(attrs=classform-contr
ol))
classMeta
model=Flower
fields=[title]
WithModelFormwedonrsquotneedtospecifythefieldsagainWealreadyaddthefieldsintheFlowermodel
FieldsarealreadyspecifiedinthemodelspyfileclassFlower(modelsModel)
title=modelsCharField(max_length=255default=)
description=modelsTextField(default=)
ThiswouldbeenoughtocreateaformtoeditallFlowerfieldsmyappformspy
myappformspyclassMyForm(ModelForm)
classMeta
model=Flower
fields=__all__lthere
ItrsquosrecommendedtoexplicitlyspecifyallthefieldslikethisthoughFieldsshouldbeexplicitlyspecified
fields=[titledescription]
Otherwiseyoucouldunintentionallyexposefieldstouserswhenyouaddthemtothemodel
AformfieldisrepresentedasanHTMLldquowidgetrdquothatproducessomedefaultmarkupWecanmodifythatwidgetintheformdefinition
AddingCSSclassforBootstraptitle=formsCharField(label=Title
widget=formsTextInput(attrs=classform-cont
rol))
Theonlyreasonwedidthisisbecausewewantedtoaddtheform-controlCSSclasstothetitleinputelementThiswaywecantakeadvantageoftheBootstraptextualformcontrolstyling
2174ExaminingtheviewfunctionInthemyappviewspyfileweaddedthecreateviewfunction
myappviewspydefcreate(request)
ifrequestmethod==POST
form=MyForm(requestPOST)
ifformis_valid()
formsave()
returnHttpResponseRedirect()
else
form=MyForm()
returnrender(requestmyappedithtmlformform
)
FirstwecheckiftherequestisPOSTIfitrsquosnotwecreateanemptyformthatwepasstotheedithtmltemplate
Emptyformispassedtothetemplateifrequestmethod==POST
else
form=MyForm()
returnrender(requestmyappedithtmlformform)
ThisisthedefaultscenariowhenyoufirstvisittheflowercreatepageWeneedtocreatetheformobjectsothattheformHTMLcanbegeneratedusingthetemplatetags
IftherequestisPOSTwecreatetheformobjectandpopulateitwiththedatafromtherequest
PopulatingtheformobjectwiththePOSTdataifrequestmethod==POST
form=MyForm(requestPOST)
ThenwecheckiftheformdataisvalidandsavetheflowerValidatingandsavingthedata
ifformis_valid()
formsave()
returnHttpResponseRedirect()
Djangohasbuilt-invalidatorsthatitusesinternallyForexampleEmailValidatorforemailaddressesandvalidate_slugforslugsIftheinputdoesnrsquotsatisfythevalidatoraValidationErrorisraised
Thesave()methodcreatestheflowerobjectfromthedataboundtotheformandstoresitinthedatabase
WhenwesubmitaformusingaPOSTrequestourcreateviewwillinstantiatetheformobjectandpopulateitwiththeformdatafromtherequestWeldquobindrdquothedatatotheformItrsquosnowaldquoboundrdquoform
Thevalidateddatacanbeaccessedintheformcleaned_datadictionaryAccessingvalidateddata
ifformis_valid()
print(formcleaned_data[title])lthere
formsave()
returnHttpResponseRedirect()
Thiswillprintthevalidatedtitlefielddataintheterminal
AndfinallyHttpResponseRedirect()redirectsthevisitortothefrontpage
218Summary
Usecsrf_tokenwithinternalPOSTformstoprotectagainstCrossSiteRequestForgeriesformtemplatevariablegeneratesmarkupforallformfieldsFormclassrepresentsaformItsfieldsmaptoHTMLelementsModelFormisahelperclassthatallowsuscreatetheFormclassfromaDjangomodelAformfieldisrepresentedasanHTMLldquowidgetrdquoYoucanmodifythiswidgetintheformdefinitionThesubmittedformisprocessedinthecreateviewDjangohasbuilt-invalidationthattriggersaValidationErrorwhenthedatadoesnrsquotvalidatevalidateddataisstoredintheformcleaned_datadictionaryInthecreateviewwebindtheformdatatotheforminstanceformsave()methodcreatesadatabaseobjectusingthebounddata
22Workingwithformseditingitems
Thischaptercovers
HowtocreateaneditformPrimarykeyandidfield
221SetupTerminal
cp-fr21-Forms-Create22-Forms-Edit
cd22-Forms-Edit
sourcevenvbinactivate
222AddingthepathEditmysiteappurlspyfileandaddtheeditpath
mysiteurlspyurlpatterns=[
path(adminadminsiteurls)
path(myapp_viewsindexname=index)
path(flowercreatemyapp_viewscreatename=create
)
path(flowereditltintpkgtmyapp_viewseditname=e
dit)lthere
]
223CreatingtheeditviewEditmyappviewspyfileandaddtheeditviewfunction
myappviewspyfromdjangoshortcutsimportrenderget_object_or_404lt
here
frommodelsimportFlower
fromdjangohttpimportHttpResponseRedirect
fromformsimportMyForm
defindex(request)
defcreate(request)
defedit(requestpk=None)lthere
flower=get_object_or_404(Flowerpk=pk)
ifrequestmethod==POST
form=MyForm(requestPOSTinstance=flower)
ifformis_valid()
formsave()
returnHttpResponseRedirect()
else
form=MyForm(instance=flower)
returnrender(requestmyappedithtmlformform
)
224UpdatingtheeditlinkEditmyappindexhtmlfileandchangetheeditlinktothis
myapptemplatesmyappindexhtmlltahref=urleditpk=flowerpkclass=card-linkgtE
ditltagt
YoucannoweditflowersbyclickingtheEditlinksonthefrontpage
225Details
2251CapturingtheidIntheeditpathwecapturetheflowerid
Editpathpath(flowereditltintpkgtmyapp_viewseditname=edit
)
ldquopkrdquoisashortcuttothemodelprimarykeyldquoidrdquoisthenameofthedefaultprimarykeyfieldTakealookatthe0001_initialpyfileinthemyappmigrations
folderDjangocreatestheidfieldautomatically
fields=[
(idmodelsAutoField)lthere
(titlemodelsCharFi)]
DjangowillautomaticallyaddtheidAutoFieldifyoudonrsquotspecifyprimary_key=Trueonanyofthefields
ItrsquosmoreflexibletousetheflowerpkshortcutwhenaccessingtheidfieldThiswayyoucanusethesamecodetoaccesstheidevenifyouchangetheprimarykeyfield
2252ExaminingtheeditviewInmyappviewspyfileweaddtheeditviewfunctionItisverymuchlikethecreateviewfunctionbutwithafewchanges
Editviewisalmostlikethecreateviewdefedit(requestpk=None)ltnew
flower=get_object_or_404(Flowerpk=pk)ltnew
ifrequestmethod==POST
form=MyForm(requestPOSTinstance=flower)ltnew
ifformis_valid()
formsave()
returnHttpResponseRedirect()
else
form=MyForm(instance=flower)ltnew
returnrender(requestmyappedithtmlformform
)
Firstwepassthecapturedpktotheviewwithpk=NoneNoneisthedefaultvalueifpkargumentisnotprovided
get_object_or_404raisesanHttp404exceptionandreturnsastandard404(pagenotfound)errorpageiftheobjectmatchingthelookupparameters(pk=pk)isnotfound
MyForminheritsfromModelFormthatcanacceptamodelinstanceasakeywordargumentThismeansthattheformsave()methodwillnowupdateanexistingflowerinsteadofcreatinganewone
Wealsouseittopopulatetheinitialformwithform=MyForm(instance=flower)Whenyouvisitflowereditltpkgtyouwillbeabletoseeandedittheexistingdata
226Summary
pkisashortcuttothemodelprimarykeyfieldDjangocreatesadefaultidfieldautomaticallyunlessyousettheprimarykeyonanyfieldwithprimary_key=Trueget_object_or_404fetchesanobjectorreturnsapagenotfoundviewifitcanrsquotfindtheobjectmatchingthelookupparametersinstancekeywordargumentallowsustoupdateanexistingobjectwithformsave()methodandpopulatetheformwithanexistingdataforediting
23Workingwithformscustomization
Thischaptercovers
HowtochangetheorderofthefieldsHowtorendervalidationerrorsmanually
231SetupTerminal
cp-fr22-Forms-Edit23-Forms-Customization
cd23-Forms-Customization
sourcevenvbinactivate
232AddingthedescriptionfieldIfyouwanttohavemorecontrolfortheformmarkupyoucanprintouttheformfieldsmanuallyLetrsquosaddadescriptionfieldtotheformandcustomizethetemplate
Editmyappformspyfileandaddthedescriptionfieldtothefieldslistmyappforms
fromdjangoimportforms
fromdjangoformsimportModelForm
frommodelsimportFlower
classMyForm(ModelForm)
title=formsCharField(label=Title
widget=formsTextInput(attrs=classform-cont
rol))
description=formsCharField(label=Descriptionlt
here
widget=formsTextarea(attrs=classform-contr
ol))
classMeta
model=Flower
fields=[titledescription]lthere
Editmyappedithtmltemplateandreplacetheformtemplatevariablewiththeselines
myapptemplatesmyappedithtmlformnon_field_errors
ltdivclass=form-groupgt
formdescriptionerrors
formdescriptionlabel_tag
formdescription
ltdivgt
ltdivclass=form-groupgt
formtitleerrors
formtitlelabel_tag
formtitle
ltdivgt
233Details
2331ChangingfieldorderIfyoujustneedtochangetheorderofthefieldsyoucandoitinthemyappformspyfile
UpdatefieldslisttochangeorderclassMeta
model=Flower
fields=[descriptiontitle]lthere
Ifyouneedmoreflexibilityeditthemyappedithtmltemplateandprinttheformfieldsmanually
2332Customizingvalidationerrors
InputinginvaliddatageneratesavalidationerrorUseformtitleerrorstodisplaythoseerrorsmanually
formnon_field_errorswillrendernon-fieldspecificgeneralerrors
Notethatformrendersallfieldswiththeerrors
YoucouldgoevenfurtherandloopthroughtheerrorsmanuallyReplaceformtitleerrorswiththeselines
Loopingthrougherrorsmanuallyifformtitleerrors
ltolclass=alertalert-dangergt
forerrorinformtitleerrors
ltligtltstronggterror|escapeltstronggtltligt
endfor
ltolgt
endif
CheckouttheofficialdocumentationformorethemingoptionshttpssamulitoForm-Templates
234Summary
Youcanchangetheformfieldorderintheformdefinitionfields=[descriptiontitle]formrendersallmarkupforthefieldsyouspecifiedintheformclassIncludingtheerrors
Formorecontrolyoucanuseformtitleerrorsformtitlelabel_tagandformtitletorendertheformmarkupmanually
24Creatinganddeletingobjects
Thischaptercovers
HowtodeleteFlowerobjectswithacustomviewHowtousethePythoninteractiveinterpretertomanipulateobjectsandinteractwithDjango
241SetupTerminal
cp-fr23-Forms-Customization24-Object-Manipulation
cd24-Object-Manipulation
sourcevenvbinactivate
242AddingthedeletepathEditmysiteurlspyfileandaddthedeletepath
mysiteurlspyurlpatterns=[
path(adminadminsiteurls)
path(myapp_viewsindexname=index)
path(flowercreatemyapp_viewscreatename=create
)
path(flowereditltintpkgtmyapp_viewseditname=e
dit)
path(flowerdeleteltintpkgtmyapp_viewsdeletenam
e=delete)lthere
]
243AddingthedeleteviewWedonrsquotnecessaryneedaformtodeleteitemsYoucouldsimplecapturethepkfromtheURLanddothedeletionlogicinaview
Editmyappviewspyfileandaddthedeleteviewmyappviewspy
defindex(request)
defcreate(request)
defedit(requestpk=None)
defdelete(requestpk=None)lthere
flower=get_object_or_404(Flowerpk=pk)
flowerdelete()
returnrender(requestmyappindexhtml)
244UpdatingthedeletelinkEditthemyappindexhtmltemplateandupdatethedeletelink
myapptemplatesmyappindexhtmlltdivclass=card-bodygt
ltahref=urleditpk=flowerpkclass=card-linkgt
Editltagt
ltahref=urldeletepk=flowerpkclass=card-link
gtDeleteltagtlthere
ltdivgt
Youcannowusethedeletelinksonthehomepagetoeraseitems
245DetailsMakesureyouhaveactivatedthevirtualenvironmentandopenthePythoninteractiveinterpreter
Interactiveinterpreterpythonmanagepyshell
gtgtgtfrommyappmodelsimportFlower
gtgtgtflower=Flower(title=Agathis)
gtgtgtflower
ltFlowerAgathisgt
gtgtgtflowersave()
pythonmanagepyshellstartstheinteractivesession
FlowermodelcanbeinstantiatedlikeanyclassFlower(title=Agathis)createsanewFlowerobjectwiththetitleldquoAgathisrdquo
Flowersave()storesitinthedatabaseVisithomepagetoconfirmthatitwasactuallycreated
Inthemyappviewspyfileweuseflowerdelete()methodtodeletetheobjectfromthedatabase
delete()methoderasestheobjectfromthedatabaseflower=get_object_or_404(Flowerpk=pk)
flowerdelete()
YoucandothesamethingintheinteractiveinterpreterInteractiveinterpreter
gtgtgtflowerdelete()
(1myappFlower1)
gtgtgt
flowerdelete()returnshowmanyobjectsweredeletedandhowmanydeletionswereexecutedbyobjecttypemyappFlower1Wedeleted1objectofthetypeFlower
YoucangetandupdateanobjectlikethisInteractiveinterpreter
gtgtgtflower=Flowerobjectsget(pk=1)
gtgtgtflower
ltFlowerAmelanchieralnifoliagt
gtgtgtflowertitle=UPDATED
gtgtgtflowersave()
gtgtgtflower
ltFlowerUPDATEDgt
gtgtgt
246Summary
YoucanusethePythoninteractiveinterpretertorunPythoncodeandinteractwithyourDjangoappsobject=Class()instantiatesaClassobjectobjectsave()savestheobjecttothedatabaseorupdatesitobjectdelete()deletestheobjectfromthedatabase
25AuthenticatinguserswithAllauth
Thischaptercovers
HowtocreateacompleteauthenticationsystemwithAllauthHowtouseBootstrap4withthedefaulttemplates
251SetupTerminal
cp-fr15-Base-Project25-Authentication
cd25-Authentication
sourcevenvbinactivate
252InstallingAllauthInstalltheAllauthpackage
Terminalpipinstalldjango-allauth
Updatethesettingspyfilemysitesettingspy
INSTALLED_APPS=[
djangocontribadmin
djangocontribauth
djangocontribcontenttypes
djangocontribsessions
djangocontribmessages
djangocontribstaticfiles
djangocontribsiteslthere
allauthlthere
allauthaccountlthere
allauthsocialaccountlthere
base
myapp
]
SITE_ID=1lthere
EMAIL_BACKEND=djangocoremailbackendsconsoleEmailBac
kendlthere
LOGIN_REDIRECT_URL=lthere
Addaccountspathtotheurlspyfilemysiteurlspy
mysiteurlspyfromdjangocontribimportadmin
fromdjangourlsimportpathincludelthere
frommyappimportviewsasmyapp_views
urlpatterns=[
path(adminadminsiteurls)
path(myapp_viewsindexname=index)
path(accountsinclude(allauthurls))lthere
]
RunmigrationsTerminal
pythonmanagepymigrate
Openanotherbrowserorlogoutandcreateatestaccountinaccountssignup
253CreatingtemplatefilesEditmysiteappsettingspyfileandaddthetemplatesfoldertotheDIRS[]list
Locatingtemplates
DIRS[ospathjoin(BASE_DIRtemplates)ospathjoin(
BASE_DIRtemplatesallauth)]
CreateatemplatesfolderintherootofthesiteCreateallauthfolderinsideitCopytheaccountfolderfromtheallauthpackagefolderinsideit
Terminalmkdirtemplates
cdtemplates
mkdirallauth
cdallauth
cp-frvenvlibpython37site-packagesallauthte
mplatesaccount
ThefolderstructureshouldnowlooklikethisAllauthtemplates
base
dbsqlite3
managepy
myapp
mysite
templates
allauth
account
basehtml
loginhtml
logouthtml
Changethebasehtmlcontentsintheaccountfoldertothistemplatesallauthaccountbasehtml
extendsbasebasehtml
LogoutinaccountslogoutandvisitaccountssigninYoushouldseetheloginformwrappedinsidethebasetheme
254UpdatingthetemplatesforBootstrap4Installdjango-widget-tweakspackage
Terminalpipinstalldjango-widget-tweaks
Addwidget_tweakstotheINSTALLED_APPSlistmysitesettingspy
INSTALLED_APPS=[
allauth
allauthaccount
allauthsocialaccount
widget_tweakslthere
base
myapp
]
Createaform_snippethtmlinsidetheroottemplatesfoldertemplatesform_snippethtml
loadwidget_tweaks
forfieldinform
ltdivclass=fieldWrappermb-1gt
fielderrors
iffieldfieldwidgetinput_type=checkbox
ltlabelclass=sr-onlyfor=form_fieldauto_idgt
form_fieldlabelltlabelgt
field|add_classform-control
else
fieldlabel_tag
field
endif
ltdivgt
endfor
Wecannowre-usethissnippettorenderallfieldsinanytemplate
EditloginhtmlfileinthetemplatesallauthaccountfolderReplacetheformelementwiththeselines
templatesallauthaccountloginhtmlltformclass=form-accountloginmethod=POSTaction=u
rlaccount_logingt
csrf_token
includeform_snippethtmllt--here--gt
ifredirect_field_value
ltinputtype=hiddenname=redirect_field_namev
alue=redirect_field_valuegt
endif
ltaclass=buttonsecondaryActiond-blockmb-2href=u
rlaccount_reset_passwordgttransForgotPassword
ltagt
ltbuttonclass=btnbtn-lgbtn-primarybtn-blocktype=su
bmitgttransSignInltbuttongt
ltformgt
Noticetheformelementform-accountCSSclassAddtheformstylinginsitecss
basestaticbasecsssitecssbody
padding-top5rem
starter-template
padding3rem15rem
text-aligncenter
footer
text-aligncenter
font-size16px
height60px
line-height60px
form-accountlthere
width100
max-width330px
padding15px
marginauto
Visitaccountsloginandyoushouldseethis
EditsignuphtmlfileinthetemplatesallauthaccountfolderReplacetheformelementwiththis
templatesallauthaccountsignuphtmlltformclass=form-accountsignupid=signup_formmethod=
postaction=urlaccount_signupgt
csrf_token
includeform_snippethtml
ifredirect_field_value
ltinputtype=hiddenname=redirect_field_nameval
ue=redirect_field_valuegt
endif
ltbuttonclass=btnbtn-lgbtn-primarybtn-blocktype=sub
mitgttransSignUpampraquoltbuttongt
ltformgt
Editpassword_changehtmlfileinthetemplatesallauthaccountfolderReplacetheformelementwiththeselines
templatesallauthaccountpassword_changehtmlltformmethod=POSTaction=urlaccount_change_password
class=form-accountpassword_changegt
csrf_token
includeform_snippethtml
ltbuttonclass=mt-1type=submitname=actiongttrans
ChangePasswordltbuttongt
ltformgt
255Details
2551ConfigurationoptionsTheAllauthpackageoffersquiteabitconfigurationoptionsLetrsquostakealookatwhatweused
mysitesettingspySITE_ID=1lthere
EMAIL_BACKEND=djangocoremailbackendsconsoleEmailBac
kendlthere
LOGIN_REDIRECT_URL=lthere
SITE_ID=1hastomatchthesiteaddedinadminsitessiteInthiscaseweusethedefaultexamplecomsite
WithEMAIL_BACKENDvariablewetellDjangotowriteemailstothestandardoutputinsteadoftryingtosendtheemailsThisisusefulfordevelopmentbutforproductionyoushouldusesomethinglikeSendGridWewilldothatintheSendingEmailschapter
Youcantrythisbyvisitingaccountspasswordreset
Emailsarewritteninthestandardoutputstream
Subject[examplecom]PasswordResetE-mail
Fromwebmasterlocalhost
Totestexampleorg
WithLOGIN_REDIRECT_URLweredirecttheusertothehomepageafterasuccessfulloginOtherwiseyouwouldberedirectedtoaprofilepagethatdoesnrsquotexistbydefault
CheckouttheofficialdocumentationformoreconfigurationoptionshttpssamulitoDjango-Allauth
2552AddingthepathsIntheurlspyfileweincludedalldjango-allauthpathswithoneline
mysiteurlspyfromdjangocontribimportadmin
fromdjangourlsimportpathincludelthere
frommyappimportviewsasmyapp_views
urlpatterns=[
path(adminadminsiteurls)
path(myapp_viewsindexname=index)
path(accountsinclude(allauthurls))lthere
]
HereisalistforallpathsitprovidesAlldjango-allauthpaths
accountssignup
accountslogin
accountslogout
accountspasswordchange
accountspasswordset
accountsinactive
accountsemail
accountsconfirm-email
accountsconfirm-emailltkeygt
accountspasswordreset
accountspasswordresetdone
accountspasswordresetkeyltuidb36gt
accountspasswordresetkeydone
accountssociallogincancelled
accountssocialloginerror
accountssocialsignup
accountssocialconnections
Notethatweonlycustomizedallmajortemplatesbutyoucantakealookatthetemplatesallauthfolderandgothroughallofthem
2553django-widget-tweaksWithdjango-widget-tweaksyoucanmanipulateformfieldrenderingintemplatesIuseittoaddtheform-controlCSSclasstoinputfields
templatesform_snippethtmlloadwidget_tweaks
forfieldinform
ltdivclass=fieldWrappermb-1gt
fielderrors
iffieldfieldwidgetinput_type=checkbox
ltlabelclass=sr-onlyfor=form_fieldauto_idgt
form_fieldlabelltlabelgt
field|add_classform-controllt--here--gt
else
fieldlabel_tag
field
endif
ltdivgt
endfor
Iuseifstatementtoexcludetheform-controlCSSclassfromcheckboxes
Readmoreaboutthedjango-widget-tweakspackagehttpssamulitoWidget-Tweaks
256Summary
Withdjango-allauthpackageyoucanaddanaccountmanagementfunctionalitywithoutwritinganycustomviews
IndevelopmentenvironmentyoucanuseEMAIL_BACKENDvariabletowriteemailstothestandardoutputforeasydebuggingWithdjango-widget-tweakpackageyoucanchangeformfieldrenderingintemplates
26Authorization
Thischaptercovers
HowtomanageuserpermissionswithgroupsHowtomanageaccessusingdecorators
261SetupTerminal
cp-fr24-Object-Manipulation26-Authorization
cd26-Authorization
sourcevenvbinactivate
262AddingtheEditorgroupVisitadminandaddanewldquoEditorrdquogroupusingtheldquo+Addrdquolink
Selectthefollowingpermissionsandclicksave
263CreatingatestuserVisitadminandaddanewuserusingtheldquo+Addrdquolink
AddusertotheEditorgroup
CheckStaffstatuscheckboxandsave
OpenanotherbrowserandloginthetestuserinadminOurtestuserhasnowpermissionstomanageFloweritems
IfyouremovethetestuserfromtheEditorgroupthentheadmininterfacewouldshowthefollowingmessage
OurtestusercanstilllogintotheadminbecausetheStaffstatusisstillenabledfortheaccount
264Usingpermissions
Editmyappindexhtmlpageandaddifstatementstochecktheuserpermissionsmyapptemplatesmyappindexhtml
requestuserget_all_permissionslt--here--gt
ltdivclass=card-columnsgt
forflowerinflowers
ifpermsmyappchange_flowerlt--here--gt
ltahref=urleditpk=flowerpkclass=card
-linkgtEditltagt
endif
ifpermsmyappdelete_flowerlt--here--gt
ltahref=urldeletepk=flowerpkclass=ca
rd-linkgtDeleteltagt
endif
endfor
ltdivgt
requestuserget_all_permissionsshowsthecurrentuserpermissions
NowonlyuserswithcorrectpermissionswillseetheEditandDeletelinks
265UsingdecoratorsButcurrentlyanyonecanmanageflowersusingourcustomformsLetrsquosrestrictaccesswithdecorators
Editmyappviewspyfileandaddthedecoratorsmyappviewspy
fromdjangocontribauthdecoratorsimportpermission_requi
redlthere
defindex(request)
permission_required(myappadd_flower)lthere
defcreate(request)
permission_required(myappchange_flower)lthere
defedit(requestpk=None)
permission_required(myappchange_delete)lthere
defdelete(requestpk=None)
Nowonlyaccountswiththerightpermissionscanaccesstheseviews
266Details
2661AuthenticationvsauthorizationAuthenticationisaboutverifyingauserAuthorizationisaboutrestrictingorallowingaccesstoresources
WithGroupsyoucangivemultiplepermissionstousersatonceTheEditorgroupcontainspermissionsforaddingchanginganddeletingflowersTheuserwhobelongstotheEditorgroupwillgetallthesepermissions
requestuserget_all_permissionsrevealsthemachinenamesforthecurrentuserpermissions
Userpermissionsmyappdelete_flower
myappchange_flower
myappadd_flower
YoucanusepermsPERMISSIONintemplatestoaccessthecurrentuserpermissions
Checkinguserpermissionsifpermsmyappchange_flower
endif
2662ControllingaccesswithdecoratorsDecoratorsallowustodynamicallyalterafunctionoraclassDjangoprovidessomeusefuldecoratorsrelatedtouseraccesshttpssamulitoAuth-Decorators
Usingadecorator
Usingadecoratorpermission_required(myappadd_flower)
defcreate(request)
Anotherusefulisthelogin_requireddecoratorlogin_requireddecorator
login_required
defprofile(request)
Inthiscaseyouwouldhavetobelogged-intoaccesstheprofilepageOtherwisethevisitorwillberedirectedtoaURLspecifiedwithsettingsLOGIN_URL
267Summary
YoucangrouppermissionsandassignuserstothesegroupsCurrentuserpermissionsareavailableintemplatesusingthepermstemplatevariablerequestuserget_all_permissionsdisplaysallpermissionsforthecurrentlogged-inuserpermission_required()decoratorchecksifthecurrentuserhasaparticularpermissionThisisaconvenientwaytorestrictaccesstospecificviewslogin_requiredisamoregeneraldecoratorthatrequiresthatuserhastobelogged-in
27Creatinganimagegallery
Thischaptercovers
HowtouploadimagesHowtoservetheimagesinlocalhostHowtoshowtheimagesinagridusingBootstrap4album
271SetupTerminal
cp-fr15-Base-Project27-Image-Gallery
cd27-Image-Gallery
sourcevenvbinactivate
272InstallingpillowInstallthepillowpackage
Terminalpipinstallpillow
273ConfiguringmediavariablesEditmysiteappsettingspyfileandspecifyMEDIA_URLandMEDIA_ROOTvariables
mysitesettingspySTATIC_URL=static
MEDIA_URL=media
MEDIA_ROOT=media
274AddingImageFieldEditmyappmodelspyfileandaddanImageField
myappmodelspyfromdjangodbimportmodels
classFlower(modelsModel)
title=modelsCharField(max_length=255default=)
description=modelsTextField(default=)
image=modelsImageField(default=blank=Trueuploa
d_to=images)lthere
def__str__(self)
returnselftitle
RunmigrationsTerminal
pythonmanagepymakemigrations
pythonmanagepymigrate
275AddingimagestoflowersVisitadminedittheflowersandaddsomeimages
YoucanfindexampleimagesinthisfolderhttpssamulitoFlowers
Imagesareuploadedinthemediaimagesfolder
276UsingthestatichelperfunctionEditmysiteappurlspyfileandusethestatic()helperfunction
mysiteurlspyfromdjangocontribimportadmin
fromdjangourlsimportpath
frommyappimportviewsasmyapp_views
fromdjangoconfimportsettingslthere
fromdjangoconfurlsstaticimportstaticlthere
urlpatterns=[
path(adminadminsiteurls)
path(myapp_viewsindexname=index)
]+static(settingsMEDIA_URLdocument_root=settingsMEDIA
_ROOT)lthere
277AddingthegridEditmyappindexhtmlfileandreplacethecontentswiththeselines
myapptemplatesmyappindexhtmlextendsbasebasehtml
blockcontent
ltdivclass=albumpy-5gt
ltdivclass=containergt
ltdivclass=rowgt
forflowerinflowers
ltdivclass=col-md-4gt
ltdivclass=cardmb-4shadow-smgt
ltimgclass=card-img-topsrc=flowe
rimageurl
alt=Cardimagecapgt
ltdivclass=card-bodygt
ltpclass=card-textgtThisisawide
rcardwithsupportingtextbelowasanaturallead-into
additionalcontentThisconten
tisalittlebitlongerltpgt
ltdivclass=d-flexjustify-content-
betweenalign-items-centergt
ltdivclass=btn-groupgt
ltbuttontype=buttonclass
=btnbtn-smbtn-outline-secondarygtViewltbuttongt
ltbuttontype=buttonclass
=btnbtn-smbtn-outline-secondarygtEditltbuttongt
ltdivgt
ltsmallclass=text-mutedgt9min
sltsmallgt
ltdivgt
ltdivgt
ltdivgt
ltdivgt
endfor
ltdivgt
ltdivgt
ltdivgt
endblock
YoucanfindthegridmarkupinherehttpssamulitoGrid
Visithomepageandyoushouldseethealbumgrid
278DetailsYouneedtoinstallthePillowlibrarytoaddanImageField
myappmodelspyimage=modelsImageField(default=blank=Trueupload_to
=images)
upload_to=imagesstorestheuploadedimagesinthemediaimagesfolder
Inthedevelopmentphaseyoucanservetheseuser-uploadedfilesusingstatic()helperfunction
myappurlspyurlpatterns=[
path(adminadminsiteurls)
path(myapp_viewsindexname=index)
]+static(settingsMEDIA_URLdocument_root=settingsMEDIA
_ROOT)lthere
ThisfunctionworksonlyindebugmodeYouhavetohaveDEBUG=TrueconfiguredinthesettingspyfileWithHerokuplatformwewillservethemediafilesfromanAmazonsAWSbucketlaterinthebook
UseflowerimageurltoaccessimageURLSintemplatesAccessingtheimageurl
ltimgclass=card-img-topsrc=flowerimageurl
ThegridisjustabasicBootstrapalbumhttpssamulitoBootstrap-Album
279Summary
PillowpackageaddsimageuploadingandprocessingcapabilitiesMEDIA_ROOTisthephysicalpathtotheimagesMEDIA_URListheURLpathyouusetoaccessthemediafilesYoucanusestatic()functiontoservethefilesindebugmodeInproductionenvironmentyouhavetoimplementotherwaystoservetheimagesIntemplatestheimageURLSareaccessedwiththefamiliardotldquordquonotationflowerimageurl
Inthenextchapterwegeneratesmallerimagesandcropthem
28Addingimagethumbnails
Thischaptercovers
HowtocreatethumbnailswithImageKit
281SetupTerminal
cp-fr27-Image-Gallery28-Image-Thumbnails
cd28-Image-Thumbnails
sourcevenvbinactivate
282InstallingImageKitTerminal
pipinstalldjango-imagekit
EditmysiteappsettingspyfileandaddimagekittotheINSTALLED_APPSlistmysitesettingspy
INSTALLED_APPS=[
base
myapp
imagekitlthere
]
283AddingthethumbnailfieldEditmyappmodelspyfileandaddtheimage_thumbnailfield
mysitemodelspyfromdjangodbimportmodels
fromimagekitmodelsimportImageSpecFieldlthere
frompilkitprocessorsimportResizeToFilllthere
classFlower(modelsModel)
title=modelsCharField(max_length=255default=)
description=modelsTextField(default=)
image=modelsImageField(default=blank=Trueuploa
d_to=images)
image_thumbnail=ImageSpecField(source=image
processors=[ResizeToFill(350200)]
format=JPEG
options=quality60)lthere
Editmyappindexhtmlfileandreplaceflowerimageurlwithflowerimage_thumbnailurl
myapptemplatesmyappindexhtmlltimgclass=card-img-topsrc=flowerimage_thumbnailur
l
VisitthehomepagetogeneratetheimagethumbnailsTheywillbeservedfrompathslikethis
mediaCACHEimagesimagesAgapanthusjpg
284DetailsItrsquosveryusefultogeneratethumbnailsforimagesYoucanalwaysaddlinkstotheoriginalimagesifneededWeuseImageKittocropandresizetheimagesThethumbnailsaregeneratedasthepagewheretheimagesareusedisaccessedthefirsttime
UsingtheoriginaluploadedimagescanresultinveryheavypagesForexampleAmelanchier_asiatica5jpgthatIusedfortestingwas43MBImageprocessingreducedthatsizeto182KB
ImageSpecFieldissimilartoImageFieldbutitautomaticallyappliestheimageprocessingwespecify
ImageSpecFielddoestheimageproccessingimage=modelsImageField(default=blank=Trueupload_to
=images)
image_thumbnail=ImageSpecField(source=image
processors=[ResizeToFill(350200)]
format=JPEG
options=quality60)
source=imageistheoriginalimagefieldWecanadddifferentprocessors(httpssamulitoProcessors)tomanipulatetheimageResizeToFillresizesandcropstheimageHerewealsospecifyimageformatandcompression
YoucanaccessthethumbnailURLusingthedotldquordquonotationintemplatesflowerimage_thumbnailurl
285Summary
CreatingthumbnailscanreducetheimagesizessubstantiallyImageKitpackageenablesaselectionofimageprocessingtools
29DeployingonHeroku
Thischaptercovers
HowtodeploytoHeroku
291SetupCreateafolderoutsidetheprojectsfolder
Terminalmkdirdeployments
cddeployments
mkdirheroku
cdheroku
python3-mvenvvenv
sourcevenvbinactivate
pipinstalldjangodjango-herokugunicorn
pipfreezegtrequirementstxt
django-adminstartprojectmysite
pythonmanagepyrunserver
django-herokupackageinstallssomedependencieslikepsycopg2forPostgreSQLsupportandwhitenoiseforservingstaticfilesstraightfromtheapp
Terminaldeploymentslthere
herokulthere
projects
292CreatingaHerokuappVisithttpssamulitoHerokuandcreateanaccount
PressCreatenewapp
Restofthechaptershowssn-01astheappnameReplaceitwiththenameofyourapp
293InstallingHerokuCLI
2931InstallationinWindowsVisithttpssamulitoHeroku-CLIanddownloadtheWindowsinstaller
2932InstallationinmacOSTerminal
Terminalxcode-select--install
brewinstallherokubrewheroku
2933InstallationinUbuntuTerminal
sudosnapinstall--classicheroku
2934AuthenticatingwithabrowserUseherokulogininterminaltologin
Terminalherokulogin
herokuPressanykeytoopenupthebrowsertologinorq
toexit
Loggingindone
Loggedinasuserexampleorg
294CreatingaProcfileCreateafilecalledProcfileintheprojectrootandwritethislineinit
Procfilecontentswebgunicornmysitewsgi
295UpdatingthesettingspyfileEditsettingspyfileandimportdjango_herokupackageonthetopandchangeDEBUGandALLOWED_HOSTSvariables
mysitesettingspyimportdjango_herokulthere
importos
DEBUG=Falselthere
ALLOWED_HOSTS=[sn-01herokuappcom]lthere
Addthefollowinglinesatthebottomofthefilemysitesettingspy
django_herokusettings(locals())
try
fromlocal_settingsimport
exceptImportError
pass
Createalocal_settingspyfilemysitelocal_settingspy
DEBUG=True
ALLOWED_HOSTS=[]
296CreatingtherepositoryVisithttpssamulitoGitandinstallGit
Createagitignorefileinthesiterootgitignorefile
venv
local_settingspy
dbsqlite3
pyc
__pycache__
py[cod]
DS_Store
VisithttpssamulitoDj-Gitignoretooseemorecomprehensivegitignoreexample
InitialisegitrepositoryandpushitTerminal
gitinit
gitadd
gitcommit-mInitial
herokugitremote-asn-01
gitpushherokumaster
RunmigrateandcreateasuperuserTerminal
herokurunpythonmanagepymigrate
herokurunpythonmanagepycreatesuperuser
Visityourappadminpagesinhttpssn-01herokuappcomadmin
NotewedonrsquotseethewelcomescreenonthefrontpagebecausetheproductionsiteisnotindebugmodeYougetldquoTherequestedURLwasnotfoundonthisserverrdquoinsteadbecausewedonrsquothaveaviewforthehomepage
297Pushingchanges
LetrsquosaddahomepageandsomeCSSstylingThedjango-herokupackageinstallstheWhitenoisepackagethatallowsyourwebapptoserveitsownstaticfilesCheckoutthenextchapteronhowtoservestaticfilesanduser-uploadedfilesfromAmazonAWS
Terminaldjango-adminstartappblog
Addanindexviewblogviewspy
fromdjangoshortcutsimportrender
defindex(request)lthere
returnrender(requestblogindexhtml)
Createanindexhtmlfilewiththiscontentblogtemplatesblogindexhtml
loadstatic
ltDOCTYPEhtmlgt
lthtmllang=engt
ltheadgt
lttitlegtBloglttitlegt
ltlinkrel=stylesheethref=staticblogcsssitec
ssgt
ltheadgt
ltbodygt
ltdivid=contentgt
lth1gtHomelth1gt
ltdivgt
ltbodygt
lthtmlgt
Youhavetocreatethefolderstructureblogtemplatesblog
Createasitecssfilewiththiscontentblogstaticblogcsssitecss
h1colorred
Youhavetocreatethefolderstructureblogstaticblogcss
Editurlspyfileandaddtheindexpathmysiteurlspy
fromdjangocontribimportadmin
fromdjangourlsimportpath
fromblogimportviewslthere
urlpatterns=[
path(adminadminsiteurls)
path(viewsindexname=index)lthere
]
AddlsquoblogrsquototheINSTALLED_APPSlistmysitesettingspy
INSTALLED_APPS=[
djangocontribstaticfiles
bloglthere
]
Terminalgitadd
gitcommit-mAddBlogapp
gitpushherokumaster
Visittheproductionsitehomepageandyoushouldseethis
Notewedidnrsquothavetorunldquoherokurunpythonmanagepymigraterdquobecausewedidnrsquotmakeanychangesthatrequiredatabaseupdates
298UpdatingthedatabaseLetrsquoscreateaPostmodelandupdatethedatabase
blogmodelspyfromdjangodbimportmodels
classPost(modelsModel)
title=modelsCharField(max_length=255default=)
Registeritinadminpyblogadminpy
fromdjangocontribimportadmin
frommodelsimportPost
adminsiteregister(Post)
RunlocalmigrationsTerminal
pythonmanagepymakemigrations
pythonmanagepymigrate
pythonmanagepycreatesuperuser
pythonmanagepyrunserver
Loginandcreateapostitemtoseethatitworkslocallybeforeyoupushit
PushthechangesTerminal
gitadd
gitcommit-mAddPostmodel
gitpushherokumaster
ApplychangestotheremotedatabaseTerminal
herokurunpythonmanagepymigrate
Visityourherokuappadminpageandaddcontent
299Summary
django-herokuaddssettingsconfigurationThisincludesthingslikeDATABASE_URLsothatyoudonrsquothavetoadddatabaseconfigurationmanuallyItalsoinstallsomeextrapackageslikewhitenoisethatallows
youtoservestaticfilesdirectlyfromtheappwithoutusingNginxAmazonS3oranyothersimilarsolutionUseldquopipfreezegtrequirementstxtrdquotogenerateadependencylistThesewillbeinstalledautomaticallywhenyoupushthecodeRemembertosetDEBUG=FalseandconfigureALLOWED_HOSTSvariableinthesettingspyfileforproductionenvironmentsItrsquosusefultocreatemultiplesettingsfileslikelocal_settingspytoaddenvironmentspecificconfigurationHerokuCLIallowsyoutointeractwiththeplatformusingacommandlineItrequiresGITtoworkYoucanrunremotecommandswithldquoherokurunltcommandgtrdquoForexampleifyoumakechangestothedatabaseschemayoushouldrunldquoherokurunpythonmanagepymigraterdquoUseldquogitpushherokumasterrdquotopushchangestotheplatformCheckouttheldquoHerokuPipelinesrdquochapteronhowtocreateaproperdeploymentflow
30UsingAmazonAWStoservefiles
Thischaptercovers
Howtoservestaticassetsanduser-uploadedfilesfromanAmazonbucket
301SetupUsetheprojectfromtheldquoHerokuDeploymentrdquochaptertotestthis
302CreatinganAmazonAWSbucketVisithttpssamulitoAWSandcreateanaccount
VisithttpssamulitoS3andaddabucket
ClickNextfortherestofthesettingsandhitCreatebucket
303SettinguppermissionsVisitServicesandclickIAMundertheSecurityIdentityampCompliancelabel
ClickUsersandAdduser
CheckProgrammaticaccess
Createanewgroup
CheckAmazonS3FullAccess
ClickNextTags
ClickNextReview
ClickCreateuser
Wewillusethisinformationinthesettingspyfile
304UpdatingsettingspyfileUpdatesettingspyfileandaddtheconfiguration
mysitesettingspydjango_herokusettings(locals())
AWS_ACCESS_KEY_ID=ACCESS_KEY
AWS_SECRET_ACCESS_KEY=SECRET
AWS_STORAGE_BUCKET_NAME=sn-test-01
AWS_DEFAULT_ACL=None
AWS_LOCATION=static
AWS_MEDIA_LOCATION=media
STATIC_URL=httpsss3amazonawscoms(AWS_STORA
GE_BUCKET_NAMEAWS_LOCATION)
STATICFILES_STORAGE=storagesbackendss3boto3S3Boto3Sto
rage
DEFAULT_FILE_STORAGE=mysitestoragesMediaStorage
try
fromlocal_settingsimport
exceptImportError
pass
Createastoragespyfileandfillitwiththeselinesmysitestoragespy
fromdjangoconfimportsettings
fromstoragesbackendss3boto3importS3Boto3Storage
classMediaStorage(S3Boto3Storage)
location=settingsAWS_MEDIA_LOCATION
file_overwrite=False
305AddinganimagefieldtothePostmodelEditblogappmodelspyfileandaddanImageField
blogmodelspy
fromdjangodbimportmodels
classPost(modelsModel)
title=modelsCharField(max_length=255default=)
image=modelsImageField(default=blank=Trueuploa
d_to=images)lthere
306InstallingpackagesInstallpackagesandpush
Terminalpipinstalldjango-storagesboto3pillow
pythonmanagepymakemigrations
pythonmanagepymigrate
pipfreezegtrequirementstxt
gitadd
gitcommit-mAdddjango-storagesboto3pillowandPost
modelimagefield
gitpushherokumaster
herokurunpythonmanagepymigrate
VisittheproductionsiteinhttpsYOUR_APPherokuappcomandcreateaPostwithanimage
ThepostimagewillbenowservedfromanURLlikethissn-test-01amazonawscommediaimagesAgapanthuspng
OpenthepagesourcecodeandyouwillseethatthestaticfilesarenowservedfromURLSlikethissn-test-01s3amazonawscomstaticadmincssbasecss
Inthebucketfolderyounowhaveseparatefoldersformediaandstaticfiles
307Summary
Boto3isanAmazonsoftwaredevelopmentkitthatallowsPythonprogramstouseserviceslikeAmazonS3Itrsquosnotuncommontoservestaticassetsanduser-uploadedfilesfromexternalsourcesAmazonS3canalsobeintegratedwithacontentdeliverynetworklikeAmazonCloudFronthttpssamulitoAmazon-CloudFront
31SettingupHerokupipelines
Thischaptercovers
HowtocreateacontinuousdeploymentworkflowwithHerokupipelines
311SetupUsetheprojectfromtheldquoHerokuDeploymentrdquochaptertotestthis
312CreatingaGitHubrepositoryVisithttpssamulitoGitHubandcreateanaccount
Createanewrepository
GotoyourprojectfolderAddaremoteandpushthecodetoGitHubTerminal
gitremoteaddorigingitgithubcomSamuliNatrisn-01git
gitpush-uoriginmaster
RefreshtheGitHubpageandyoushouldseetheprojectcode
313CreatingapipelineVisityourHerokuappDeploypageandcreateapipeline
PressConnecttoGitHub
LogintoGitHubandAuthorizeheroku
SearchfortherepositoryandConnectit
VisitthePipelinepageandEnableAutomaticDeploys
314TestingdeploymentEdittheindexhtmltemplateandchangetheldquoHomerdquotext
blogtemplatesblogindexhtmlloadstatic
ltDOCTYPEhtmlgt
lthtmllang=engt
ltheadgt
lttitlegtBloglttitlegt
ltlinkrel=stylesheethref=staticblogcsssitec
ssgt
ltheadgt
ltbodygt
ltdivid=contentgt
lth1gtHome(Update)lth1gtlthere
ltdivgt
ltbodygt
lthtmlgt
Terminalgitadd
gitcommit-mUpdatehomepage
gitpush
InamomentyouwillseeldquoBuildingapprdquotextonthepage
AndldquoDeployedrdquotextwhenthedeploymentisready
VisittheappURLandyoushouldseethechanges
ThesedeploymentswillalsoshowintheGitHubDeploymentssection
315AddingaproductionappVisitthePipelinepage
AddaProductionapp
PressyourstagingappPromotetoproductionbutton
Visityourproductionapphomepageanditshouldlooklikethestagingapphomepage
316EnablingreviewappsVisitthePipelinepageandpressEnableReviewApps
Createanappjsonfile
ScrolltothebottomandpressCommittoRepo
CheckCreatenewreviewappshellipautomaticallyandDestroystalereviewappsPressEnable
Notethatreviewappsmayincurdynoandadd-onchargeshttpssamulitoReview-Apps
YoucanalsonotchecktheCreatenewreviewappshellipautomaticallyoptionandcreatepreviewappsmanuallyonthePipelinepage
317UsingpullrequestsLetrsquosmakeachangeandcreateapullrequest
PullchangesandcreateabranchTerminal
gitpull
gitcheckout-bnew_homepage
Weneedtopulltheappjsonfilethattheplatformaddedtotherepo
Edittheindexhtmltemplateandmakesomechanges
blogtemplatesblogindexhtmlltdivid=contentgt
lth1gtNEWFANCYHOMEPAGElth1gtlt--here--gt
ltdivgt
Terminalgitadd
gitcommit-mNewhomepagesuggestion
gitpush--set-upstreamoriginnew_homepage
UselinkintheTerminaltocreateaPullrequestorvisitthePullrequestspageonGitHub
WriteadescriptionandcreateaPullrequest
VisitthePipelinepageandclickOpenappinbrowserafterthepreviewappisready
Youcannowevaluatethepullrequestinthepreviewapp
VisitGitHubandmergethepullrequest
VisitthePipelinepageandwaitforthestagingapptobedeployedPressPromotetoproductionandthenewfancyhomepageisnowlive
ThepullrequestandmergingflowisalsovisibleinGitHub
318DeletingthebranchWedonrsquotneedthenew_homepagebranchanymoresinceitrsquosnowmergedtothemasterbranch
Terminalgitbranch
gitcheckoutmaster
gitpull
gitbranch-dnew_homepage
319Summary
HerokuprovidesanicecontinuousdeliveryworkflowoutoftheboxReviewappsallowyoutotestGitHubpullrequestswithdisposableHerokuapps
32SendingemailswithSendGrid
Thischaptercovers
HowtosendemailswithSendGrid
321CreatinganaccountVisithttpssamulitoSendGridandcreateanaccount
CopythebaseprojectTerminal
cp-fr15-Base-Project32-Sending-Emails
cd32-Sending-Emails
sourcevenvbinactivate
Editsettingspyfileandaddthefollowingconfigurationusingtheusernameandpasswordyouprovidedinthesign-inprocess
mysitesettingspy
EMAIL_HOST=smtpsendgridnet
EMAIL_HOST_USER=sendgrid_username
EMAIL_HOST_PASSWORD=sendgrid_password
EMAIL_PORT=587
EMAIL_USE_TLS=True
TestthemailintheinteractiveinterpreterInteractiveinterpreter
pythonmanagepyshell
gtgtgtfromdjangocoremailimportsend_mail
gtgtgtsend_mail(SubjecthereHereisthemessageadmi
n-mailgmailcom[some-other-mailgmailcom]fail_sile
ntly=False)
Youshouldnowreceivetheemailinyourinbox
322Summary
SendingemailswithSendGridisjustmatterofcreatinganaccountwiththeserviceandaddingtherightconfigurationtothesettingspyfile
Licenses
ImagesinthebookandsourcecoderepositoryarelicensedunderCCBY-SA30andCCBY-SA40
ldquoAmelanchierAsiaticardquobyKENPEIislicensedunderCCBY-SA30
ldquoAgapanthusafricanusrdquobyKurtStuberislicensedunderCCBY-SA30
ldquoAmelanchieralnifoliaatIcicleCanyonChelanCountyWashingtonrdquobyThayneTuasonislicensedunderCCBY-SA40
- Preface
- About this book
-
- Who is this book for
- What this book is NOT about
- How this book is organized
-
- Chapters 1-7
- Chapters 8-10
- Chapters 11-13
- Chapters 14-16
- Chapters 17-20
- Chapters 21-24
- Chapters 25-26
- Chapters 27-28
- Chapters 29-32
-
- About the author
-
- 1 Installing Python on Windows
-
- 11 Downloading and installing Python
- 12 Using the interactive prompt
- 13 Details
-
- 131 Python interpreter
-
- 14 Summary
-
- 2 Installing Python on macOS
-
- 21 Downloading and installing Python
- 22 Using the interactive prompt
- 23 Details
-
- 231 Python interpreter
-
- 24 Summary
-
- 3 Installing Python on Linux
-
- 31 Installing Python
- 32 Using the interactive prompt
- 33 Details
-
- 331 Python interpreter
-
- 34 Summary
-
- 4 Creating virtual environments in Windows
-
- 41 Creating and activating virtual environments
- 42 Summary
-
- 5 Creating virtual environments in macOS
-
- 51 Creating and activating virtual environments
- 52 Summary
-
- 6 Creating virtual environments in Linux
-
- 61 Creating and activating virtual environments
- 62 Summary
-
- 7 Virtual environments and pip
-
- 71 Why use virtual environments
- 72 Details
-
- 721 Organizing folders
- 722 Freezing requirements
- 723 Excluding venv from the repository
- 724 Using other tools
- 725 Using python vs python3
-
- 73 Summary
-
- 8 Creating a Django project
-
- 81 Setup
- 82 Creating a new Project
- 83 Running the development server
- 84 Details
- 85 Summary
-
- 9 Creating a Hello World app
-
- 91 Setup
- 92 Creating apps
- 93 Creating template files
- 94 Creating views
- 95 Adding a homepage path
- 96 Summary
-
- 10 Examining the project structure and apps
-
- 101 Adding features with apps
- 102 Exploring the project structure
- 103 Exploring the project package
- 104 Summary
-
- 11 Working with template inheritance
-
- 111 Setup
- 112 Creating a base app
- 113 Extending templates
- 114 Details
- 115 Summary
-
- 12 Installing Bootstrap 4 theme
-
- 121 Setup
- 122 Modifying an existing template
- 123 Updating the homepage template
- 124 Details
- 125 Summary
-
- 13 Managing static files
-
- 131 Setup
- 132 Creating a stylesheet file
- 133 Details
-
- 1331 Working with static files
- 1332 Using the static tag
- 1333 Forcing cache refresh with versioning
-
- 134 Summary
-
- 14 Creating models
-
- 141 Setup
- 142 Creating the Flower model
- 143 Listing flowers
- 144 Details
-
- 1441 Explaining models
- 1442 Returning a string representation
- 1443 Making database queries