Modular settings for Django

This is the first post in a series about useful methods to simplify the development and the installation of Django. In this specific post I’m proposing a way to organize the settings into a module.

I have been always bothered by the settings file because it is needed to change it everytime we go from development server to production server: one has mainly to change the database, the debug option and the static/media options. This prevents us to copy at one time all the files (or we have to change the settings file elsewhere, e.g. in wsgi.py) and it is unnecessarily complicated; also versioning is harder because we do not want to let sensitive information (secret key, etc.) be on internet. So after some thoughts (and maybe some readings on the web I do not remember) I came to a solution to this problem.

Here are the steps to follow:

  1. First let’s suppose that your project follows the following structure:
    project/
        __init__.py
        manage.py
        wsgi.py
        main/
            __init__.py
            settings.py
            urls.py

    Let be sure that the wsgi.py and manage.py files define correctly where are the Django settings:

    os.environ.setdefault("DJANGO_SETTINGS_MODULE", "main.settings")
  2. Now the idea is to turn our settings.py file into a Python module, in which the __init__.py will store options common to dev and prod and which imports a dev/prod specific module. Since even for dev settings different persons can have different needs, we define only a generic file ex_settings.py for the specific options, which will be derive in two other files: dev_settings.py and prod_settings.py. So we delete settings.py and in place we create a the following directoy in the main module of our project:
    settings/
        __init__.py
        ex_settings.py

    Note that the versioning tree will just contain these files, and the development tree will have dev_settings.py further. The one specific to the prod server will only be created on it. This enables us to version only the common and dev settings.

  3. The head of the __init__.py file contains the following lines:
    from os.path import join, abspath, dirname
    
    PROJECT_DIR = dirname(dirname(abspath(__file__)))
    
    DEBUG = True
    DEBUG_TEMPLATE = DEBUG
    
    if DEBUG is True:
        from dev_settings import *
    else:
        from prod_settings import *
    
    (...)
    
    TEMPLATE_DIRS = (
        join(PROJECT_DIR, 'templates'),
    )
    
    STATICFILES_DIRS = (
        join(PROJECT_DIR, 'static'),
    )
    
    (...)
    
    del PROJECT_DIR

    I have defined the project path in order to define system independent path for the static and template files (note that media should not be stored in the same way). The dots represents all the other common options, that you can find by comparing the dev files below and your canonical settings.py.

  4. The ex_settings.py is:
    from os.path import join
    
    ADMINS = (
        ('Admin', 'admin@email.com'),
    )
    MANAGERS = ADMINS
    
    # Directory where your files directories (media, static...) are stored
    # (absolute path).
    FILES_DIR = '/abs/path/to/files/'
    
    DATABASES = {
        'default': {
            'ENGINE': 'django.db.backends.mysql',
            'NAME': 'project',
            'USER': '',
            'PASSWORD': '',
            'HOST': '',
            'PORT': '',
        }
    }
    
    # Absolute filesystem path to the directory that will hold user-uploaded files.
    # Example: "/home/media/media.lawrence.com/media/"
    MEDIA_ROOT = join(FILES_DIR, 'media/')
    # URL that handles the media served from MEDIA_ROOT. Make sure to use a
    # trailing slash.
    # Examples: "http://media.lawrence.com/media/", "http://example.com/media/"
    MEDIA_URL = '/media/'
    
    # Absolute path to the directory static files should be collected to.
    # Don't put anything in this directory yourself; store your static files
    # in apps' "static/" subdirectories and in STATICFILES_DIRS.
    # Example: "/home/media/media.lawrence.com/static/"
    STATIC_ROOT = join(FILES_DIR, 'static/')
    # URL prefix for static files.
    # Example: "http://media.lawrence.com/static/"
    STATIC_URL = '/static/'
    
    SECRET_KEY = ''
    
    del FILES_DIR

    This last file should be written to fit your project and indicates what are the options to fill.

  5. Copy the file ex_settings.py in your development folder, rename it to dev_settings.py and change the option. In the same way on the prod server create prod_settings.py. Now if you copy the tree from the dev to prod server, then prod_settings.py will not be override; one just has to DEBUG to False.
  6. Finally be sure that your versioning system will ignore dev_settings.py (and to be careful also prod_settings.py).

It would be useful to select automatically the adapted module (e.g. by looking if a wsgi instance is running), and this would allow to move the debug option in the specific settings to let us change this option if we want to debug the prod server (here one has to copy the prod settings as dev if one needs to debug the prod server).

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *