Commit c643e12f authored by Adrian Holovaty's avatar Adrian Holovaty
Browse files

Fixed #1321 -- Made DJANGO_SETTINGS_MODULE optional. You can now call...

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
parent 27612d8b
Loading
Loading
Loading
Loading
+78 −13
Original line number Diff line number Diff line
@@ -12,10 +12,61 @@ from django.conf import global_settings

ENVIRONMENT_VARIABLE = "DJANGO_SETTINGS_MODULE"

class Settings:
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 __init__(self, settings_module):
    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:
    def __init__(self, settings_module):
        # update this dict from global settings (but only for ALL_CAPS settings)
        for setting in dir(global_settings):
            if setting == setting.upper():
@@ -27,7 +78,7 @@ class Settings:
        try:
            mod = __import__(self.SETTINGS_MODULE, '', '', [''])
        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
        # as strings.
@@ -56,18 +107,32 @@ class Settings:
        # move the time zone info into os.environ
        os.environ['TZ'] = self.TIME_ZONE

# try to load DJANGO_SETTINGS_MODULE
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
    def get_all_members(self):
        return dir(self)

# instantiate the configuration object
settings = Settings(settings_module)
class UserSettingsHolder:
    """
    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
from django.utils import translation
translation.install()
+7 −3
Original line number Diff line number Diff line
@@ -327,14 +327,18 @@ def get_digit(value, arg):
# DATES           #
###################

def date(value, arg=settings.DATE_FORMAT):
def date(value, arg=None):
    "Formats a date according to the given format"
    from django.utils.dateformat import format
    if arg is None:
        arg = settings.DATE_FORMAT
    return format(value, arg)

def time(value, arg=settings.TIME_FORMAT):
def time(value, arg=None):
    "Formats a time according to the given format"
    from django.utils.dateformat import time_format
    if arg is None:
        arg = settings.TIME_FORMAT
    return time_format(value, arg)

def timesince(value):
+7 −4
Original line number Diff line number Diff line
@@ -117,9 +117,12 @@ def translation(language):

    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('.')
        project = __import__(parts[0], {}, {}, [])
        projectpath = os.path.join(os.path.dirname(project.__file__), 'locale')
    else:
        projectpath = None

    def _fetch(lang, fallback=None):

@@ -155,7 +158,7 @@ def translation(language):
                if os.path.isdir(localepath):
                    res = _merge(localepath)

        if os.path.isdir(projectpath):
        if projectpath and os.path.isdir(projectpath):
            res = _merge(projectpath)

        for appname in settings.INSTALLED_APPS:
+11 −0
Original line number Diff line number Diff line
@@ -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
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:

    * ``$APPPATH/locale/<language>/LC_MESSAGES/django.(po|mo)``
+67 −0
Original line number Diff line number Diff line
@@ -724,3 +724,70 @@ Django apps. Just follow these conventions:
    * For settings that are sequences, use tuples instead of lists. This is
      purely for performance.
    * 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.
Loading