django-staticfiles-finder

BaseFinder是所有Finder的基类:

class BaseFinder(object):
    """
    A base file finder to be used for custom staticfiles finder classes.
    """

    def find(self, path, all=False):
        """
        Given a relative file path this ought to find an
        absolute file path.

        If the ``all`` parameter is ``False`` (default) only
        the first found file path will be returned; if set
        to ``True`` a list of all found files paths is returned.
        """
        raise NotImplementedError('subclasses of BaseFinder must provide a find() method')

    def list(self, ignore_patterns):
        """
        Given an optional list of paths to ignore, this should return
        a two item iterable consisting of the relative path and storage
        instance.
        """
        raise NotImplementedError('subclasses of BaseFinder must provide a list() method')

BaseFinder定义了两个方法find和list。

子类FileSystemFinder则实现了settings.STATICFILES_DIRS的寻找。

class FileSystemFinder(BaseFinder):
    """
    A static files finder that uses the ``STATICFILES_DIRS`` setting
    to locate files.
    """
    def __init__(self, app_names=None, *args, **kwargs):
        # List of locations with static files
        self.locations = []
        # Maps dir paths to an appropriate storage instance
        self.storages = OrderedDict()
        if not isinstance(settings.STATICFILES_DIRS, (list, tuple)):
            raise ImproperlyConfigured(
                "Your STATICFILES_DIRS setting is not a tuple or list; "
                "perhaps you forgot a trailing comma?")
        for root in settings.STATICFILES_DIRS:
            if isinstance(root, (list, tuple)):
                prefix, root = root
            else:
                prefix = ''
            if settings.STATIC_ROOT and os.path.abspath(settings.STATIC_ROOT) == os.path.abspath(root):
                raise ImproperlyConfigured(
                    "The STATICFILES_DIRS setting should "
                    "not contain the STATIC_ROOT setting")
            if (prefix, root) not in self.locations:
                self.locations.append((prefix, root))
        for prefix, root in self.locations:
            filesystem_storage = FileSystemStorage(location=root)
            filesystem_storage.prefix = prefix
            self.storages[root] = filesystem_storage
        super(FileSystemFinder, self).__init__(*args, **kwargs)


FileSystemFinder类的初始化方法__init__,主要是初始化了self.locations和self.storages两个属性。

self.locations的格式为 

[(prefix, dir), (prefix, dir), ...]

self.storages的格式为

{dir: FileSystemStorage, dir: FileSystemStorage, ...}


find方法负责寻找文件的位置:

find只是循环遍历self.locations,然后调用find_location方法在每个dir寻找。

def find(self, path, all=False):
        """
        Looks for files in the extra locations
        as defined in ``STATICFILES_DIRS``.
        """
        matches = []
        for prefix, root in self.locations:
            if root not in searched_locations:
                searched_locations.append(root)
            matched_path = self.find_location(root, path, prefix)
            if matched_path:
                if not all:
                    return matched_path
                matches.append(matched_path)
        return matches

find_location负责在给定的root目录下, 寻找文件名为path的文件位置。

    def find_location(self, root, path, prefix=None):
        """
        Finds a requested static file in a location, returning the found
        absolute path (or ``None`` if no match).
        """
        if prefix:
            prefix = '%s%s' % (prefix, os.sep)
            if not path.startswith(prefix):
                return None
            path = path[len(prefix):]
        path = safe_join(root, path)
        if os.path.exists(path):
            return path


list负责展示文件列表:

    def list(self, ignore_patterns):
        """
        List all files in all locations.
        """
        for prefix, root in self.locations:
            storage = self.storages[root]
            for path in utils.get_files(storage, ignore_patterns):
                yield path, storage


调用get_files获取path列表。

def get_files(storage, ignore_patterns=None, location=''):
    """
    Recursively walk the storage directories yielding the paths
    of all files that should be copied.
    """
    if ignore_patterns is None:
        ignore_patterns = []
    directories, files = storage.listdir(location)
    for fn in files:
        if matches_patterns(fn, ignore_patterns):
            continue
        if location:
            fn = os.path.join(location, fn)
        yield fn
    for dir in directories:
        if matches_patterns(dir, ignore_patterns):
            continue
        if location:
            dir = os.path.join(location, dir)
        for fn in get_files(storage, ignore_patterns, dir):
            yield fn

这里显示利用storage对象,得到文件列表,然后将结果通过ignore_patterns过滤,返回过滤后的文件。


AppDirectoriesFinder负责每个app下面的static文件的查找。

class AppDirectoriesFinder(BaseFinder):
    """
    A static files finder that looks in the directory of each app as
    specified in the source_dir attribute.
    """
    storage_class = FileSystemStorage
    source_dir = 'static'

    def __init__(self, app_names=None, *args, **kwargs):
        # The list of apps that are handled
        self.apps = []
        # Mapping of app names to storage instances
        self.storages = OrderedDict()
        
        app_configs = apps.get_app_configs()
        if app_names:
            app_names = set(app_names)
            app_configs = [ac for ac in app_configs if ac.name in app_names]
            
        for app_config in app_configs:
            app_storage = self.storage_class(os.path.join(app_config.path, self.source_dir))
            if os.path.isdir(app_storage.location):
                self.storages[app_config.name] = app_storage
                if app_config.name not in self.apps:
                    self.apps.append(app_config.name)
        super(AppDirectoriesFinder, self).__init__(*args, **kwargs)


self.apps的格式为:

[app_name, app_name, ...]

self.storages的格式为:

{app_name: FileSystemStorage, app_name: FileSystemStorage, ...}


调用apps模块的get_app_configs函数,获取app_config。

然后更新self.apps和self.storages

def find(self, path, all=False):
        """
        Looks for files in the app directories.
        """
        matches = []
        for app in self.apps:
            app_location = self.storages[app].location
            if app_location not in searched_locations:
                searched_locations.append(app_location)
                
            match = self.find_in_app(app, path)
            
            if match:
                if not all:
                    return match
                matches.append(match)
        return matches

find方法循环遍历self.apps,调用find_in_app方法指定一个app中寻找。

def find_in_app(self, app, path):
        """
        Find a requested static file in an app's static locations.
        """
        storage = self.storages.get(app, None)
        if storage:
            # 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的exists方法,来判断是否存在。

def list(self, ignore_patterns):
        """
        List all files in all app storages.
        """
        for storage in six.itervalues(self.storages):
            if storage.exists(''):  # check if storage location exists
                for path in utils.get_files(storage, ignore_patterns):
                    yield path, storage


FileSystemFinder和AppDirectoriesFinder都也使用了FileSystemStorage,对于每一个目录,都有对应的storage。

不同的是FileSystemFinder通过os.path.exist判断文件是否存在,而AppDirectoriesFinder是通过storage.exist判断的。

转载于:https://my.oschina.net/u/569730/blog/364869

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值