django best practices
Post on 05-Dec-2014
1.754 Views
Preview:
DESCRIPTION
TRANSCRIPT
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 StructureREADME.mdrequirements.txtcircle.ymlfabfile.py.gitignorevenv/docs/conf/ newrelic.iniproject_name/ __init__.py urls.py wsgi.py settings/ lib/ base/ apps/
Project StructureREADME.mdrequirements.txtcircle.ymlfabfile.py.gitignorevenv/docs/conf/ newrelic.iniproject_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 StructureREADME.mdrequirements.txtcircle.ymlfabfile.py.gitignorevenv/docs/conf/ newrelic.iniproject_name/ __init__.py urls.py wsgi.py settings/ lib/ base/ apps/
Requirements
● We use pip, with pretty results● Pin your versions
Project StructureREADME.mdrequirements.txtcircle.ymlfabfile.py.gitignorevenv/docs/conf/ newrelic.iniproject_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 StructureREADME.mdrequirements.txtcircle.ymlfabfile.py.gitignorevenv/docs/conf/ newrelic.iniproject_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 StructureREADME.mdrequirements.txtcircle.ymlfabfile.py.gitignorevenv/docs/conf/ newrelic.iniproject_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 StructureREADME.mdrequirements.txtcircle.ymlfabfile.py.gitignorevenv/docs/conf/ newrelic.iniproject_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 StructureREADME.mdrequirements.txtcircle.ymlfabfile.py.gitignorevenv/docs/conf/ newrelic.iniproject_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 StructureREADME.mdrequirements.txtcircle.ymlfabfile.py.gitignorevenv/docs/conf/ newrelic.iniproject_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 StructureREADME.mdrequirements.txtcircle.ymlfabfile.py.gitignorevenv/docs/conf/ newrelic.iniproject_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 StructureREADME.mdrequirements.txtcircle.ymlfabfile.py.gitignorevenv/docs/conf/ newrelic.iniproject_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 StructureREADME.mdrequirements.txtcircle.ymlfabfile.py.gitignorevenv/docs/conf/ newrelic.iniproject_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 StructureREADME.mdrequirements.txtcircle.ymlfabfile.py.gitignorevenv/docs/conf/ newrelic.iniproject_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 StructureREADME.mdrequirements.txtcircle.ymlfabfile.py.gitignorevenv/docs/conf/ newrelic.iniproject_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 StructureREADME.mdrequirements.txtcircle.ymlfabfile.py.gitignorevenv/docs/conf/ newrelic.iniproject_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 StructureREADME.mdrequirements.txtcircle.ymlfabfile.py.gitignorevenv/docs/conf/ newrelic.iniproject_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 Structureapp_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 Structureapp_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 Structureapp_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 Structureapp_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 Structureapp_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 Structureapp_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 Structureapp_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 Structureapp_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 Structureapp_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 Structureapp_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 Structureapp_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 Structureapp_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?
top related