diff --git a/djangoblog/plugin_manage/loader.py b/djangoblog/plugin_manage/loader.py index ee750d0d..63814822 100644 --- a/djangoblog/plugin_manage/loader.py +++ b/djangoblog/plugin_manage/loader.py @@ -1,64 +1,124 @@ +# 插件加载与管理模块 +# 该模块提供了Django应用中插件的动态加载、注册和查询功能 +# 主要功能包括:从指定目录加载激活的插件、维护插件注册表、提供多种插件查询接口 +# 插件需符合特定结构(包含plugin.py及插件实例),通过Django配置指定激活的插件和插件目录 + import os import logging from django.conf import settings +# 初始化日志记录器,用于记录插件加载过程中的信息和错误 logger = logging.getLogger(__name__) -# 全局插件注册表 +# 全局插件注册表,存储所有已成功加载的插件实例 _loaded_plugins = [] + def load_plugins(): """ - Dynamically loads and initializes plugins from the 'plugins' directory. - This function is intended to be called when the Django app registry is ready. + 从'plugins'目录动态加载并初始化激活的插件。 + 该函数应在Django应用注册表就绪后调用(确保Django配置已加载)。 + 加载逻辑:遍历配置中激活的插件列表,检查插件目录结构完整性,导入并初始化插件实例。 """ global _loaded_plugins + # 重置插件注册表,避免重复加载 _loaded_plugins = [] - + + # 遍历配置中激活的插件名称列表(settings.ACTIVE_PLUGINS定义需加载的插件) for plugin_name in settings.ACTIVE_PLUGINS: + # 构建插件目录的绝对路径(settings.PLUGINS_DIR为插件根目录) plugin_path = os.path.join(settings.PLUGINS_DIR, plugin_name) + # 检查插件目录是否存在且包含必要的plugin.py文件(插件入口) if os.path.isdir(plugin_path) and os.path.exists(os.path.join(plugin_path, 'plugin.py')): try: - # 导入插件模块 + # 动态导入插件模块:从plugins.插件名.plugin导入模块 + # fromlist=['plugin']确保导入子模块而非父模块 plugin_module = __import__(f'plugins.{plugin_name}.plugin', fromlist=['plugin']) - - # 获取插件实例 + + # 检查导入的模块是否包含'plugin'属性(插件实例) if hasattr(plugin_module, 'plugin'): + # 获取插件实例并添加到全局注册表 plugin_instance = plugin_module.plugin _loaded_plugins.append(plugin_instance) + # 记录成功加载日志,包含插件名称和插件定义的名称 logger.info(f"Successfully loaded plugin: {plugin_name} - {plugin_instance.PLUGIN_NAME}") else: + # 插件模块结构不完整(缺少plugin实例)时记录警告 logger.warning(f"Plugin {plugin_name} does not have 'plugin' instance") - + except ImportError as e: + # 捕获导入错误(如模块不存在、依赖缺失等) logger.error(f"Failed to import plugin: {plugin_name}", exc_info=e) except AttributeError as e: + # 捕获属性错误(如插件实例缺少必要属性) logger.error(f"Failed to get plugin instance: {plugin_name}", exc_info=e) except Exception as e: + # 捕获其他未预期的错误 logger.error(f"Unexpected error loading plugin: {plugin_name}", exc_info=e) + def get_loaded_plugins(): - """获取所有已加载的插件""" + """ + 获取所有已加载的插件实例列表。 + + 返回: + list: 包含所有成功加载的插件实例的列表 + """ return _loaded_plugins + def get_plugin_by_name(plugin_name): - """根据名称获取插件""" + """ + 根据插件名称查询插件实例(实际查询的是plugin_slug属性,可能与函数名存在命名兼容)。 + + 参数: + plugin_name: 要查询的插件slug名称 + + 返回: + 匹配的插件实例,若未找到则返回None + """ for plugin in _loaded_plugins: if plugin.plugin_slug == plugin_name: return plugin return None + def get_plugin_by_slug(plugin_slug): - """根据slug获取插件""" + """ + 根据插件slug查询插件实例(与plugin_slug属性精确匹配)。 + + 参数: + plugin_slug: 要查询的插件slug标识 + + 返回: + 匹配的插件实例,若未找到则返回None + """ for plugin in _loaded_plugins: if plugin.plugin_slug == plugin_slug: return plugin return None + def get_plugins_info(): - """获取所有插件的信息""" + """ + 获取所有已加载插件的信息字典列表。 + 信息由插件的get_plugin_info()方法提供,通常包含名称、描述、版本等元数据。 + + 返回: + list: 每个元素为一个插件的信息字典 + """ return [plugin.get_plugin_info() for plugin in _loaded_plugins] + def get_plugins_by_position(position): - """获取支持指定位置的插件""" - return [plugin for plugin in _loaded_plugins if position in plugin.SUPPORTED_POSITIONS] \ No newline at end of file + """ + 获取支持指定位置的所有插件实例(基于插件的SUPPORTED_POSITIONS属性筛选)。 + 用于在页面特定位置渲染插件内容(如侧边栏、页头等)。 + + 参数: + position: 位置标识(如'sidebar'、'header'等,对应POSITION_HOOKS中的键) + + 返回: + list: 所有支持该位置的插件实例 + """ + return [plugin for plugin in _loaded_plugins if position in plugin.SUPPORTED_POSITIONS] \ No newline at end of file