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.
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
Close
Hashes for django-flexisettings-0.2.2.tar.gz
Algorithm | Hash digest | |
---|---|---|
SHA256 | 74e4f7f60a8eb7d0cc0426df6220c14f00963e3542f9a4b4e967a0880afe75a7 |
|
MD5 | bc42a444470b2d79cdb52fd1fa1ae06f |
|
BLAKE2b-256 | f04d84efff7ea38665bbaab1261ce332e4bf94cc59edb47bc086ab719c3cde31 |