How to keep your django project settings organized
I like to keep my code organized. One of the issues I came across when exploring django coding is the 'settings mess'. Django settings are loaded on a project -and not application- basis. Having a single python module to define settings for a ton of applications is at least frustrating. When looking for a solution to this problem I found this blog post which cleared my head.
Now I always use the
inject_app_defaults function in all my yawd projects to allow for application settings as follows:
Figure 1. An example project tree
Consider the above project tree. The project 'MyProject' contains a single application, named 'myapp'. Inside the __init__.py project module I always put the
inject_app_defaults code. This function accepts an application name as argument, attempts to load the application's local settings module and injects the settings defined in this (local) module to the project's global settings. Therefore, the project's __init__.py module looks like this:
def inject_app_defaults(application): """Inject an application's default settings""" try: __import__('%s.settings' % application) import sys # Import our defaults, project defaults, and project settings _app_settings = sys.modules['%s.settings' % application] _def_settings = sys.modules['django.conf.global_settings'] _settings = sys.modules['django.conf'].settings # Add the values from the application.settings module for _k in dir(_app_settings): if _k.isupper(): # Add the value to the default settings module setattr(_def_settings, _k, getattr(_app_settings, _k)) # Add the value to the settings, if not already present if not hasattr(_settings, _k): setattr(_settings, _k, getattr(_app_settings, _k)) except ImportError: # Silently skip failing settings modules pass
To take advantage of the above snippet, we should first define a settings.py module inside our 'myapp' application, as shown in Figure 1.
from django.conf import settings MY_APP_SETTING = getattr(settings, 'MY_APP_SETTING', 'Hello settings...') MY_APP_SETTING_2 = getattr(settings, 'MY_APP_SETTING_2', '..local settings!')
getattr method allows for overriding your local application settings in the main project settings module. Finally, to make it work we just need to call the
inject_app_defaults and inject the settings to the project's global settings. For this to happen automatically as soon as the application is loaded we place the following inside the application's __init__ module:
from MyProject import inject_app_defaults inject_app_defaults(__name__)
Everything should be in place by now. All you need to do is access your setting the usual way:
from django.conf import settings print settings.MY_APP_SETTING