Skip to content

Instantly share code, notes, and snippets.

@r1chardj0n3s
Created August 20, 2012 01:04
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save r1chardj0n3s/3398973 to your computer and use it in GitHub Desktop.
Save r1chardj0n3s/3398973 to your computer and use it in GitHub Desktop.
How to set up Django

A Django site has a few components:

  • the core software and 3rd party modules (installed with pip into a virtualenv)
  • settings.py (identified by the DJANGO_SETTINGS_MODULE environment variable) known as "the settings file"
  • manage.py (which basically takes over from django-admin once your site is created)
  • urls.py (referenced by settings file)
  • the apps you create and 3rd party apps
  • static content to support the site

Optionally your site may also have:

  • files uploaded to the site which need to be served from the site

The typical site directory looks like this:

my_site
my_site/__init__.py
my_site/settings.py
my_site/manage.py
my_site/urls.py

The settings file (settings.py) is pretty much a custom file per site that uses a bunch of Django applications (even if there's really only the one core application you're deploying there you inevitably end up using a bunch of Django core applications alongside it like authentication and admin.)

Fortunately the static content and uploaded file content are managed by the settings file parameters STATIC_ROOT (and STATIC_URL) and MEDIA_ROOT (and MEDIA_URL). For more information about dealing with static files see the official static files HOWTO.

Generally speaking the settings file should be version-controlled, but if it's stored in a public repository then there'll be content that should never be checked in. This includes such things as the database credentials, the SECRET_KEY and possibly other values (like SENTRY_DSN, etc.)

Three approaches are possible, depending on the expected variations of the settings file (that is, how often you expect it to change over the lifespan of a deployment):

  1. The easiest, but least flexible approach is to mock up the settings file with dummy values and when deploying make a copy of the file for production and edit the appropriate values into that copy.
  2. If the file only has a couple of values that you wish to remove from the repository then you can have them stored in separate files. This approach would typically be used where you only have one deployment of the application, or where all the deployments are identical. The secret valies are then read in by the settings file like so:

SECRET_KEY = open('/home/user/secret-key.txt', 'r').read().strip()

  1. The third option, for use when you have several such values and varying deployments, is to store them in a separate Python file and invoke that file from your settings file. At the very end of your settings file, add:

    # now load local modifications to these settings
    import os
    with open(os.environ['DJANGO_LOCAL_SETTINGS']) as f:
        exec f

Then you set the environment variable DJANGO_LOCAL_SETTINGS to point to a Python source file which contains the customisations of the repository settings file, for example:

DEBUG = True
TEMPLATE_DEBUG = DEBUG

ADMINS.append(('Richard Jones', 'richard@host.example'))

DATABASES['default'] = dict(
    ENGINE = 'django.db.backends.postgresql_psycopg2',
    NAME = 'pyweek',
    USER = 'richard',
    PASSWORD = 'jfruj3hsie',
)    

STATIC_ROOT = '/path/to/static/media'
MEDIA_ROOT = '/path/to/uploaded/media'

SECRET_KEY = '7$LQcfFv_KB}+RXH,)do&jYF.S$WLZv^u+)5qbzT>HphM1uc'

SENTRY_DSN = 'https://cf8bcc5a9a0e617fcba15d5c5e08383f:297c61c2b58a68b837cf2adb12bc1a20@app.getsentry.com/757'

This allows you to mess with settings without affecting the checked-out settings file.

@r1chardj0n3s
Copy link
Author

Need to add something about manage.py and urls.py and making the site directory a Python package.

@r1chardj0n3s
Copy link
Author

STATIC* and MEDIA* need to be customised per site installation anyway so they need to be included in the settings modifications.

I should mention WSGI too and maybe a basic apache config.

@malcolmt
Copy link

Another way to handle per-machine settings that is used in a few places (including most places I touch) is to have a directory like site_settings that contains files named after the output of platform.node().replace(".", "").replace("-", "") or something similar that's likely to be unchanging. Then you can import those, run through their values and poke any all-uppercase ones into globals() in the main settings file. Fractionally more code than you have above, but feels more comfortable to not use exec.

@malcolmt
Copy link

Forgot to mention: whilst what you've written above isn't inaccurate about my_site/, be aware that's no longer the top-level directory in a Django project. I'm not 100% happy (far from it) with the naming given to directories now as a result of "django-admin.py startproject", but newly created projects (>= Django 1.4) give you my_site/my_site/ and put things inside the inner dir. Existing code still works -- like the pyweek code -- but newer code will be laid out differently if you let django-admin.py do the initial setup.

@freakboy3742
Copy link

Three other approaches I've seen:

  1. Exploit the features of your devops system (chef, puppet, whatever), and use a templated settings.py file. This really just moves the goalposts to where you version control your devops configuration.
  2. Have a version controlled common_settings.py file that includes all the non-sensitive configuration bits, then make settings.py not version controlled, and containing all the sensitive bits, and put:
from common_settings import *
 at the start of your common_settings.py file.
  1. Have a version controlled settings.py, and then a non-version controlled local_settings.py that contains sensitive settings bits, and put the
from local_settings import *
 at the end of your settings.py file.

I've used both 2 and 3 on various projects; no real benefit either way, it's just a matter of which settings can be assumed to exist. It works especially well if you keep all your non-repository configuration files in a site settings directory somewhere, and you symlink the appropriate one in as the local non-version controlled settings file.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment