Keep It Simple, Stupid
Fat Models, Helper Modules, Thin Views, Stupid Templates
# Stdlib imports from math import sqrt from os.path import abspath # Core Django imports from django.db import models from django.utils.translation import ugettext_lazy as _ # Third-party app imports from django_extensions.db.models import TimeStampedModel # Imports from your apps from otherapp.models import BananaSplit from .models import WaffleCone from .forms import WaffleConeForm
Remember Guido's words: code is read much more often than it is written (reference).
#! /usr/bin/env python # -*- coding: utf-8 -*- import os import sys _a_global_var = 2 # so it won't get imported by 'from foo import *' _b_global_var = 3 THIS_IS_A_CONSTANT = 'whatever' # 2 empty lines between top-level funcs + classes def this_is_a_function(): pass class ThisIsSomeClass(object): """Write docstrings for ALL public classes, funcs and methods. Class and exception names are CapWords. """ a = 2 b = 4 _internal_variable = 3 class_ = 'foo' # trailing underscore to avoid conflict with builtin # this will trigger name mangling to further discourage use from outside # this is also very useful if you intend your class to be subclassed, and # the children might also use the same var name for something else; e.g. # for simple variables like 'a' above. Name mangling will ensure that # *your* a and the children's a will not collide. __internal_var = 4 # NEVER use double leading and trailing underscores for your own names __nooooooodontdoit__ = 0 # some examples of how to wrap code to conform to 79-columns limit: def __init__(self): pass # 1 empty line between in-class def'ns def this_is_a_method(self, x, y=None): """Method and function names are lower_case_with_underscores. Always use self as first arg. """ pass @classmethod def bar(cls): """Use cls!""" pass # This will give a better default string representation of the class def __unicode__(self): return u"Class Representation"
Modified from http://wwd.ca/blog/2009/07/09/pep-8-cheatsheet/
Have multiple settings files, ALL of them tracked in the version control system.
settings/ __init__.py base.py local.py staging.py test.py production.py
Everything should import from base.py
# settings/local.py from .base import *
Use environment variables for production
# settings/base.py import os from django.core.exceptions import ImproperlyConfigured def get_env_variable(var_name): """ Get the environment variable or return exception """ try: return os.environ[var_name] except KeyError: error_msg = "Set the %s environment variable" % var_name raise ImproperlyConfigured(error_msg)
And never hardcode paths, use these helper functions.
# At the top of settings/base.py from os.path import join, abspath, dirname here = lambda *x: join(abspath(dirname(__file__)), *x) PROJECT_ROOT = here("..", "..") root = lambda *x: join(abspath(PROJECT_ROOT), *x) # Configuring MEDIA_ROOT MEDIA_ROOT = root('media') # Additional locations of static files STATICFILES_DIRS = ( root('assets'), ) # Configuring TEMPLATE_DIRS TEMPLATE_DIRS = ( root('templates'), )
Execute a diff between default and project settings with this command.
manage.py diff-settings
Have multiple requirements files, at least one for every environment.
requirements/ base.txt local.txt staging.txt test.txt production.txt
Everything should import from base.txt
-r base.txt django-debug-toolbar==0.9.4
If a requirements.txt is needed in the top-level directory, just put this inside.
-r requirements/production.txt
Add Indexes only as needed. It is best to start without any index and just add them when you really need them.
Regarding inheritance, avoid Multi-Table Inheritance when possible. Abstract base classes are a better alternative.
Start Normalized. All data should be stored only once in the database, and reference it from multiple models. Before Denormalizing, try to use the Cache. And Denormalize Only If Absolutely Needed.
In string-based fields (CharField, TextField, SlugField, EmailField, …) do NOT use null=True.
With BooleanField do NOT use null=True or blank=True (NullBooleanField is available for this case).
The http://ccbv.co.uk/ website contains a list of all the Django's class-based generic views, with detailed descriptions, full methods and attributes.
To view the auto-generated documentation of the CBV (including the UML) http://epydoc.pythondiary.com/generic-views/ has a really good reference.
When creating CBV, mixins go to the left side, and the classes provided by Django to the far right side.
self.assertIn("Content of the message to check", response.cookies['messages'].value)
self.assertIsNotNone(response.context['form']['field_to_test'].errors)
self.assertEqual(form["field_to_test"].errors, [force_text(form.error_messages['error_message'])])
Check that the cookie is only valid for the current browser session:
self.assertEquals(self.client.cookies.get('sessionid')['expires'], "")
Check that the cookie has an expiration date set:
self.assertNotEquals(self.client.cookies.get('sessionid')['expires'], "")