Table Of ContentTwo Scoops of Django
Best Practices For Django 1.5
Daniel Greenfeld
Audrey Roy
TwoScoopsofDjango:BestPracticesforDjango1.5
FirstEdition,FinalVersion,20130823
byDanielGreenfeldandAudreyRoy
Copyright⃝c 2013DanielGreenfeld,AudreyRoy,andCartwheelWeb.
Allrightsreserved.(cid:315)isbookmaynotbereproducedinanyform,inwholeorinpart,withoutwrittenpermissionfromthe
authors,exceptinthecaseofbriefquotationsembodiedinarticlesorreviews.
LimitofLiabilityandDisclaimerofWarranty:(cid:315)eauthorshaveusedtheirbesteffortsinpreparingthisbook,andthe
informationprovidedherein“asis.”(cid:315)einformationprovidedissoldwithoutwarranty,eitherexpressorimplied.Neitherthe
authorsnorCartwheelWebwillbeheldliableforanydamagestobecausedeitherdirectlyorindirectlybythecontentsof
thisbook.
Trademarks:Ratherthanindicatingeveryoccurrenceofatrademarkednameassuch,thisbookusesthenamesonlyinan
editorialfashionandtothebene(cid:320)tofthetrademarkownerwithnointentionofinfringementofthetrademark.
(cid:315)irdprinting,August2013
Formoreinformation,visithttps://django.2scoops.org.
For Malcolm Tredinnick
1971-2013
We miss you.
iii
Contents
ListofFigures xv
ListofTables xvii
Authors’Notes xix
AFewWordsFromDanielGreenfeld . . . . . . . . . . . . . . . . . . . . . . . . . . . xix
AFewWordsFromAudreyRoy . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . xx
Introduction xxi
AWordAboutOurRecommendations . . . . . . . . . . . . . . . . . . . . . . . . . . xxi
WhyTwoScoopsofDjango? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . xxii
BeforeYouBegin . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . xxiii
(cid:315)isbookisintendedforDjango1.5andPython2.7.x . . . . . . . . . . . . . . . xxiii
EachChapterStandsOnItsOwn . . . . . . . . . . . . . . . . . . . . . . . . . . xxiii
ConventionsUsedin(cid:315)isBook. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . xxiv
CoreConcepts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . xxv
KeepItSimple,Stupid . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . xxv
FatModels,HelperModules,(cid:315)inViews,StupidTemplates . . . . . . . . . . . . xxvi
StartWithDjangoByDefault . . . . . . . . . . . . . . . . . . . . . . . . . . . . xxvi
StandontheShouldersofGiants . . . . . . . . . . . . . . . . . . . . . . . . . . . xxvi
1 CodingStyle 1
1.1 (cid:315)eImportanceofMakingYourCodeReadable . . . . . . . . . . . . . . . . . . . 1
1.2 PEP8 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2
1.3 (cid:315)eWordonImports . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2
1.4 UseExplicitRelativeImports . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
1.5 AvoidUsingImport* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
1.6 DjangoCodingStyleGuidelines . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
iv
Contents
1.7 NeverCodetotheIDE(orTextEditor) . . . . . . . . . . . . . . . . . . . . . . . 8
1.8 Summary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
2 (cid:315)eOptimalDjangoEnvironmentSetup 9
2.1 UsetheSameDatabaseEngineEverywhere . . . . . . . . . . . . . . . . . . . . . 9
2.1.1 FixturesAreNotaMagicSolution . . . . . . . . . . . . . . . . . . . . . 9
2.1.2 YouCan’tExamineanExactCopyofProductionDataLocally . . . . . . 10
2.1.3 DifferentDatabasesHaveDifferentFieldTypes/Constraints . . . . . . . 10
2.2 UsePipandVirtualenv . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
2.3 InstallDjangoandOtherDependenciesviaPip . . . . . . . . . . . . . . . . . . . 13
2.4 UseaVersionControlSystem . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
2.5 Summary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
3 HowtoLayOutDjangoProjects 15
3.1 Django1.5’sDefaultProjectLayout . . . . . . . . . . . . . . . . . . . . . . . . . 15
3.2 OurPreferredProjectLayout . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16
3.2.1 TopLevel:RepositoryRoot. . . . . . . . . . . . . . . . . . . . . . . . . 16
3.2.2 SecondLevel:DjangoProjectRoot. . . . . . . . . . . . . . . . . . . . . 16
3.2.3 (cid:315)irdLevel:Con(cid:320)gurationRoot . . . . . . . . . . . . . . . . . . . . . . 17
3.3 SampleProjectLayout . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17
3.4 WhatAbouttheVirtualenv? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20
3.5 UsingaStartprojectTemplatetoGenerateOurLayout . . . . . . . . . . . . . . . 21
3.6 OtherAlternatives . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22
3.7 Summary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22
4 FundamentalsofDjangoAppDesign 23
4.1 (cid:315)eGoldenRuleofDjangoAppDesign . . . . . . . . . . . . . . . . . . . . . . . 23
4.1.1 APracticalExampleofAppsinaProject. . . . . . . . . . . . . . . . . . 24
4.2 WhattoNameYourDjangoApps . . . . . . . . . . . . . . . . . . . . . . . . . . 25
4.3 WheninDoubt,KeepAppsSmall . . . . . . . . . . . . . . . . . . . . . . . . . . 26
4.4 Summary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26
5 SettingsandRequirementsFiles 27
5.1 AvoidNon-VersionedLocalSettings . . . . . . . . . . . . . . . . . . . . . . . . . 28
5.2 UsingMultipleSettingsFiles . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29
5.2.1 ADevelopmentSettingsExample . . . . . . . . . . . . . . . . . . . . . 32
5.2.2 MultipleDevelopmentSettings. . . . . . . . . . . . . . . . . . . . . . . 33
v
Contents
5.3 KeepSecretKeysOutWithEnvironmentVariables . . . . . . . . . . . . . . . . . 34
5.3.1 ACautionBeforeUsingEnvironmentVariablesforSecrets . . . . . . . . 35
5.3.2 HowtoSetEnvironmentVariablesLocally . . . . . . . . . . . . . . . . 35
5.4 HowtoSetEnvironmentVariablesinProduction . . . . . . . . . . . . . . . . . . 37
5.4.1 HandlingMissingSecretKeyExceptions . . . . . . . . . . . . . . . . . 38
5.5 UsingMultipleRequirementsFiles . . . . . . . . . . . . . . . . . . . . . . . . . . 40
5.5.1 InstallingFromMultipleRequirementsFiles. . . . . . . . . . . . . . . . 41
5.5.2 UsingMultipleRequirementsFilesWithPlatformsasaService(PaaS). . 42
5.6 HandlingFilePathsinSettings. . . . . . . . . . . . . . . . . . . . . . . . . . . . 42
5.7 Summary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45
6 Database/ModelBestPractices 47
6.1 Basics . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 48
6.1.1 BreakUpAppsWithTooManyModels . . . . . . . . . . . . . . . . . . 48
6.1.2 Don’tDropDowntoRawSQLUntilIt’sNecessary . . . . . . . . . . . . 48
6.1.3 AddIndexesasNeeded . . . . . . . . . . . . . . . . . . . . . . . . . . . 49
6.1.4 BeCarefulWithModelInheritance . . . . . . . . . . . . . . . . . . . . 49
6.1.5 ModelInheritanceinPractice:(cid:315)eTimeStampedModel . . . . . . . . . 51
6.1.6 UseSouthforMigrations . . . . . . . . . . . . . . . . . . . . . . . . . . 53
6.2 DjangoModelDesign . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53
6.2.1 StartNormalized . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 54
6.2.2 CacheBeforeDenormalizing . . . . . . . . . . . . . . . . . . . . . . . . 54
6.2.3 DenormalizeOnlyifAbsolutelyNeeded . . . . . . . . . . . . . . . . . . 54
6.2.4 WhentoUseNullandBlank . . . . . . . . . . . . . . . . . . . . . . . . 55
6.3 ModelManagers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 56
6.4 Summary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 58
7 Function-andClass-BasedViews 61
7.1 WhentoUseFBVsorCBVs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 61
7.2 KeepViewLogicOutofURLConfs . . . . . . . . . . . . . . . . . . . . . . . . . 63
7.3 SticktoLooseCouplinginURLConfs. . . . . . . . . . . . . . . . . . . . . . . . 64
7.3.1 Whatifwearen’tusingCBVs? . . . . . . . . . . . . . . . . . . . . . . . 66
7.4 TrytoKeepBusinessLogicOutofViews . . . . . . . . . . . . . . . . . . . . . . 66
7.5 Summary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 66
8 BestPracticesforClass-BasedViews 69
vi
Contents
8.1 UsingMixinsWithCBVs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 70
8.2 WhichDjangoCBVShouldBeUsedforWhatTask? . . . . . . . . . . . . . . . . 72
8.3 GeneralTipsforDjangoCBVs . . . . . . . . . . . . . . . . . . . . . . . . . . . . 73
8.3.1 ConstrainingDjangoCBVAccesstoAuthenticatedUsers . . . . . . . . 73
8.3.2 PerformingCustomActionsonViewsWithValidForms . . . . . . . . . 74
8.3.3 PerformingCustomActionsonViewsWithInvalidForms . . . . . . . . 75
8.4 HowCBVsandFormsFitTogether . . . . . . . . . . . . . . . . . . . . . . . . . 76
8.4.1 Views+ModelFormExample . . . . . . . . . . . . . . . . . . . . . . . 77
8.4.2 Views+FormExample . . . . . . . . . . . . . . . . . . . . . . . . . . . 81
8.5 Summary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 83
9 CommonPatternsforForms 85
9.1 (cid:315)ePowerofDjangoForms . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 85
9.2 Pattern1:SimpleModelFormWithDefaultValidators . . . . . . . . . . . . . . . 86
9.3 Pattern2:CustomFormFieldValidatorsinModelForms . . . . . . . . . . . . . . 87
9.4 Pattern3:OverridingtheCleanStageofValidation . . . . . . . . . . . . . . . . . 91
9.5 Pattern4:HackingFormFields(2CBVs,2Forms,1Model) . . . . . . . . . . . . 94
9.6 Pattern5:ReusableSearchMixinView . . . . . . . . . . . . . . . . . . . . . . . 98
9.7 Summary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 100
10 More(cid:315)ingstoKnowAboutForms 101
10.1 UsethePOSTMethodinHTMLForms . . . . . . . . . . . . . . . . . . . . . . 101
10.1.1 Don’tDisableDjango’sCSRFProtection. . . . . . . . . . . . . . . . . . 102
10.2 KnowHowFormValidationWorks . . . . . . . . . . . . . . . . . . . . . . . . . 102
10.2.1 FormDataIsSavedtotheForm,(cid:315)entheModelInstance . . . . . . . . 103
10.3 Summary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 104
11 BuildingRESTAPIsinDjango 105
11.1 FundamentalsofBasicRESTAPIDesign . . . . . . . . . . . . . . . . . . . . . . 105
11.2 ImplementingaSimpleJSONAPI . . . . . . . . . . . . . . . . . . . . . . . . . . 107
11.3 RESTAPIArchitecture . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 110
11.3.1 CodeforanAppShouldRemainintheApp . . . . . . . . . . . . . . . . 110
11.3.2 TrytoKeepBusinessLogicOutofAPIViews . . . . . . . . . . . . . . 110
11.3.3 GroupingAPIURLs . . . . . . . . . . . . . . . . . . . . . . . . . . . . 110
11.3.4 TestYourAPI . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 112
11.4 AJAXandtheCSRFToken . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 112
vii
Contents
11.4.1 PostingDataviaAJAX . . . . . . . . . . . . . . . . . . . . . . . . . . . 112
11.5 AdditionalReading . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 114
11.6 Summary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 114
12 Templates:BestPractices 115
12.1 FollowaMinimalistApproach . . . . . . . . . . . . . . . . . . . . . . . . . . . . 115
12.2 TemplateArchitecturePatterns . . . . . . . . . . . . . . . . . . . . . . . . . . . . 116
12.2.1 2-TierTemplateArchitectureExample . . . . . . . . . . . . . . . . . . . 116
12.2.2 3-TierTemplateArchitectureExample . . . . . . . . . . . . . . . . . . . 116
12.2.3 FlatIsBetter(cid:315)anNested . . . . . . . . . . . . . . . . . . . . . . . . . 117
12.3 LimitProcessinginTemplates . . . . . . . . . . . . . . . . . . . . . . . . . . . . 118
12.3.1 Gotcha1:AggregationinTemplates . . . . . . . . . . . . . . . . . . . . 120
12.3.2 Gotcha2:FilteringWithConditionalsinTemplates . . . . . . . . . . . 122
12.3.3 Gotcha3:ComplexImpliedQueriesinTemplates . . . . . . . . . . . . . 124
12.3.4 Gotcha4:HiddenCPULoadinTemplates . . . . . . . . . . . . . . . . 125
12.3.5 Gotcha5:HiddenRESTAPICallsinTemplates . . . . . . . . . . . . . 126
12.4 Don’tBotherMakingYourGeneratedHTMLPretty . . . . . . . . . . . . . . . . 126
12.5 ExploringTemplateInheritance . . . . . . . . . . . . . . . . . . . . . . . . . . . 127
12.6 block.superGivesthePowerofControl . . . . . . . . . . . . . . . . . . . . . . . 131
12.7 Useful(cid:315)ingstoConsider . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 132
12.7.1 AvoidCouplingStylesTooTightlytoPythonCode . . . . . . . . . . . . 132
12.7.2 CommonConventions . . . . . . . . . . . . . . . . . . . . . . . . . . . 133
12.7.3 Location,Location,Location! . . . . . . . . . . . . . . . . . . . . . . . 133
12.7.4 UseNamedContextObjects . . . . . . . . . . . . . . . . . . . . . . . . 133
12.7.5 UseURLNamesInsteadofHardcodedPaths . . . . . . . . . . . . . . . 134
12.7.6 DebuggingComplexTemplates . . . . . . . . . . . . . . . . . . . . . . 135
12.7.7 Don’tReplacetheDjangoTemplateEngine . . . . . . . . . . . . . . . . 135
12.8 Summary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 135
13 TemplateTagsandFilters 137
13.1 FiltersAreFunctions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 137
13.1.1 FiltersAreEasytoTest . . . . . . . . . . . . . . . . . . . . . . . . . . . 138
13.1.2 Filters,CodeReuse,andPerformance . . . . . . . . . . . . . . . . . . . 138
13.1.3 WhentoWriteFilters . . . . . . . . . . . . . . . . . . . . . . . . . . . 138
13.2 CustomTemplateTags . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 138
13.2.1 TemplateTagsAreHarderToDebug . . . . . . . . . . . . . . . . . . . 139
viii
Description:Two Scoops of Django: Best Practices For Django 1.5 is chock-full of material that will help you with your Django projects.We'll introduce you to various tips, tricks, patterns, code snippets, and techniques that we've picked up over the years.This book is great for:Beginners who have just finished