Two 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: