Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Stopped staticfiles app from requiring a models module when looking f…

…or static files. Also removed a bit of code smell in the prefix handling by saving it in the source file storage.

git-svn-id: http://code.djangoproject.com/svn/django/trunk@15219 bcc190cf-cafb-0310-a4f2-bffc1f526a37
  • Loading branch information...
commit 645eb2b26b01520d7e98cb3c2f671e254571a090 1 parent 6c361ec
Jannis Leidel jezdez authored
61 django/contrib/staticfiles/finders.py
View
@@ -55,7 +55,9 @@ def __init__(self, apps=None, *args, **kwargs):
self.locations.add((prefix, root))
# Don't initialize multiple storages for the same location
for prefix, root in self.locations:
- self.storages[root] = FileSystemStorage(location=root)
+ filesystem_storage = FileSystemStorage(location=root)
+ filesystem_storage.prefix = prefix
+ self.storages[root] = filesystem_storage
super(FileSystemFinder, self).__init__(*args, **kwargs)
@@ -94,7 +96,7 @@ def list(self, ignore_patterns):
for prefix, root in self.locations:
storage = self.storages[root]
for path in utils.get_files(storage, ignore_patterns):
- yield path, prefix, storage
+ yield path, storage
class AppDirectoriesFinder(BaseFinder):
@@ -105,14 +107,18 @@ class AppDirectoriesFinder(BaseFinder):
storage_class = AppStaticStorage
def __init__(self, apps=None, *args, **kwargs):
- # Maps app modules to appropriate storage instances
+ # The list of apps that are handled
+ self.apps = []
+ # Mapping of app module paths to storage instances
self.storages = SortedDict()
- if apps is not None:
- self.apps = apps
- else:
- self.apps = models.get_apps()
- for app in self.apps:
- self.storages[app] = self.storage_class(app)
+ if apps is None:
+ apps = settings.INSTALLED_APPS
+ for app in apps:
+ app_storage = self.storage_class(app)
+ if os.path.isdir(app_storage.location):
+ self.storages[app] = app_storage
+ if app not in self.apps:
+ self.apps.append(app)
super(AppDirectoriesFinder, self).__init__(*args, **kwargs)
def list(self, ignore_patterns):
@@ -121,9 +127,8 @@ def list(self, ignore_patterns):
"""
for storage in self.storages.itervalues():
if storage.exists(''): # check if storage location exists
- prefix = storage.get_prefix()
for path in utils.get_files(storage, ignore_patterns):
- yield path, prefix, storage
+ yield path, storage
def find(self, path, all=False):
"""
@@ -131,29 +136,29 @@ def find(self, path, all=False):
"""
matches = []
for app in self.apps:
- app_matches = self.find_in_app(app, path)
- if app_matches:
+ match = self.find_in_app(app, path)
+ if match:
if not all:
- return app_matches
- matches.append(app_matches)
+ return match
+ matches.append(match)
return matches
def find_in_app(self, app, path):
"""
Find a requested static file in an app's static locations.
"""
- storage = self.storages[app]
- prefix = storage.get_prefix()
- if prefix:
- prefix = '%s%s' % (prefix, os.sep)
- if not path.startswith(prefix):
- return None
- path = path[len(prefix):]
- # only try to find a file if the source dir actually exists
- if storage.exists(path):
- matched_path = storage.path(path)
- if matched_path:
- return matched_path
+ storage = self.storages.get(app, None)
+ if storage:
+ if storage.prefix:
+ prefix = '%s%s' % (storage.prefix, os.sep)
+ if not path.startswith(prefix):
+ return None
+ path = path[len(prefix):]
+ # only try to find a file if the source dir actually exists
+ if storage.exists(path):
+ matched_path = storage.path(path)
+ if matched_path:
+ return matched_path
class BaseStorageFinder(BaseFinder):
@@ -196,7 +201,7 @@ def list(self, ignore_patterns):
List all files of the storage.
"""
for path in utils.get_files(self.storage, ignore_patterns):
- yield path, '', self.storage
+ yield path, self.storage
class DefaultStorageFinder(BaseStorageFinder):
"""
10 django/contrib/staticfiles/management/commands/collectstatic.py
View
@@ -75,8 +75,8 @@ def handle_noargs(self, **options):
raise CommandError("Collecting static files cancelled.")
for finder in finders.get_finders():
- for source, prefix, storage in finder.list(ignore_patterns):
- self.copy_file(source, prefix, storage, **options)
+ for source, storage in finder.list(ignore_patterns):
+ self.copy_file(source, storage, **options)
actual_count = len(self.copied_files) + len(self.symlinked_files)
unmodified_count = len(self.unmodified_files)
@@ -97,7 +97,7 @@ def log(self, msg, level=2):
if self.verbosity >= level:
self.stdout.write(msg)
- def copy_file(self, source, prefix, source_storage, **options):
+ def copy_file(self, source, source_storage, **options):
"""
Attempt to copy (or symlink) ``source`` to ``destination``,
returning True if successful.
@@ -107,8 +107,8 @@ def copy_file(self, source, prefix, source_storage, **options):
source_last_modified = source_storage.modified_time(source)
except (OSError, NotImplementedError):
source_last_modified = None
- if prefix:
- destination = os.path.join(prefix, source)
+ if getattr(source_storage, 'prefix', None):
+ destination = os.path.join(source_storage.prefix, source)
else:
destination = source
symlink = options['link']
50 django/contrib/staticfiles/storage.py
View
@@ -38,50 +38,22 @@ class AppStaticStorage(FileSystemStorage):
A file system storage backend that takes an app module and works
for the ``static`` directory of it.
"""
+ prefix = None
source_dir = 'static'
def __init__(self, app, *args, **kwargs):
"""
Returns a static file storage if available in the given app.
"""
- # app is actually the models module of the app. Remove the '.models'.
- bits = app.__name__.split('.')[:-1]
- self.app_name = bits[-1]
- self.app_module = '.'.join(bits)
- # The models module (app) may be a package in which case
- # dirname(app.__file__) would be wrong. Import the actual app
- # as opposed to the models module.
- app = import_module(self.app_module)
- location = self.get_location(os.path.dirname(app.__file__))
- super(AppStaticStorage, self).__init__(location, *args, **kwargs)
-
- def get_location(self, app_root):
- """
- Given the app root, return the location of the static files of an app,
- by default 'static'. We special case the admin app here since it has
- its static files in 'media'.
- """
+ # app is the actual app module
+ self.app_module = app
+ # We special case the admin app here since it has its static files
+ # in 'media' for historic reasons.
if self.app_module == 'django.contrib.admin':
- return os.path.join(app_root, 'media')
- return os.path.join(app_root, self.source_dir)
-
- def get_prefix(self):
- """
- Return the path name that should be prepended to files for this app.
- """
- if self.app_module == 'django.contrib.admin':
- return self.app_name
- return None
+ self.prefix = 'admin'
+ self.source_dir = 'media'
+ mod = import_module(self.app_module)
+ mod_path = os.path.dirname(mod.__file__)
+ location = os.path.join(mod_path, self.source_dir)
+ super(AppStaticStorage, self).__init__(location, *args, **kwargs)
- def get_files(self, ignore_patterns=[]):
- """
- Return a list containing the relative source paths for all files that
- should be copied for an app.
- """
- files = []
- prefix = self.get_prefix()
- for path in utils.get_files(self, ignore_patterns):
- if prefix:
- path = os.path.join(prefix, path)
- files.append(path)
- return files
39 django/contrib/staticfiles/utils.py
View
@@ -3,32 +3,35 @@
from django.conf import settings
from django.core.exceptions import ImproperlyConfigured
-def get_files(storage, ignore_patterns=[], location=''):
+def is_ignored(path, ignore_patterns=[]):
"""
- Recursively walk the storage directories gathering a complete
- list of files that should be copied, returning this list.
+ Return True or False depending on whether the ``path`` should be
+ ignored (if it matches any pattern in ``ignore_patterns``).
"""
- def is_ignored(path):
- """
- Return True or False depending on whether the ``path`` should be
- ignored (if it matches any pattern in ``ignore_patterns``).
- """
- for pattern in ignore_patterns:
- if fnmatch.fnmatchcase(path, pattern):
- return True
- return False
+ for pattern in ignore_patterns:
+ if fnmatch.fnmatchcase(path, pattern):
+ return True
+ return False
+def get_files(storage, ignore_patterns=[], location=''):
+ """
+ Recursively walk the storage directories yielding the paths
+ of all files that should be copied.
+ """
directories, files = storage.listdir(location)
- static_files = [location and os.path.join(location, fn) or fn
- for fn in files
- if not is_ignored(fn)]
+ for fn in files:
+ if is_ignored(fn, ignore_patterns):
+ continue
+ if location:
+ fn = os.path.join(location, fn)
+ yield fn
for dir in directories:
- if is_ignored(dir):
+ if is_ignored(dir, ignore_patterns):
continue
if location:
dir = os.path.join(location, dir)
- static_files.extend(get_files(storage, ignore_patterns, dir))
- return static_files
+ for fn in get_files(storage, ignore_patterns, dir):
+ yield fn
def check_settings():
"""
5 docs/ref/contrib/staticfiles.txt
View
@@ -103,9 +103,8 @@ setting.
.. note::
- When using the :class:`AppDirectoriesFinder` finder, make sure your apps can
- be found by Django's app loading mechanism. Simply include a ``models``
- module (an empty ``models.py`` file suffices) and add the app to the
+ When using the :class:`AppDirectoriesFinder` finder, make sure your apps
+ can be found by staticfiles. Simply add the app to the
:setting:`INSTALLED_APPS` setting of your site.
Static file finders are currently considered a private interface, and this
6 tests/regressiontests/staticfiles_tests/tests.py
View
@@ -34,9 +34,6 @@ def setUp(self):
self.old_debug = settings.DEBUG
self.old_installed_apps = settings.INSTALLED_APPS
- # We have to load these apps to test staticfiles.
- load_app('regressiontests.staticfiles_tests.apps.test')
- load_app('regressiontests.staticfiles_tests.apps.no_label')
site_media = os.path.join(TEST_ROOT, 'project', 'site_media')
settings.DEBUG = True
settings.MEDIA_ROOT = os.path.join(site_media, 'media')
@@ -53,8 +50,11 @@ def setUp(self):
'django.contrib.staticfiles.finders.DefaultStorageFinder',
)
settings.INSTALLED_APPS = [
+ 'django.contrib.admin',
'django.contrib.staticfiles',
'regressiontests.staticfiles_tests',
+ 'regressiontests.staticfiles_tests.apps.test',
+ 'regressiontests.staticfiles_tests.apps.no_label',
]
# Clear the cached default_storage out, this is because when it first
Please sign in to comment.
Something went wrong with that request. Please try again.