Django Best Practices
Django Best Practices#
Some Important Rules#
Keep it simple#
When building software projects, each piece of unnecessary complexity makes it harder to add new features and maintain old ones
Simplicity is the ultimate sophistication - Leonardo Da Vinci
Fat Models, Utility Modules, Thin Views, Stupid Templates#
Stay away from putting more logic in views and templates
Start with Django by default#
Forget custom modules, keep to standard django as far as possible
Stay Aware of Django design philosophies#
Check django’s design philosophy
12 Factor App#
Be aware and implement The 12 factor app
Coding Style#
Make your code readable#
Readable code is easier to maintain.
- avoid abbreviating variable names
- Write out function argument names
- Document your classes and methods
- comment code
- refactor repeated code into reusable functions
- keep functions short, you shouldn’t need to scroll
Shortcuts come at the expense of hours of technical debt
Write out the entire variable name balance_sheet_decrease
instead of bsd
Pep-8#
There is a linter for your text editor
Also use flake8 for checking code quality and as part of CI
79 Character limit#
The 79 character limit should be adhered to on open source, 99 on closed project projects.
Imports#
Imports should be grouped in this order:
- Standard library imports
- Related-third party imports (Imports from django, then those related to django)
- Local app or library specific imports
Use Explicit relative imports#
With hardcoded imports, you can’t just change the name of the app, you have to change all the imports as well.
It also helps to tell global imports from local imports
# Use this relative import
from .models import WaffleCone
# Instead of
from cones.models import WaffleCone
Avoid using import *#
# Use
from django import forms
# Instead of
from django.forms import *
because there can be naming collisions like:
# Don't do this models overrites the forms
from django.forms import CharField
from django.db.models import CharField
to overcome naming collisions you can use as
from django.db.models import CharField as ModelCharField
from django.forms import CharField as FormCharField
Django coding Style#
Use django style guide#
Use underscore in url() name#
# wrong
name='add-topping'
# correct
name='add_topping'
url(
regex='^add/$',
view=views.add_topping,
name='add_topping'
),
Also use underscores in template block names ie. content_block
Choose a Javascript or HTML style guide#
Never Code to the IDE or Text Editor#
Never code to the IDE or Text Editor
Development Setup#
- Use the same db engine in all environments everywhere
- Fixtures are not a reliable tool for moving data from different environments, they are fine to use for basic data with
loaddata
anddumpdata
though. - Dob’t use
sqlite3
withdjango
in production - Use pip and virtualenv - toptip: use virtualenvwrapper, unfortunately I have found it quite difficult to set up.
Instead of typing something like
source Users/surfer190/projects/my-project/env/bin/activate
You can simply type
workon my-project
- Install django with
pip
and userequirement
files - Eliminate differences between environments
* Operating system differences - windows, osX, ubuntu * Python setup differences - python version * developer setup differences
How to Layout Django Projects#
Use Cookie Cutter as a reference
Recommended setup#
- Top level repo root:
readme.md
,gitignore
,requirements.txt
- Second level: project root:
django project
- Configuration root:
settings module
Django App Design Fundamentals#
Write apps that do one thing and do it well
Each app should be tightly focused on its task
It should be explained in a simple sentence (with not many ands...
)
Naming your Apps#
Your app’s name should be the plural
form of the app’s main model: flavours
, animals
, polls
, dreams
There are many exceptions: blog
being one
Also be aware of the url
so that it seperates which part of the site
When in doubt, keep apps small
Uncommon App Modules#
api/
- A package for isolating various modules when creating an APIbehaviours.py
- Option for locating model mixinsconstants.py
- App level settings, if there are enough of themdecorators.py
- Where we locate decoratorsdb/
- custom db fields or componentsfields.py
- used for form fields, sometimes for model fields when not enough code for fulldb
packagefactories.py
- where we create test data factorieshelpers.py
- helper functionsmanagers.py
- Move custom model managers to this modulesignals.py
- custom signals (argued against)utils.py
- same ashelpers
viewmixins.py
- view modules can be thinned by putting view mixings here
Settings#
- All settings should be version controlled
- Don’t repeat yourself - inherit from a base settings file
- Keep secret keys safe, outside version control
Don’t use the local_settings.py
as it can cause headaches
Instead of having a single settings.py
file, use multiple files in the settings/
directory
base.py
local.py
staging.py
test.py
production.py
Each settings module should have its own requirements
file
python manage.py runserver --settings=twoscoops.settings.local
Specify the settings file to use
Rather make use of environment settings
Models#
Don’t rush into creating models
If an app has more than 20 models, it should be broken down into smaller apps
Avoid multi-table inheritance
The TimeStamed Model#
Adds a created
and modified
fields for all models, as an abstract class.
No seperate tables are created. The fields are merely added to the new models.
from django.db import models
class TimeStampedModel(models.Model):
"""
An abstract base class model that provides self-
updating ``created`` and ``modified`` fields
"""
created = models.DateTimeField(auto_now_add=True)
modified = models.DateTimeField(auto_now=True)
class Meta:
abstract = True
Usage:
from django.db import models
from core.models import TimeStampedModel
class Flavour(TimeStampedModel):
title = models.CharField(max_length=200)
Migrations#
Make a new migration after each new model
Always put data migration code into version control
Stay normalised and use caching, try and avoid denormalisation asmuch as possible
Null and Blank#
When to use null=True
and blank=True
FileField
and ImageField
use blank
BooleanField
, use NullBooleanField