Django - The Easy Way: A step-by-step guide on building Django websites, 2nd Edition

165

Transcript of Django - The Easy Way: A step-by-step guide on building Django websites, 2nd Edition

Page 1: 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
                                                                                        • 145 Summary
                                                                                          • 15 Creating a base project
                                                                                            • 151 Setup
                                                                                            • 152 Adding a description field
                                                                                            • 153 Adding masonry like columns
                                                                                            • 154 Adding a footer
                                                                                            • 155 Summary
                                                                                              • 16 Creating a detail page
                                                                                                • 161 Setup
                                                                                                • 162 Adding a detail page path
                                                                                                • 163 Creating the detail view
                                                                                                • 164 Creating the detail page template
                                                                                                • 165 Creating slugs
                                                                                                • 166 Updating the path
                                                                                                • 167 Defining get_absolute_url() method
                                                                                                • 168 Using url tag
                                                                                                • 169 Details
                                                                                                  • 1691 Capturing URL values
                                                                                                  • 1692 Using view parameters
                                                                                                  • 1693 Explaining slugs
                                                                                                  • 1694 Reversing URLS
                                                                                                    • 1610 Summary
                                                                                                      • 17 Adding category as a many-to-one relationhip
                                                                                                        • 171 Setup
                                                                                                        • 172 Adding category field and model
                                                                                                        • 173 Updating the homepage template
                                                                                                        • 174 Details
                                                                                                          • 1741 Examining many-to-one relationships
                                                                                                          • 1742 Accessing related objects
                                                                                                            • 175 Summary
                                                                                                              • 18 Referencing tags with a ManyToMany field
                                                                                                                • 181 Setup
                                                                                                                • 182 Adding the tags field
                                                                                                                • 183 Updating the homepage template
                                                                                                                • 184 Summary
                                                                                                                  • 19 Creating a tags page
                                                                                                                    • 191 Setup
                                                                                                                    • 192 Adding tags path
                                                                                                                    • 193 Adding the slug field
                                                                                                                    • 194 Creating the tags view
                                                                                                                    • 195 Updating homepage template
                                                                                                                    • 196 Details
                                                                                                                      • 1961 Doing lookups across relationships
                                                                                                                      • 1962 Reusing templates
                                                                                                                        • 197 Summary
                                                                                                                          • 20 Creating a search feature
                                                                                                                            • 201 Setup
                                                                                                                            • 202 Adding a search form
                                                                                                                            • 203 Updating the index view
                                                                                                                            • 204 Details
                                                                                                                            • 205 Summary
                                                                                                                              • 21 Working with forms creating items
                                                                                                                                • 211 Setup
                                                                                                                                • 212 Creating the edit form
                                                                                                                                • 213 Creating the form class
                                                                                                                                • 214 Updating urlpatterns
                                                                                                                                • 215 Creating the view function
                                                                                                                                • 216 Adding a menu item
                                                                                                                                • 217 Details
                                                                                                                                  • 2171 Protecting against cross site request forgeries
                                                                                                                                  • 2172 Adding form fields
                                                                                                                                  • 2173 Using the Form class
                                                                                                                                  • 2174 Examining the view function
                                                                                                                                    • 218 Summary
                                                                                                                                      • 22 Working with forms editing items
                                                                                                                                        • 221 Setup
                                                                                                                                        • 222 Adding the path
                                                                                                                                        • 223 Creating the edit view
                                                                                                                                        • 224 Updating the edit link
                                                                                                                                        • 225 Details
                                                                                                                                          • 2251 Capturing the id
                                                                                                                                          • 2252 Examining the edit view
                                                                                                                                            • 226 Summary
                                                                                                                                              • 23 Working with forms customization
                                                                                                                                                • 231 Setup
                                                                                                                                                • 232 Adding the description field
                                                                                                                                                • 233 Details
                                                                                                                                                  • 2331 Changing field order
                                                                                                                                                  • 2332 Customizing validation errors
                                                                                                                                                    • 234 Summary
                                                                                                                                                      • 24 Creating and deleting objects
                                                                                                                                                        • 241 Setup
                                                                                                                                                        • 242 Adding the delete path
                                                                                                                                                        • 243 Adding the delete view
                                                                                                                                                        • 244 Updating the delete link
                                                                                                                                                        • 245 Details
                                                                                                                                                        • 246 Summary
                                                                                                                                                          • 25 Authenticating users with Allauth
                                                                                                                                                            • 251 Setup
                                                                                                                                                            • 252 Installing Allauth
                                                                                                                                                            • 253 Creating template files
                                                                                                                                                            • 254 Updating the templates for Bootstrap 4
                                                                                                                                                            • 255 Details
                                                                                                                                                              • 2551 Configuration options
                                                                                                                                                              • 2552 Adding the paths
                                                                                                                                                              • 2553 django-widget-tweaks
                                                                                                                                                                • 256 Summary
                                                                                                                                                                  • 26 Authorization
                                                                                                                                                                    • 261 Setup
                                                                                                                                                                    • 262 Adding the Editor group
                                                                                                                                                                    • 263 Creating a test user
                                                                                                                                                                    • 264 Using permissions
                                                                                                                                                                    • 265 Using decorators
                                                                                                                                                                    • 266 Details
                                                                                                                                                                      • 2661 Authentication vs authorization
                                                                                                                                                                      • 2662 Controlling access with decorators
                                                                                                                                                                        • 267 Summary
                                                                                                                                                                          • 27 Creating an image gallery
                                                                                                                                                                            • 271 Setup
                                                                                                                                                                            • 272 Installing pillow
                                                                                                                                                                            • 273 Configuring media variables
                                                                                                                                                                            • 274 Adding ImageField
                                                                                                                                                                            • 275 Adding images to flowers
                                                                                                                                                                            • 276 Using the static helper function
                                                                                                                                                                            • 277 Adding the grid
                                                                                                                                                                            • 278 Details
                                                                                                                                                                            • 279 Summary
                                                                                                                                                                              • 28 Adding image thumbnails
                                                                                                                                                                                • 281 Setup
                                                                                                                                                                                • 282 Installing ImageKit
                                                                                                                                                                                • 283 Adding the thumbnail field
                                                                                                                                                                                • 284 Details
                                                                                                                                                                                • 285 Summary
                                                                                                                                                                                  • 29 Deploying on Heroku
                                                                                                                                                                                    • 291 Setup
                                                                                                                                                                                    • 292 Creating a Heroku app
                                                                                                                                                                                    • 293 Installing Heroku CLI
                                                                                                                                                                                      • 2931 Installation in Windows
                                                                                                                                                                                      • 2932 Installation in macOS
                                                                                                                                                                                      • 2933 Installation in Ubuntu
                                                                                                                                                                                      • 2934 Authenticating with a browser
                                                                                                                                                                                        • 294 Creating a Procfile
                                                                                                                                                                                        • 295 Updating the settingspy file
                                                                                                                                                                                        • 296 Creating the repository
                                                                                                                                                                                        • 297 Pushing changes
                                                                                                                                                                                        • 298 Updating the database
                                                                                                                                                                                        • 299 Summary
                                                                                                                                                                                          • 30 Using Amazon AWS to serve files
                                                                                                                                                                                            • 301 Setup
                                                                                                                                                                                            • 302 Creating an Amazon AWS bucket
                                                                                                                                                                                            • 303 Setting up permissions
                                                                                                                                                                                            • 304 Updating settingspy file
                                                                                                                                                                                            • 305 Adding an image field to the Post model
                                                                                                                                                                                            • 306 Installing packages
                                                                                                                                                                                            • 307 Summary
                                                                                                                                                                                              • 31 Setting up Heroku pipelines
                                                                                                                                                                                                • 311 Setup
                                                                                                                                                                                                • 312 Creating a GitHub repository
                                                                                                                                                                                                • 313 Creating a pipeline
                                                                                                                                                                                                • 314 Testing deployment
                                                                                                                                                                                                • 315 Adding a production app
                                                                                                                                                                                                • 316 Enabling review apps
                                                                                                                                                                                                • 317 Using pull requests
                                                                                                                                                                                                • 318 Deleting the branch
                                                                                                                                                                                                • 319 Summary
                                                                                                                                                                                                  • 32 Sending emails with SendGrid
                                                                                                                                                                                                    • 321 Creating an account
                                                                                                                                                                                                    • 322 Summary
                                                                                                                                                                                                      • Licenses
Page 2: Django - The Easy Way: A step-by-step guide on building Django websites, 2nd Edition

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
                                                                                        • 145 Summary
                                                                                          • 15 Creating a base project
                                                                                            • 151 Setup
                                                                                            • 152 Adding a description field
                                                                                            • 153 Adding masonry like columns
                                                                                            • 154 Adding a footer
                                                                                            • 155 Summary
                                                                                              • 16 Creating a detail page
                                                                                                • 161 Setup
                                                                                                • 162 Adding a detail page path
                                                                                                • 163 Creating the detail view
                                                                                                • 164 Creating the detail page template
                                                                                                • 165 Creating slugs
                                                                                                • 166 Updating the path
                                                                                                • 167 Defining get_absolute_url() method
                                                                                                • 168 Using url tag
                                                                                                • 169 Details
                                                                                                  • 1691 Capturing URL values
                                                                                                  • 1692 Using view parameters
                                                                                                  • 1693 Explaining slugs
                                                                                                  • 1694 Reversing URLS
                                                                                                    • 1610 Summary
                                                                                                      • 17 Adding category as a many-to-one relationhip
                                                                                                        • 171 Setup
                                                                                                        • 172 Adding category field and model
                                                                                                        • 173 Updating the homepage template
                                                                                                        • 174 Details
                                                                                                          • 1741 Examining many-to-one relationships
                                                                                                          • 1742 Accessing related objects
                                                                                                            • 175 Summary
                                                                                                              • 18 Referencing tags with a ManyToMany field
                                                                                                                • 181 Setup
                                                                                                                • 182 Adding the tags field
                                                                                                                • 183 Updating the homepage template
                                                                                                                • 184 Summary
                                                                                                                  • 19 Creating a tags page
                                                                                                                    • 191 Setup
                                                                                                                    • 192 Adding tags path
                                                                                                                    • 193 Adding the slug field
                                                                                                                    • 194 Creating the tags view
                                                                                                                    • 195 Updating homepage template
                                                                                                                    • 196 Details
                                                                                                                      • 1961 Doing lookups across relationships
                                                                                                                      • 1962 Reusing templates
                                                                                                                        • 197 Summary
                                                                                                                          • 20 Creating a search feature
                                                                                                                            • 201 Setup
                                                                                                                            • 202 Adding a search form
                                                                                                                            • 203 Updating the index view
                                                                                                                            • 204 Details
                                                                                                                            • 205 Summary
                                                                                                                              • 21 Working with forms creating items
                                                                                                                                • 211 Setup
                                                                                                                                • 212 Creating the edit form
                                                                                                                                • 213 Creating the form class
                                                                                                                                • 214 Updating urlpatterns
                                                                                                                                • 215 Creating the view function
                                                                                                                                • 216 Adding a menu item
                                                                                                                                • 217 Details
                                                                                                                                  • 2171 Protecting against cross site request forgeries
                                                                                                                                  • 2172 Adding form fields
                                                                                                                                  • 2173 Using the Form class
                                                                                                                                  • 2174 Examining the view function
                                                                                                                                    • 218 Summary
                                                                                                                                      • 22 Working with forms editing items
                                                                                                                                        • 221 Setup
                                                                                                                                        • 222 Adding the path
                                                                                                                                        • 223 Creating the edit view
                                                                                                                                        • 224 Updating the edit link
                                                                                                                                        • 225 Details
                                                                                                                                          • 2251 Capturing the id
                                                                                                                                          • 2252 Examining the edit view
                                                                                                                                            • 226 Summary
                                                                                                                                              • 23 Working with forms customization
                                                                                                                                                • 231 Setup
                                                                                                                                                • 232 Adding the description field
                                                                                                                                                • 233 Details
                                                                                                                                                  • 2331 Changing field order
                                                                                                                                                  • 2332 Customizing validation errors
                                                                                                                                                    • 234 Summary
                                                                                                                                                      • 24 Creating and deleting objects
                                                                                                                                                        • 241 Setup
                                                                                                                                                        • 242 Adding the delete path
                                                                                                                                                        • 243 Adding the delete view
                                                                                                                                                        • 244 Updating the delete link
                                                                                                                                                        • 245 Details
                                                                                                                                                        • 246 Summary
                                                                                                                                                          • 25 Authenticating users with Allauth
                                                                                                                                                            • 251 Setup
                                                                                                                                                            • 252 Installing Allauth
                                                                                                                                                            • 253 Creating template files
                                                                                                                                                            • 254 Updating the templates for Bootstrap 4
                                                                                                                                                            • 255 Details
                                                                                                                                                              • 2551 Configuration options
                                                                                                                                                              • 2552 Adding the paths
                                                                                                                                                              • 2553 django-widget-tweaks
                                                                                                                                                                • 256 Summary
                                                                                                                                                                  • 26 Authorization
                                                                                                                                                                    • 261 Setup
                                                                                                                                                                    • 262 Adding the Editor group
                                                                                                                                                                    • 263 Creating a test user
                                                                                                                                                                    • 264 Using permissions
                                                                                                                                                                    • 265 Using decorators
                                                                                                                                                                    • 266 Details
                                                                                                                                                                      • 2661 Authentication vs authorization
                                                                                                                                                                      • 2662 Controlling access with decorators
                                                                                                                                                                        • 267 Summary
                                                                                                                                                                          • 27 Creating an image gallery
                                                                                                                                                                            • 271 Setup
                                                                                                                                                                            • 272 Installing pillow
                                                                                                                                                                            • 273 Configuring media variables
                                                                                                                                                                            • 274 Adding ImageField
                                                                                                                                                                            • 275 Adding images to flowers
                                                                                                                                                                            • 276 Using the static helper function
                                                                                                                                                                            • 277 Adding the grid
                                                                                                                                                                            • 278 Details
                                                                                                                                                                            • 279 Summary
                                                                                                                                                                              • 28 Adding image thumbnails
                                                                                                                                                                                • 281 Setup
                                                                                                                                                                                • 282 Installing ImageKit
                                                                                                                                                                                • 283 Adding the thumbnail field
                                                                                                                                                                                • 284 Details
                                                                                                                                                                                • 285 Summary
                                                                                                                                                                                  • 29 Deploying on Heroku
                                                                                                                                                                                    • 291 Setup
                                                                                                                                                                                    • 292 Creating a Heroku app
                                                                                                                                                                                    • 293 Installing Heroku CLI
                                                                                                                                                                                      • 2931 Installation in Windows
                                                                                                                                                                                      • 2932 Installation in macOS
                                                                                                                                                                                      • 2933 Installation in Ubuntu
                                                                                                                                                                                      • 2934 Authenticating with a browser
                                                                                                                                                                                        • 294 Creating a Procfile
                                                                                                                                                                                        • 295 Updating the settingspy file
                                                                                                                                                                                        • 296 Creating the repository
                                                                                                                                                                                        • 297 Pushing changes
                                                                                                                                                                                        • 298 Updating the database
                                                                                                                                                                                        • 299 Summary
                                                                                                                                                                                          • 30 Using Amazon AWS to serve files
                                                                                                                                                                                            • 301 Setup
                                                                                                                                                                                            • 302 Creating an Amazon AWS bucket
                                                                                                                                                                                            • 303 Setting up permissions
                                                                                                                                                                                            • 304 Updating settingspy file
                                                                                                                                                                                            • 305 Adding an image field to the Post model
                                                                                                                                                                                            • 306 Installing packages
                                                                                                                                                                                            • 307 Summary
                                                                                                                                                                                              • 31 Setting up Heroku pipelines
                                                                                                                                                                                                • 311 Setup
                                                                                                                                                                                                • 312 Creating a GitHub repository
                                                                                                                                                                                                • 313 Creating a pipeline
                                                                                                                                                                                                • 314 Testing deployment
                                                                                                                                                                                                • 315 Adding a production app
                                                                                                                                                                                                • 316 Enabling review apps
                                                                                                                                                                                                • 317 Using pull requests
                                                                                                                                                                                                • 318 Deleting the branch
                                                                                                                                                                                                • 319 Summary
                                                                                                                                                                                                  • 32 Sending emails with SendGrid
                                                                                                                                                                                                    • 321 Creating an account
                                                                                                                                                                                                    • 322 Summary
                                                                                                                                                                                                      • Licenses
Page 3: Django - The Easy Way: A step-by-step guide on building Django websites, 2nd Edition

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
                                                                                        • 145 Summary
                                                                                          • 15 Creating a base project
                                                                                            • 151 Setup
                                                                                            • 152 Adding a description field
                                                                                            • 153 Adding masonry like columns
                                                                                            • 154 Adding a footer
                                                                                            • 155 Summary
                                                                                              • 16 Creating a detail page
                                                                                                • 161 Setup
                                                                                                • 162 Adding a detail page path
                                                                                                • 163 Creating the detail view
                                                                                                • 164 Creating the detail page template
                                                                                                • 165 Creating slugs
                                                                                                • 166 Updating the path
                                                                                                • 167 Defining get_absolute_url() method
                                                                                                • 168 Using url tag
                                                                                                • 169 Details
                                                                                                  • 1691 Capturing URL values
                                                                                                  • 1692 Using view parameters
                                                                                                  • 1693 Explaining slugs
                                                                                                  • 1694 Reversing URLS
                                                                                                    • 1610 Summary
                                                                                                      • 17 Adding category as a many-to-one relationhip
                                                                                                        • 171 Setup
                                                                                                        • 172 Adding category field and model
                                                                                                        • 173 Updating the homepage template
                                                                                                        • 174 Details
                                                                                                          • 1741 Examining many-to-one relationships
                                                                                                          • 1742 Accessing related objects
                                                                                                            • 175 Summary
                                                                                                              • 18 Referencing tags with a ManyToMany field
                                                                                                                • 181 Setup
                                                                                                                • 182 Adding the tags field
                                                                                                                • 183 Updating the homepage template
                                                                                                                • 184 Summary
                                                                                                                  • 19 Creating a tags page
                                                                                                                    • 191 Setup
                                                                                                                    • 192 Adding tags path
                                                                                                                    • 193 Adding the slug field
                                                                                                                    • 194 Creating the tags view
                                                                                                                    • 195 Updating homepage template
                                                                                                                    • 196 Details
                                                                                                                      • 1961 Doing lookups across relationships
                                                                                                                      • 1962 Reusing templates
                                                                                                                        • 197 Summary
                                                                                                                          • 20 Creating a search feature
                                                                                                                            • 201 Setup
                                                                                                                            • 202 Adding a search form
                                                                                                                            • 203 Updating the index view
                                                                                                                            • 204 Details
                                                                                                                            • 205 Summary
                                                                                                                              • 21 Working with forms creating items
                                                                                                                                • 211 Setup
                                                                                                                                • 212 Creating the edit form
                                                                                                                                • 213 Creating the form class
                                                                                                                                • 214 Updating urlpatterns
                                                                                                                                • 215 Creating the view function
                                                                                                                                • 216 Adding a menu item
                                                                                                                                • 217 Details
                                                                                                                                  • 2171 Protecting against cross site request forgeries
                                                                                                                                  • 2172 Adding form fields
                                                                                                                                  • 2173 Using the Form class
                                                                                                                                  • 2174 Examining the view function
                                                                                                                                    • 218 Summary
                                                                                                                                      • 22 Working with forms editing items
                                                                                                                                        • 221 Setup
                                                                                                                                        • 222 Adding the path
                                                                                                                                        • 223 Creating the edit view
                                                                                                                                        • 224 Updating the edit link
                                                                                                                                        • 225 Details
                                                                                                                                          • 2251 Capturing the id
                                                                                                                                          • 2252 Examining the edit view
                                                                                                                                            • 226 Summary
                                                                                                                                              • 23 Working with forms customization
                                                                                                                                                • 231 Setup
                                                                                                                                                • 232 Adding the description field
                                                                                                                                                • 233 Details
                                                                                                                                                  • 2331 Changing field order
                                                                                                                                                  • 2332 Customizing validation errors
                                                                                                                                                    • 234 Summary
                                                                                                                                                      • 24 Creating and deleting objects
                                                                                                                                                        • 241 Setup
                                                                                                                                                        • 242 Adding the delete path
                                                                                                                                                        • 243 Adding the delete view
                                                                                                                                                        • 244 Updating the delete link
                                                                                                                                                        • 245 Details
                                                                                                                                                        • 246 Summary
                                                                                                                                                          • 25 Authenticating users with Allauth
                                                                                                                                                            • 251 Setup
                                                                                                                                                            • 252 Installing Allauth
                                                                                                                                                            • 253 Creating template files
                                                                                                                                                            • 254 Updating the templates for Bootstrap 4
                                                                                                                                                            • 255 Details
                                                                                                                                                              • 2551 Configuration options
                                                                                                                                                              • 2552 Adding the paths
                                                                                                                                                              • 2553 django-widget-tweaks
                                                                                                                                                                • 256 Summary
                                                                                                                                                                  • 26 Authorization
                                                                                                                                                                    • 261 Setup
                                                                                                                                                                    • 262 Adding the Editor group
                                                                                                                                                                    • 263 Creating a test user
                                                                                                                                                                    • 264 Using permissions
                                                                                                                                                                    • 265 Using decorators
                                                                                                                                                                    • 266 Details
                                                                                                                                                                      • 2661 Authentication vs authorization
                                                                                                                                                                      • 2662 Controlling access with decorators
                                                                                                                                                                        • 267 Summary
                                                                                                                                                                          • 27 Creating an image gallery
                                                                                                                                                                            • 271 Setup
                                                                                                                                                                            • 272 Installing pillow
                                                                                                                                                                            • 273 Configuring media variables
                                                                                                                                                                            • 274 Adding ImageField
                                                                                                                                                                            • 275 Adding images to flowers
                                                                                                                                                                            • 276 Using the static helper function
                                                                                                                                                                            • 277 Adding the grid
                                                                                                                                                                            • 278 Details
                                                                                                                                                                            • 279 Summary
                                                                                                                                                                              • 28 Adding image thumbnails
                                                                                                                                                                                • 281 Setup
                                                                                                                                                                                • 282 Installing ImageKit
                                                                                                                                                                                • 283 Adding the thumbnail field
                                                                                                                                                                                • 284 Details
                                                                                                                                                                                • 285 Summary
                                                                                                                                                                                  • 29 Deploying on Heroku
                                                                                                                                                                                    • 291 Setup
                                                                                                                                                                                    • 292 Creating a Heroku app
                                                                                                                                                                                    • 293 Installing Heroku CLI
                                                                                                                                                                                      • 2931 Installation in Windows
                                                                                                                                                                                      • 2932 Installation in macOS
                                                                                                                                                                                      • 2933 Installation in Ubuntu
                                                                                                                                                                                      • 2934 Authenticating with a browser
                                                                                                                                                                                        • 294 Creating a Procfile
                                                                                                                                                                                        • 295 Updating the settingspy file
                                                                                                                                                                                        • 296 Creating the repository
                                                                                                                                                                                        • 297 Pushing changes
                                                                                                                                                                                        • 298 Updating the database
                                                                                                                                                                                        • 299 Summary
                                                                                                                                                                                          • 30 Using Amazon AWS to serve files
                                                                                                                                                                                            • 301 Setup
                                                                                                                                                                                            • 302 Creating an Amazon AWS bucket
                                                                                                                                                                                            • 303 Setting up permissions
                                                                                                                                                                                            • 304 Updating settingspy file
                                                                                                                                                                                            • 305 Adding an image field to the Post model
                                                                                                                                                                                            • 306 Installing packages
                                                                                                                                                                                            • 307 Summary
                                                                                                                                                                                              • 31 Setting up Heroku pipelines
                                                                                                                                                                                                • 311 Setup
                                                                                                                                                                                                • 312 Creating a GitHub repository
                                                                                                                                                                                                • 313 Creating a pipeline
                                                                                                                                                                                                • 314 Testing deployment
                                                                                                                                                                                                • 315 Adding a production app
                                                                                                                                                                                                • 316 Enabling review apps
                                                                                                                                                                                                • 317 Using pull requests
                                                                                                                                                                                                • 318 Deleting the branch
                                                                                                                                                                                                • 319 Summary
                                                                                                                                                                                                  • 32 Sending emails with SendGrid
                                                                                                                                                                                                    • 321 Creating an account
                                                                                                                                                                                                    • 322 Summary
                                                                                                                                                                                                      • Licenses
Page 4: Django - The Easy Way: A step-by-step guide on building Django websites, 2nd Edition

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
                                                                                        • 145 Summary
                                                                                          • 15 Creating a base project
                                                                                            • 151 Setup
                                                                                            • 152 Adding a description field
                                                                                            • 153 Adding masonry like columns
                                                                                            • 154 Adding a footer
                                                                                            • 155 Summary
                                                                                              • 16 Creating a detail page
                                                                                                • 161 Setup
                                                                                                • 162 Adding a detail page path
                                                                                                • 163 Creating the detail view
                                                                                                • 164 Creating the detail page template
                                                                                                • 165 Creating slugs
                                                                                                • 166 Updating the path
                                                                                                • 167 Defining get_absolute_url() method
                                                                                                • 168 Using url tag
                                                                                                • 169 Details
                                                                                                  • 1691 Capturing URL values
                                                                                                  • 1692 Using view parameters
                                                                                                  • 1693 Explaining slugs
                                                                                                  • 1694 Reversing URLS
                                                                                                    • 1610 Summary
                                                                                                      • 17 Adding category as a many-to-one relationhip
                                                                                                        • 171 Setup
                                                                                                        • 172 Adding category field and model
                                                                                                        • 173 Updating the homepage template
                                                                                                        • 174 Details
                                                                                                          • 1741 Examining many-to-one relationships
                                                                                                          • 1742 Accessing related objects
                                                                                                            • 175 Summary
                                                                                                              • 18 Referencing tags with a ManyToMany field
                                                                                                                • 181 Setup
                                                                                                                • 182 Adding the tags field
                                                                                                                • 183 Updating the homepage template
                                                                                                                • 184 Summary
                                                                                                                  • 19 Creating a tags page
                                                                                                                    • 191 Setup
                                                                                                                    • 192 Adding tags path
                                                                                                                    • 193 Adding the slug field
                                                                                                                    • 194 Creating the tags view
                                                                                                                    • 195 Updating homepage template
                                                                                                                    • 196 Details
                                                                                                                      • 1961 Doing lookups across relationships
                                                                                                                      • 1962 Reusing templates
                                                                                                                        • 197 Summary
                                                                                                                          • 20 Creating a search feature
                                                                                                                            • 201 Setup
                                                                                                                            • 202 Adding a search form
                                                                                                                            • 203 Updating the index view
                                                                                                                            • 204 Details
                                                                                                                            • 205 Summary
                                                                                                                              • 21 Working with forms creating items
                                                                                                                                • 211 Setup
                                                                                                                                • 212 Creating the edit form
                                                                                                                                • 213 Creating the form class
                                                                                                                                • 214 Updating urlpatterns
                                                                                                                                • 215 Creating the view function
                                                                                                                                • 216 Adding a menu item
                                                                                                                                • 217 Details
                                                                                                                                  • 2171 Protecting against cross site request forgeries
                                                                                                                                  • 2172 Adding form fields
                                                                                                                                  • 2173 Using the Form class
                                                                                                                                  • 2174 Examining the view function
                                                                                                                                    • 218 Summary
                                                                                                                                      • 22 Working with forms editing items
                                                                                                                                        • 221 Setup
                                                                                                                                        • 222 Adding the path
                                                                                                                                        • 223 Creating the edit view
                                                                                                                                        • 224 Updating the edit link
                                                                                                                                        • 225 Details
                                                                                                                                          • 2251 Capturing the id
                                                                                                                                          • 2252 Examining the edit view
                                                                                                                                            • 226 Summary
                                                                                                                                              • 23 Working with forms customization
                                                                                                                                                • 231 Setup
                                                                                                                                                • 232 Adding the description field
                                                                                                                                                • 233 Details
                                                                                                                                                  • 2331 Changing field order
                                                                                                                                                  • 2332 Customizing validation errors
                                                                                                                                                    • 234 Summary
                                                                                                                                                      • 24 Creating and deleting objects
                                                                                                                                                        • 241 Setup
                                                                                                                                                        • 242 Adding the delete path
                                                                                                                                                        • 243 Adding the delete view
                                                                                                                                                        • 244 Updating the delete link
                                                                                                                                                        • 245 Details
                                                                                                                                                        • 246 Summary
                                                                                                                                                          • 25 Authenticating users with Allauth
                                                                                                                                                            • 251 Setup
                                                                                                                                                            • 252 Installing Allauth
                                                                                                                                                            • 253 Creating template files
                                                                                                                                                            • 254 Updating the templates for Bootstrap 4
                                                                                                                                                            • 255 Details
                                                                                                                                                              • 2551 Configuration options
                                                                                                                                                              • 2552 Adding the paths
                                                                                                                                                              • 2553 django-widget-tweaks
                                                                                                                                                                • 256 Summary
                                                                                                                                                                  • 26 Authorization
                                                                                                                                                                    • 261 Setup
                                                                                                                                                                    • 262 Adding the Editor group
                                                                                                                                                                    • 263 Creating a test user
                                                                                                                                                                    • 264 Using permissions
                                                                                                                                                                    • 265 Using decorators
                                                                                                                                                                    • 266 Details
                                                                                                                                                                      • 2661 Authentication vs authorization
                                                                                                                                                                      • 2662 Controlling access with decorators
                                                                                                                                                                        • 267 Summary
                                                                                                                                                                          • 27 Creating an image gallery
                                                                                                                                                                            • 271 Setup
                                                                                                                                                                            • 272 Installing pillow
                                                                                                                                                                            • 273 Configuring media variables
                                                                                                                                                                            • 274 Adding ImageField
                                                                                                                                                                            • 275 Adding images to flowers
                                                                                                                                                                            • 276 Using the static helper function
                                                                                                                                                                            • 277 Adding the grid
                                                                                                                                                                            • 278 Details
                                                                                                                                                                            • 279 Summary
                                                                                                                                                                              • 28 Adding image thumbnails
                                                                                                                                                                                • 281 Setup
                                                                                                                                                                                • 282 Installing ImageKit
                                                                                                                                                                                • 283 Adding the thumbnail field
                                                                                                                                                                                • 284 Details
                                                                                                                                                                                • 285 Summary
                                                                                                                                                                                  • 29 Deploying on Heroku
                                                                                                                                                                                    • 291 Setup
                                                                                                                                                                                    • 292 Creating a Heroku app
                                                                                                                                                                                    • 293 Installing Heroku CLI
                                                                                                                                                                                      • 2931 Installation in Windows
                                                                                                                                                                                      • 2932 Installation in macOS
                                                                                                                                                                                      • 2933 Installation in Ubuntu
                                                                                                                                                                                      • 2934 Authenticating with a browser
                                                                                                                                                                                        • 294 Creating a Procfile
                                                                                                                                                                                        • 295 Updating the settingspy file
                                                                                                                                                                                        • 296 Creating the repository
                                                                                                                                                                                        • 297 Pushing changes
                                                                                                                                                                                        • 298 Updating the database
                                                                                                                                                                                        • 299 Summary
                                                                                                                                                                                          • 30 Using Amazon AWS to serve files
                                                                                                                                                                                            • 301 Setup
                                                                                                                                                                                            • 302 Creating an Amazon AWS bucket
                                                                                                                                                                                            • 303 Setting up permissions
                                                                                                                                                                                            • 304 Updating settingspy file
                                                                                                                                                                                            • 305 Adding an image field to the Post model
                                                                                                                                                                                            • 306 Installing packages
                                                                                                                                                                                            • 307 Summary
                                                                                                                                                                                              • 31 Setting up Heroku pipelines
                                                                                                                                                                                                • 311 Setup
                                                                                                                                                                                                • 312 Creating a GitHub repository
                                                                                                                                                                                                • 313 Creating a pipeline
                                                                                                                                                                                                • 314 Testing deployment
                                                                                                                                                                                                • 315 Adding a production app
                                                                                                                                                                                                • 316 Enabling review apps
                                                                                                                                                                                                • 317 Using pull requests
                                                                                                                                                                                                • 318 Deleting the branch
                                                                                                                                                                                                • 319 Summary
                                                                                                                                                                                                  • 32 Sending emails with SendGrid
                                                                                                                                                                                                    • 321 Creating an account
                                                                                                                                                                                                    • 322 Summary
                                                                                                                                                                                                      • Licenses
Page 5: Django - The Easy Way: A step-by-step guide on building Django websites, 2nd Edition

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
                                                                                        • 145 Summary
                                                                                          • 15 Creating a base project
                                                                                            • 151 Setup
                                                                                            • 152 Adding a description field
                                                                                            • 153 Adding masonry like columns
                                                                                            • 154 Adding a footer
                                                                                            • 155 Summary
                                                                                              • 16 Creating a detail page
                                                                                                • 161 Setup
                                                                                                • 162 Adding a detail page path
                                                                                                • 163 Creating the detail view
                                                                                                • 164 Creating the detail page template
                                                                                                • 165 Creating slugs
                                                                                                • 166 Updating the path
                                                                                                • 167 Defining get_absolute_url() method
                                                                                                • 168 Using url tag
                                                                                                • 169 Details
                                                                                                  • 1691 Capturing URL values
                                                                                                  • 1692 Using view parameters
                                                                                                  • 1693 Explaining slugs
                                                                                                  • 1694 Reversing URLS
                                                                                                    • 1610 Summary
                                                                                                      • 17 Adding category as a many-to-one relationhip
                                                                                                        • 171 Setup
                                                                                                        • 172 Adding category field and model
                                                                                                        • 173 Updating the homepage template
                                                                                                        • 174 Details
                                                                                                          • 1741 Examining many-to-one relationships
                                                                                                          • 1742 Accessing related objects
                                                                                                            • 175 Summary
                                                                                                              • 18 Referencing tags with a ManyToMany field
                                                                                                                • 181 Setup
                                                                                                                • 182 Adding the tags field
                                                                                                                • 183 Updating the homepage template
                                                                                                                • 184 Summary
                                                                                                                  • 19 Creating a tags page
                                                                                                                    • 191 Setup
                                                                                                                    • 192 Adding tags path
                                                                                                                    • 193 Adding the slug field
                                                                                                                    • 194 Creating the tags view
                                                                                                                    • 195 Updating homepage template
                                                                                                                    • 196 Details
                                                                                                                      • 1961 Doing lookups across relationships
                                                                                                                      • 1962 Reusing templates
                                                                                                                        • 197 Summary
                                                                                                                          • 20 Creating a search feature
                                                                                                                            • 201 Setup
                                                                                                                            • 202 Adding a search form
                                                                                                                            • 203 Updating the index view
                                                                                                                            • 204 Details
                                                                                                                            • 205 Summary
                                                                                                                              • 21 Working with forms creating items
                                                                                                                                • 211 Setup
                                                                                                                                • 212 Creating the edit form
                                                                                                                                • 213 Creating the form class
                                                                                                                                • 214 Updating urlpatterns
                                                                                                                                • 215 Creating the view function
                                                                                                                                • 216 Adding a menu item
                                                                                                                                • 217 Details
                                                                                                                                  • 2171 Protecting against cross site request forgeries
                                                                                                                                  • 2172 Adding form fields
                                                                                                                                  • 2173 Using the Form class
                                                                                                                                  • 2174 Examining the view function
                                                                                                                                    • 218 Summary
                                                                                                                                      • 22 Working with forms editing items
                                                                                                                                        • 221 Setup
                                                                                                                                        • 222 Adding the path
                                                                                                                                        • 223 Creating the edit view
                                                                                                                                        • 224 Updating the edit link
                                                                                                                                        • 225 Details
                                                                                                                                          • 2251 Capturing the id
                                                                                                                                          • 2252 Examining the edit view
                                                                                                                                            • 226 Summary
                                                                                                                                              • 23 Working with forms customization
                                                                                                                                                • 231 Setup
                                                                                                                                                • 232 Adding the description field
                                                                                                                                                • 233 Details
                                                                                                                                                  • 2331 Changing field order
                                                                                                                                                  • 2332 Customizing validation errors
                                                                                                                                                    • 234 Summary
                                                                                                                                                      • 24 Creating and deleting objects
                                                                                                                                                        • 241 Setup
                                                                                                                                                        • 242 Adding the delete path
                                                                                                                                                        • 243 Adding the delete view
                                                                                                                                                        • 244 Updating the delete link
                                                                                                                                                        • 245 Details
                                                                                                                                                        • 246 Summary
                                                                                                                                                          • 25 Authenticating users with Allauth
                                                                                                                                                            • 251 Setup
                                                                                                                                                            • 252 Installing Allauth
                                                                                                                                                            • 253 Creating template files
                                                                                                                                                            • 254 Updating the templates for Bootstrap 4
                                                                                                                                                            • 255 Details
                                                                                                                                                              • 2551 Configuration options
                                                                                                                                                              • 2552 Adding the paths
                                                                                                                                                              • 2553 django-widget-tweaks
                                                                                                                                                                • 256 Summary
                                                                                                                                                                  • 26 Authorization
                                                                                                                                                                    • 261 Setup
                                                                                                                                                                    • 262 Adding the Editor group
                                                                                                                                                                    • 263 Creating a test user
                                                                                                                                                                    • 264 Using permissions
                                                                                                                                                                    • 265 Using decorators
                                                                                                                                                                    • 266 Details
                                                                                                                                                                      • 2661 Authentication vs authorization
                                                                                                                                                                      • 2662 Controlling access with decorators
                                                                                                                                                                        • 267 Summary
                                                                                                                                                                          • 27 Creating an image gallery
                                                                                                                                                                            • 271 Setup
                                                                                                                                                                            • 272 Installing pillow
                                                                                                                                                                            • 273 Configuring media variables
                                                                                                                                                                            • 274 Adding ImageField
                                                                                                                                                                            • 275 Adding images to flowers
                                                                                                                                                                            • 276 Using the static helper function
                                                                                                                                                                            • 277 Adding the grid
                                                                                                                                                                            • 278 Details
                                                                                                                                                                            • 279 Summary
                                                                                                                                                                              • 28 Adding image thumbnails
                                                                                                                                                                                • 281 Setup
                                                                                                                                                                                • 282 Installing ImageKit
                                                                                                                                                                                • 283 Adding the thumbnail field
                                                                                                                                                                                • 284 Details
                                                                                                                                                                                • 285 Summary
                                                                                                                                                                                  • 29 Deploying on Heroku
                                                                                                                                                                                    • 291 Setup
                                                                                                                                                                                    • 292 Creating a Heroku app
                                                                                                                                                                                    • 293 Installing Heroku CLI
                                                                                                                                                                                      • 2931 Installation in Windows
                                                                                                                                                                                      • 2932 Installation in macOS
                                                                                                                                                                                      • 2933 Installation in Ubuntu
                                                                                                                                                                                      • 2934 Authenticating with a browser
                                                                                                                                                                                        • 294 Creating a Procfile
                                                                                                                                                                                        • 295 Updating the settingspy file
                                                                                                                                                                                        • 296 Creating the repository
                                                                                                                                                                                        • 297 Pushing changes
                                                                                                                                                                                        • 298 Updating the database
                                                                                                                                                                                        • 299 Summary
                                                                                                                                                                                          • 30 Using Amazon AWS to serve files
                                                                                                                                                                                            • 301 Setup
                                                                                                                                                                                            • 302 Creating an Amazon AWS bucket
                                                                                                                                                                                            • 303 Setting up permissions
                                                                                                                                                                                            • 304 Updating settingspy file
                                                                                                                                                                                            • 305 Adding an image field to the Post model
                                                                                                                                                                                            • 306 Installing packages
                                                                                                                                                                                            • 307 Summary
                                                                                                                                                                                              • 31 Setting up Heroku pipelines
                                                                                                                                                                                                • 311 Setup
                                                                                                                                                                                                • 312 Creating a GitHub repository
                                                                                                                                                                                                • 313 Creating a pipeline
                                                                                                                                                                                                • 314 Testing deployment
                                                                                                                                                                                                • 315 Adding a production app
                                                                                                                                                                                                • 316 Enabling review apps
                                                                                                                                                                                                • 317 Using pull requests
                                                                                                                                                                                                • 318 Deleting the branch
                                                                                                                                                                                                • 319 Summary
                                                                                                                                                                                                  • 32 Sending emails with SendGrid
                                                                                                                                                                                                    • 321 Creating an account
                                                                                                                                                                                                    • 322 Summary
                                                                                                                                                                                                      • Licenses
Page 6: Django - The Easy Way: A step-by-step guide on building Django websites, 2nd Edition

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
                                                                                        • 145 Summary
                                                                                          • 15 Creating a base project
                                                                                            • 151 Setup
                                                                                            • 152 Adding a description field
                                                                                            • 153 Adding masonry like columns
                                                                                            • 154 Adding a footer
                                                                                            • 155 Summary
                                                                                              • 16 Creating a detail page
                                                                                                • 161 Setup
                                                                                                • 162 Adding a detail page path
                                                                                                • 163 Creating the detail view
                                                                                                • 164 Creating the detail page template
                                                                                                • 165 Creating slugs
                                                                                                • 166 Updating the path
                                                                                                • 167 Defining get_absolute_url() method
                                                                                                • 168 Using url tag
                                                                                                • 169 Details
                                                                                                  • 1691 Capturing URL values
                                                                                                  • 1692 Using view parameters
                                                                                                  • 1693 Explaining slugs
                                                                                                  • 1694 Reversing URLS
                                                                                                    • 1610 Summary
                                                                                                      • 17 Adding category as a many-to-one relationhip
                                                                                                        • 171 Setup
                                                                                                        • 172 Adding category field and model
                                                                                                        • 173 Updating the homepage template
                                                                                                        • 174 Details
                                                                                                          • 1741 Examining many-to-one relationships
                                                                                                          • 1742 Accessing related objects
                                                                                                            • 175 Summary
                                                                                                              • 18 Referencing tags with a ManyToMany field
                                                                                                                • 181 Setup
                                                                                                                • 182 Adding the tags field
                                                                                                                • 183 Updating the homepage template
                                                                                                                • 184 Summary
                                                                                                                  • 19 Creating a tags page
                                                                                                                    • 191 Setup
                                                                                                                    • 192 Adding tags path
                                                                                                                    • 193 Adding the slug field
                                                                                                                    • 194 Creating the tags view
                                                                                                                    • 195 Updating homepage template
                                                                                                                    • 196 Details
                                                                                                                      • 1961 Doing lookups across relationships
                                                                                                                      • 1962 Reusing templates
                                                                                                                        • 197 Summary
                                                                                                                          • 20 Creating a search feature
                                                                                                                            • 201 Setup
                                                                                                                            • 202 Adding a search form
                                                                                                                            • 203 Updating the index view
                                                                                                                            • 204 Details
                                                                                                                            • 205 Summary
                                                                                                                              • 21 Working with forms creating items
                                                                                                                                • 211 Setup
                                                                                                                                • 212 Creating the edit form
                                                                                                                                • 213 Creating the form class
                                                                                                                                • 214 Updating urlpatterns
                                                                                                                                • 215 Creating the view function
                                                                                                                                • 216 Adding a menu item
                                                                                                                                • 217 Details
                                                                                                                                  • 2171 Protecting against cross site request forgeries
                                                                                                                                  • 2172 Adding form fields
                                                                                                                                  • 2173 Using the Form class
                                                                                                                                  • 2174 Examining the view function
                                                                                                                                    • 218 Summary
                                                                                                                                      • 22 Working with forms editing items
                                                                                                                                        • 221 Setup
                                                                                                                                        • 222 Adding the path
                                                                                                                                        • 223 Creating the edit view
                                                                                                                                        • 224 Updating the edit link
                                                                                                                                        • 225 Details
                                                                                                                                          • 2251 Capturing the id
                                                                                                                                          • 2252 Examining the edit view
                                                                                                                                            • 226 Summary
                                                                                                                                              • 23 Working with forms customization
                                                                                                                                                • 231 Setup
                                                                                                                                                • 232 Adding the description field
                                                                                                                                                • 233 Details
                                                                                                                                                  • 2331 Changing field order
                                                                                                                                                  • 2332 Customizing validation errors
                                                                                                                                                    • 234 Summary
                                                                                                                                                      • 24 Creating and deleting objects
                                                                                                                                                        • 241 Setup
                                                                                                                                                        • 242 Adding the delete path
                                                                                                                                                        • 243 Adding the delete view
                                                                                                                                                        • 244 Updating the delete link
                                                                                                                                                        • 245 Details
                                                                                                                                                        • 246 Summary
                                                                                                                                                          • 25 Authenticating users with Allauth
                                                                                                                                                            • 251 Setup
                                                                                                                                                            • 252 Installing Allauth
                                                                                                                                                            • 253 Creating template files
                                                                                                                                                            • 254 Updating the templates for Bootstrap 4
                                                                                                                                                            • 255 Details
                                                                                                                                                              • 2551 Configuration options
                                                                                                                                                              • 2552 Adding the paths
                                                                                                                                                              • 2553 django-widget-tweaks
                                                                                                                                                                • 256 Summary
                                                                                                                                                                  • 26 Authorization
                                                                                                                                                                    • 261 Setup
                                                                                                                                                                    • 262 Adding the Editor group
                                                                                                                                                                    • 263 Creating a test user
                                                                                                                                                                    • 264 Using permissions
                                                                                                                                                                    • 265 Using decorators
                                                                                                                                                                    • 266 Details
                                                                                                                                                                      • 2661 Authentication vs authorization
                                                                                                                                                                      • 2662 Controlling access with decorators
                                                                                                                                                                        • 267 Summary
                                                                                                                                                                          • 27 Creating an image gallery
                                                                                                                                                                            • 271 Setup
                                                                                                                                                                            • 272 Installing pillow
                                                                                                                                                                            • 273 Configuring media variables
                                                                                                                                                                            • 274 Adding ImageField
                                                                                                                                                                            • 275 Adding images to flowers
                                                                                                                                                                            • 276 Using the static helper function
                                                                                                                                                                            • 277 Adding the grid
                                                                                                                                                                            • 278 Details
                                                                                                                                                                            • 279 Summary
                                                                                                                                                                              • 28 Adding image thumbnails
                                                                                                                                                                                • 281 Setup
                                                                                                                                                                                • 282 Installing ImageKit
                                                                                                                                                                                • 283 Adding the thumbnail field
                                                                                                                                                                                • 284 Details
                                                                                                                                                                                • 285 Summary
                                                                                                                                                                                  • 29 Deploying on Heroku
                                                                                                                                                                                    • 291 Setup
                                                                                                                                                                                    • 292 Creating a Heroku app
                                                                                                                                                                                    • 293 Installing Heroku CLI
                                                                                                                                                                                      • 2931 Installation in Windows
                                                                                                                                                                                      • 2932 Installation in macOS
                                                                                                                                                                                      • 2933 Installation in Ubuntu
                                                                                                                                                                                      • 2934 Authenticating with a browser
                                                                                                                                                                                        • 294 Creating a Procfile
                                                                                                                                                                                        • 295 Updating the settingspy file
                                                                                                                                                                                        • 296 Creating the repository
                                                                                                                                                                                        • 297 Pushing changes
                                                                                                                                                                                        • 298 Updating the database
                                                                                                                                                                                        • 299 Summary
                                                                                                                                                                                          • 30 Using Amazon AWS to serve files
                                                                                                                                                                                            • 301 Setup
                                                                                                                                                                                            • 302 Creating an Amazon AWS bucket
                                                                                                                                                                                            • 303 Setting up permissions
                                                                                                                                                                                            • 304 Updating settingspy file
                                                                                                                                                                                            • 305 Adding an image field to the Post model
                                                                                                                                                                                            • 306 Installing packages
                                                                                                                                                                                            • 307 Summary
                                                                                                                                                                                              • 31 Setting up Heroku pipelines
                                                                                                                                                                                                • 311 Setup
                                                                                                                                                                                                • 312 Creating a GitHub repository
                                                                                                                                                                                                • 313 Creating a pipeline
                                                                                                                                                                                                • 314 Testing deployment
                                                                                                                                                                                                • 315 Adding a production app
                                                                                                                                                                                                • 316 Enabling review apps
                                                                                                                                                                                                • 317 Using pull requests
                                                                                                                                                                                                • 318 Deleting the branch
                                                                                                                                                                                                • 319 Summary
                                                                                                                                                                                                  • 32 Sending emails with SendGrid
                                                                                                                                                                                                    • 321 Creating an account
                                                                                                                                                                                                    • 322 Summary
                                                                                                                                                                                                      • Licenses
Page 7: Django - The Easy Way: A step-by-step guide on building Django websites, 2nd Edition

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
                                                                                        • 145 Summary
                                                                                          • 15 Creating a base project
                                                                                            • 151 Setup
                                                                                            • 152 Adding a description field
                                                                                            • 153 Adding masonry like columns
                                                                                            • 154 Adding a footer
                                                                                            • 155 Summary
                                                                                              • 16 Creating a detail page
                                                                                                • 161 Setup
                                                                                                • 162 Adding a detail page path
                                                                                                • 163 Creating the detail view
                                                                                                • 164 Creating the detail page template
                                                                                                • 165 Creating slugs
                                                                                                • 166 Updating the path
                                                                                                • 167 Defining get_absolute_url() method
                                                                                                • 168 Using url tag
                                                                                                • 169 Details
                                                                                                  • 1691 Capturing URL values
                                                                                                  • 1692 Using view parameters
                                                                                                  • 1693 Explaining slugs
                                                                                                  • 1694 Reversing URLS
                                                                                                    • 1610 Summary
                                                                                                      • 17 Adding category as a many-to-one relationhip
                                                                                                        • 171 Setup
                                                                                                        • 172 Adding category field and model
                                                                                                        • 173 Updating the homepage template
                                                                                                        • 174 Details
                                                                                                          • 1741 Examining many-to-one relationships
                                                                                                          • 1742 Accessing related objects
                                                                                                            • 175 Summary
                                                                                                              • 18 Referencing tags with a ManyToMany field
                                                                                                                • 181 Setup
                                                                                                                • 182 Adding the tags field
                                                                                                                • 183 Updating the homepage template
                                                                                                                • 184 Summary
                                                                                                                  • 19 Creating a tags page
                                                                                                                    • 191 Setup
                                                                                                                    • 192 Adding tags path
                                                                                                                    • 193 Adding the slug field
                                                                                                                    • 194 Creating the tags view
                                                                                                                    • 195 Updating homepage template
                                                                                                                    • 196 Details
                                                                                                                      • 1961 Doing lookups across relationships
                                                                                                                      • 1962 Reusing templates
                                                                                                                        • 197 Summary
                                                                                                                          • 20 Creating a search feature
                                                                                                                            • 201 Setup
                                                                                                                            • 202 Adding a search form
                                                                                                                            • 203 Updating the index view
                                                                                                                            • 204 Details
                                                                                                                            • 205 Summary
                                                                                                                              • 21 Working with forms creating items
                                                                                                                                • 211 Setup
                                                                                                                                • 212 Creating the edit form
                                                                                                                                • 213 Creating the form class
                                                                                                                                • 214 Updating urlpatterns
                                                                                                                                • 215 Creating the view function
                                                                                                                                • 216 Adding a menu item
                                                                                                                                • 217 Details
                                                                                                                                  • 2171 Protecting against cross site request forgeries
                                                                                                                                  • 2172 Adding form fields
                                                                                                                                  • 2173 Using the Form class
                                                                                                                                  • 2174 Examining the view function
                                                                                                                                    • 218 Summary
                                                                                                                                      • 22 Working with forms editing items
                                                                                                                                        • 221 Setup
                                                                                                                                        • 222 Adding the path
                                                                                                                                        • 223 Creating the edit view
                                                                                                                                        • 224 Updating the edit link
                                                                                                                                        • 225 Details
                                                                                                                                          • 2251 Capturing the id
                                                                                                                                          • 2252 Examining the edit view
                                                                                                                                            • 226 Summary
                                                                                                                                              • 23 Working with forms customization
                                                                                                                                                • 231 Setup
                                                                                                                                                • 232 Adding the description field
                                                                                                                                                • 233 Details
                                                                                                                                                  • 2331 Changing field order
                                                                                                                                                  • 2332 Customizing validation errors
                                                                                                                                                    • 234 Summary
                                                                                                                                                      • 24 Creating and deleting objects
                                                                                                                                                        • 241 Setup
                                                                                                                                                        • 242 Adding the delete path
                                                                                                                                                        • 243 Adding the delete view
                                                                                                                                                        • 244 Updating the delete link
                                                                                                                                                        • 245 Details
                                                                                                                                                        • 246 Summary
                                                                                                                                                          • 25 Authenticating users with Allauth
                                                                                                                                                            • 251 Setup
                                                                                                                                                            • 252 Installing Allauth
                                                                                                                                                            • 253 Creating template files
                                                                                                                                                            • 254 Updating the templates for Bootstrap 4
                                                                                                                                                            • 255 Details
                                                                                                                                                              • 2551 Configuration options
                                                                                                                                                              • 2552 Adding the paths
                                                                                                                                                              • 2553 django-widget-tweaks
                                                                                                                                                                • 256 Summary
                                                                                                                                                                  • 26 Authorization
                                                                                                                                                                    • 261 Setup
                                                                                                                                                                    • 262 Adding the Editor group
                                                                                                                                                                    • 263 Creating a test user
                                                                                                                                                                    • 264 Using permissions
                                                                                                                                                                    • 265 Using decorators
                                                                                                                                                                    • 266 Details
                                                                                                                                                                      • 2661 Authentication vs authorization
                                                                                                                                                                      • 2662 Controlling access with decorators
                                                                                                                                                                        • 267 Summary
                                                                                                                                                                          • 27 Creating an image gallery
                                                                                                                                                                            • 271 Setup
                                                                                                                                                                            • 272 Installing pillow
                                                                                                                                                                            • 273 Configuring media variables
                                                                                                                                                                            • 274 Adding ImageField
                                                                                                                                                                            • 275 Adding images to flowers
                                                                                                                                                                            • 276 Using the static helper function
                                                                                                                                                                            • 277 Adding the grid
                                                                                                                                                                            • 278 Details
                                                                                                                                                                            • 279 Summary
                                                                                                                                                                              • 28 Adding image thumbnails
                                                                                                                                                                                • 281 Setup
                                                                                                                                                                                • 282 Installing ImageKit
                                                                                                                                                                                • 283 Adding the thumbnail field
                                                                                                                                                                                • 284 Details
                                                                                                                                                                                • 285 Summary
                                                                                                                                                                                  • 29 Deploying on Heroku
                                                                                                                                                                                    • 291 Setup
                                                                                                                                                                                    • 292 Creating a Heroku app
                                                                                                                                                                                    • 293 Installing Heroku CLI
                                                                                                                                                                                      • 2931 Installation in Windows
                                                                                                                                                                                      • 2932 Installation in macOS
                                                                                                                                                                                      • 2933 Installation in Ubuntu
                                                                                                                                                                                      • 2934 Authenticating with a browser
                                                                                                                                                                                        • 294 Creating a Procfile
                                                                                                                                                                                        • 295 Updating the settingspy file
                                                                                                                                                                                        • 296 Creating the repository
                                                                                                                                                                                        • 297 Pushing changes
                                                                                                                                                                                        • 298 Updating the database
                                                                                                                                                                                        • 299 Summary
                                                                                                                                                                                          • 30 Using Amazon AWS to serve files
                                                                                                                                                                                            • 301 Setup
                                                                                                                                                                                            • 302 Creating an Amazon AWS bucket
                                                                                                                                                                                            • 303 Setting up permissions
                                                                                                                                                                                            • 304 Updating settingspy file
                                                                                                                                                                                            • 305 Adding an image field to the Post model
                                                                                                                                                                                            • 306 Installing packages
                                                                                                                                                                                            • 307 Summary
                                                                                                                                                                                              • 31 Setting up Heroku pipelines
                                                                                                                                                                                                • 311 Setup
                                                                                                                                                                                                • 312 Creating a GitHub repository
                                                                                                                                                                                                • 313 Creating a pipeline
                                                                                                                                                                                                • 314 Testing deployment
                                                                                                                                                                                                • 315 Adding a production app
                                                                                                                                                                                                • 316 Enabling review apps
                                                                                                                                                                                                • 317 Using pull requests
                                                                                                                                                                                                • 318 Deleting the branch
                                                                                                                                                                                                • 319 Summary
                                                                                                                                                                                                  • 32 Sending emails with SendGrid
                                                                                                                                                                                                    • 321 Creating an account
                                                                                                                                                                                                    • 322 Summary
                                                                                                                                                                                                      • Licenses
Page 8: Django - The Easy Way: A step-by-step guide on building Django websites, 2nd Edition

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
                                                                                        • 145 Summary
                                                                                          • 15 Creating a base project
                                                                                            • 151 Setup
                                                                                            • 152 Adding a description field
                                                                                            • 153 Adding masonry like columns
                                                                                            • 154 Adding a footer
                                                                                            • 155 Summary
                                                                                              • 16 Creating a detail page
                                                                                                • 161 Setup
                                                                                                • 162 Adding a detail page path
                                                                                                • 163 Creating the detail view
                                                                                                • 164 Creating the detail page template
                                                                                                • 165 Creating slugs
                                                                                                • 166 Updating the path
                                                                                                • 167 Defining get_absolute_url() method
                                                                                                • 168 Using url tag
                                                                                                • 169 Details
                                                                                                  • 1691 Capturing URL values
                                                                                                  • 1692 Using view parameters
                                                                                                  • 1693 Explaining slugs
                                                                                                  • 1694 Reversing URLS
                                                                                                    • 1610 Summary
                                                                                                      • 17 Adding category as a many-to-one relationhip
                                                                                                        • 171 Setup
                                                                                                        • 172 Adding category field and model
                                                                                                        • 173 Updating the homepage template
                                                                                                        • 174 Details
                                                                                                          • 1741 Examining many-to-one relationships
                                                                                                          • 1742 Accessing related objects
                                                                                                            • 175 Summary
                                                                                                              • 18 Referencing tags with a ManyToMany field
                                                                                                                • 181 Setup
                                                                                                                • 182 Adding the tags field
                                                                                                                • 183 Updating the homepage template
                                                                                                                • 184 Summary
                                                                                                                  • 19 Creating a tags page
                                                                                                                    • 191 Setup
                                                                                                                    • 192 Adding tags path
                                                                                                                    • 193 Adding the slug field
                                                                                                                    • 194 Creating the tags view
                                                                                                                    • 195 Updating homepage template
                                                                                                                    • 196 Details
                                                                                                                      • 1961 Doing lookups across relationships
                                                                                                                      • 1962 Reusing templates
                                                                                                                        • 197 Summary
                                                                                                                          • 20 Creating a search feature
                                                                                                                            • 201 Setup
                                                                                                                            • 202 Adding a search form
                                                                                                                            • 203 Updating the index view
                                                                                                                            • 204 Details
                                                                                                                            • 205 Summary
                                                                                                                              • 21 Working with forms creating items
                                                                                                                                • 211 Setup
                                                                                                                                • 212 Creating the edit form
                                                                                                                                • 213 Creating the form class
                                                                                                                                • 214 Updating urlpatterns
                                                                                                                                • 215 Creating the view function
                                                                                                                                • 216 Adding a menu item
                                                                                                                                • 217 Details
                                                                                                                                  • 2171 Protecting against cross site request forgeries
                                                                                                                                  • 2172 Adding form fields
                                                                                                                                  • 2173 Using the Form class
                                                                                                                                  • 2174 Examining the view function
                                                                                                                                    • 218 Summary
                                                                                                                                      • 22 Working with forms editing items
                                                                                                                                        • 221 Setup
                                                                                                                                        • 222 Adding the path
                                                                                                                                        • 223 Creating the edit view
                                                                                                                                        • 224 Updating the edit link
                                                                                                                                        • 225 Details
                                                                                                                                          • 2251 Capturing the id
                                                                                                                                          • 2252 Examining the edit view
                                                                                                                                            • 226 Summary
                                                                                                                                              • 23 Working with forms customization
                                                                                                                                                • 231 Setup
                                                                                                                                                • 232 Adding the description field
                                                                                                                                                • 233 Details
                                                                                                                                                  • 2331 Changing field order
                                                                                                                                                  • 2332 Customizing validation errors
                                                                                                                                                    • 234 Summary
                                                                                                                                                      • 24 Creating and deleting objects
                                                                                                                                                        • 241 Setup
                                                                                                                                                        • 242 Adding the delete path
                                                                                                                                                        • 243 Adding the delete view
                                                                                                                                                        • 244 Updating the delete link
                                                                                                                                                        • 245 Details
                                                                                                                                                        • 246 Summary
                                                                                                                                                          • 25 Authenticating users with Allauth
                                                                                                                                                            • 251 Setup
                                                                                                                                                            • 252 Installing Allauth
                                                                                                                                                            • 253 Creating template files
                                                                                                                                                            • 254 Updating the templates for Bootstrap 4
                                                                                                                                                            • 255 Details
                                                                                                                                                              • 2551 Configuration options
                                                                                                                                                              • 2552 Adding the paths
                                                                                                                                                              • 2553 django-widget-tweaks
                                                                                                                                                                • 256 Summary
                                                                                                                                                                  • 26 Authorization
                                                                                                                                                                    • 261 Setup
                                                                                                                                                                    • 262 Adding the Editor group
                                                                                                                                                                    • 263 Creating a test user
                                                                                                                                                                    • 264 Using permissions
                                                                                                                                                                    • 265 Using decorators
                                                                                                                                                                    • 266 Details
                                                                                                                                                                      • 2661 Authentication vs authorization
                                                                                                                                                                      • 2662 Controlling access with decorators
                                                                                                                                                                        • 267 Summary
                                                                                                                                                                          • 27 Creating an image gallery
                                                                                                                                                                            • 271 Setup
                                                                                                                                                                            • 272 Installing pillow
                                                                                                                                                                            • 273 Configuring media variables
                                                                                                                                                                            • 274 Adding ImageField
                                                                                                                                                                            • 275 Adding images to flowers
                                                                                                                                                                            • 276 Using the static helper function
                                                                                                                                                                            • 277 Adding the grid
                                                                                                                                                                            • 278 Details
                                                                                                                                                                            • 279 Summary
                                                                                                                                                                              • 28 Adding image thumbnails
                                                                                                                                                                                • 281 Setup
                                                                                                                                                                                • 282 Installing ImageKit
                                                                                                                                                                                • 283 Adding the thumbnail field
                                                                                                                                                                                • 284 Details
                                                                                                                                                                                • 285 Summary
                                                                                                                                                                                  • 29 Deploying on Heroku
                                                                                                                                                                                    • 291 Setup
                                                                                                                                                                                    • 292 Creating a Heroku app
                                                                                                                                                                                    • 293 Installing Heroku CLI
                                                                                                                                                                                      • 2931 Installation in Windows
                                                                                                                                                                                      • 2932 Installation in macOS
                                                                                                                                                                                      • 2933 Installation in Ubuntu
                                                                                                                                                                                      • 2934 Authenticating with a browser
                                                                                                                                                                                        • 294 Creating a Procfile
                                                                                                                                                                                        • 295 Updating the settingspy file
                                                                                                                                                                                        • 296 Creating the repository
                                                                                                                                                                                        • 297 Pushing changes
                                                                                                                                                                                        • 298 Updating the database
                                                                                                                                                                                        • 299 Summary
                                                                                                                                                                                          • 30 Using Amazon AWS to serve files
                                                                                                                                                                                            • 301 Setup
                                                                                                                                                                                            • 302 Creating an Amazon AWS bucket
                                                                                                                                                                                            • 303 Setting up permissions
                                                                                                                                                                                            • 304 Updating settingspy file
                                                                                                                                                                                            • 305 Adding an image field to the Post model
                                                                                                                                                                                            • 306 Installing packages
                                                                                                                                                                                            • 307 Summary
                                                                                                                                                                                              • 31 Setting up Heroku pipelines
                                                                                                                                                                                                • 311 Setup
                                                                                                                                                                                                • 312 Creating a GitHub repository
                                                                                                                                                                                                • 313 Creating a pipeline
                                                                                                                                                                                                • 314 Testing deployment
                                                                                                                                                                                                • 315 Adding a production app
                                                                                                                                                                                                • 316 Enabling review apps
                                                                                                                                                                                                • 317 Using pull requests
                                                                                                                                                                                                • 318 Deleting the branch
                                                                                                                                                                                                • 319 Summary
                                                                                                                                                                                                  • 32 Sending emails with SendGrid
                                                                                                                                                                                                    • 321 Creating an account
                                                                                                                                                                                                    • 322 Summary
                                                                                                                                                                                                      • Licenses
Page 9: Django - The Easy Way: A step-by-step guide on building Django websites, 2nd Edition

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
                                                                                        • 145 Summary
                                                                                          • 15 Creating a base project
                                                                                            • 151 Setup
                                                                                            • 152 Adding a description field
                                                                                            • 153 Adding masonry like columns
                                                                                            • 154 Adding a footer
                                                                                            • 155 Summary
                                                                                              • 16 Creating a detail page
                                                                                                • 161 Setup
                                                                                                • 162 Adding a detail page path
                                                                                                • 163 Creating the detail view
                                                                                                • 164 Creating the detail page template
                                                                                                • 165 Creating slugs
                                                                                                • 166 Updating the path
                                                                                                • 167 Defining get_absolute_url() method
                                                                                                • 168 Using url tag
                                                                                                • 169 Details
                                                                                                  • 1691 Capturing URL values
                                                                                                  • 1692 Using view parameters
                                                                                                  • 1693 Explaining slugs
                                                                                                  • 1694 Reversing URLS
                                                                                                    • 1610 Summary
                                                                                                      • 17 Adding category as a many-to-one relationhip
                                                                                                        • 171 Setup
                                                                                                        • 172 Adding category field and model
                                                                                                        • 173 Updating the homepage template
                                                                                                        • 174 Details
                                                                                                          • 1741 Examining many-to-one relationships
                                                                                                          • 1742 Accessing related objects
                                                                                                            • 175 Summary
                                                                                                              • 18 Referencing tags with a ManyToMany field
                                                                                                                • 181 Setup
                                                                                                                • 182 Adding the tags field
                                                                                                                • 183 Updating the homepage template
                                                                                                                • 184 Summary
                                                                                                                  • 19 Creating a tags page
                                                                                                                    • 191 Setup
                                                                                                                    • 192 Adding tags path
                                                                                                                    • 193 Adding the slug field
                                                                                                                    • 194 Creating the tags view
                                                                                                                    • 195 Updating homepage template
                                                                                                                    • 196 Details
                                                                                                                      • 1961 Doing lookups across relationships
                                                                                                                      • 1962 Reusing templates
                                                                                                                        • 197 Summary
                                                                                                                          • 20 Creating a search feature
                                                                                                                            • 201 Setup
                                                                                                                            • 202 Adding a search form
                                                                                                                            • 203 Updating the index view
                                                                                                                            • 204 Details
                                                                                                                            • 205 Summary
                                                                                                                              • 21 Working with forms creating items
                                                                                                                                • 211 Setup
                                                                                                                                • 212 Creating the edit form
                                                                                                                                • 213 Creating the form class
                                                                                                                                • 214 Updating urlpatterns
                                                                                                                                • 215 Creating the view function
                                                                                                                                • 216 Adding a menu item
                                                                                                                                • 217 Details
                                                                                                                                  • 2171 Protecting against cross site request forgeries
                                                                                                                                  • 2172 Adding form fields
                                                                                                                                  • 2173 Using the Form class
                                                                                                                                  • 2174 Examining the view function
                                                                                                                                    • 218 Summary
                                                                                                                                      • 22 Working with forms editing items
                                                                                                                                        • 221 Setup
                                                                                                                                        • 222 Adding the path
                                                                                                                                        • 223 Creating the edit view
                                                                                                                                        • 224 Updating the edit link
                                                                                                                                        • 225 Details
                                                                                                                                          • 2251 Capturing the id
                                                                                                                                          • 2252 Examining the edit view
                                                                                                                                            • 226 Summary
                                                                                                                                              • 23 Working with forms customization
                                                                                                                                                • 231 Setup
                                                                                                                                                • 232 Adding the description field
                                                                                                                                                • 233 Details
                                                                                                                                                  • 2331 Changing field order
                                                                                                                                                  • 2332 Customizing validation errors
                                                                                                                                                    • 234 Summary
                                                                                                                                                      • 24 Creating and deleting objects
                                                                                                                                                        • 241 Setup
                                                                                                                                                        • 242 Adding the delete path
                                                                                                                                                        • 243 Adding the delete view
                                                                                                                                                        • 244 Updating the delete link
                                                                                                                                                        • 245 Details
                                                                                                                                                        • 246 Summary
                                                                                                                                                          • 25 Authenticating users with Allauth
                                                                                                                                                            • 251 Setup
                                                                                                                                                            • 252 Installing Allauth
                                                                                                                                                            • 253 Creating template files
                                                                                                                                                            • 254 Updating the templates for Bootstrap 4
                                                                                                                                                            • 255 Details
                                                                                                                                                              • 2551 Configuration options
                                                                                                                                                              • 2552 Adding the paths
                                                                                                                                                              • 2553 django-widget-tweaks
                                                                                                                                                                • 256 Summary
                                                                                                                                                                  • 26 Authorization
                                                                                                                                                                    • 261 Setup
                                                                                                                                                                    • 262 Adding the Editor group
                                                                                                                                                                    • 263 Creating a test user
                                                                                                                                                                    • 264 Using permissions
                                                                                                                                                                    • 265 Using decorators
                                                                                                                                                                    • 266 Details
                                                                                                                                                                      • 2661 Authentication vs authorization
                                                                                                                                                                      • 2662 Controlling access with decorators
                                                                                                                                                                        • 267 Summary
                                                                                                                                                                          • 27 Creating an image gallery
                                                                                                                                                                            • 271 Setup
                                                                                                                                                                            • 272 Installing pillow
                                                                                                                                                                            • 273 Configuring media variables
                                                                                                                                                                            • 274 Adding ImageField
                                                                                                                                                                            • 275 Adding images to flowers
                                                                                                                                                                            • 276 Using the static helper function
                                                                                                                                                                            • 277 Adding the grid
                                                                                                                                                                            • 278 Details
                                                                                                                                                                            • 279 Summary
                                                                                                                                                                              • 28 Adding image thumbnails
                                                                                                                                                                                • 281 Setup
                                                                                                                                                                                • 282 Installing ImageKit
                                                                                                                                                                                • 283 Adding the thumbnail field
                                                                                                                                                                                • 284 Details
                                                                                                                                                                                • 285 Summary
                                                                                                                                                                                  • 29 Deploying on Heroku
                                                                                                                                                                                    • 291 Setup
                                                                                                                                                                                    • 292 Creating a Heroku app
                                                                                                                                                                                    • 293 Installing Heroku CLI
                                                                                                                                                                                      • 2931 Installation in Windows
                                                                                                                                                                                      • 2932 Installation in macOS
                                                                                                                                                                                      • 2933 Installation in Ubuntu
                                                                                                                                                                                      • 2934 Authenticating with a browser
                                                                                                                                                                                        • 294 Creating a Procfile
                                                                                                                                                                                        • 295 Updating the settingspy file
                                                                                                                                                                                        • 296 Creating the repository
                                                                                                                                                                                        • 297 Pushing changes
                                                                                                                                                                                        • 298 Updating the database
                                                                                                                                                                                        • 299 Summary
                                                                                                                                                                                          • 30 Using Amazon AWS to serve files
                                                                                                                                                                                            • 301 Setup
                                                                                                                                                                                            • 302 Creating an Amazon AWS bucket
                                                                                                                                                                                            • 303 Setting up permissions
                                                                                                                                                                                            • 304 Updating settingspy file
                                                                                                                                                                                            • 305 Adding an image field to the Post model
                                                                                                                                                                                            • 306 Installing packages
                                                                                                                                                                                            • 307 Summary
                                                                                                                                                                                              • 31 Setting up Heroku pipelines
                                                                                                                                                                                                • 311 Setup
                                                                                                                                                                                                • 312 Creating a GitHub repository
                                                                                                                                                                                                • 313 Creating a pipeline
                                                                                                                                                                                                • 314 Testing deployment
                                                                                                                                                                                                • 315 Adding a production app
                                                                                                                                                                                                • 316 Enabling review apps
                                                                                                                                                                                                • 317 Using pull requests
                                                                                                                                                                                                • 318 Deleting the branch
                                                                                                                                                                                                • 319 Summary
                                                                                                                                                                                                  • 32 Sending emails with SendGrid
                                                                                                                                                                                                    • 321 Creating an account
                                                                                                                                                                                                    • 322 Summary
                                                                                                                                                                                                      • Licenses
Page 10: Django - The Easy Way: A step-by-step guide on building Django websites, 2nd Edition

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
                                                                                        • 145 Summary
                                                                                          • 15 Creating a base project
                                                                                            • 151 Setup
                                                                                            • 152 Adding a description field
                                                                                            • 153 Adding masonry like columns
                                                                                            • 154 Adding a footer
                                                                                            • 155 Summary
                                                                                              • 16 Creating a detail page
                                                                                                • 161 Setup
                                                                                                • 162 Adding a detail page path
                                                                                                • 163 Creating the detail view
                                                                                                • 164 Creating the detail page template
                                                                                                • 165 Creating slugs
                                                                                                • 166 Updating the path
                                                                                                • 167 Defining get_absolute_url() method
                                                                                                • 168 Using url tag
                                                                                                • 169 Details
                                                                                                  • 1691 Capturing URL values
                                                                                                  • 1692 Using view parameters
                                                                                                  • 1693 Explaining slugs
                                                                                                  • 1694 Reversing URLS
                                                                                                    • 1610 Summary
                                                                                                      • 17 Adding category as a many-to-one relationhip
                                                                                                        • 171 Setup
                                                                                                        • 172 Adding category field and model
                                                                                                        • 173 Updating the homepage template
                                                                                                        • 174 Details
                                                                                                          • 1741 Examining many-to-one relationships
                                                                                                          • 1742 Accessing related objects
                                                                                                            • 175 Summary
                                                                                                              • 18 Referencing tags with a ManyToMany field
                                                                                                                • 181 Setup
                                                                                                                • 182 Adding the tags field
                                                                                                                • 183 Updating the homepage template
                                                                                                                • 184 Summary
                                                                                                                  • 19 Creating a tags page
                                                                                                                    • 191 Setup
                                                                                                                    • 192 Adding tags path
                                                                                                                    • 193 Adding the slug field
                                                                                                                    • 194 Creating the tags view
                                                                                                                    • 195 Updating homepage template
                                                                                                                    • 196 Details
                                                                                                                      • 1961 Doing lookups across relationships
                                                                                                                      • 1962 Reusing templates
                                                                                                                        • 197 Summary
                                                                                                                          • 20 Creating a search feature
                                                                                                                            • 201 Setup
                                                                                                                            • 202 Adding a search form
                                                                                                                            • 203 Updating the index view
                                                                                                                            • 204 Details
                                                                                                                            • 205 Summary
                                                                                                                              • 21 Working with forms creating items
                                                                                                                                • 211 Setup
                                                                                                                                • 212 Creating the edit form
                                                                                                                                • 213 Creating the form class
                                                                                                                                • 214 Updating urlpatterns
                                                                                                                                • 215 Creating the view function
                                                                                                                                • 216 Adding a menu item
                                                                                                                                • 217 Details
                                                                                                                                  • 2171 Protecting against cross site request forgeries
                                                                                                                                  • 2172 Adding form fields
                                                                                                                                  • 2173 Using the Form class
                                                                                                                                  • 2174 Examining the view function
                                                                                                                                    • 218 Summary
                                                                                                                                      • 22 Working with forms editing items
                                                                                                                                        • 221 Setup
                                                                                                                                        • 222 Adding the path
                                                                                                                                        • 223 Creating the edit view
                                                                                                                                        • 224 Updating the edit link
                                                                                                                                        • 225 Details
                                                                                                                                          • 2251 Capturing the id
                                                                                                                                          • 2252 Examining the edit view
                                                                                                                                            • 226 Summary
                                                                                                                                              • 23 Working with forms customization
                                                                                                                                                • 231 Setup
                                                                                                                                                • 232 Adding the description field
                                                                                                                                                • 233 Details
                                                                                                                                                  • 2331 Changing field order
                                                                                                                                                  • 2332 Customizing validation errors
                                                                                                                                                    • 234 Summary
                                                                                                                                                      • 24 Creating and deleting objects
                                                                                                                                                        • 241 Setup
                                                                                                                                                        • 242 Adding the delete path
                                                                                                                                                        • 243 Adding the delete view
                                                                                                                                                        • 244 Updating the delete link
                                                                                                                                                        • 245 Details
                                                                                                                                                        • 246 Summary
                                                                                                                                                          • 25 Authenticating users with Allauth
                                                                                                                                                            • 251 Setup
                                                                                                                                                            • 252 Installing Allauth
                                                                                                                                                            • 253 Creating template files
                                                                                                                                                            • 254 Updating the templates for Bootstrap 4
                                                                                                                                                            • 255 Details
                                                                                                                                                              • 2551 Configuration options
                                                                                                                                                              • 2552 Adding the paths
                                                                                                                                                              • 2553 django-widget-tweaks
                                                                                                                                                                • 256 Summary
                                                                                                                                                                  • 26 Authorization
                                                                                                                                                                    • 261 Setup
                                                                                                                                                                    • 262 Adding the Editor group
                                                                                                                                                                    • 263 Creating a test user
                                                                                                                                                                    • 264 Using permissions
                                                                                                                                                                    • 265 Using decorators
                                                                                                                                                                    • 266 Details
                                                                                                                                                                      • 2661 Authentication vs authorization
                                                                                                                                                                      • 2662 Controlling access with decorators
                                                                                                                                                                        • 267 Summary
                                                                                                                                                                          • 27 Creating an image gallery
                                                                                                                                                                            • 271 Setup
                                                                                                                                                                            • 272 Installing pillow
                                                                                                                                                                            • 273 Configuring media variables
                                                                                                                                                                            • 274 Adding ImageField
                                                                                                                                                                            • 275 Adding images to flowers
                                                                                                                                                                            • 276 Using the static helper function
                                                                                                                                                                            • 277 Adding the grid
                                                                                                                                                                            • 278 Details
                                                                                                                                                                            • 279 Summary
                                                                                                                                                                              • 28 Adding image thumbnails
                                                                                                                                                                                • 281 Setup
                                                                                                                                                                                • 282 Installing ImageKit
                                                                                                                                                                                • 283 Adding the thumbnail field
                                                                                                                                                                                • 284 Details
                                                                                                                                                                                • 285 Summary
                                                                                                                                                                                  • 29 Deploying on Heroku
                                                                                                                                                                                    • 291 Setup
                                                                                                                                                                                    • 292 Creating a Heroku app
                                                                                                                                                                                    • 293 Installing Heroku CLI
                                                                                                                                                                                      • 2931 Installation in Windows
                                                                                                                                                                                      • 2932 Installation in macOS
                                                                                                                                                                                      • 2933 Installation in Ubuntu
                                                                                                                                                                                      • 2934 Authenticating with a browser
                                                                                                                                                                                        • 294 Creating a Procfile
                                                                                                                                                                                        • 295 Updating the settingspy file
                                                                                                                                                                                        • 296 Creating the repository
                                                                                                                                                                                        • 297 Pushing changes
                                                                                                                                                                                        • 298 Updating the database
                                                                                                                                                                                        • 299 Summary
                                                                                                                                                                                          • 30 Using Amazon AWS to serve files
                                                                                                                                                                                            • 301 Setup
                                                                                                                                                                                            • 302 Creating an Amazon AWS bucket
                                                                                                                                                                                            • 303 Setting up permissions
                                                                                                                                                                                            • 304 Updating settingspy file
                                                                                                                                                                                            • 305 Adding an image field to the Post model
                                                                                                                                                                                            • 306 Installing packages
                                                                                                                                                                                            • 307 Summary
                                                                                                                                                                                              • 31 Setting up Heroku pipelines
                                                                                                                                                                                                • 311 Setup
                                                                                                                                                                                                • 312 Creating a GitHub repository
                                                                                                                                                                                                • 313 Creating a pipeline
                                                                                                                                                                                                • 314 Testing deployment
                                                                                                                                                                                                • 315 Adding a production app
                                                                                                                                                                                                • 316 Enabling review apps
                                                                                                                                                                                                • 317 Using pull requests
                                                                                                                                                                                                • 318 Deleting the branch
                                                                                                                                                                                                • 319 Summary
                                                                                                                                                                                                  • 32 Sending emails with SendGrid
                                                                                                                                                                                                    • 321 Creating an account
                                                                                                                                                                                                    • 322 Summary
                                                                                                                                                                                                      • Licenses
Page 11: Django - The Easy Way: A step-by-step guide on building Django websites, 2nd Edition

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
                                                                                        • 145 Summary
                                                                                          • 15 Creating a base project
                                                                                            • 151 Setup
                                                                                            • 152 Adding a description field
                                                                                            • 153 Adding masonry like columns
                                                                                            • 154 Adding a footer
                                                                                            • 155 Summary
                                                                                              • 16 Creating a detail page
                                                                                                • 161 Setup
                                                                                                • 162 Adding a detail page path
                                                                                                • 163 Creating the detail view
                                                                                                • 164 Creating the detail page template
                                                                                                • 165 Creating slugs
                                                                                                • 166 Updating the path
                                                                                                • 167 Defining get_absolute_url() method
                                                                                                • 168 Using url tag
                                                                                                • 169 Details
                                                                                                  • 1691 Capturing URL values
                                                                                                  • 1692 Using view parameters
                                                                                                  • 1693 Explaining slugs
                                                                                                  • 1694 Reversing URLS
                                                                                                    • 1610 Summary
                                                                                                      • 17 Adding category as a many-to-one relationhip
                                                                                                        • 171 Setup
                                                                                                        • 172 Adding category field and model
                                                                                                        • 173 Updating the homepage template
                                                                                                        • 174 Details
                                                                                                          • 1741 Examining many-to-one relationships
                                                                                                          • 1742 Accessing related objects
                                                                                                            • 175 Summary
                                                                                                              • 18 Referencing tags with a ManyToMany field
                                                                                                                • 181 Setup
                                                                                                                • 182 Adding the tags field
                                                                                                                • 183 Updating the homepage template
                                                                                                                • 184 Summary
                                                                                                                  • 19 Creating a tags page
                                                                                                                    • 191 Setup
                                                                                                                    • 192 Adding tags path
                                                                                                                    • 193 Adding the slug field
                                                                                                                    • 194 Creating the tags view
                                                                                                                    • 195 Updating homepage template
                                                                                                                    • 196 Details
                                                                                                                      • 1961 Doing lookups across relationships
                                                                                                                      • 1962 Reusing templates
                                                                                                                        • 197 Summary
                                                                                                                          • 20 Creating a search feature
                                                                                                                            • 201 Setup
                                                                                                                            • 202 Adding a search form
                                                                                                                            • 203 Updating the index view
                                                                                                                            • 204 Details
                                                                                                                            • 205 Summary
                                                                                                                              • 21 Working with forms creating items
                                                                                                                                • 211 Setup
                                                                                                                                • 212 Creating the edit form
                                                                                                                                • 213 Creating the form class
                                                                                                                                • 214 Updating urlpatterns
                                                                                                                                • 215 Creating the view function
                                                                                                                                • 216 Adding a menu item
                                                                                                                                • 217 Details
                                                                                                                                  • 2171 Protecting against cross site request forgeries
                                                                                                                                  • 2172 Adding form fields
                                                                                                                                  • 2173 Using the Form class
                                                                                                                                  • 2174 Examining the view function
                                                                                                                                    • 218 Summary
                                                                                                                                      • 22 Working with forms editing items
                                                                                                                                        • 221 Setup
                                                                                                                                        • 222 Adding the path
                                                                                                                                        • 223 Creating the edit view
                                                                                                                                        • 224 Updating the edit link
                                                                                                                                        • 225 Details
                                                                                                                                          • 2251 Capturing the id
                                                                                                                                          • 2252 Examining the edit view
                                                                                                                                            • 226 Summary
                                                                                                                                              • 23 Working with forms customization
                                                                                                                                                • 231 Setup
                                                                                                                                                • 232 Adding the description field
                                                                                                                                                • 233 Details
                                                                                                                                                  • 2331 Changing field order
                                                                                                                                                  • 2332 Customizing validation errors
                                                                                                                                                    • 234 Summary
                                                                                                                                                      • 24 Creating and deleting objects
                                                                                                                                                        • 241 Setup
                                                                                                                                                        • 242 Adding the delete path
                                                                                                                                                        • 243 Adding the delete view
                                                                                                                                                        • 244 Updating the delete link
                                                                                                                                                        • 245 Details
                                                                                                                                                        • 246 Summary
                                                                                                                                                          • 25 Authenticating users with Allauth
                                                                                                                                                            • 251 Setup
                                                                                                                                                            • 252 Installing Allauth
                                                                                                                                                            • 253 Creating template files
                                                                                                                                                            • 254 Updating the templates for Bootstrap 4
                                                                                                                                                            • 255 Details
                                                                                                                                                              • 2551 Configuration options
                                                                                                                                                              • 2552 Adding the paths
                                                                                                                                                              • 2553 django-widget-tweaks
                                                                                                                                                                • 256 Summary
                                                                                                                                                                  • 26 Authorization
                                                                                                                                                                    • 261 Setup
                                                                                                                                                                    • 262 Adding the Editor group
                                                                                                                                                                    • 263 Creating a test user
                                                                                                                                                                    • 264 Using permissions
                                                                                                                                                                    • 265 Using decorators
                                                                                                                                                                    • 266 Details
                                                                                                                                                                      • 2661 Authentication vs authorization
                                                                                                                                                                      • 2662 Controlling access with decorators
                                                                                                                                                                        • 267 Summary
                                                                                                                                                                          • 27 Creating an image gallery
                                                                                                                                                                            • 271 Setup
                                                                                                                                                                            • 272 Installing pillow
                                                                                                                                                                            • 273 Configuring media variables
                                                                                                                                                                            • 274 Adding ImageField
                                                                                                                                                                            • 275 Adding images to flowers
                                                                                                                                                                            • 276 Using the static helper function
                                                                                                                                                                            • 277 Adding the grid
                                                                                                                                                                            • 278 Details
                                                                                                                                                                            • 279 Summary
                                                                                                                                                                              • 28 Adding image thumbnails
                                                                                                                                                                                • 281 Setup
                                                                                                                                                                                • 282 Installing ImageKit
                                                                                                                                                                                • 283 Adding the thumbnail field
                                                                                                                                                                                • 284 Details
                                                                                                                                                                                • 285 Summary
                                                                                                                                                                                  • 29 Deploying on Heroku
                                                                                                                                                                                    • 291 Setup
                                                                                                                                                                                    • 292 Creating a Heroku app
                                                                                                                                                                                    • 293 Installing Heroku CLI
                                                                                                                                                                                      • 2931 Installation in Windows
                                                                                                                                                                                      • 2932 Installation in macOS
                                                                                                                                                                                      • 2933 Installation in Ubuntu
                                                                                                                                                                                      • 2934 Authenticating with a browser
                                                                                                                                                                                        • 294 Creating a Procfile
                                                                                                                                                                                        • 295 Updating the settingspy file
                                                                                                                                                                                        • 296 Creating the repository
                                                                                                                                                                                        • 297 Pushing changes
                                                                                                                                                                                        • 298 Updating the database
                                                                                                                                                                                        • 299 Summary
                                                                                                                                                                                          • 30 Using Amazon AWS to serve files
                                                                                                                                                                                            • 301 Setup
                                                                                                                                                                                            • 302 Creating an Amazon AWS bucket
                                                                                                                                                                                            • 303 Setting up permissions
                                                                                                                                                                                            • 304 Updating settingspy file
                                                                                                                                                                                            • 305 Adding an image field to the Post model
                                                                                                                                                                                            • 306 Installing packages
                                                                                                                                                                                            • 307 Summary
                                                                                                                                                                                              • 31 Setting up Heroku pipelines
                                                                                                                                                                                                • 311 Setup
                                                                                                                                                                                                • 312 Creating a GitHub repository
                                                                                                                                                                                                • 313 Creating a pipeline
                                                                                                                                                                                                • 314 Testing deployment
                                                                                                                                                                                                • 315 Adding a production app
                                                                                                                                                                                                • 316 Enabling review apps
                                                                                                                                                                                                • 317 Using pull requests
                                                                                                                                                                                                • 318 Deleting the branch
                                                                                                                                                                                                • 319 Summary
                                                                                                                                                                                                  • 32 Sending emails with SendGrid
                                                                                                                                                                                                    • 321 Creating an account
                                                                                                                                                                                                    • 322 Summary
                                                                                                                                                                                                      • Licenses
Page 12: Django - The Easy Way: A step-by-step guide on building Django websites, 2nd Edition

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
                                                                                        • 145 Summary
                                                                                          • 15 Creating a base project
                                                                                            • 151 Setup
                                                                                            • 152 Adding a description field
                                                                                            • 153 Adding masonry like columns
                                                                                            • 154 Adding a footer
                                                                                            • 155 Summary
                                                                                              • 16 Creating a detail page
                                                                                                • 161 Setup
                                                                                                • 162 Adding a detail page path
                                                                                                • 163 Creating the detail view
                                                                                                • 164 Creating the detail page template
                                                                                                • 165 Creating slugs
                                                                                                • 166 Updating the path
                                                                                                • 167 Defining get_absolute_url() method
                                                                                                • 168 Using url tag
                                                                                                • 169 Details
                                                                                                  • 1691 Capturing URL values
                                                                                                  • 1692 Using view parameters
                                                                                                  • 1693 Explaining slugs
                                                                                                  • 1694 Reversing URLS
                                                                                                    • 1610 Summary
                                                                                                      • 17 Adding category as a many-to-one relationhip
                                                                                                        • 171 Setup
                                                                                                        • 172 Adding category field and model
                                                                                                        • 173 Updating the homepage template
                                                                                                        • 174 Details
                                                                                                          • 1741 Examining many-to-one relationships
                                                                                                          • 1742 Accessing related objects
                                                                                                            • 175 Summary
                                                                                                              • 18 Referencing tags with a ManyToMany field
                                                                                                                • 181 Setup
                                                                                                                • 182 Adding the tags field
                                                                                                                • 183 Updating the homepage template
                                                                                                                • 184 Summary
                                                                                                                  • 19 Creating a tags page
                                                                                                                    • 191 Setup
                                                                                                                    • 192 Adding tags path
                                                                                                                    • 193 Adding the slug field
                                                                                                                    • 194 Creating the tags view
                                                                                                                    • 195 Updating homepage template
                                                                                                                    • 196 Details
                                                                                                                      • 1961 Doing lookups across relationships
                                                                                                                      • 1962 Reusing templates
                                                                                                                        • 197 Summary
                                                                                                                          • 20 Creating a search feature
                                                                                                                            • 201 Setup
                                                                                                                            • 202 Adding a search form
                                                                                                                            • 203 Updating the index view
                                                                                                                            • 204 Details
                                                                                                                            • 205 Summary
                                                                                                                              • 21 Working with forms creating items
                                                                                                                                • 211 Setup
                                                                                                                                • 212 Creating the edit form
                                                                                                                                • 213 Creating the form class
                                                                                                                                • 214 Updating urlpatterns
                                                                                                                                • 215 Creating the view function
                                                                                                                                • 216 Adding a menu item
                                                                                                                                • 217 Details
                                                                                                                                  • 2171 Protecting against cross site request forgeries
                                                                                                                                  • 2172 Adding form fields
                                                                                                                                  • 2173 Using the Form class
                                                                                                                                  • 2174 Examining the view function
                                                                                                                                    • 218 Summary
                                                                                                                                      • 22 Working with forms editing items
                                                                                                                                        • 221 Setup
                                                                                                                                        • 222 Adding the path
                                                                                                                                        • 223 Creating the edit view
                                                                                                                                        • 224 Updating the edit link
                                                                                                                                        • 225 Details
                                                                                                                                          • 2251 Capturing the id
                                                                                                                                          • 2252 Examining the edit view
                                                                                                                                            • 226 Summary
                                                                                                                                              • 23 Working with forms customization
                                                                                                                                                • 231 Setup
                                                                                                                                                • 232 Adding the description field
                                                                                                                                                • 233 Details
                                                                                                                                                  • 2331 Changing field order
                                                                                                                                                  • 2332 Customizing validation errors
                                                                                                                                                    • 234 Summary
                                                                                                                                                      • 24 Creating and deleting objects
                                                                                                                                                        • 241 Setup
                                                                                                                                                        • 242 Adding the delete path
                                                                                                                                                        • 243 Adding the delete view
                                                                                                                                                        • 244 Updating the delete link
                                                                                                                                                        • 245 Details
                                                                                                                                                        • 246 Summary
                                                                                                                                                          • 25 Authenticating users with Allauth
                                                                                                                                                            • 251 Setup
                                                                                                                                                            • 252 Installing Allauth
                                                                                                                                                            • 253 Creating template files
                                                                                                                                                            • 254 Updating the templates for Bootstrap 4
                                                                                                                                                            • 255 Details
                                                                                                                                                              • 2551 Configuration options
                                                                                                                                                              • 2552 Adding the paths
                                                                                                                                                              • 2553 django-widget-tweaks
                                                                                                                                                                • 256 Summary
                                                                                                                                                                  • 26 Authorization
                                                                                                                                                                    • 261 Setup
                                                                                                                                                                    • 262 Adding the Editor group
                                                                                                                                                                    • 263 Creating a test user
                                                                                                                                                                    • 264 Using permissions
                                                                                                                                                                    • 265 Using decorators
                                                                                                                                                                    • 266 Details
                                                                                                                                                                      • 2661 Authentication vs authorization
                                                                                                                                                                      • 2662 Controlling access with decorators
                                                                                                                                                                        • 267 Summary
                                                                                                                                                                          • 27 Creating an image gallery
                                                                                                                                                                            • 271 Setup
                                                                                                                                                                            • 272 Installing pillow
                                                                                                                                                                            • 273 Configuring media variables
                                                                                                                                                                            • 274 Adding ImageField
                                                                                                                                                                            • 275 Adding images to flowers
                                                                                                                                                                            • 276 Using the static helper function
                                                                                                                                                                            • 277 Adding the grid
                                                                                                                                                                            • 278 Details
                                                                                                                                                                            • 279 Summary
                                                                                                                                                                              • 28 Adding image thumbnails
                                                                                                                                                                                • 281 Setup
                                                                                                                                                                                • 282 Installing ImageKit
                                                                                                                                                                                • 283 Adding the thumbnail field
                                                                                                                                                                                • 284 Details
                                                                                                                                                                                • 285 Summary
                                                                                                                                                                                  • 29 Deploying on Heroku
                                                                                                                                                                                    • 291 Setup
                                                                                                                                                                                    • 292 Creating a Heroku app
                                                                                                                                                                                    • 293 Installing Heroku CLI
                                                                                                                                                                                      • 2931 Installation in Windows
                                                                                                                                                                                      • 2932 Installation in macOS
                                                                                                                                                                                      • 2933 Installation in Ubuntu
                                                                                                                                                                                      • 2934 Authenticating with a browser
                                                                                                                                                                                        • 294 Creating a Procfile
                                                                                                                                                                                        • 295 Updating the settingspy file
                                                                                                                                                                                        • 296 Creating the repository
                                                                                                                                                                                        • 297 Pushing changes
                                                                                                                                                                                        • 298 Updating the database
                                                                                                                                                                                        • 299 Summary
                                                                                                                                                                                          • 30 Using Amazon AWS to serve files
                                                                                                                                                                                            • 301 Setup
                                                                                                                                                                                            • 302 Creating an Amazon AWS bucket
                                                                                                                                                                                            • 303 Setting up permissions
                                                                                                                                                                                            • 304 Updating settingspy file
                                                                                                                                                                                            • 305 Adding an image field to the Post model
                                                                                                                                                                                            • 306 Installing packages
                                                                                                                                                                                            • 307 Summary
                                                                                                                                                                                              • 31 Setting up Heroku pipelines
                                                                                                                                                                                                • 311 Setup
                                                                                                                                                                                                • 312 Creating a GitHub repository
                                                                                                                                                                                                • 313 Creating a pipeline
                                                                                                                                                                                                • 314 Testing deployment
                                                                                                                                                                                                • 315 Adding a production app
                                                                                                                                                                                                • 316 Enabling review apps
                                                                                                                                                                                                • 317 Using pull requests
                                                                                                                                                                                                • 318 Deleting the branch
                                                                                                                                                                                                • 319 Summary
                                                                                                                                                                                                  • 32 Sending emails with SendGrid
                                                                                                                                                                                                    • 321 Creating an account
                                                                                                                                                                                                    • 322 Summary
                                                                                                                                                                                                      • Licenses
Page 13: Django - The Easy Way: A step-by-step guide on building Django websites, 2nd Edition

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
                                                                                        • 145 Summary
                                                                                          • 15 Creating a base project
                                                                                            • 151 Setup
                                                                                            • 152 Adding a description field
                                                                                            • 153 Adding masonry like columns
                                                                                            • 154 Adding a footer
                                                                                            • 155 Summary
                                                                                              • 16 Creating a detail page
                                                                                                • 161 Setup
                                                                                                • 162 Adding a detail page path
                                                                                                • 163 Creating the detail view
                                                                                                • 164 Creating the detail page template
                                                                                                • 165 Creating slugs
                                                                                                • 166 Updating the path
                                                                                                • 167 Defining get_absolute_url() method
                                                                                                • 168 Using url tag
                                                                                                • 169 Details
                                                                                                  • 1691 Capturing URL values
                                                                                                  • 1692 Using view parameters
                                                                                                  • 1693 Explaining slugs
                                                                                                  • 1694 Reversing URLS
                                                                                                    • 1610 Summary
                                                                                                      • 17 Adding category as a many-to-one relationhip
                                                                                                        • 171 Setup
                                                                                                        • 172 Adding category field and model
                                                                                                        • 173 Updating the homepage template
                                                                                                        • 174 Details
                                                                                                          • 1741 Examining many-to-one relationships
                                                                                                          • 1742 Accessing related objects
                                                                                                            • 175 Summary
                                                                                                              • 18 Referencing tags with a ManyToMany field
                                                                                                                • 181 Setup
                                                                                                                • 182 Adding the tags field
                                                                                                                • 183 Updating the homepage template
                                                                                                                • 184 Summary
                                                                                                                  • 19 Creating a tags page
                                                                                                                    • 191 Setup
                                                                                                                    • 192 Adding tags path
                                                                                                                    • 193 Adding the slug field
                                                                                                                    • 194 Creating the tags view
                                                                                                                    • 195 Updating homepage template
                                                                                                                    • 196 Details
                                                                                                                      • 1961 Doing lookups across relationships
                                                                                                                      • 1962 Reusing templates
                                                                                                                        • 197 Summary
                                                                                                                          • 20 Creating a search feature
                                                                                                                            • 201 Setup
                                                                                                                            • 202 Adding a search form
                                                                                                                            • 203 Updating the index view
                                                                                                                            • 204 Details
                                                                                                                            • 205 Summary
                                                                                                                              • 21 Working with forms creating items
                                                                                                                                • 211 Setup
                                                                                                                                • 212 Creating the edit form
                                                                                                                                • 213 Creating the form class
                                                                                                                                • 214 Updating urlpatterns
                                                                                                                                • 215 Creating the view function
                                                                                                                                • 216 Adding a menu item
                                                                                                                                • 217 Details
                                                                                                                                  • 2171 Protecting against cross site request forgeries
                                                                                                                                  • 2172 Adding form fields
                                                                                                                                  • 2173 Using the Form class
                                                                                                                                  • 2174 Examining the view function
                                                                                                                                    • 218 Summary
                                                                                                                                      • 22 Working with forms editing items
                                                                                                                                        • 221 Setup
                                                                                                                                        • 222 Adding the path
                                                                                                                                        • 223 Creating the edit view
                                                                                                                                        • 224 Updating the edit link
                                                                                                                                        • 225 Details
                                                                                                                                          • 2251 Capturing the id
                                                                                                                                          • 2252 Examining the edit view
                                                                                                                                            • 226 Summary
                                                                                                                                              • 23 Working with forms customization
                                                                                                                                                • 231 Setup
                                                                                                                                                • 232 Adding the description field
                                                                                                                                                • 233 Details
                                                                                                                                                  • 2331 Changing field order
                                                                                                                                                  • 2332 Customizing validation errors
                                                                                                                                                    • 234 Summary
                                                                                                                                                      • 24 Creating and deleting objects
                                                                                                                                                        • 241 Setup
                                                                                                                                                        • 242 Adding the delete path
                                                                                                                                                        • 243 Adding the delete view
                                                                                                                                                        • 244 Updating the delete link
                                                                                                                                                        • 245 Details
                                                                                                                                                        • 246 Summary
                                                                                                                                                          • 25 Authenticating users with Allauth
                                                                                                                                                            • 251 Setup
                                                                                                                                                            • 252 Installing Allauth
                                                                                                                                                            • 253 Creating template files
                                                                                                                                                            • 254 Updating the templates for Bootstrap 4
                                                                                                                                                            • 255 Details
                                                                                                                                                              • 2551 Configuration options
                                                                                                                                                              • 2552 Adding the paths
                                                                                                                                                              • 2553 django-widget-tweaks
                                                                                                                                                                • 256 Summary
                                                                                                                                                                  • 26 Authorization
                                                                                                                                                                    • 261 Setup
                                                                                                                                                                    • 262 Adding the Editor group
                                                                                                                                                                    • 263 Creating a test user
                                                                                                                                                                    • 264 Using permissions
                                                                                                                                                                    • 265 Using decorators
                                                                                                                                                                    • 266 Details
                                                                                                                                                                      • 2661 Authentication vs authorization
                                                                                                                                                                      • 2662 Controlling access with decorators
                                                                                                                                                                        • 267 Summary
                                                                                                                                                                          • 27 Creating an image gallery
                                                                                                                                                                            • 271 Setup
                                                                                                                                                                            • 272 Installing pillow
                                                                                                                                                                            • 273 Configuring media variables
                                                                                                                                                                            • 274 Adding ImageField
                                                                                                                                                                            • 275 Adding images to flowers
                                                                                                                                                                            • 276 Using the static helper function
                                                                                                                                                                            • 277 Adding the grid
                                                                                                                                                                            • 278 Details
                                                                                                                                                                            • 279 Summary
                                                                                                                                                                              • 28 Adding image thumbnails
                                                                                                                                                                                • 281 Setup
                                                                                                                                                                                • 282 Installing ImageKit
                                                                                                                                                                                • 283 Adding the thumbnail field
                                                                                                                                                                                • 284 Details
                                                                                                                                                                                • 285 Summary
                                                                                                                                                                                  • 29 Deploying on Heroku
                                                                                                                                                                                    • 291 Setup
                                                                                                                                                                                    • 292 Creating a Heroku app
                                                                                                                                                                                    • 293 Installing Heroku CLI
                                                                                                                                                                                      • 2931 Installation in Windows
                                                                                                                                                                                      • 2932 Installation in macOS
                                                                                                                                                                                      • 2933 Installation in Ubuntu
                                                                                                                                                                                      • 2934 Authenticating with a browser
                                                                                                                                                                                        • 294 Creating a Procfile
                                                                                                                                                                                        • 295 Updating the settingspy file
                                                                                                                                                                                        • 296 Creating the repository
                                                                                                                                                                                        • 297 Pushing changes
                                                                                                                                                                                        • 298 Updating the database
                                                                                                                                                                                        • 299 Summary
                                                                                                                                                                                          • 30 Using Amazon AWS to serve files
                                                                                                                                                                                            • 301 Setup
                                                                                                                                                                                            • 302 Creating an Amazon AWS bucket
                                                                                                                                                                                            • 303 Setting up permissions
                                                                                                                                                                                            • 304 Updating settingspy file
                                                                                                                                                                                            • 305 Adding an image field to the Post model
                                                                                                                                                                                            • 306 Installing packages
                                                                                                                                                                                            • 307 Summary
                                                                                                                                                                                              • 31 Setting up Heroku pipelines
                                                                                                                                                                                                • 311 Setup
                                                                                                                                                                                                • 312 Creating a GitHub repository
                                                                                                                                                                                                • 313 Creating a pipeline
                                                                                                                                                                                                • 314 Testing deployment
                                                                                                                                                                                                • 315 Adding a production app
                                                                                                                                                                                                • 316 Enabling review apps
                                                                                                                                                                                                • 317 Using pull requests
                                                                                                                                                                                                • 318 Deleting the branch
                                                                                                                                                                                                • 319 Summary
                                                                                                                                                                                                  • 32 Sending emails with SendGrid
                                                                                                                                                                                                    • 321 Creating an account
                                                                                                                                                                                                    • 322 Summary
                                                                                                                                                                                                      • Licenses
Page 14: Django - The Easy Way: A step-by-step guide on building Django websites, 2nd Edition

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
                                                                                        • 145 Summary
                                                                                          • 15 Creating a base project
                                                                                            • 151 Setup
                                                                                            • 152 Adding a description field
                                                                                            • 153 Adding masonry like columns
                                                                                            • 154 Adding a footer
                                                                                            • 155 Summary
                                                                                              • 16 Creating a detail page
                                                                                                • 161 Setup
                                                                                                • 162 Adding a detail page path
                                                                                                • 163 Creating the detail view
                                                                                                • 164 Creating the detail page template
                                                                                                • 165 Creating slugs
                                                                                                • 166 Updating the path
                                                                                                • 167 Defining get_absolute_url() method
                                                                                                • 168 Using url tag
                                                                                                • 169 Details
                                                                                                  • 1691 Capturing URL values
                                                                                                  • 1692 Using view parameters
                                                                                                  • 1693 Explaining slugs
                                                                                                  • 1694 Reversing URLS
                                                                                                    • 1610 Summary
                                                                                                      • 17 Adding category as a many-to-one relationhip
                                                                                                        • 171 Setup
                                                                                                        • 172 Adding category field and model
                                                                                                        • 173 Updating the homepage template
                                                                                                        • 174 Details
                                                                                                          • 1741 Examining many-to-one relationships
                                                                                                          • 1742 Accessing related objects
                                                                                                            • 175 Summary
                                                                                                              • 18 Referencing tags with a ManyToMany field
                                                                                                                • 181 Setup
                                                                                                                • 182 Adding the tags field
                                                                                                                • 183 Updating the homepage template
                                                                                                                • 184 Summary
                                                                                                                  • 19 Creating a tags page
                                                                                                                    • 191 Setup
                                                                                                                    • 192 Adding tags path
                                                                                                                    • 193 Adding the slug field
                                                                                                                    • 194 Creating the tags view
                                                                                                                    • 195 Updating homepage template
                                                                                                                    • 196 Details
                                                                                                                      • 1961 Doing lookups across relationships
                                                                                                                      • 1962 Reusing templates
                                                                                                                        • 197 Summary
                                                                                                                          • 20 Creating a search feature
                                                                                                                            • 201 Setup
                                                                                                                            • 202 Adding a search form
                                                                                                                            • 203 Updating the index view
                                                                                                                            • 204 Details
                                                                                                                            • 205 Summary
                                                                                                                              • 21 Working with forms creating items
                                                                                                                                • 211 Setup
                                                                                                                                • 212 Creating the edit form
                                                                                                                                • 213 Creating the form class
                                                                                                                                • 214 Updating urlpatterns
                                                                                                                                • 215 Creating the view function
                                                                                                                                • 216 Adding a menu item
                                                                                                                                • 217 Details
                                                                                                                                  • 2171 Protecting against cross site request forgeries
                                                                                                                                  • 2172 Adding form fields
                                                                                                                                  • 2173 Using the Form class
                                                                                                                                  • 2174 Examining the view function
                                                                                                                                    • 218 Summary
                                                                                                                                      • 22 Working with forms editing items
                                                                                                                                        • 221 Setup
                                                                                                                                        • 222 Adding the path
                                                                                                                                        • 223 Creating the edit view
                                                                                                                                        • 224 Updating the edit link
                                                                                                                                        • 225 Details
                                                                                                                                          • 2251 Capturing the id
                                                                                                                                          • 2252 Examining the edit view
                                                                                                                                            • 226 Summary
                                                                                                                                              • 23 Working with forms customization
                                                                                                                                                • 231 Setup
                                                                                                                                                • 232 Adding the description field
                                                                                                                                                • 233 Details
                                                                                                                                                  • 2331 Changing field order
                                                                                                                                                  • 2332 Customizing validation errors
                                                                                                                                                    • 234 Summary
                                                                                                                                                      • 24 Creating and deleting objects
                                                                                                                                                        • 241 Setup
                                                                                                                                                        • 242 Adding the delete path
                                                                                                                                                        • 243 Adding the delete view
                                                                                                                                                        • 244 Updating the delete link
                                                                                                                                                        • 245 Details
                                                                                                                                                        • 246 Summary
                                                                                                                                                          • 25 Authenticating users with Allauth
                                                                                                                                                            • 251 Setup
                                                                                                                                                            • 252 Installing Allauth
                                                                                                                                                            • 253 Creating template files
                                                                                                                                                            • 254 Updating the templates for Bootstrap 4
                                                                                                                                                            • 255 Details
                                                                                                                                                              • 2551 Configuration options
                                                                                                                                                              • 2552 Adding the paths
                                                                                                                                                              • 2553 django-widget-tweaks
                                                                                                                                                                • 256 Summary
                                                                                                                                                                  • 26 Authorization
                                                                                                                                                                    • 261 Setup
                                                                                                                                                                    • 262 Adding the Editor group
                                                                                                                                                                    • 263 Creating a test user
                                                                                                                                                                    • 264 Using permissions
                                                                                                                                                                    • 265 Using decorators
                                                                                                                                                                    • 266 Details
                                                                                                                                                                      • 2661 Authentication vs authorization
                                                                                                                                                                      • 2662 Controlling access with decorators
                                                                                                                                                                        • 267 Summary
                                                                                                                                                                          • 27 Creating an image gallery
                                                                                                                                                                            • 271 Setup
                                                                                                                                                                            • 272 Installing pillow
                                                                                                                                                                            • 273 Configuring media variables
                                                                                                                                                                            • 274 Adding ImageField
                                                                                                                                                                            • 275 Adding images to flowers
                                                                                                                                                                            • 276 Using the static helper function
                                                                                                                                                                            • 277 Adding the grid
                                                                                                                                                                            • 278 Details
                                                                                                                                                                            • 279 Summary
                                                                                                                                                                              • 28 Adding image thumbnails
                                                                                                                                                                                • 281 Setup
                                                                                                                                                                                • 282 Installing ImageKit
                                                                                                                                                                                • 283 Adding the thumbnail field
                                                                                                                                                                                • 284 Details
                                                                                                                                                                                • 285 Summary
                                                                                                                                                                                  • 29 Deploying on Heroku
                                                                                                                                                                                    • 291 Setup
                                                                                                                                                                                    • 292 Creating a Heroku app
                                                                                                                                                                                    • 293 Installing Heroku CLI
                                                                                                                                                                                      • 2931 Installation in Windows
                                                                                                                                                                                      • 2932 Installation in macOS
                                                                                                                                                                                      • 2933 Installation in Ubuntu
                                                                                                                                                                                      • 2934 Authenticating with a browser
                                                                                                                                                                                        • 294 Creating a Procfile
                                                                                                                                                                                        • 295 Updating the settingspy file
                                                                                                                                                                                        • 296 Creating the repository
                                                                                                                                                                                        • 297 Pushing changes
                                                                                                                                                                                        • 298 Updating the database
                                                                                                                                                                                        • 299 Summary
                                                                                                                                                                                          • 30 Using Amazon AWS to serve files
                                                                                                                                                                                            • 301 Setup
                                                                                                                                                                                            • 302 Creating an Amazon AWS bucket
                                                                                                                                                                                            • 303 Setting up permissions
                                                                                                                                                                                            • 304 Updating settingspy file
                                                                                                                                                                                            • 305 Adding an image field to the Post model
                                                                                                                                                                                            • 306 Installing packages
                                                                                                                                                                                            • 307 Summary
                                                                                                                                                                                              • 31 Setting up Heroku pipelines
                                                                                                                                                                                                • 311 Setup
                                                                                                                                                                                                • 312 Creating a GitHub repository
                                                                                                                                                                                                • 313 Creating a pipeline
                                                                                                                                                                                                • 314 Testing deployment
                                                                                                                                                                                                • 315 Adding a production app
                                                                                                                                                                                                • 316 Enabling review apps
                                                                                                                                                                                                • 317 Using pull requests
                                                                                                                                                                                                • 318 Deleting the branch
                                                                                                                                                                                                • 319 Summary
                                                                                                                                                                                                  • 32 Sending emails with SendGrid
                                                                                                                                                                                                    • 321 Creating an account
                                                                                                                                                                                                    • 322 Summary
                                                                                                                                                                                                      • Licenses
Page 15: Django - The Easy Way: A step-by-step guide on building Django websites, 2nd Edition

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
                                                                                        • 145 Summary
                                                                                          • 15 Creating a base project
                                                                                            • 151 Setup
                                                                                            • 152 Adding a description field
                                                                                            • 153 Adding masonry like columns
                                                                                            • 154 Adding a footer
                                                                                            • 155 Summary
                                                                                              • 16 Creating a detail page
                                                                                                • 161 Setup
                                                                                                • 162 Adding a detail page path
                                                                                                • 163 Creating the detail view
                                                                                                • 164 Creating the detail page template
                                                                                                • 165 Creating slugs
                                                                                                • 166 Updating the path
                                                                                                • 167 Defining get_absolute_url() method
                                                                                                • 168 Using url tag
                                                                                                • 169 Details
                                                                                                  • 1691 Capturing URL values
                                                                                                  • 1692 Using view parameters
                                                                                                  • 1693 Explaining slugs
                                                                                                  • 1694 Reversing URLS
                                                                                                    • 1610 Summary
                                                                                                      • 17 Adding category as a many-to-one relationhip
                                                                                                        • 171 Setup
                                                                                                        • 172 Adding category field and model
                                                                                                        • 173 Updating the homepage template
                                                                                                        • 174 Details
                                                                                                          • 1741 Examining many-to-one relationships
                                                                                                          • 1742 Accessing related objects
                                                                                                            • 175 Summary
                                                                                                              • 18 Referencing tags with a ManyToMany field
                                                                                                                • 181 Setup
                                                                                                                • 182 Adding the tags field
                                                                                                                • 183 Updating the homepage template
                                                                                                                • 184 Summary
                                                                                                                  • 19 Creating a tags page
                                                                                                                    • 191 Setup
                                                                                                                    • 192 Adding tags path
                                                                                                                    • 193 Adding the slug field
                                                                                                                    • 194 Creating the tags view
                                                                                                                    • 195 Updating homepage template
                                                                                                                    • 196 Details
                                                                                                                      • 1961 Doing lookups across relationships
                                                                                                                      • 1962 Reusing templates
                                                                                                                        • 197 Summary
                                                                                                                          • 20 Creating a search feature
                                                                                                                            • 201 Setup
                                                                                                                            • 202 Adding a search form
                                                                                                                            • 203 Updating the index view
                                                                                                                            • 204 Details
                                                                                                                            • 205 Summary
                                                                                                                              • 21 Working with forms creating items
                                                                                                                                • 211 Setup
                                                                                                                                • 212 Creating the edit form
                                                                                                                                • 213 Creating the form class
                                                                                                                                • 214 Updating urlpatterns
                                                                                                                                • 215 Creating the view function
                                                                                                                                • 216 Adding a menu item
                                                                                                                                • 217 Details
                                                                                                                                  • 2171 Protecting against cross site request forgeries
                                                                                                                                  • 2172 Adding form fields
                                                                                                                                  • 2173 Using the Form class
                                                                                                                                  • 2174 Examining the view function
                                                                                                                                    • 218 Summary
                                                                                                                                      • 22 Working with forms editing items
                                                                                                                                        • 221 Setup
                                                                                                                                        • 222 Adding the path
                                                                                                                                        • 223 Creating the edit view
                                                                                                                                        • 224 Updating the edit link
                                                                                                                                        • 225 Details
                                                                                                                                          • 2251 Capturing the id
                                                                                                                                          • 2252 Examining the edit view
                                                                                                                                            • 226 Summary
                                                                                                                                              • 23 Working with forms customization
                                                                                                                                                • 231 Setup
                                                                                                                                                • 232 Adding the description field
                                                                                                                                                • 233 Details
                                                                                                                                                  • 2331 Changing field order
                                                                                                                                                  • 2332 Customizing validation errors
                                                                                                                                                    • 234 Summary
                                                                                                                                                      • 24 Creating and deleting objects
                                                                                                                                                        • 241 Setup
                                                                                                                                                        • 242 Adding the delete path
                                                                                                                                                        • 243 Adding the delete view
                                                                                                                                                        • 244 Updating the delete link
                                                                                                                                                        • 245 Details
                                                                                                                                                        • 246 Summary
                                                                                                                                                          • 25 Authenticating users with Allauth
                                                                                                                                                            • 251 Setup
                                                                                                                                                            • 252 Installing Allauth
                                                                                                                                                            • 253 Creating template files
                                                                                                                                                            • 254 Updating the templates for Bootstrap 4
                                                                                                                                                            • 255 Details
                                                                                                                                                              • 2551 Configuration options
                                                                                                                                                              • 2552 Adding the paths
                                                                                                                                                              • 2553 django-widget-tweaks
                                                                                                                                                                • 256 Summary
                                                                                                                                                                  • 26 Authorization
                                                                                                                                                                    • 261 Setup
                                                                                                                                                                    • 262 Adding the Editor group
                                                                                                                                                                    • 263 Creating a test user
                                                                                                                                                                    • 264 Using permissions
                                                                                                                                                                    • 265 Using decorators
                                                                                                                                                                    • 266 Details
                                                                                                                                                                      • 2661 Authentication vs authorization
                                                                                                                                                                      • 2662 Controlling access with decorators
                                                                                                                                                                        • 267 Summary
                                                                                                                                                                          • 27 Creating an image gallery
                                                                                                                                                                            • 271 Setup
                                                                                                                                                                            • 272 Installing pillow
                                                                                                                                                                            • 273 Configuring media variables
                                                                                                                                                                            • 274 Adding ImageField
                                                                                                                                                                            • 275 Adding images to flowers
                                                                                                                                                                            • 276 Using the static helper function
                                                                                                                                                                            • 277 Adding the grid
                                                                                                                                                                            • 278 Details
                                                                                                                                                                            • 279 Summary
                                                                                                                                                                              • 28 Adding image thumbnails
                                                                                                                                                                                • 281 Setup
                                                                                                                                                                                • 282 Installing ImageKit
                                                                                                                                                                                • 283 Adding the thumbnail field
                                                                                                                                                                                • 284 Details
                                                                                                                                                                                • 285 Summary
                                                                                                                                                                                  • 29 Deploying on Heroku
                                                                                                                                                                                    • 291 Setup
                                                                                                                                                                                    • 292 Creating a Heroku app
                                                                                                                                                                                    • 293 Installing Heroku CLI
                                                                                                                                                                                      • 2931 Installation in Windows
                                                                                                                                                                                      • 2932 Installation in macOS
                                                                                                                                                                                      • 2933 Installation in Ubuntu
                                                                                                                                                                                      • 2934 Authenticating with a browser
                                                                                                                                                                                        • 294 Creating a Procfile
                                                                                                                                                                                        • 295 Updating the settingspy file
                                                                                                                                                                                        • 296 Creating the repository
                                                                                                                                                                                        • 297 Pushing changes
                                                                                                                                                                                        • 298 Updating the database
                                                                                                                                                                                        • 299 Summary
                                                                                                                                                                                          • 30 Using Amazon AWS to serve files
                                                                                                                                                                                            • 301 Setup
                                                                                                                                                                                            • 302 Creating an Amazon AWS bucket
                                                                                                                                                                                            • 303 Setting up permissions
                                                                                                                                                                                            • 304 Updating settingspy file
                                                                                                                                                                                            • 305 Adding an image field to the Post model
                                                                                                                                                                                            • 306 Installing packages
                                                                                                                                                                                            • 307 Summary
                                                                                                                                                                                              • 31 Setting up Heroku pipelines
                                                                                                                                                                                                • 311 Setup
                                                                                                                                                                                                • 312 Creating a GitHub repository
                                                                                                                                                                                                • 313 Creating a pipeline
                                                                                                                                                                                                • 314 Testing deployment
                                                                                                                                                                                                • 315 Adding a production app
                                                                                                                                                                                                • 316 Enabling review apps
                                                                                                                                                                                                • 317 Using pull requests
                                                                                                                                                                                                • 318 Deleting the branch
                                                                                                                                                                                                • 319 Summary
                                                                                                                                                                                                  • 32 Sending emails with SendGrid
                                                                                                                                                                                                    • 321 Creating an account
                                                                                                                                                                                                    • 322 Summary
                                                                                                                                                                                                      • Licenses
Page 16: Django - The Easy Way: A step-by-step guide on building Django websites, 2nd Edition

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
                                                                                        • 145 Summary
                                                                                          • 15 Creating a base project
                                                                                            • 151 Setup
                                                                                            • 152 Adding a description field
                                                                                            • 153 Adding masonry like columns
                                                                                            • 154 Adding a footer
                                                                                            • 155 Summary
                                                                                              • 16 Creating a detail page
                                                                                                • 161 Setup
                                                                                                • 162 Adding a detail page path
                                                                                                • 163 Creating the detail view
                                                                                                • 164 Creating the detail page template
                                                                                                • 165 Creating slugs
                                                                                                • 166 Updating the path
                                                                                                • 167 Defining get_absolute_url() method
                                                                                                • 168 Using url tag
                                                                                                • 169 Details
                                                                                                  • 1691 Capturing URL values
                                                                                                  • 1692 Using view parameters
                                                                                                  • 1693 Explaining slugs
                                                                                                  • 1694 Reversing URLS
                                                                                                    • 1610 Summary
                                                                                                      • 17 Adding category as a many-to-one relationhip
                                                                                                        • 171 Setup
                                                                                                        • 172 Adding category field and model
                                                                                                        • 173 Updating the homepage template
                                                                                                        • 174 Details
                                                                                                          • 1741 Examining many-to-one relationships
                                                                                                          • 1742 Accessing related objects
                                                                                                            • 175 Summary
                                                                                                              • 18 Referencing tags with a ManyToMany field
                                                                                                                • 181 Setup
                                                                                                                • 182 Adding the tags field
                                                                                                                • 183 Updating the homepage template
                                                                                                                • 184 Summary
                                                                                                                  • 19 Creating a tags page
                                                                                                                    • 191 Setup
                                                                                                                    • 192 Adding tags path
                                                                                                                    • 193 Adding the slug field
                                                                                                                    • 194 Creating the tags view
                                                                                                                    • 195 Updating homepage template
                                                                                                                    • 196 Details
                                                                                                                      • 1961 Doing lookups across relationships
                                                                                                                      • 1962 Reusing templates
                                                                                                                        • 197 Summary
                                                                                                                          • 20 Creating a search feature
                                                                                                                            • 201 Setup
                                                                                                                            • 202 Adding a search form
                                                                                                                            • 203 Updating the index view
                                                                                                                            • 204 Details
                                                                                                                            • 205 Summary
                                                                                                                              • 21 Working with forms creating items
                                                                                                                                • 211 Setup
                                                                                                                                • 212 Creating the edit form
                                                                                                                                • 213 Creating the form class
                                                                                                                                • 214 Updating urlpatterns
                                                                                                                                • 215 Creating the view function
                                                                                                                                • 216 Adding a menu item
                                                                                                                                • 217 Details
                                                                                                                                  • 2171 Protecting against cross site request forgeries
                                                                                                                                  • 2172 Adding form fields
                                                                                                                                  • 2173 Using the Form class
                                                                                                                                  • 2174 Examining the view function
                                                                                                                                    • 218 Summary
                                                                                                                                      • 22 Working with forms editing items
                                                                                                                                        • 221 Setup
                                                                                                                                        • 222 Adding the path
                                                                                                                                        • 223 Creating the edit view
                                                                                                                                        • 224 Updating the edit link
                                                                                                                                        • 225 Details
                                                                                                                                          • 2251 Capturing the id
                                                                                                                                          • 2252 Examining the edit view
                                                                                                                                            • 226 Summary
                                                                                                                                              • 23 Working with forms customization
                                                                                                                                                • 231 Setup
                                                                                                                                                • 232 Adding the description field
                                                                                                                                                • 233 Details
                                                                                                                                                  • 2331 Changing field order
                                                                                                                                                  • 2332 Customizing validation errors
                                                                                                                                                    • 234 Summary
                                                                                                                                                      • 24 Creating and deleting objects
                                                                                                                                                        • 241 Setup
                                                                                                                                                        • 242 Adding the delete path
                                                                                                                                                        • 243 Adding the delete view
                                                                                                                                                        • 244 Updating the delete link
                                                                                                                                                        • 245 Details
                                                                                                                                                        • 246 Summary
                                                                                                                                                          • 25 Authenticating users with Allauth
                                                                                                                                                            • 251 Setup
                                                                                                                                                            • 252 Installing Allauth
                                                                                                                                                            • 253 Creating template files
                                                                                                                                                            • 254 Updating the templates for Bootstrap 4
                                                                                                                                                            • 255 Details
                                                                                                                                                              • 2551 Configuration options
                                                                                                                                                              • 2552 Adding the paths
                                                                                                                                                              • 2553 django-widget-tweaks
                                                                                                                                                                • 256 Summary
                                                                                                                                                                  • 26 Authorization
                                                                                                                                                                    • 261 Setup
                                                                                                                                                                    • 262 Adding the Editor group
                                                                                                                                                                    • 263 Creating a test user
                                                                                                                                                                    • 264 Using permissions
                                                                                                                                                                    • 265 Using decorators
                                                                                                                                                                    • 266 Details
                                                                                                                                                                      • 2661 Authentication vs authorization
                                                                                                                                                                      • 2662 Controlling access with decorators
                                                                                                                                                                        • 267 Summary
                                                                                                                                                                          • 27 Creating an image gallery
                                                                                                                                                                            • 271 Setup
                                                                                                                                                                            • 272 Installing pillow
                                                                                                                                                                            • 273 Configuring media variables
                                                                                                                                                                            • 274 Adding ImageField
                                                                                                                                                                            • 275 Adding images to flowers
                                                                                                                                                                            • 276 Using the static helper function
                                                                                                                                                                            • 277 Adding the grid
                                                                                                                                                                            • 278 Details
                                                                                                                                                                            • 279 Summary
                                                                                                                                                                              • 28 Adding image thumbnails
                                                                                                                                                                                • 281 Setup
                                                                                                                                                                                • 282 Installing ImageKit
                                                                                                                                                                                • 283 Adding the thumbnail field
                                                                                                                                                                                • 284 Details
                                                                                                                                                                                • 285 Summary
                                                                                                                                                                                  • 29 Deploying on Heroku
                                                                                                                                                                                    • 291 Setup
                                                                                                                                                                                    • 292 Creating a Heroku app
                                                                                                                                                                                    • 293 Installing Heroku CLI
                                                                                                                                                                                      • 2931 Installation in Windows
                                                                                                                                                                                      • 2932 Installation in macOS
                                                                                                                                                                                      • 2933 Installation in Ubuntu
                                                                                                                                                                                      • 2934 Authenticating with a browser
                                                                                                                                                                                        • 294 Creating a Procfile
                                                                                                                                                                                        • 295 Updating the settingspy file
                                                                                                                                                                                        • 296 Creating the repository
                                                                                                                                                                                        • 297 Pushing changes
                                                                                                                                                                                        • 298 Updating the database
                                                                                                                                                                                        • 299 Summary
                                                                                                                                                                                          • 30 Using Amazon AWS to serve files
                                                                                                                                                                                            • 301 Setup
                                                                                                                                                                                            • 302 Creating an Amazon AWS bucket
                                                                                                                                                                                            • 303 Setting up permissions
                                                                                                                                                                                            • 304 Updating settingspy file
                                                                                                                                                                                            • 305 Adding an image field to the Post model
                                                                                                                                                                                            • 306 Installing packages
                                                                                                                                                                                            • 307 Summary
                                                                                                                                                                                              • 31 Setting up Heroku pipelines
                                                                                                                                                                                                • 311 Setup
                                                                                                                                                                                                • 312 Creating a GitHub repository
                                                                                                                                                                                                • 313 Creating a pipeline
                                                                                                                                                                                                • 314 Testing deployment
                                                                                                                                                                                                • 315 Adding a production app
                                                                                                                                                                                                • 316 Enabling review apps
                                                                                                                                                                                                • 317 Using pull requests
                                                                                                                                                                                                • 318 Deleting the branch
                                                                                                                                                                                                • 319 Summary
                                                                                                                                                                                                  • 32 Sending emails with SendGrid
                                                                                                                                                                                                    • 321 Creating an account
                                                                                                                                                                                                    • 322 Summary
                                                                                                                                                                                                      • Licenses
Page 17: Django - The Easy Way: A step-by-step guide on building Django websites, 2nd Edition
Page 18: Django - The Easy Way: A step-by-step guide on building Django websites, 2nd Edition
Page 19: Django - The Easy Way: A step-by-step guide on building Django websites, 2nd Edition
Page 20: Django - The Easy Way: A step-by-step guide on building Django websites, 2nd Edition
Page 21: Django - The Easy Way: A step-by-step guide on building Django websites, 2nd Edition
Page 22: Django - The Easy Way: A step-by-step guide on building Django websites, 2nd Edition
Page 23: Django - The Easy Way: A step-by-step guide on building Django websites, 2nd Edition
Page 24: Django - The Easy Way: A step-by-step guide on building Django websites, 2nd Edition
Page 25: Django - The Easy Way: A step-by-step guide on building Django websites, 2nd Edition
Page 26: Django - The Easy Way: A step-by-step guide on building Django websites, 2nd Edition
Page 27: Django - The Easy Way: A step-by-step guide on building Django websites, 2nd Edition
Page 28: Django - The Easy Way: A step-by-step guide on building Django websites, 2nd Edition
Page 29: Django - The Easy Way: A step-by-step guide on building Django websites, 2nd Edition
Page 30: Django - The Easy Way: A step-by-step guide on building Django websites, 2nd Edition
Page 31: Django - The Easy Way: A step-by-step guide on building Django websites, 2nd Edition
Page 32: Django - The Easy Way: A step-by-step guide on building Django websites, 2nd Edition
Page 33: Django - The Easy Way: A step-by-step guide on building Django websites, 2nd Edition
Page 34: Django - The Easy Way: A step-by-step guide on building Django websites, 2nd Edition
Page 35: Django - The Easy Way: A step-by-step guide on building Django websites, 2nd Edition
Page 36: Django - The Easy Way: A step-by-step guide on building Django websites, 2nd Edition
Page 37: Django - The Easy Way: A step-by-step guide on building Django websites, 2nd Edition
Page 38: Django - The Easy Way: A step-by-step guide on building Django websites, 2nd Edition
Page 39: Django - The Easy Way: A step-by-step guide on building Django websites, 2nd Edition
Page 40: Django - The Easy Way: A step-by-step guide on building Django websites, 2nd Edition
Page 41: Django - The Easy Way: A step-by-step guide on building Django websites, 2nd Edition
Page 42: Django - The Easy Way: A step-by-step guide on building Django websites, 2nd Edition
Page 43: Django - The Easy Way: A step-by-step guide on building Django websites, 2nd Edition
Page 44: Django - The Easy Way: A step-by-step guide on building Django websites, 2nd Edition
Page 45: Django - The Easy Way: A step-by-step guide on building Django websites, 2nd Edition
Page 46: Django - The Easy Way: A step-by-step guide on building Django websites, 2nd Edition
Page 47: Django - The Easy Way: A step-by-step guide on building Django websites, 2nd Edition
Page 48: Django - The Easy Way: A step-by-step guide on building Django websites, 2nd Edition
Page 49: Django - The Easy Way: A step-by-step guide on building Django websites, 2nd Edition
Page 50: Django - The Easy Way: A step-by-step guide on building Django websites, 2nd Edition
Page 51: Django - The Easy Way: A step-by-step guide on building Django websites, 2nd Edition
Page 52: Django - The Easy Way: A step-by-step guide on building Django websites, 2nd Edition
Page 53: Django - The Easy Way: A step-by-step guide on building Django websites, 2nd Edition
Page 54: Django - The Easy Way: A step-by-step guide on building Django websites, 2nd Edition
Page 55: Django - The Easy Way: A step-by-step guide on building Django websites, 2nd Edition
Page 56: Django - The Easy Way: A step-by-step guide on building Django websites, 2nd Edition
Page 57: Django - The Easy Way: A step-by-step guide on building Django websites, 2nd Edition
Page 58: Django - The Easy Way: A step-by-step guide on building Django websites, 2nd Edition
Page 59: Django - The Easy Way: A step-by-step guide on building Django websites, 2nd Edition
Page 60: Django - The Easy Way: A step-by-step guide on building Django websites, 2nd Edition
Page 61: Django - The Easy Way: A step-by-step guide on building Django websites, 2nd Edition
Page 62: Django - The Easy Way: A step-by-step guide on building Django websites, 2nd Edition
Page 63: Django - The Easy Way: A step-by-step guide on building Django websites, 2nd Edition
Page 64: Django - The Easy Way: A step-by-step guide on building Django websites, 2nd Edition
Page 65: Django - The Easy Way: A step-by-step guide on building Django websites, 2nd Edition
Page 66: Django - The Easy Way: A step-by-step guide on building Django websites, 2nd Edition
Page 67: Django - The Easy Way: A step-by-step guide on building Django websites, 2nd Edition
Page 68: Django - The Easy Way: A step-by-step guide on building Django websites, 2nd Edition
Page 69: Django - The Easy Way: A step-by-step guide on building Django websites, 2nd Edition
Page 70: Django - The Easy Way: A step-by-step guide on building Django websites, 2nd Edition
Page 71: Django - The Easy Way: A step-by-step guide on building Django websites, 2nd Edition
Page 72: Django - The Easy Way: A step-by-step guide on building Django websites, 2nd Edition
Page 73: Django - The Easy Way: A step-by-step guide on building Django websites, 2nd Edition
Page 74: Django - The Easy Way: A step-by-step guide on building Django websites, 2nd Edition
Page 75: Django - The Easy Way: A step-by-step guide on building Django websites, 2nd Edition
Page 76: Django - The Easy Way: A step-by-step guide on building Django websites, 2nd Edition
Page 77: Django - The Easy Way: A step-by-step guide on building Django websites, 2nd Edition
Page 78: Django - The Easy Way: A step-by-step guide on building Django websites, 2nd Edition
Page 79: Django - The Easy Way: A step-by-step guide on building Django websites, 2nd Edition
Page 80: Django - The Easy Way: A step-by-step guide on building Django websites, 2nd Edition
Page 81: Django - The Easy Way: A step-by-step guide on building Django websites, 2nd Edition
Page 82: Django - The Easy Way: A step-by-step guide on building Django websites, 2nd Edition
Page 83: Django - The Easy Way: A step-by-step guide on building Django websites, 2nd Edition
Page 84: Django - The Easy Way: A step-by-step guide on building Django websites, 2nd Edition
Page 85: Django - The Easy Way: A step-by-step guide on building Django websites, 2nd Edition
Page 86: Django - The Easy Way: A step-by-step guide on building Django websites, 2nd Edition
Page 87: Django - The Easy Way: A step-by-step guide on building Django websites, 2nd Edition
Page 88: Django - The Easy Way: A step-by-step guide on building Django websites, 2nd Edition
Page 89: Django - The Easy Way: A step-by-step guide on building Django websites, 2nd Edition
Page 90: Django - The Easy Way: A step-by-step guide on building Django websites, 2nd Edition
Page 91: Django - The Easy Way: A step-by-step guide on building Django websites, 2nd Edition
Page 92: Django - The Easy Way: A step-by-step guide on building Django websites, 2nd Edition
Page 93: Django - The Easy Way: A step-by-step guide on building Django websites, 2nd Edition
Page 94: Django - The Easy Way: A step-by-step guide on building Django websites, 2nd Edition
Page 95: Django - The Easy Way: A step-by-step guide on building Django websites, 2nd Edition
Page 96: Django - The Easy Way: A step-by-step guide on building Django websites, 2nd Edition
Page 97: Django - The Easy Way: A step-by-step guide on building Django websites, 2nd Edition
Page 98: Django - The Easy Way: A step-by-step guide on building Django websites, 2nd Edition
Page 99: Django - The Easy Way: A step-by-step guide on building Django websites, 2nd Edition
Page 100: Django - The Easy Way: A step-by-step guide on building Django websites, 2nd Edition
Page 101: Django - The Easy Way: A step-by-step guide on building Django websites, 2nd Edition
Page 102: Django - The Easy Way: A step-by-step guide on building Django websites, 2nd Edition
Page 103: Django - The Easy Way: A step-by-step guide on building Django websites, 2nd Edition
Page 104: Django - The Easy Way: A step-by-step guide on building Django websites, 2nd Edition
Page 105: Django - The Easy Way: A step-by-step guide on building Django websites, 2nd Edition
Page 106: Django - The Easy Way: A step-by-step guide on building Django websites, 2nd Edition
Page 107: Django - The Easy Way: A step-by-step guide on building Django websites, 2nd Edition
Page 108: Django - The Easy Way: A step-by-step guide on building Django websites, 2nd Edition
Page 109: Django - The Easy Way: A step-by-step guide on building Django websites, 2nd Edition
Page 110: Django - The Easy Way: A step-by-step guide on building Django websites, 2nd Edition
Page 111: Django - The Easy Way: A step-by-step guide on building Django websites, 2nd Edition
Page 112: Django - The Easy Way: A step-by-step guide on building Django websites, 2nd Edition
Page 113: Django - The Easy Way: A step-by-step guide on building Django websites, 2nd Edition
Page 114: Django - The Easy Way: A step-by-step guide on building Django websites, 2nd Edition
Page 115: Django - The Easy Way: A step-by-step guide on building Django websites, 2nd Edition
Page 116: Django - The Easy Way: A step-by-step guide on building Django websites, 2nd Edition
Page 117: Django - The Easy Way: A step-by-step guide on building Django websites, 2nd Edition
Page 118: Django - The Easy Way: A step-by-step guide on building Django websites, 2nd Edition
Page 119: Django - The Easy Way: A step-by-step guide on building Django websites, 2nd Edition
Page 120: Django - The Easy Way: A step-by-step guide on building Django websites, 2nd Edition
Page 121: Django - The Easy Way: A step-by-step guide on building Django websites, 2nd Edition
Page 122: Django - The Easy Way: A step-by-step guide on building Django websites, 2nd Edition
Page 123: Django - The Easy Way: A step-by-step guide on building Django websites, 2nd Edition
Page 124: Django - The Easy Way: A step-by-step guide on building Django websites, 2nd Edition
Page 125: Django - The Easy Way: A step-by-step guide on building Django websites, 2nd Edition
Page 126: Django - The Easy Way: A step-by-step guide on building Django websites, 2nd Edition
Page 127: Django - The Easy Way: A step-by-step guide on building Django websites, 2nd Edition
Page 128: Django - The Easy Way: A step-by-step guide on building Django websites, 2nd Edition
Page 129: Django - The Easy Way: A step-by-step guide on building Django websites, 2nd Edition
Page 130: Django - The Easy Way: A step-by-step guide on building Django websites, 2nd Edition
Page 131: Django - The Easy Way: A step-by-step guide on building Django websites, 2nd Edition
Page 132: Django - The Easy Way: A step-by-step guide on building Django websites, 2nd Edition
Page 133: Django - The Easy Way: A step-by-step guide on building Django websites, 2nd Edition
Page 134: Django - The Easy Way: A step-by-step guide on building Django websites, 2nd Edition
Page 135: Django - The Easy Way: A step-by-step guide on building Django websites, 2nd Edition
Page 136: Django - The Easy Way: A step-by-step guide on building Django websites, 2nd Edition
Page 137: Django - The Easy Way: A step-by-step guide on building Django websites, 2nd Edition
Page 138: Django - The Easy Way: A step-by-step guide on building Django websites, 2nd Edition
Page 139: Django - The Easy Way: A step-by-step guide on building Django websites, 2nd Edition
Page 140: Django - The Easy Way: A step-by-step guide on building Django websites, 2nd Edition
Page 141: Django - The Easy Way: A step-by-step guide on building Django websites, 2nd Edition
Page 142: Django - The Easy Way: A step-by-step guide on building Django websites, 2nd Edition
Page 143: Django - The Easy Way: A step-by-step guide on building Django websites, 2nd Edition
Page 144: Django - The Easy Way: A step-by-step guide on building Django websites, 2nd Edition
Page 145: Django - The Easy Way: A step-by-step guide on building Django websites, 2nd Edition
Page 146: Django - The Easy Way: A step-by-step guide on building Django websites, 2nd Edition
Page 147: Django - The Easy Way: A step-by-step guide on building Django websites, 2nd Edition
Page 148: Django - The Easy Way: A step-by-step guide on building Django websites, 2nd Edition
Page 149: Django - The Easy Way: A step-by-step guide on building Django websites, 2nd Edition
Page 150: Django - The Easy Way: A step-by-step guide on building Django websites, 2nd Edition
Page 151: Django - The Easy Way: A step-by-step guide on building Django websites, 2nd Edition
Page 152: Django - The Easy Way: A step-by-step guide on building Django websites, 2nd Edition
Page 153: Django - The Easy Way: A step-by-step guide on building Django websites, 2nd Edition
Page 154: Django - The Easy Way: A step-by-step guide on building Django websites, 2nd Edition
Page 155: Django - The Easy Way: A step-by-step guide on building Django websites, 2nd Edition
Page 156: Django - The Easy Way: A step-by-step guide on building Django websites, 2nd Edition
Page 157: Django - The Easy Way: A step-by-step guide on building Django websites, 2nd Edition
Page 158: Django - The Easy Way: A step-by-step guide on building Django websites, 2nd Edition
Page 159: Django - The Easy Way: A step-by-step guide on building Django websites, 2nd Edition
Page 160: Django - The Easy Way: A step-by-step guide on building Django websites, 2nd Edition
Page 161: Django - The Easy Way: A step-by-step guide on building Django websites, 2nd Edition
Page 162: Django - The Easy Way: A step-by-step guide on building Django websites, 2nd Edition
Page 163: Django - The Easy Way: A step-by-step guide on building Django websites, 2nd Edition
Page 164: Django - The Easy Way: A step-by-step guide on building Django websites, 2nd Edition