Skip to main content

Django flexible settings with running environment support, separate security files and project layout detection.

Project description

# django-flexisettings

Several issues with the standard settings.py are solved in that project :

* get any security configuration (password, secret key, API key, etc)
out of the main settings file
* support multiple environments in a flexible way
* automatic discovery and configuration of common project layouts

Qualities of the resulting code :

* generic, don't presume about anything concerning the project
* flexible, allow several configurations to live in the same place and
easily switch between them
* simple


# Installation

```shell
$ pip install django-flexisettings
```


# Quickstart

## Development

Edit `manage.py`, modify the value of `DJANGO_SETTINGS_MODULE` to point
at `flexisettings.settings` and add `FLEXI_WRAPPED_MODULE` to point at
you project's settings:
```
[...]
if __name__ == "__main__":
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "flexisettings.settings")
os.environ.setdefault("FLEXI_WRAPPED_MODULE", "myproject.settings")
[...]
```


## Production

Edit `myproject/wsgi.py`, modify the value of `DJANGO_SETTINGS_MODULE`
to point at `flexisettings.settings` and add `FLEXI_WRAPPED_MODULE` to
point at you project's settings:
```
[...]
import os

os.environ.setdefault("DJANGO_SETTINGS_MODULE", "flexisettings.settings")
os.environ.setdefault("FLEXI_WRAPPED_MODULE", "myproject.settings")
[...]
```

To run the project with gunicorn, check the paragraph "Gunicorn
configuration".


## ALL GLORY TO FLEXISETTINGS

This is all you need to get `flexisettings` to run your settings. At
this stage, **nothing** in the configuration object is changed, it is
simply wrapped in `flexisettings` proxy object.

Read further for more powerful features of `flexisettings`.


# Configuration

### DJANGO\_SETTINGS\_MODULE

Environment variable to set to point at `flexisettings.settings`, more
details in the [django
documentation](https://docs.djangoproject.com/en/dev/topics/settings/#envvar-DJANGO_SETTINGS_MODULE).


### FLEXI\_WRAPPED\_MODULE

Environment variable to set to point at your django settings, this
environment variable has to be set for `flexisettings` to work.


### FLEXI\_RUN\_ENV

String defining the running environment, used when trying to load
settings depending on the defined running environment.


### FLEXI\_SYS\_PATH

List of paths to add to `sys.path` if they exist, defaults to `['apps',
'lib']`. This will be done if `FLEXI_LAYOUT_DISCOVERY` is `True`.


### FLEXI\_AUTORELOAD

Boolean affecting the autoreload machinery for settings. If set to
`True`, it should make the django autoreload code work when changing any
settings file found in `flexisettings.settings._wrapped_modules`. If set
to `False`, the autoreload will not work on settings. The code is a bit
tricky, not guaranteed to work and might have unsuspected effects, hence
the possibility to disable. Defaults to `True` to preserve django
default behavior.


### FLEXI\_LAYOUT\_DISCOVERY

Boolean that determines if `flexisettings` tries to be smart about your
project layout. It will add any `FLEXI_MEDIA_FOLDER`, `FLEXI_STATIC_FOLDER`,
`FLEXI_TEMPLATE_FOLDERS` folder to the appropriate configuration variables if
they are not already set.


### FLEXI\_MEDIA\_FOLDER

The media folder name to look for when doing layout discovery, defaults to
`'media'`.


### FLEXI\_STATIC\_FOLDER

The static folder name to look for when doing layout discovery, defaults to
`'static'`.


### FLEXI\_TEMPLATE\_FOLDERS

A tuple of template folder names to look for when doing layout discovery,
defaults to `('templates', )`.


### FLEXI\_SITE\_ROOT

Path to the site root, everything that should not be tracked in a VCS
but is still part of your website. For example, the `MEDIA_ROOT` folder
should reside in the site root. This path defaults to
`FLEX_PROJECT_ROOT`.


### FLEXI\_PROJECT\_ROOT

Path to the django project, basically everything that should be tracked
in a VCS. This path defaults to the `dirname()` of the settings folder.


# Example configuration

* edit `env.py` to set the working environment, let's use `prod` here :

```shell
$ cat myproject/env.py
# environment declaration
FLEXI_RUN_ENV = 'prod'
```

* edit `security.py` to set the `SECRET_KEY` value :

```shell
$ grep SECRET_KEY myproject/security.py
SECRET_KEY = 'alongandcomplexsecretstring'
```

* set security variables in `security_prod.py` to be used in any
settings file.

```shell
$ grep DEFAULTDB myproject/security_prod.py
DEFAULTDB_NAME = 'dbname'
DEFAULTDB_USER = 'dbuser'
DEFAULTDB_PWD = 'secret'
```

* edit `settings_prod.py` to override generic settings like `DATABASES`,
`MEDIA_ROOT`, `TIME_ZONE`...

```shell
$ cat myproject/settings/settings_prod.py
[...]
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql_psycopg2',
'NAME': DEFAULTDB_NAME,
'USER': DEFAULTDB_USER,
'PASSWORD': DEFAULTDB_PWD,
'HOST': '',
'PORT': '',
}
}
[...]
```


# Layout

```
myproject/__init__.py
env.py
security.py
security_RUN_ENV.py
settings.py
settings_RUN_ENV.py
```

* `env.py` has a single variable `FLEXI_RUN_ENV` that defines a running
environment. This variable is then used to call different profiles of
configuration depending on the running environment like `dev`, `stage`
and `prod`. The `FLEXI_RUN_ENV` variable can also be set by
environment, the environment takes precedence over `env.py`. Example :
```shell
$ export FLEXI_RUN_ENV='dev'; python manage.py runserver
```
* `security.py` holds all the common security variables for the project,
probably a good place for `SECRET_KEY`.
* `security_RUN_ENV` specific environment security variables, dedicated
database passwords should go there. Setting defined here will override
settings defined in `security.py`.
* `settings.py` the classic settings file found in all django projects.
* `settings_RUN_ENV.py` gathers local settings for a given running
environment, settings defined here will override settings defined in
`settings.py`.


# Loading order

The modules are loaded in the following order :

1. `myproject/env.py`
2. `myproject/security.py`
3. `myproject/security_RUN_ENV.py`
4. `myproject/settings.py`
5. `myproject/settings_RUN_ENV.py`


# Gunicorn configuration

Following [django's
recommandations](https://docs.djangoproject.com/en/1.5/howto/deployment/wsgi/gunicorn/)
on how to use gunicorn, the project will run in WSGI mode.

First edit the `myproject/wsgi.py` file as shown in the "Quickstart"
paragraph.

## Command line

$ cd /path/to/myproject
$ /path/to/venv/bin/python gunicorn --workers=42 myproject.wsgi:application

## Debian

The configuration file for gunicorn should be saved as
`/etc/gunicorn.d/myproject` and contain:

```
CONFIG = {
'python': '/path/to/venv/bin/python',
'working_dir': '/path/to/myproject',
'user': 'www-data',
'group': 'www-data',
'args': (
'myproject.wsgi:application',
),
}
```

Extra options that could be useful in the `args` tuple:

* `'--bind=ip:port'`: set which ip and port the process whould bind to
* `'--workers=#'`: set the number of workers to spawn

For more information on gunicorn configuration, [read the
docs](http://docs.gunicorn.org/en/latest/configure.html).


# Security files

A very simple way to make sure that passwords are not pushed in your VCS
is to exclude any file matching `myproject/security*`. It would also be
a good idea to reduce the access to such files by removing read rights
for users other than the one running django.


# Miscellaneous

If the `FLEXI_RUN_ENV` variable is false in python, the only settings
files read are `security.py` and `settings.py`.

Modifying the settings does not reload the server when using `manage.py
runserver`.

Files that should not be pushed to your VCS are :

* `env.py` : to allow for multiple environments to run at the same time
and avoid problems with git pulls. For this you can add
`myproject/env.py` in `.gitignore`.
* any security file : repeat after me, any security data in your VCS is
a **bad idea**. For this you can add `myproject/security*.py` in
`.gitignore`.


# Debugging

To help in the debugging process, it is possible to know which files
have been included in the final settings object by accessing
`flexisettings.settings._wrapped_modules`. An example from the unit
tests, the project name is 'testProject' and the running environment is
't':

```
$ python manage.py shell
[...]
>>> import flexisettings.settings
>>> flexisettings.settings._wrapped_modules
{'testProject.env': '/path/to/django-flexisettings/t/testProject/env.py',
'testProject.security': '/path/to/django-flexisettings/t/testProject/security.py',
'testProject.settings': '/path/to/django-flexisettings/t/testProject/settings.py',
'testProject.settings_t': '/path/to/django-flexisettings/t/testProject/settings_t.py'}
```


# References

* [Django project](https://www.djangoproject.com/)
* [Django settings](https://docs.djangoproject.com/en/dev/topics/settings/)
* [Splitting up the settings file](https://code.djangoproject.com/wiki/SplitSettings)


## Project layouts

* [Django Project Conventions, Revisited](http://zacharyvoase.com/2010/02/03/django-project-conventions/) (Zachary Voase)
* [django-resusable-app](http://django-reusable-app-docs.readthedocs.org/en/latest/index.html)
* [pinax-project-zero](https://github.com/pinax/pinax-project-zero)
* [Django Project Structure](http://www.deploydjango.com/django_project_structure/)
* [A general django project structure or folder layout](http://timmyomahony.com/blog/2012/11/09/general-django-project-structure-or-folder-layout/)


# License

django-flexisettings is published under a 3-clause BSD license, see LICENSE.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

django-flexisettings-0.2.2.tar.gz (8.9 kB view hashes)

Uploaded Source

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page