1
0
mirror of https://github.com/django/django.git synced 2025-07-19 17:19:12 +00:00

Removed some import-time dependencies on Django's settings.

Now you can import the file storage stuff and still call settings.configure()
afterwards. There is still one import-time usage of settings in
django.contrib.comments, but that's unavoidable.

Backport of r9945 and r9946 from trunk (this is needed in order to fix #8193 in
a clean fashion, which is why it's being backported).

git-svn-id: http://code.djangoproject.com/svn/django/branches/releases/1.0.X@9947 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
Malcolm Tredinnick 2009-03-02 04:57:03 +00:00
parent 9576353835
commit 32be118081
3 changed files with 66 additions and 37 deletions

View File

@ -8,40 +8,19 @@ a list of all possible variables.
import os import os
import time # Needed for Windows import time # Needed for Windows
from django.conf import global_settings from django.conf import global_settings
from django.utils.functional import LazyObject
ENVIRONMENT_VARIABLE = "DJANGO_SETTINGS_MODULE" ENVIRONMENT_VARIABLE = "DJANGO_SETTINGS_MODULE"
class LazySettings(object): class LazySettings(LazyObject):
""" """
A lazy proxy for either global Django settings or a custom settings object. A lazy proxy for either global Django settings or a custom settings object.
The user can manually configure settings prior to using them. Otherwise, The user can manually configure settings prior to using them. Otherwise,
Django uses the settings module pointed to by DJANGO_SETTINGS_MODULE. Django uses the settings module pointed to by DJANGO_SETTINGS_MODULE.
""" """
def __init__(self): def _setup(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':
# Assign directly to self.__dict__, because otherwise we'd call
# __setattr__(), which would be an infinite loop.
self.__dict__['_target'] = value
else:
if self._target is None:
self._import_settings()
setattr(self._target, name, value)
def _import_settings(self):
""" """
Load the settings module pointed to by the environment variable. This 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 is used the first time we need any settings at all, if the user has not
@ -56,7 +35,7 @@ class LazySettings(object):
# problems with Python's interactive help. # problems with Python's interactive help.
raise ImportError("Settings cannot be imported, because environment variable %s is undefined." % ENVIRONMENT_VARIABLE) raise ImportError("Settings cannot be imported, because environment variable %s is undefined." % ENVIRONMENT_VARIABLE)
self._target = Settings(settings_module) self._wrapped = Settings(settings_module)
def configure(self, default_settings=global_settings, **options): def configure(self, default_settings=global_settings, **options):
""" """
@ -69,13 +48,13 @@ class LazySettings(object):
holder = UserSettingsHolder(default_settings) holder = UserSettingsHolder(default_settings)
for name, value in options.items(): for name, value in options.items():
setattr(holder, name, value) setattr(holder, name, value)
self._target = holder self._wrapped = holder
def configured(self): def configured(self):
""" """
Returns True if the settings have already been configured. Returns True if the settings have already been configured.
""" """
return bool(self._target) return bool(self._wrapped)
configured = property(configured) configured = property(configured)
class Settings(object): class Settings(object):

View File

@ -4,11 +4,12 @@ import urlparse
from django.conf import settings from django.conf import settings
from django.core.exceptions import ImproperlyConfigured, SuspiciousOperation from django.core.exceptions import ImproperlyConfigured, SuspiciousOperation
from django.utils.encoding import force_unicode
from django.utils.text import get_valid_filename
from django.utils._os import safe_join
from django.core.files import locks, File from django.core.files import locks, File
from django.core.files.move import file_move_safe from django.core.files.move import file_move_safe
from django.utils.encoding import force_unicode
from django.utils.functional import LazyObject
from django.utils.text import get_valid_filename
from django.utils._os import safe_join
__all__ = ('Storage', 'FileSystemStorage', 'DefaultStorage', 'default_storage') __all__ = ('Storage', 'FileSystemStorage', 'DefaultStorage', 'default_storage')
@ -116,12 +117,20 @@ class Storage(object):
""" """
raise NotImplementedError() raise NotImplementedError()
# Needed by django.utils.functional.LazyObject (via DefaultStorage).
def get_all_members(self):
return self.__members__
class FileSystemStorage(Storage): class FileSystemStorage(Storage):
""" """
Standard filesystem storage Standard filesystem storage
""" """
def __init__(self, location=settings.MEDIA_ROOT, base_url=settings.MEDIA_URL): def __init__(self, location=None, base_url=None):
if location is None:
location = settings.MEDIA_ROOT
if base_url is None:
base_url = settings.MEDIA_URL
self.location = os.path.abspath(location) self.location = os.path.abspath(location)
self.base_url = base_url self.base_url = base_url
@ -212,7 +221,9 @@ class FileSystemStorage(Storage):
raise ValueError("This file is not accessible via a URL.") raise ValueError("This file is not accessible via a URL.")
return urlparse.urljoin(self.base_url, name).replace('\\', '/') return urlparse.urljoin(self.base_url, name).replace('\\', '/')
def get_storage_class(import_path): def get_storage_class(import_path=None):
if import_path is None:
import_path = settings.DEFAULT_FILE_STORAGE
try: try:
dot = import_path.rindex('.') dot = import_path.rindex('.')
except ValueError: except ValueError:
@ -227,5 +238,8 @@ def get_storage_class(import_path):
except AttributeError: except AttributeError:
raise ImproperlyConfigured('Storage module "%s" does not define a "%s" class.' % (module, classname)) raise ImproperlyConfigured('Storage module "%s" does not define a "%s" class.' % (module, classname))
DefaultStorage = get_storage_class(settings.DEFAULT_FILE_STORAGE) class DefaultStorage(LazyObject):
def _setup(self):
self._wrapped = get_storage_class()()
default_storage = DefaultStorage() default_storage = DefaultStorage()

View File

@ -251,3 +251,39 @@ def allow_lazy(func, *resultclasses):
return func(*args, **kwargs) return func(*args, **kwargs)
return lazy(func, *resultclasses)(*args, **kwargs) return lazy(func, *resultclasses)(*args, **kwargs)
return wraps(func)(wrapper) return wraps(func)(wrapper)
class LazyObject(object):
"""
A wrapper for another class that can be used to delay instantiation of the
wrapped class.
This is useful, for example, if the wrapped class needs to use Django
settings at creation time: we want to permit it to be imported without
accessing settings.
"""
def __init__(self):
self._wrapped = None
def __getattr__(self, name):
if self._wrapped is None:
self._setup()
if name == "__members__":
# Used to implement dir(obj)
return self._wrapped.get_all_members()
return getattr(self._wrapped, name)
def __setattr__(self, name, value):
if name == "_wrapped":
# Assign to __dict__ to avoid infinite __setattr__ loops.
self.__dict__["_wrapped"] = value
else:
if self._wrapped is None:
self._setup()
setattr(self._wrapped, name, value)
def _setup(self):
"""
Must be implemented by subclasses to initialise the wrapped object.
"""
raise NotImplementedError