Django Best Practices
Disclaimer
● This talk should take approximately 1 month
● I don't always take my own advice
● I'm not an expert
● I'm going to forget something
● You have a different opinion than me
A note on personal philosophy
● Organization makes chaos manageable
○ PEP8
○ Code standards
○ DRY
○ Hierarchical organization lets me understand what I
need to to solve the problem in front of me
A note on personal philosophy
● Provide value with as few LOC as possible
○ "Everything should be made as simple as possible,
but not simpler"
● "Unix Philosophy"
○ Read "The Art of Unix Programming"
○ Things should fail noisily
○ Don't surprise me
Project Structure
README.md
requirements.txt
circle.yml
fabfile.py
.gitignore
venv/
docs/
conf/
newrelic.ini
project_name/
__init__.py
urls.py
wsgi.py
settings/
lib/
base/
apps/
Project Structure
README.md
requirements.txt
circle.yml
fabfile.py
.gitignore
venv/
docs/
conf/
newrelic.ini
project_name/
__init__.py
urls.py
wsgi.py
settings/
lib/
base/
apps/
README
● Your project should have a README
○ Seriously
○ You want to go on vacation
● Format it in some way that's easy to read
○ duh
● What should probably be there
○ Installation instructions
○ Design decisions
○ Contribution information (or put this in a Contributing file)
Project Structure
README.md
requirements.txt
circle.yml
fabfile.py
.gitignore
venv/
docs/
conf/
newrelic.ini
project_name/
__init__.py
urls.py
wsgi.py
settings/
lib/
base/
apps/
Requirements
● We use pip, with pretty results
● Pin your versions
Project Structure
README.md
requirements.txt
circle.yml
fabfile.py
.gitignore
venv/
docs/
conf/
newrelic.ini
project_name/
__init__.py
urls.py
wsgi.py
settings/
lib/
base/
apps/
Continuous Integration
● Run your tests regularly
● We use circleci
○ Pretty simple
○ Integrates with github
○ still working out their own bugs
● Other options
○ Buildbot
○ Jenkins
○ TravisCI
○ Codeship.io
Project Structure
README.md
requirements.txt
circle.yml
fabfile.py
.gitignore
venv/
docs/
conf/
newrelic.ini
project_name/
__init__.py
urls.py
wsgi.py
settings/
lib/
base/
apps/
Fabric
● Useful for deployment to remote machines
○ Supports parallel remote execution
● Nice python replacement for
○ Bash scripts
○ Makefiles
○ Duct Tape
Project Structure
README.md
requirements.txt
circle.yml
fabfile.py
.gitignore
venv/
docs/
conf/
newrelic.ini
project_name/
__init__.py
urls.py
wsgi.py
settings/
lib/
base/
apps/
Things that shouldn't be in the
REPO
● Generated Files
● Data files
● .pyc files
● Backup files
● Cat pictures
○ Ok, maybe cat pictures
Project Structure
README.md
requirements.txt
circle.yml
fabfile.py
.gitignore
venv/
docs/
conf/
newrelic.ini
project_name/
__init__.py
urls.py
wsgi.py
settings/
lib/
base/
apps/
virtualenv
● Oh my god use it
● Keeps your projects from stepping on each
other
● World Peace
● Kittens
Project Structure
README.md
requirements.txt
circle.yml
fabfile.py
.gitignore
venv/
docs/
conf/
newrelic.ini
project_name/
__init__.py
urls.py
wsgi.py
settings/
lib/
base/
apps/
Documentation
● IMHO lots of docs in the root make a project
hard to navigate
● Plaintext format that can generate html docs
preferred
○ ReStructured Text
○ Sphinx
Project Structure
README.md
requirements.txt
circle.yml
fabfile.py
.gitignore
venv/
docs/
conf/
newrelic.ini
project_name/
__init__.py
urls.py
wsgi.py
settings/
lib/
base/
apps/
Project Configuration
● Non-sensitive configuration files
● Avoid putting these in root, again
hierarchical structure
Project Structure
README.md
requirements.txt
circle.yml
fabfile.py
.gitignore
venv/
docs/
conf/
newrelic.ini
project_name/
__init__.py
urls.py
wsgi.py
settings/
lib/
base/
apps/
Newrelic
● Makes my life so much better
● Monitoring
○ Exceptions
○ Response Time / Profiling
○ Database profiling
● Alternatives
○ Sentry (FOSS)
○ App Dynamics
Project Structure
README.md
requirements.txt
circle.yml
fabfile.py
.gitignore
venv/
docs/
conf/
newrelic.ini
project_name/
__init__.py
urls.py
wsgi.py
settings/
lib/
base/
apps/
Root project urls
● If at all possible should only include app's url
patterns
from django.conf.urls import patterns, url, include
urlpatterns = patterns(
'project',
url(r'achievements/', include('achievements.urls'))
)
Project Structure
README.md
requirements.txt
circle.yml
fabfile.py
.gitignore
venv/
docs/
conf/
newrelic.ini
project_name/
__init__.py
urls.py
wsgi.py
settings/
lib/
base/
apps/
WSGI
● How your webserver actually hooks into your
app
● WSGI middlewares can go here
○ Haven't ever found a user for them
Project Structure
README.md
requirements.txt
circle.yml
fabfile.py
.gitignore
venv/
docs/
conf/
newrelic.ini
project_name/
__init__.py
urls.py
wsgi.py
settings/
lib/
base/
apps/
Settings
● Recently we've started using environment
variables with some success
● We've also used approaches where we have
a settings directory who's __init__.py file
determins appropriate settings for
environment
● Try to be organized, honestly, just use ENV
Project Structure
README.md
requirements.txt
circle.yml
fabfile.py
.gitignore
venv/
docs/
conf/
newrelic.ini
project_name/
__init__.py
urls.py
wsgi.py
settings/
lib/
base/
apps/
Unpackaged dependencies
● Whenever possible use pip / setuptools
● Put django snippets / projects that aren't in
pypi in lib/
● If you're going to do something dirty try to be
organized about it
Project Structure
README.md
requirements.txt
circle.yml
fabfile.py
.gitignore
venv/
docs/
conf/
newrelic.ini
project_name/
__init__.py
urls.py
wsgi.py
settings/
lib/
base/
apps/
Project specific Code
● As much as possible bundle code into
reusable apps
● Things that might have to go here
○ Custom test runners
○ Project middlewares
○ Project template context processors
○ Functions that don't make sense elsewhere
○ dbrouters
Project Structure
README.md
requirements.txt
circle.yml
fabfile.py
.gitignore
venv/
docs/
conf/
newrelic.ini
project_name/
__init__.py
urls.py
wsgi.py
settings/
lib/
base/
apps/
Django Applications
● Re-usuable apps make Django awesome
○ Use relative imports
○ Try to not include anything project specific
● Combine / split projects
○ Possible with proper organization :)
App Directory Structure
app_name/
tests.py
models.py
urls.py
admin.py
views.py
api.py
tasks.py
migrations/
management/
__init__.py
commands/
command_name.py
static/
app_name/
js/
css/
img/
templates/
app_name/
Application Tests
● You should have tests
○ TDD/BDD if possible
○ IMHO your model tests / design give better ROI
○ If you find a bug write a test to reproduce, fix
○ Seriously testing will save you time
○ Really
○ Please
App Directory Structure
app_name/
tests.py
models.py
urls.py
admin.py
views.py
api.py
tasks.py
migrations/
management/
__init__.py
commands/
command_name.py
static/
app_name/
js/
css/
img/
templates/
app_name/
Models
● Models are the lifeblood of your apps
○ Start with model design first
○ Design your data model well and views will come
naturally
● Model Managers are pretty awesome
○ Your views (controllers) should be able to call 1/2
model manager methods in order to get what it
needs otherwise code needs to be refactored into a
model manager
● Querysets can be subclassed as well
○ can make view / task code much much easier
○ DRY
App Directory Structure
app_name/
tests.py
models.py
urls.py
admin.py
views.py
api.py
tasks.py
migrations/
management/
__init__.py
commands/
command_name.py
static/
app_name/
js/
css/
img/
templates/
app_name/
Application Urls
● All views accessible in an app should be
bundled into an app level urls file
● Use named url patterns to separate patterns
from controllers.
App Directory Structure
app_name/
tests.py
models.py
urls.py
admin.py
views.py
api.py
tasks.py
migrations/
management/
__init__.py
commands/
command_name.py
static/
app_name/
js/
css/
img/
templates/
app_name/
Django Admin
● Major win
● Use django admin for as much as you can
● Most aspects are subclassable/extentable
● Your business guys don't need shiny UI
App Directory Structure
app_name/
tests.py
models.py
urls.py
admin.py
views.py
api.py
tasks.py
migrations/
management/
__init__.py
commands/
command_name.py
static/
app_name/
js/
css/
img/
templates/
app_name/
Application Views
● Make the views as simple as possible
○ Template views can probably be functions that call
render
○ If a view has lots of model calls that code can
probably go into a manager
■ Manager are easier to test
■ If managers have lots of interdependencies your
data model probably needs to be refactored
● Use django shortcuts when possible
● IMHO template logic is ok to a point if it
simplifies view code, but don't go overboard
App Directory Structure
app_name/
tests.py
models.py
urls.py
admin.py
views.py
api.py
tasks.py
migrations/
management/
__init__.py
commands/
command_name.py
static/
app_name/
js/
css/
img/
templates/
app_name/
Tasty Pie
● Don't re-invent the wheel
● Tastypie is useful for most (but not all)
RESTful applications
● The code is already tested
● You don't need as much control over JSON
structure as you think.
● This is a separate talk, but be aware of it.
App Directory Structure
app_name/
tests.py
models.py
urls.py
admin.py
views.py
api.py
tasks.py
migrations/
management/
__init__.py
commands/
command_name.py
static/
app_name/
js/
css/
img/
templates/
app_name/
Background / Async in Django
● There are lots of choices for this
● ZMQ
○ Lots of options for routing
○ VERY flexible
○ VERY fast
○ VERY cool
○ Django z-tasks looks promising
○ BUT
■ Have to write your own workers
■ Have to write your own logging / monitoring
■ Have to understand a fair amount to make it work
correctly.
■ SO...
Celery
● Should be your default choice for async
● Very simple python API
○ Async tasks
○ Tasks in the future
○ Cron replacement
● Workers are already written
● Integrated with new relic
○ Ops have been much easier for us
○ Traceback monitoring major win
App Directory Structure
app_name/
tests.py
models.py
urls.py
admin.py
views.py
api.py
tasks.py
forms.py
migrations/
management/
__init__.py
commands/
command_name.py
static/
app_name/
js/
css/
img/
templates/
app_name/
Django Forms
● Model Forms
○ DRY
○ Handles validation in a declarative way
○ Will make your life better
● Django crispy forms
○ More control
App Directory Structure
app_name/
tests.py
models.py
urls.py
admin.py
views.py
api.py
tasks.py
migrations/
management/
__init__.py
commands/
command_name.py
static/
app_name/
js/
css/
img/
templates/
app_name/
South
● Reproducible migrations
○ Schema migrations
○ Data migrations
○ Test runner
○ Probably going to be included in Django 1.6
○ Migration dependencies can be defined
App Directory Structure
app_name/
tests.py
models.py
urls.py
admin.py
views.py
api.py
tasks.py
migrations/
management/
__init__.py
commands/
command_name.py
static/
app_name/
js/
css/
img/
templates/
app_name/
Management Commands
● We used to use these for cron jobs
○ Celery beat is nicer now
● Helpful for project wide scripts that require
django context
App Directory Structure
app_name/
tests.py
models.py
urls.py
admin.py
views.py
api.py
tasks.py
migrations/
management/
__init__.py
commands/
command_name.py
static/
app_name/
js/
css/
img/
templates/
app_name/
Static Files
● Namespace your static files
○ app_name/static/app_name
○ avoids collisions
○ common static files can go in the base of the project
App Directory Structure
app_name/
tests.py
models.py
urls.py
admin.py
views.py
api.py
tasks.py
migrations/
management/
__init__.py
commands/
command_name.py
static/
app_name/
js/
css/
img/
templates/
app_name/
Application templates
● Same as static files, namespace them
● Use template inheritance
○ DRY
● Use named url patterns in your templates
● Don't go overboard with template logic
○ If you must check out template includes
○ Huge templates are hard to read
● Lots of view code data munging can be
replaced with template filters.
● Django templates are really controllers
○ Let templates act like views, handle presentation.
Other things you should be aware of
● Middlewares
● Class Based Views
● Template Context Processors
● Custom Template Tags
Django Apps that make me happy
● Django Extensions
○ Werkzeug
● South
○ Probably coming to Django 1.6
Tools you should use
● Code Quality
○ PEP8
○ Pyflakes
○ Pychecker
○ jshint
○ jslint
● Development Environment
○ ack-grep
○ emacs :)
● Infrastructure
○ PGbouncer
What did I forget?

Django best practices