The Django documentation mentions that you can add your own settings to django.conf.settings
. So if my project's settings.py
defines
APPLES = 1
I can access that with settings.APPLES
in my apps in that project.
But if my settings.py
doesn't define that value, accessing settings.APPLES
obviously won't work. Is there some way to define a default value for APPLES
that is used if there is no explicit setting in settings.py
?
I'd like best to define the default value in the module/package that requires the setting.
In my apps, I have a seperate settings.py file. In that file I have a get() function that does a look up in the projects settings.py file and if not found returns the default value.
from django.conf import settings
def get(key, default):
return getattr(settings, key, default)
APPLES = get('APPLES', 1)
Then where I need to access APPLES I have:
from myapp import settings as myapp_settings
myapp_settings.APPLES
This allows an override in the projects settings.py, getattr will check there first and return the value if the attribute is found or use the default defined in your apps settings file.
How about just:
getattr(app_settings, 'SOME_SETTING', 'default value')
Here are two solutions. For both you can set settings.py
files in your applications and fill them with default values.
Configure default value for a single application
Use from MYAPP import settings
instead of from django.conf import settings
in your code.
Edit YOURAPP/__init__.py
:
from django.conf import settings as user_settings
from . import settings as default_settings
class AppSettings:
def __getattr__(self, name):
# If the setting you want is filled by the user, let's use it.
if hasattr(user_settings, name):
return getattr(user_settings, name)
# If the setting you want has a default value, let's use it.
if hasattr(default_settings, name):
return getattr(default_settings, name)
raise AttributeError("'Settings' object has no attribute '%s'" % name)
settings = AppSettings()
Configure default values for a whole project
Use from MYPROJECT import settings
instead of from django.conf import settings
in your code.
Edit MYPROJECT/MYPROJECT/__init__.py
import os, sys, importlib
from . import settings as user_settings
def get_local_apps():
"""Returns the locally installed apps names"""
apps = []
for app in user_settings.INSTALLED_APPS:
path = os.path.join(user_settings.BASE_DIR, app)
if os.path.exists(path) and app != __name__:
apps.append(sys.modules[app])
return apps
class AppSettings:
SETTINGS_MODULE = 'settings'
def __getattr__(self, setting_name):
# If the setting you want is filled by the user, let's use it.
if hasattr(user_settings, setting_name):
return getattr(user_settings, setting_name)
# Let's check every local app loaded by django.
for app in get_local_apps():
module_source = os.path.join(app.__path__[0], "%s.py" % self.SETTINGS_MODULE)
module_binary = os.path.join(app.__path__[0], "%s.pyc" % self.SETTINGS_MODULE)
if os.path.exists(module_source) or os.path.exists(module_binary):
module = importlib.import_module("%s.%s" % (app.__name__, self.SETTINGS_MODULE))
# Let's take the first default value for this setting we can find in any app
if hasattr(module, setting_name):
return getattr(module, setting_name)
raise AttributeError("'Settings' object has no attribute '%s'" % setting_name)
settings = AppSettings()
This solution may seem more easier to install, but it does not guarantee that the good default value will be returned. If several applications declare the same variable in their settings.py, you can not be sure which one will return the default value you asked.
Starting from Mike's answer, I now wrapped the default setting handling into a class with easy to use interface.
Helper module:
from django.conf import settings
class SettingsView(object):
class Defaults(object):
pass
def __init__(self):
self.defaults = SettingsView.Defaults()
def __getattr__(self, name):
return getattr(settings, name, getattr(self.defaults, name))
Usage:
from localconf import SettingsView
settings = SettingsView()
settings.defaults.APPLES = 1
print settings.APPLES
This prints the value from django.conf.settings
, or the default if it isn't set there. This settings
object can also be used to access all the standard setting values.
I recently had the same problem and created a Django app that is designed to be used for exactly such a case. It allows you to define default values for certain settings. It then first checks whether the setting is set in the global settings file. If not, it will return the default value.
I've extended it to also allow for some type checking or pre handling of the default value (e.g. a dotted class path can be converted to the class itself on load)
The app can be found at: https://pypi.python.org/pypi?name=django-pluggableappsettings&version=0.2.0&:action=display