Fixed #1321 -- Made DJANGO_SETTINGS_MODULE optional. You can now call django.conf.settings.configure() to set settings manually if you don't have a settings module. Thanks, Malcolm Tredinnick, Luke Plant, Fredrik Lundh
git-svn-id: http://code.djangoproject.com/svn/django/trunk@2927 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
parent
27612d8b7d
commit
c643e12faf
|
@ -12,10 +12,61 @@ from django.conf import global_settings
|
||||||
|
|
||||||
ENVIRONMENT_VARIABLE = "DJANGO_SETTINGS_MODULE"
|
ENVIRONMENT_VARIABLE = "DJANGO_SETTINGS_MODULE"
|
||||||
|
|
||||||
|
class LazySettings:
|
||||||
|
"""
|
||||||
|
A lazy proxy for either global Django settings or a custom settings object.
|
||||||
|
The user can manually configure settings prior to using them. Otherwise,
|
||||||
|
Django uses the settings module pointed to by DJANGO_SETTINGS_MODULE.
|
||||||
|
"""
|
||||||
|
def __init__(self):
|
||||||
|
# _target must be either None or something that supports attribute
|
||||||
|
# access (getattr, hasattr, etc).
|
||||||
|
self._target = None
|
||||||
|
|
||||||
|
def __getattr__(self, name):
|
||||||
|
if self._target is None:
|
||||||
|
self._import_settings()
|
||||||
|
if name == '__members__':
|
||||||
|
# Used to implement dir(obj), for example.
|
||||||
|
return self._target.get_all_members()
|
||||||
|
return getattr(self._target, name)
|
||||||
|
|
||||||
|
def __setattr__(self, name, value):
|
||||||
|
if name == '_target':
|
||||||
|
self.__dict__['_target'] = value
|
||||||
|
else:
|
||||||
|
setattr(self._target, name, value)
|
||||||
|
|
||||||
|
def _import_settings(self):
|
||||||
|
"""
|
||||||
|
Load the settings module pointed to by the environment variable. This
|
||||||
|
is used the first time we need any settings at all, if the user has not
|
||||||
|
previously configured the settings manually.
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
settings_module = os.environ[ENVIRONMENT_VARIABLE]
|
||||||
|
if not settings_module: # If it's set but is an empty string.
|
||||||
|
raise KeyError
|
||||||
|
except KeyError:
|
||||||
|
raise EnvironmentError, "Environment variable %s is undefined." % ENVIRONMENT_VARIABLE
|
||||||
|
|
||||||
|
self._target = Settings(settings_module)
|
||||||
|
|
||||||
|
def configure(self, default_settings=global_settings, **options):
|
||||||
|
"""
|
||||||
|
Called to manually configure the settings. The 'default_settings'
|
||||||
|
parameter sets where to retrieve any unspecified values from (its
|
||||||
|
argument must support attribute access (__getattr__)).
|
||||||
|
"""
|
||||||
|
if self._target != None:
|
||||||
|
raise EnvironmentError, 'Settings already configured.'
|
||||||
|
holder = UserSettingsHolder(default_settings)
|
||||||
|
for name, value in options.items():
|
||||||
|
setattr(holder, name, value)
|
||||||
|
self._target = holder
|
||||||
|
|
||||||
class Settings:
|
class Settings:
|
||||||
|
|
||||||
def __init__(self, settings_module):
|
def __init__(self, settings_module):
|
||||||
|
|
||||||
# update this dict from global settings (but only for ALL_CAPS settings)
|
# update this dict from global settings (but only for ALL_CAPS settings)
|
||||||
for setting in dir(global_settings):
|
for setting in dir(global_settings):
|
||||||
if setting == setting.upper():
|
if setting == setting.upper():
|
||||||
|
@ -27,7 +78,7 @@ class Settings:
|
||||||
try:
|
try:
|
||||||
mod = __import__(self.SETTINGS_MODULE, '', '', [''])
|
mod = __import__(self.SETTINGS_MODULE, '', '', [''])
|
||||||
except ImportError, e:
|
except ImportError, e:
|
||||||
raise EnvironmentError, "Could not import settings '%s' (is it on sys.path?): %s" % (self.SETTINGS_MODULE, e)
|
raise EnvironmentError, "Could not import settings '%s' (Is it on sys.path? Does it have syntax errors?): %s" % (self.SETTINGS_MODULE, e)
|
||||||
|
|
||||||
# Settings that should be converted into tuples if they're mistakenly entered
|
# Settings that should be converted into tuples if they're mistakenly entered
|
||||||
# as strings.
|
# as strings.
|
||||||
|
@ -56,18 +107,32 @@ class Settings:
|
||||||
# move the time zone info into os.environ
|
# move the time zone info into os.environ
|
||||||
os.environ['TZ'] = self.TIME_ZONE
|
os.environ['TZ'] = self.TIME_ZONE
|
||||||
|
|
||||||
# try to load DJANGO_SETTINGS_MODULE
|
def get_all_members(self):
|
||||||
try:
|
return dir(self)
|
||||||
settings_module = os.environ[ENVIRONMENT_VARIABLE]
|
|
||||||
if not settings_module: # If it's set but is an empty string.
|
|
||||||
raise KeyError
|
|
||||||
except KeyError:
|
|
||||||
raise EnvironmentError, "Environment variable %s is undefined." % ENVIRONMENT_VARIABLE
|
|
||||||
|
|
||||||
# instantiate the configuration object
|
class UserSettingsHolder:
|
||||||
settings = Settings(settings_module)
|
"""
|
||||||
|
Holder for user configured settings.
|
||||||
|
"""
|
||||||
|
# SETTINGS_MODULE does not really make sense in the manually configured
|
||||||
|
# (standalone) case.
|
||||||
|
SETTINGS_MODULE = None
|
||||||
|
|
||||||
|
def __init__(self, default_settings):
|
||||||
|
"""
|
||||||
|
Requests for configuration variables not in this class are satisfied
|
||||||
|
from the module specified in default_settings (if possible).
|
||||||
|
"""
|
||||||
|
self.default_settings = default_settings
|
||||||
|
|
||||||
|
def __getattr__(self, name):
|
||||||
|
return getattr(self.default_settings, name)
|
||||||
|
|
||||||
|
def get_all_members(self):
|
||||||
|
return dir(self) + dir(self.default_settings)
|
||||||
|
|
||||||
|
settings = LazySettings()
|
||||||
|
|
||||||
# install the translation machinery so that it is available
|
# install the translation machinery so that it is available
|
||||||
from django.utils import translation
|
from django.utils import translation
|
||||||
translation.install()
|
translation.install()
|
||||||
|
|
||||||
|
|
|
@ -327,14 +327,18 @@ def get_digit(value, arg):
|
||||||
# DATES #
|
# DATES #
|
||||||
###################
|
###################
|
||||||
|
|
||||||
def date(value, arg=settings.DATE_FORMAT):
|
def date(value, arg=None):
|
||||||
"Formats a date according to the given format"
|
"Formats a date according to the given format"
|
||||||
from django.utils.dateformat import format
|
from django.utils.dateformat import format
|
||||||
|
if arg is None:
|
||||||
|
arg = settings.DATE_FORMAT
|
||||||
return format(value, arg)
|
return format(value, arg)
|
||||||
|
|
||||||
def time(value, arg=settings.TIME_FORMAT):
|
def time(value, arg=None):
|
||||||
"Formats a time according to the given format"
|
"Formats a time according to the given format"
|
||||||
from django.utils.dateformat import time_format
|
from django.utils.dateformat import time_format
|
||||||
|
if arg is None:
|
||||||
|
arg = settings.TIME_FORMAT
|
||||||
return time_format(value, arg)
|
return time_format(value, arg)
|
||||||
|
|
||||||
def timesince(value):
|
def timesince(value):
|
||||||
|
|
|
@ -117,9 +117,12 @@ def translation(language):
|
||||||
|
|
||||||
globalpath = os.path.join(os.path.dirname(sys.modules[settings.__module__].__file__), 'locale')
|
globalpath = os.path.join(os.path.dirname(sys.modules[settings.__module__].__file__), 'locale')
|
||||||
|
|
||||||
|
if settings.SETTINGS_MODULE is not None:
|
||||||
parts = settings.SETTINGS_MODULE.split('.')
|
parts = settings.SETTINGS_MODULE.split('.')
|
||||||
project = __import__(parts[0], {}, {}, [])
|
project = __import__(parts[0], {}, {}, [])
|
||||||
projectpath = os.path.join(os.path.dirname(project.__file__), 'locale')
|
projectpath = os.path.join(os.path.dirname(project.__file__), 'locale')
|
||||||
|
else:
|
||||||
|
projectpath = None
|
||||||
|
|
||||||
def _fetch(lang, fallback=None):
|
def _fetch(lang, fallback=None):
|
||||||
|
|
||||||
|
@ -155,7 +158,7 @@ def translation(language):
|
||||||
if os.path.isdir(localepath):
|
if os.path.isdir(localepath):
|
||||||
res = _merge(localepath)
|
res = _merge(localepath)
|
||||||
|
|
||||||
if os.path.isdir(projectpath):
|
if projectpath and os.path.isdir(projectpath):
|
||||||
res = _merge(projectpath)
|
res = _merge(projectpath)
|
||||||
|
|
||||||
for appname in settings.INSTALLED_APPS:
|
for appname in settings.INSTALLED_APPS:
|
||||||
|
|
|
@ -540,6 +540,17 @@ you can override base translations in your project path. Or, you can just build
|
||||||
a big project out of several apps and put all translations into one big project
|
a big project out of several apps and put all translations into one big project
|
||||||
message file. The choice is yours.
|
message file. The choice is yours.
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
|
||||||
|
If you're using manually configured settings, as described in the
|
||||||
|
`settings documentation`_, the ``locale`` directory in the project
|
||||||
|
directory will not be examined, since Django loses the ability to work out
|
||||||
|
the location of the project directory. (Django normally uses the location
|
||||||
|
of the settings file to determine this, and a settings file doesn't exist
|
||||||
|
if you're manually configuring your settings.)
|
||||||
|
|
||||||
|
.. _settings documentation: http://www.djangoproject.com/documentation/settings/#using-settings-without-the-django-settings-module-environment-variable
|
||||||
|
|
||||||
All message file repositories are structured the same way. They are:
|
All message file repositories are structured the same way. They are:
|
||||||
|
|
||||||
* ``$APPPATH/locale/<language>/LC_MESSAGES/django.(po|mo)``
|
* ``$APPPATH/locale/<language>/LC_MESSAGES/django.(po|mo)``
|
||||||
|
|
|
@ -724,3 +724,70 @@ Django apps. Just follow these conventions:
|
||||||
* For settings that are sequences, use tuples instead of lists. This is
|
* For settings that are sequences, use tuples instead of lists. This is
|
||||||
purely for performance.
|
purely for performance.
|
||||||
* Don't reinvent an already-existing setting.
|
* Don't reinvent an already-existing setting.
|
||||||
|
|
||||||
|
Using settings without setting DJANGO_SETTINGS_MODULE
|
||||||
|
=====================================================
|
||||||
|
|
||||||
|
In some cases, you might want to bypass the ``DJANGO_SETTINGS_MODULE``
|
||||||
|
environment variable. For example, if you're using the template system by
|
||||||
|
itself, you likely don't want to have to set up an environment variable
|
||||||
|
pointing to a settings module.
|
||||||
|
|
||||||
|
In these cases, you can configure Django's settings manually. Do this by
|
||||||
|
calling ``django.conf.settings.configure()``.
|
||||||
|
|
||||||
|
Example::
|
||||||
|
|
||||||
|
from django.conf import settings
|
||||||
|
|
||||||
|
settings.configure(DEBUG=True, TEMPLATE_DEBUG=True,
|
||||||
|
TEMPLATE_DIRS=('/home/web-apps/myapp', '/home/web-apps/base'))
|
||||||
|
|
||||||
|
Pass ``configure()`` as many keyword arguments as you'd like, with each keyword
|
||||||
|
argument representing a setting and its value. Each argument name should be all
|
||||||
|
uppercase, with the same name as the settings described above. If a particular
|
||||||
|
setting is not passed to ``configure()`` and is needed at some later point,
|
||||||
|
Django will use the default setting value.
|
||||||
|
|
||||||
|
Custom default settings
|
||||||
|
-----------------------
|
||||||
|
|
||||||
|
If you'd like default values to come from somewhere other than
|
||||||
|
``django.conf.global_settings``, you can pass in a module or class that
|
||||||
|
provides the default settings as the ``default_settings`` argument (or as the
|
||||||
|
first positional argument) in the call to ``configure()``.
|
||||||
|
|
||||||
|
In this example, default settings are taken from ``myapp_defaults``, and the
|
||||||
|
``DEBUG`` setting is set to ``True``, regardless of its value in
|
||||||
|
``myapp_defaults``::
|
||||||
|
|
||||||
|
from django.conf import settings
|
||||||
|
from myapp import myapp_defaults
|
||||||
|
|
||||||
|
settings.configure(default_settings=myapp_defaults, DEBUG=True)
|
||||||
|
|
||||||
|
The following example, which uses ``myapp_defaults`` as a positional argument,
|
||||||
|
is equivalent::
|
||||||
|
|
||||||
|
settings.configure(myapp_defaults, DEBUG = True)
|
||||||
|
|
||||||
|
Either configure() or DJANGO_SETTINGS_MODULE is required
|
||||||
|
--------------------------------------------------------
|
||||||
|
|
||||||
|
If you're not setting the ``DJANGO_SETTINGS_MODULE`` environment variable, you
|
||||||
|
*must* call ``configure()`` at some point before using any code that reads
|
||||||
|
settings.
|
||||||
|
|
||||||
|
If you don't set ``DJANGO_SETTINGS_MODULE`` and don't call ``configure()``,
|
||||||
|
Django will raise an ``EnvironmentError`` exception the first time a setting
|
||||||
|
is accessed.
|
||||||
|
|
||||||
|
If you set ``DJANGO_SETTINGS_MODULE``, access settings values somehow, *then*
|
||||||
|
call ``configure()``, Django will raise an ``EnvironmentError`` saying settings
|
||||||
|
have already been configured.
|
||||||
|
|
||||||
|
Also, it's an error to call ``configure()`` more than once, or to call
|
||||||
|
``configure()`` after any setting has been accessed.
|
||||||
|
|
||||||
|
It boils down to this: Use exactly one of either ``configure()`` or
|
||||||
|
``DJANGO_SETTINGS_MODULE``. Not both, and not neither.
|
||||||
|
|
|
@ -7,6 +7,10 @@ perspective -- how it works and how to extend it. If you're just looking for
|
||||||
reference on the language syntax, see
|
reference on the language syntax, see
|
||||||
`The Django template language: For template authors`_.
|
`The Django template language: For template authors`_.
|
||||||
|
|
||||||
|
If you're looking to use the Django template system as part of another
|
||||||
|
application -- i.e., without the rest of the framework -- make sure to read
|
||||||
|
the `configuration`_ section later in this document.
|
||||||
|
|
||||||
.. _`The Django template language: For template authors`: http://www.djangoproject.com/documentation/templates/
|
.. _`The Django template language: For template authors`: http://www.djangoproject.com/documentation/templates/
|
||||||
|
|
||||||
Basics
|
Basics
|
||||||
|
@ -876,3 +880,37 @@ The only new concept here is the ``self.nodelist.render(context)`` in
|
||||||
For more examples of complex rendering, see the source code for ``{% if %}``,
|
For more examples of complex rendering, see the source code for ``{% if %}``,
|
||||||
``{% for %}``, ``{% ifequal %}`` and ``{% ifchanged %}``. They live in
|
``{% for %}``, ``{% ifequal %}`` and ``{% ifchanged %}``. They live in
|
||||||
``django/template/defaulttags.py``.
|
``django/template/defaulttags.py``.
|
||||||
|
|
||||||
|
.. _configuration:
|
||||||
|
|
||||||
|
Configuring the template system in standalone mode
|
||||||
|
==================================================
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
|
||||||
|
This section is only of interest to people trying to use the template
|
||||||
|
system as an output component in another application. If you are using the
|
||||||
|
template system as part of a Django application, nothing here applies to
|
||||||
|
you.
|
||||||
|
|
||||||
|
Normally, Django will load all the configuration information it needs from its
|
||||||
|
own default configuration file, combined with the settings in the module given
|
||||||
|
in the ``DJANGO_SETTINGS_MODULE`` environment variable. But if you're using the
|
||||||
|
template system independently of the rest of Django, the environment variable
|
||||||
|
approach isn't very convenient, because you probably want to configure the
|
||||||
|
template system in line with the rest of your application rather than dealing
|
||||||
|
with settings files and pointing to them via environment variables.
|
||||||
|
|
||||||
|
To solve this problem, you need to use the manual configuration option
|
||||||
|
described in the `settings file`_ documentation. Simply import the appropriate
|
||||||
|
pieces of the templating system and then, *before* you call any of the
|
||||||
|
templating functions, call ``django.conf.settings.configure()`` with any
|
||||||
|
settings you wish to specify. You might want to consider setting at least
|
||||||
|
``TEMPLATE_DIRS`` (if you are going to use template loaders),
|
||||||
|
``DEFAULT_CHARSET`` (although the default of ``utf-8`` is probably fine) and
|
||||||
|
``TEMPLATE_DEBUG``. All available settings are described in the
|
||||||
|
`settings documentation`_, and any setting starting with *TEMPLATE_*
|
||||||
|
is of obvious interest.
|
||||||
|
|
||||||
|
.. _settings file: http://www.djangoproject.com/documentation/settings/#using-settings-without-the-django-settings-module-environment-variable
|
||||||
|
.. _settings documentation: http://www.djangoproject.com/documentation/settings/
|
||||||
|
|
|
@ -507,4 +507,5 @@ def run_tests(verbosity=0, standalone=False):
|
||||||
raise Exception, msg
|
raise Exception, msg
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
settings.configure()
|
||||||
run_tests(1, True)
|
run_tests(1, True)
|
||||||
|
|
|
@ -73,6 +73,10 @@ class TestRunner:
|
||||||
def run_tests(self):
|
def run_tests(self):
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
|
|
||||||
|
# An empty access of the settings to force the default options to be
|
||||||
|
# installed prior to assigning to them.
|
||||||
|
settings.INSTALLED_APPS
|
||||||
|
|
||||||
# Manually set INSTALLED_APPS to point to the test models.
|
# Manually set INSTALLED_APPS to point to the test models.
|
||||||
settings.INSTALLED_APPS = [MODEL_TESTS_DIR_NAME + '.' + a for a in get_test_models()]
|
settings.INSTALLED_APPS = [MODEL_TESTS_DIR_NAME + '.' + a for a in get_test_models()]
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue