django best practices

213
Django Best Practices March, 2014 / Abdullah Cetin CAVDAR @accavdar

Upload: abdullah-cetin-cavdar

Post on 17-Jul-2015

546 views

Category:

Technology


0 download

TRANSCRIPT

Page 1: Django Best Practices

Django BestPractices

March, 2014 / Abdullah Cetin CAVDAR @accavdar

Page 2: Django Best Practices

This presentation is prepared based on the great book by and

Two Scoops ofDjango: Best Practices For Django 1.5 Daniel Greenfeld

Audrey Roy

Page 3: Django Best Practices

Core Concepts

Page 4: Django Best Practices

KISSKeep It Simple, Stupid

Page 5: Django Best Practices

Fat Models, Helper Modules,Thin Views, Stupid TemplatesPut more logic into anything but views and templatesTemplate tags and filters should contain the minimum logic possible

Page 6: Django Best Practices

Start With Django by DefaultIf we run into obstacles, we explore all possibilities before replacingcore Django components

Page 7: Django Best Practices

Coding Style

Page 8: Django Best Practices

The Importance of Making YourCode Readable

Avoid abbreviating variable namesGood: balance_sheet_decreaseBad: bsd or bal_s_d

Write out your function argument namesDocument your classes and methodsRefactor repeated lines of code into reusable functions or methods

Page 9: Django Best Practices

PEP8Use 4 spaces per indentation levelSeparate top-level function and class definitions with two blank linesMethod definitions inside a class are separated by a single blank line

Page 10: Django Best Practices

The Word on ImportsThe Order:

Standard library importsImports from core DjangoImports from third-party appsImports from the apps that you created as part of your Django project

Page 11: Django Best Practices

The Word on Imports

Page 12: Django Best Practices

Use Explicit Relative ImportsDon't do this:

Page 13: Django Best Practices

Use Explicit Relative ImportsDo this:

Page 14: Django Best Practices

Import Types

Page 15: Django Best Practices

Get into the habit of using explicit relativeimports

Page 16: Django Best Practices

Avoid Using Import *Don't do this:

Page 17: Django Best Practices

Avoid Using Import *The reason for this is to avoid implicitly loading all of another Pythonmodule’s locals into and over our current module’s namespace, which

can produce unpredictable and sometimes catastrophic results.

Page 18: Django Best Practices

Django Coding Style GuidelinesUse underscores (the '_' character) in URL pattern names rather thandashes as this is friendlier to more IDEs and text editors.For the same reason, use underscores rather than dashes in templateblock names.Follow the commonly used naming pattern of <app_name>_tags.pyfor template tags

Django Coding Style Guidelines

Page 19: Django Best Practices

SummaryFollow a consistent coding styleProjects with varying styles are much harder to maintain, slowingdevelopment and increasing the chances of developer mistakes

Page 20: Django Best Practices

The Optimal DjangoEnvironment Setup

Page 21: Django Best Practices

Use the Same Database EngineEverywhere

A common developer pitfall is using SQLite3 for local development andPostgreSQL (or another database besides SQLite3) in production.

They may not behave identical in different environments.Fixtures Are Not a Magic SolutionYou Can’t Examine an Exact Copy of Production Data LocallyDifferent Databases Have Different Field Types/Constraints

Page 22: Django Best Practices

Use Pip and VirtualenvPip is used to manage and install Python packagesWithout virtualenv you have to update dependency versions everytime you switch projectsIf that sounds tedious, keep in mind that most real Django projectshave at least a dozen dependencies to maintain$ source ~/Envs/udemy/bin/activate

Page 23: Django Best Practices

Install Django and OtherDependencies via Pip

Page 24: Django Best Practices

Use a Version Control System

Page 25: Django Best Practices

How to Layout Django Projects

Page 26: Django Best Practices

Prefered Project Layout

Page 27: Django Best Practices

Top Level: Repository RootThe top-level <repository_root>/ directory is the absolute rootdirectory of the projectPlace other critical components like the README.rst, docs/ directory,design/ directory, .gitignore, requirements.txt files, and other high-level files that are required for deployment

Page 28: Django Best Practices

Second Level: Django ProjectRoot

This directory contains the <configuration_root>, media and staticdirectories, a site-wide templates directory, as well as Django appsspecific to your particular project

Page 29: Django Best Practices

Third Level: Configuration Root<configuration_root> directory is where the settings module and baseURLConf (urls.py) are placedThis must be a valid Python package (containing an __init__.py module)

Page 30: Django Best Practices

Sample Project Layout

Page 31: Django Best Practices

What About the Virtualenv?Put all our environments in one directory and all our projects inanother

Page 32: Django Best Practices

TIP: Listing Current Dependenciespip freeze --local

Page 33: Django Best Practices

Template to Generate Layoutdjango-admin.py startproject --

template=https://github.com/twoscoops/django-twoscoops-project/zipball/master --extension=py,rst,html $project-name

Page 34: Django Best Practices

SummaryWhatever layout is chosen should be documented clearly

Page 35: Django Best Practices

Fundamentals of Django AppDesign

Page 36: Django Best Practices

DefinitionsA Django project is a web application powered by the Django webframeworkDjango apps are small libraries designed to represent a single aspectof a project. A Django project is made up of many Django apps. Someof those apps are internal to the project and will never be reused;others are third-party Django packages.Third-party Django packages are simply pluggable, reusable Djangoapps that have been packaged with the Python packaging tools.

Page 37: Django Best Practices

The Golden Rule of Django AppDesign

"Write programs that do one thing and do it well"

Page 38: Django Best Practices

The Golden Rule of Django AppDesign

Each app should be tightly focused on its taskIf an app can’t be explained in a single sentence of moderate length, oryou need to say 'and' more than once, it probably means the app is too

big and should be broken up

Page 39: Django Best Practices

What to Name Your DjangoApps

When possible keep to single word names like flavors, animals, blog,polls, dreams, estimates, and finances. A good, obvious app namemakes the project easier to maintainAs a general rule, the app’s name should be a plural version of theapp’s main model, but there are many good exceptions to this rule,blog being one of the most common onesUse valid, PEP 8-compliant, importable Python package names: short,all-lowercase names without numbers, dashes, periods, spaces, orspecial characters. If needed for readability, you can use underscoresto separate words, although the use of underscores is discouraged

Page 40: Django Best Practices

When in Doubt, Keep AppsSmall

Try and keep your apps small. Remember, it’s better to have many smallapps than to have a few giant apps.

Page 41: Django Best Practices

SummaryEach Django app should be tightly-focused on its own task, possess asimple, easy-to-remember nameIf an app seems too complex, it should be broken up into smaller apps

Page 42: Django Best Practices

Settings and RequirementsFiles

Page 43: Django Best Practices

Best PracticesAll settings files need to be version-controlled

This is especially true in production environments, where dates,times, and explanations for settings changes absolutely must betracked

Don’t Repeat YourselfYou should inherit from a base settings file rather than cutting-and-pasting from one file to another

Keep secret keys safeThey should be kept out of version control

Page 44: Django Best Practices

Avoid Non-Versioned LocalSettings

Let’s break up development, staging, test, and production settings intoseparate components that inherit from a common base file all tracked

by version control

Page 45: Django Best Practices

Using Multiple Settings Files

Page 46: Django Best Practices
Page 47: Django Best Practices

TIP: Multiple Files with Continuous Integration Servers

You’ll also want to have a ci.py module containing that server’s settings.

Page 48: Django Best Practices

Run Serverpython manage.py runserver --settings=udemy.settings.local

Page 49: Django Best Practices

--settings orDJANGO_SETTINGS_MODULE

Page 50: Django Best Practices

DEV Settings Example

Page 51: Django Best Practices

Keep Secret Keys Out with EnvironmentVariables

Secrets often should be just that: secret! Keeping them in versioncontrol means that everyone with repository access has access tothemSecret keys are configuration values, not code

Page 52: Django Best Practices

To resolve this, our answer is touse environment variables

Page 53: Django Best Practices

Benefits of Using EVKeeping secrets out of settings allows you to store every settings file inversion control without hesitation. All of your Python code reallyshould be stored in version control, including your settingsInstead of each developer maintaining an easily-outdated, copy-and-pasted version of the local_settings.py.example file for their owndevelopment purposes, everyone shares the same version-controlledsettings/local.pySystem administrators can rapidly deploy the project without havingto modify files containing Python codeMost platforms-as-a-service recommend the use of environmentvariables for configuration and have built-in features for setting andmanaging them

Page 54: Django Best Practices

Local Settings & Usage

Page 55: Django Best Practices

Using Multiple RequirementsFiles

First create a requirements/ directory in the <repository_root>Then create '.txt' files that match the contents of your settingsdirectory

Page 56: Django Best Practices

Sample Configbase.txt

local.txt

Page 57: Django Best Practices

Install From Reqs Filefor development env

for production env

Page 58: Django Best Practices

Handling File Paths in SettingsDon't hardcode your paths

Page 59: Django Best Practices

Hardcoded PathsDon't do this:

Page 60: Django Best Practices

Relative Paths with UnipathDo this:

Page 61: Django Best Practices

Relative Paths with Std LibsDo this:

Page 62: Django Best Practices

SummaryEverything except for critical security related values ought to betracked in version controlAny project that’s destined for a real live production server is bound toneed multiple settings and requirements filesThe same thing applies to requirements files. Working with untrackeddependency differences increases risk as much as untracked settings

Page 63: Django Best Practices

Database/Model Best Practices

Page 64: Django Best Practices

BasicsBreak Up Apps With Too Many ModelsDon’t Drop Down to Raw SQL Until It’s NecessaryAdd Indexes as NeededBe Careful With Model InheritanceUse South for Migrations

Page 65: Django Best Practices

Consider Adding Indexes?The index is used frequently, as in 10-25% of all queriesThere is real data, or something that approximates real data, so wecan analyze the results of indexingWe can run tests to determine if indexing generates an improvementin results

Page 66: Django Best Practices

Django Model InheritanceNo Model Inheritance if models have a common field, give both models

that fieldPro: Makes it easiest to understand at a glance how Django modelsmap to database tablesCon: If there are a lot of fields duplicated across models, this can behard to maintain

Page 67: Django Best Practices

Django Model InheritanceAbstract base classes tables are only created for derived models

Pro: Having the common fields in an abstract parent class saves usfrom typing them more than once. We don’t get the overhead of extratables and joins that are incurred from multi-table inheritanceCon: We cannot use the parent class in isolation

Page 68: Django Best Practices

Django Model InheritanceMulti-table inheritance tables are created for both parent and child. An

implied OneToOneField links parent and childPro: Gives each model its own table, so that we can query eitherparent or child model. Also gives us the ability to get to a child objectfrom a parent object: parent.childCon: Adds substantial overhead since each query on a child tablerequires joins with all parent tables. We strongly recommend againstusing multi-table inheritance

Page 69: Django Best Practices

Django Model InheritanceProxy Models a table is only created for the original model

Pro: Allows us to have an alias of a model with different PythonbehaviorCon: We cannot change the model’s fields

Page 70: Django Best Practices

WARNING: Avoid Multi-TableInheritance

Multi-table inheritance, sometimes called "concrete inheritance" isconsidered by the authors and many other developers to be a bad thing.

We strongly recommend against using it

Page 71: Django Best Practices

Django Model Design

Page 72: Django Best Practices

Design BasicsStart NormalizedCache Before DenormalizingDenormalize Only if Absolutely NeededWhen to Use Null and Blank

Page 73: Django Best Practices

Null vs. Blank

Page 74: Django Best Practices

Model Managers

Page 75: Django Best Practices

Model Managers BasicsEvery time we use the Django ORM to query a model, we are using an

interface called a model manager to interact with the databaseDjango provides a default model manager for each model class, but we

can define our own

Page 76: Django Best Practices

Custom Model Manager

Page 77: Django Best Practices

Custom Model Manager

Page 78: Django Best Practices

SummaryTake the time to design models thoughtfullyStart normalized, and only denormalize if you’ve already exploredother options thoroughlyTry to address your performance issues with cachingDon’t forget to use indexes. Add indexes when you have a better feelIf you decide to use model inheritance, inherit from abstract baseclasses rather than concrete models. You’ll save yourself from theconfusion of dealing with implicit, unneeded joinsUse South to manage your data and schema migrations

Page 79: Django Best Practices

Function- and Class- BasedViews

Page 80: Django Best Practices

When to use FBV or CBVs

Page 81: Django Best Practices

Keep View Logic Out ofURLConfs

The views modules should contain view logicThe URL modules should contain URL logic

Page 82: Django Best Practices
Page 83: Django Best Practices

Stick to Loose Coupling inURLConfs

Page 84: Django Best Practices
Page 85: Django Best Practices
Page 86: Django Best Practices

Best PracticesDon’t Repeat Yourself: No argument or attribute is repeated betweenviewsLoose coupling: We’ve removed the model and template names fromthe URLConf because views should be views and URLConfs should beURLConfs. We should be able to call our views from one or moreURLConfs, and our approach lets us do just thatURLConfs should do one thing and do it well: Related to our previousbullet, our URLConf is now focused primarily on just one thing: URLrouting. We aren’t tracking down view logic across both views andURLConfs, we just look in our viewsOur views benefit from being class-based: Our views, by having aformal definition in the views module, can inherit from other classes.This means adding authentication, authorization, new contentformats, or anything other business requirement tossed our way ismuch easier to handleInfinite flexibility: Our views, by having a formal definition in the viewsmodule, can implement their own custom logic

Page 87: Django Best Practices

Try to Keep Business Logic Outof Views

Placing so much logic in our views made it much harder to deliver newformats such as PDF or REST APIBusiness logic is placed into easily reusable components, and calledfrom within views, it makes extending components of the project todo more things much easier

Page 88: Django Best Practices

Best Practices for Class-BasedViews

Page 89: Django Best Practices

Guideline when writing CBVsLess view code is betterNever repeat code in viewsViews should handle presentation logic. Try to keep business logic inmodels when possible, or in forms if you mustKeep your views simpleKeep your mixins simpler

Page 90: Django Best Practices

Mixin RulesThe base view classes provided by Django always go to the rightMixins go to the left of the base viewMixins should inherit from Python’s built-in object type

Page 91: Django Best Practices
Page 92: Django Best Practices

Django CBVs

Page 93: Django Best Practices

Constraining Django CBV Access toAuthenticated Users

PS: It uses braces lib

Page 94: Django Best Practices

Things to Know About Forms

Page 95: Django Best Practices

Statistics95% of Django projects should use ModelForms91% of all Django projects use ModelForms80% of ModelForms require trivial logic20% of ModelForms require complicated logic

Page 96: Django Best Practices

Use the POST Method in HTMLForms

Every HTML form that alters data must submit its data via the POSTmethod

The only exception you’ll ever see to using POST in forms is with searchforms, which typically submit queries that don’t result in any alteration

of data.

Page 97: Django Best Practices

Know How Form Validation WorksWhen you call form.is_valid(), a lot of things happen behind the scenes.

The following things occur according to this workflow:If the form has bound data, form.is_valid() calls the form.full_clean()methodform.full_clean() iterates through the form fields and each fieldvalidates itself:

Data coming into the field is coerced into Python via theto_python() method or raises a ValidationErrorData is validated against field-specific rules, including customvalidators. Failure raises a ValidationErrorIf there are any custom clean_ <field>() methods in the form, theyare called at this time

form.full_clean() executes the form.clean() methodIf it’s a ModelForm instance, form._post_clean() does the following:

Sets ModelForm data to the Model instance, regardless of whetherform.is_valid() is True or FalseCalls the model’s clean() method. For reference, saving a modelinstance through the ORM does not call the model’s clean() method

Page 98: Django Best Practices

Form Data Is Saved to the Form, Then theModel Instance

First, form data is saved to the form instanceLater, form data is saved to the model instance

Page 99: Django Best Practices

SummaryOnce you dig into forms, keep yourself focused on clarity of code and

testability

Page 100: Django Best Practices

Building REST APIs in Django

Page 101: Django Best Practices

Fundamentals of Basic RESTAPI Design

Page 102: Django Best Practices

NotesIf you’re implementing a read-only API, you might only need toimplement GET methodsIf you’re implementing a read-write API you must at least also usePOST, but should also consider using PUT and DELETEBy definition, GET, PUT, and DELETE are idempotent. POST andPATCH are notPATCH is often not implemented, but it’s a good idea to implement itif your API supports PUT requests

Page 103: Django Best Practices

Status Codes

Page 104: Django Best Practices

Implementing a Simple JSON APIUse django-rest-framework

Page 105: Django Best Practices
Page 106: Django Best Practices
Page 107: Django Best Practices
Page 108: Django Best Practices
Page 109: Django Best Practices

REST API Architecture

Page 110: Django Best Practices

Code for an App Should Remain in the AppREST API views should go into views.py modules and follow the same

guidelines we endorse when it comes to any other viewThe same goes for app or model specific serializers and renderers.

Page 111: Django Best Practices

Try to Keep Business Logic Out of APIViews

It’s a good idea to try to keep as much logic as possible out of API views

Page 112: Django Best Practices

Grouping API URLsHow do you build a project-wide API that looks like this?

Page 113: Django Best Practices

SolutionWhen building a project-wide API we write the REST views in the

views.py modules, wire them into a URLConf called something likecore/api.py or core/apiv1.py and include that from the project root’s

urls.py module

Page 114: Django Best Practices
Page 115: Django Best Practices

Templates: Best Practices

Page 116: Django Best Practices

Follow a Minimalist ApproachFind simple, elegant ways to put more of your business logic into Python

code rather than into templates

Page 117: Django Best Practices

Template Architecture Patterns2-Tier Template Architecture Example3-Tier Template Architecture Example

Page 118: Django Best Practices

2-Tier Template ArchitectureExample

Page 119: Django Best Practices

3-Tier Template ArchitectureExample

Page 120: Django Best Practices

Flat Is Better Than NestedComplex template hierarchies make it exceedingly difficult to debug,

modify, and extend HTML pages and tie in CSS stylesWhen you have large, multi-line chunks of the same or very similar code

in separate templates, refactoring that code into reusable blocks willmake your code more maintainable.

Page 121: Django Best Practices

Template Best PracticesLimit Processing in Templates

Try to think about caching to handle template inefficienciesDon't Aggregate in Templates

Ex: Birth Date -> AgeDon't Filter With Conditionals in TemplatesDon't Use Complex Implied Queries in TemplatesAvoid Hidden CPU Load in Templates

Ex: Take image processing out of templates and into views,models, helper methods, or asynchronous messages queues likeCelery

Avoid Hidden REST API Calls in TemplatesAn example is querying an unfortunately slow maps API hosted bya third-party service

Page 122: Django Best Practices

Don't Filter With Conditionals inTemplates

Don't do this:

Page 123: Django Best Practices

Don't Filter With Conditionals inTemplates

Do this:

Page 124: Django Best Practices

Don't Filter With Conditionals inTemplates

Do this:

Page 125: Django Best Practices

Don't Use Complex ImpliedQueries in Templates

Don't do this:

Page 126: Django Best Practices

Don't Use Complex ImpliedQueries in Templates

Use select_related() methodDo this:

Page 127: Django Best Practices

Exploring Template Inheritance

Page 128: Django Best Practices

Template Tags

Page 129: Django Best Practices
Page 130: Django Best Practices
Page 131: Django Best Practices

Template Objects

Page 132: Django Best Practices

{block super}

Page 133: Django Best Practices

Use URL Names Instead of HardcodedPaths

Page 134: Django Best Practices

Trade offs of Replacing CoreComponents

Page 135: Django Best Practices

Short Answer: Don’t do it

Page 136: Django Best Practices

Dealing with the User Model

Page 137: Django Best Practices

Finding the User Model

Page 138: Django Best Practices

Use settings.AUTH_USER_MODEL forForeign Keys

Page 139: Django Best Practices

Custom User ModelOption 1: Linking Back From a Related ModelOption 2: Subclass AbstractUserOption 3: Subclass AbstractBaseUser

Page 140: Django Best Practices

Linking Back From a Related Model

Page 141: Django Best Practices

Subclass AbstractUser

Page 142: Django Best Practices

Subclass AbstractBaseUserAbstractBaseUser is the bare-bones option with only 3 fields: password,

last_login, and is_activeChoose this option if:

You’re unhappy with the fields that the User model provides bydefault, such as first_name and last_nameYou prefer to subclass from an extremely bare-bones clean slate butwant to take advantage of the AbstractBaseUser sane defaultapproach to storing passwords

Official Doc: Customizing User

Page 143: Django Best Practices
Page 144: Django Best Practices

SummaryDepending on the needs of a project, they can either continue with the

current way of doing things or customize the actual user model

Page 145: Django Best Practices

Testing

Page 146: Django Best Practices

Useful Libraries For Testing DjangoProjects

Use coverage.py and django-discover-runner

Page 147: Django Best Practices

How to Structure TestsThe first thing we do is delete the default but useless tests.py module

that django-admin.py startapp createsIn its place, we create a tests directory and place an __init__.py file in it so

it becomes a valid Python module. Then, inside the new tests module,because most apps need them, we create test_forms.py, test_models.py,test_views.py modules. Tests that apply to forms go into test_forms.py,

model tests go into test_models.py, and so on

Page 148: Django Best Practices

Test Structure

Page 149: Django Best Practices

TIP: Prefix Test Modules With test_It’s critically important that we always prefix test modules with test_,

otherwise we can’t configure django-discover-runner to discover just ourtest files.

Page 150: Django Best Practices

How to Write Unit Tests

Page 151: Django Best Practices

Each Test Method Tests One ThingA single test should assert the behavior of a single view, model, form,

method or functionBe absolutely minimalistic when constructing the environment

Page 152: Django Best Practices

Don’t Write Tests That Have to Be TestedTests should be written as simply as possible. If the code in a test or

called to help run a test feels complicated or abstracted, then you havea problem

Don’t Repeat Yourself Doesn’t Apply to Writing Tests

Page 153: Django Best Practices

PACKAGE TIP: Tools to Generate Test Datafactory_boy A package that generates model test datamodel_mommy Another package that generates model test datamock Not explicitly for Django, this allows you to replace parts of yoursystem with mock objects

Page 154: Django Best Practices

Things That Should Be Tested

EverythingViews, Models, Forms, Validators, Filters, Signals, Template Tags, ...

Page 155: Django Best Practices

Continuous Integration (CI)For medium and large projects, we recommend setting up a continuous

integration (CI) server to run the project’s test suite whenever code iscommitted and pushed to the project repo

Page 156: Django Best Practices

Test CoverageTry to get test coverage as high as possible. Every work day we increaseour test coverage is a victory, and every day the coverage goes down is a

loss

Page 157: Django Best Practices

Setup a Test RunnerCreate a settings/test.py module and add the following

Page 158: Django Best Practices

Run Tests and Generate Coverage Report

Page 159: Django Best Practices

Generate Report

Page 160: Django Best Practices

Playing the Game of Test CoverageThe game has a single rule:

Mandate that no commit can lower testcoverage

Page 161: Django Best Practices

Finding and ReducingBottlenecks

Page 162: Django Best Practices

Speed Up Query-Heavy PagesUse django-debug-toolbar to help you determine where most of yourqueries are coming from. Configure it to include the SQLDebugPanelAdd django-cache-panel to your project, but only configured to runwhen settings/dev.py module is called. This will increase visibility intowhat your cache is doingdjango-extensions comes with a tool called RunProfileServer thatstarts Django’s runserver command with hotshot/profiling toolsenabledReduce the Number of Queries

Use select_related() in your ORMImplement caching using a key/value store such as Memcached

Speed Up Common Queries

Page 163: Django Best Practices

TIP: Use EXPLAIN ANALYZE / EXPLAINIf you’re using PostgreSQL, you can use EXPLAIN ANALYZE to get an

extremely detailed query plan and analysis of any raw SQL query. TheMySQL equivalent is the EXPLAIN command, which isn’t as detailed but

is still helpful

Page 164: Django Best Practices

Get the Most Out of Your DatabaseDon’t add logs to the database. They will slow DB performanceDon’t store ephemeral data in the database. This includes examplessuch as django.contrib.sessions, django.contrib.messages, andmetrics. Instead, move this data to things like Memcached, Redis,Riak, and other non-relational storesTry performance tuning for your database (ex: MySQL)

Page 165: Django Best Practices

Cache Queries With Memcached or RedisSimply setting up Django’s built-in caching system with Memcached or

Redis

Page 166: Django Best Practices

Identify Specific Places to CacheWhich views/templates contain the most queries?Which URLs are being requested the most?When should a cache for a page be invalidated?

Page 167: Django Best Practices

Consider Third-Party Caching PackagesAdditional Features of 3rd party packages:

Caching of QuerySetsCache invalidation settings/mechanismsAlternative or experimental approaches to cachingEx: django-cache-machine, johnny-cache

Page 168: Django Best Practices

Compression and Minification of HTML,CSS, and JavaScript

Django provides tools for you: GZipMiddleware and the {% spaceless %}template tag. However, compression and minification take up system

resources, which can create bottlenecks of their ownA better approach is to use Apache and Nginx web servers configured to

compress the outgoing content

Page 169: Django Best Practices

Use Upstream Caching or a ContentDelivery Network

Upstream caches such as Varnish are very useful. They run in front ofyour web server and speed up web page or content serving significantlyContent Delivery Networks (CDNs) like Akamai and Amazon Cloudfront

serve static media such as images, video, CSS, and JavaScript files

Page 170: Django Best Practices

Security Best Practices

Page 171: Django Best Practices

Harden Your ServersChange your SSH port and disable/remove unnecessary services

Page 172: Django Best Practices

Know Django’s Security FeaturesDjango has lots of security features. Know how to configure them.

Django security features include:Cross-site scripting (XSS) protectionCross-site request forgery (CSRF) protectionSQL injection protectionClickjacking protectionSupport for SSL/HTTPS, including secure cookiesValidation of files uploaded by usersSecure password storage, using the PBKDF2 algorithm with a SHA256hash by defaultAutomatic HTML escaping

Page 173: Django Best Practices

Turn Off DEBUG Mode in ProductionYour production site should not be running in DEBUG mode

Page 174: Django Best Practices

Keep Your Secret Keys SecretKeep Secret Keys Out With Environment Variables

Page 175: Django Best Practices

HTTPS EverywhereIt is always better to deploy a site behind HTTPSTwo packages that force HTTPS/SSL across your entire site throughDjango middleware

django-sslifydjango-secure

Page 176: Django Best Practices

Use HTTP Strict Transport Security (HSTS)When you enable HSTS, your site’s web pages include a HTTP header

that tells HSTS-compliant browsers to only connect to the site via secureconnections:

Page 177: Django Best Practices

Use Secure CookiesYour site’s cookies should also be served over HTTPS. You’ll need to set

the following in your settings:HSTS-compliant browsers will redirect HTTP links to HTTPSIf a secure connection isn’t possible (e.g. the certificate is self-signed orexpired), an error message will be shown and access will bedisallowed

Page 178: Django Best Practices

Use Django’s Allowed Hosts ValidationYou must set ALLOWED_HOSTS in your settings to a list of allowed

host/domain names. This is a security measure to prevent use of fakeHTTP Host headers to submit requests

Page 179: Django Best Practices

Always Use CSRF Protection With HTTPForms That Modify Data

Django comes with Cross-site Request Forgery Protection (CSRF) built inYou should use Django’s CsrfViewMiddleware as blanket protection

across your site rather than manually decorating views with csrf_protect

Page 180: Django Best Practices

Prevent Against Cross-Site Scripting (XSS)Attacks

Django by default escapes a lot of specific characters meaning mostattacks fail

Page 181: Django Best Practices

Defend Against Python Code InjectionAttacks

Beware of the eval(), exec(), and execfile() built-ins. If your projectallows arbitrary strings or files to be passed into any of thesefunctions, you are leaving your system open to attackNever unpickle data received from an untrusted or unauthenticatedsourceValidate All User Input With Django Forms

Page 182: Django Best Practices

Handle User-Uploaded Files CarefullyPay close attention to where you’re uploading them and what type offiles they are, to avoid security holesUse the python-magic library to check the uploaded file’s headers

Page 183: Django Best Practices

Don’t Use ModelForms.Meta.excludeWhen using ModelForms, always use Meta.fields. Never use

Meta.exclude. The use of Meta.exclude is considered a grave securityrisk. We can’t stress this strongly enough. Don’t do it

Page 184: Django Best Practices

Meta.fields vs. Meta.exclude

Page 185: Django Best Practices

Beware of SQL Injection AttacksThe Django ORM generates properly-escaped SQL which will protectyour site from users attempting to execute malignant, arbitrary SQL

codeWhen using raw SQL, be especially careful to escape your SQL code

properly

Page 186: Django Best Practices

Never Store Credit Card DataWe recommend using third-party services like Stripe, Balanced

Payments, PayPal, and others that handle storing this information foryou

Page 187: Django Best Practices

Secure the Django AdminSince the Django admin gives your site admins special powers thatordinary users don’t have, it’s good practice to make it extra secure

Change the Default Admin URLUse django-admin-honeypotOnly Allow Admin Access via HTTPSLimit Admin Access Based on IP

Page 188: Django Best Practices

Monitor Your SitesCheck your web servers’ access and error logs regularly. Install

monitoring tools and check on them frequently

Page 189: Django Best Practices

Keep Your Dependencies Up-to-DateYou should always update your projects to work with the latest stable

release of Django. This is particularly important when a release includessecurity fixes

Page 190: Django Best Practices

Put Up a Vulnerability Reporting PageIt’s a good idea to publish information on your site about how users can

report security vulnerabilities to you

Page 191: Django Best Practices

Logging

Page 192: Django Best Practices

When to Use Each Log LevelLOG Levels: DEBUG, INFO, WARNING, ERROR, and CRITICAL

In your production environment, we recommend using every log levelexcept for DEBUG

Page 193: Django Best Practices

Log Catastrophes With CRITICALEx: if your code relies on an internal web service being available, and ifthat web service is part of your site’s core functionality, then you mightlog at the CRITICAL level anytime that the web service is inaccessible

Page 194: Django Best Practices

Log Production Errors With ERRORWe recommend that you use the ERROR log level whenever you need tolog an error that is worthy of being emailed to you or your site admins

Page 195: Django Best Practices

Log Lower-Priority Problems WithWARNING

This level is good for logging events that are unusual and potentiallybad, but not as bad as ERROR-level events

Ex: if you are using django-admin-honeypot to set up a fake admin/login form, you might want to log intruders' login attempts to this level

Page 196: Django Best Practices

Log Useful State Information With INFOStartup and shutdown of important components not loggedelsewhereState changes that occur in response to important eventsChanges to permissions, e.g. when users are granted admin access

Page 197: Django Best Practices

Log Debug-Related Messages to DEBUG

Page 198: Django Best Practices

Log Tracebacks When Catching ExceptionsLogger.exception() automatically includes the traceback and logs atERROR levelFor other log levels, use the optional exc_info keyword argument

Page 199: Django Best Practices

One Logger Per Module That Uses LoggingWhenever you use logging in another module, don’t import and reuse a

logger from elsewhere. Instead, define a new logger specific to themodule like this

Page 200: Django Best Practices

Log Locally to Rotating FilesA common way to set up log rotation is to use the UNIX logrotate utility

with logging.handlers.WatchedFileHandler

Page 201: Django Best Practices

Other Logging TipsControl the logging in settings files per the Django documentation onloggingWhile debugging, use the Python logger at DEBUG levelAfter running tests at DEBUG level, try running them at INFO andWARNING levels. The reduction in information you see may help youidentify upcoming deprecations for third-party librariesDon’t wait until it’s too late to add logging. You’ll be grateful for yourlogs if and when your site failsUse logutils utility for advanced logging features

Page 202: Django Best Practices

Random Utilities

Page 203: Django Best Practices

Create a Core App for Your UtilitiesOur way of handling our utilities is to place them into a Django app

called core that contains modules which contains functions and objectsfor use across a project

Page 204: Django Best Practices

Django’s Own Swiss Army KnifeDjango has a number of useful helper functions that don’t have a better

home than the django.utils package

Page 205: Django Best Practices

django.contrib.humanizehis is a set of localized template filters designed to give user presented

data a more 'human' touch

Page 206: Django Best Practices

django.utils.html.remove_tags(value,tags)

When you need to accept content from users and want to strip out a listof tags, this function removes those tags for you while keeping all other

content untouched

Page 207: Django Best Practices

django.utils.html.strip_tags(value)When you need to accept content from users and have to strip out

anything that could be HTML, this function removes those tags for youwhile keeping all the existing text between tags

Page 208: Django Best Practices

django.utils.text.slugify(value)Whatever you do, don’t write your own version of the slugify() function;

as any inconsistency from what Django does with this function will causesubtle yet nasty problems. Instead, use the same function that Django

uses and slugify() consistently

Page 209: Django Best Practices

django.utils.timezoneWhen you use Django’s time zone support, date and time information isstored in the database uniformly in UTC format and converted to local

time zones as needed

Page 210: Django Best Practices

django.utils.translationMuch of the non-English speaking world appreciates use of this tool, as

it provides Django’s i18n support

Page 211: Django Best Practices

Deploying Django Projects

Page 212: Django Best Practices

Using Your Own Web ServersYou should deploy your Django projects with WSGI

Most common setup:Gunicorn behind a Nginx proxyApache with mod_wsgi

Page 213: Django Best Practices

Quick Comparison