Open edX Platform Django 配置体系解析从 openedx/envs/common.py 到 LMS/CMS 环境设置的三层架构【免费下载链接】openedx-platformThe Open edX LMS Studio, powering education sites around the world!项目地址: https://gitcode.com/GitHub_Trending/ed/openedx-platformOpen edX 平台edx-platform通过三层 Django 配置模块组织全站配置平台级公共配置 openedx/envs/common.py约 3062 行、LMS 配置 lms/envs/common.py约 3306 行、CMS/Studio 配置 cms/envs/common.py约 1359 行。本文以官方设置参考文档 docs/references/settings.rst 为骨架讲清这套配置的分层继承关系、Derived派生设置的计算机制、FEATURES特性开关代理以及运维人员如何安全地覆盖设置项——读完后你可以独立完成查看最终生效配置、编写自定义 DJANGO_SETTINGS_MODULE、排查配置覆盖链三类操作。一、设置参考文档是如何自动生成的官方设置参考页 settings.rst 本身只有 25 行其内容不是手写的而是通过 Sphinx 指令自动从源码抽取Settings This is the list of (non-toggle) Django settings defined in the common.py modules of edx-platform. .. note:: Toggle settings, which enable or disable a specific feature, are documented in the :ref:feature toggles featuretoggles section. Platform-Wide Settings ---------------------- .. settings:: :folder_path: openedx/envs/common.py LMS Settings ------------ .. settings:: :folder_path: lms/envs/common.py CMS Settings ------------ .. settings:: :folder_path: cms/envs/common.py三个关键机制值得注意.. settings::指令由 Sphinx 扩展code_annotations.contrib.sphinx.extensions.settings提供在 docs/conf.py 中注册。构建文档时它扫描指定文件里所有大写顶层变量即 Django 设置名并结合源码中的注释生成条目化的设置列表同时把每个设置链接到对应源码行。设置与功能开关分而治之文档明确说明 toggle 类设置形如# .. toggle_name: settings.XXX注释块不在此页而是收录在 featuretoggles.rst 中。以 lms/envs/common.py 为例其中包含 69 处toggle_name注释如settings.ENABLE_MASQUERADE、settings.DISPLAY_HISTOGRAMS_TO_STAFFCMS 侧有 16 处。这种非开关设置看 settings 页、开关设置看 toggles 页的划分是查阅配置时的第一条经验法则。文档构建即代码检查docs/conf.py 在构建前设置DJANGO_SETTINGS_MODULE docs.docs_settings并执行django.setup()确保 LMS 与 Studio 全部代码可被成功导入。因此设置文件里任何导入错误都会直接暴露为文档构建失败。二、三层设置的分层继承关系整个配置体系是一棵星号导入 逐项覆盖的树openedx/envs/common.py 平台级LMS 与 CMS 共享的基础默认值路径、Django 内建项、缓存、DB、模板、Celery、JWT…… ├── lms/envs/common.py LMSfrom openedx.envs.common import * 后叠加 LMS 专属设置与 FEATURES │ ├── lms/envs/test.py 单元测试环境末尾调用 derive_settings(__name__) │ └── lms/envs/production.py 生产环境加载 LMS_CFG 指向的 YAML 覆盖 └── cms/envs/common.py CMS/Studio同样 from openedx.envs.common import * 后叠加 CMS 专属设置 ├── cms/envs/test.py └── cms/envs/production.py继承方式的证据直接写在源码里lms/envs/common.py 与 cms/envs/common.py 都执行from openedx.envs.common import *附带pylint: disablewildcard-import随后各自定义FEATURES FeaturesProxy(globals())特性开关代理lms/envs/common.py#L72、cms/envs/common.py#L58。openedx/envs/common.py 的模块 docstring 还特别警告了一个实操陷阱WARNING: Mutable values defined in this file may be unintentionally modified downstream…… if an LMS settings module modifies a mutable value defined here, the final value of the corresponding CMS setting may also be affected. To avoid this risk, create a deep copy of the value in the module that modifies it.即因为 CMS 会导入 LMS 会导入的共享可变值若你的下游设置文件直接就地修改mutate某个列表/字典可能污染其他服务的最终配置——正确做法是深拷贝后再修改。按 ADR 0022-settings-simplification.rst 的目标结构这套分层的定位是openedx/envs/common.py尽可能集中 LMS/CMS 共享配置给出合理的、生产可用的默认值production-ready defaults对密钥类设置给出明显错误的占位默认值obviously-wrong defaults确保不会被误用于生产lms/envs/common.py/cms/envs/common.py在此之上扩展出各服务的生产可用配置并作为运行管理命令的默认设置文件可用DJANGO_SETTINGS_MODULE覆盖该 ADR 还明确了当前配置体系的演进方向逐步把production.py中的默认值上浮到common.py让运维通过自定义DJANGO_SETTINGS_MODULE派生自common.py来完成覆盖。三、平台级核心设置逐项解读openedx/envs/common.py以下按 openedx/envs/common.py 源码中的分区##### Section Name #####头注释梳理最重要的设置项。完整列表请在文档构建产物中通过.. settings::指令生成的页面查阅此处给出高频项与源码依据。3.1 路径与运行基础Paths / Django Built-Ins设置默认值说明源码位置REPO_ROOT仓库根目录由path(__file__).abspath()推导其余路径常量都基于它openedx/envs/common.py#L98-L104COURSES_ROOT/DATA_DIRENV_ROOT / data课程数据根目录ENV_ROOT为存放 edx-platform 的上级目录venv 同级同上DEBUGFalse生产默认关闭调试L108USE_TZ/TIME_ZONETrue/UTC统一 UTC 时区L110-L111SECRET_KEYdev key典型明显错误占位值生产环境必须覆盖L118SECURE_PROXY_SSL_HEADER(HTTP_X_FORWARDED_PROTO, https)源码注释强调启用后服务器必须位于会剥离该头的代理之后否则用户可伪造 https 状态L120-L123SESSION_ENGINEdjango.contrib.sessions.backends.cache会话存缓存序列化器为openedx.core.lib.session_serializers.PickleSerializerL129-L131CSRF_COOKIE_AGE60*60*24*7*52一年源码同时警告CSRF_COOKIE_SECURE False的默认值强烈建议在面向终端用户的环境中覆盖L133-L136ALLOWED_HOSTS[*]仅适合开发/测试L138ROOT_URLCONFDerived(lambda settings: f{settings.SERVICE_VARIANT}.urls)派生设置的典型用法LMS 得到lms.urls、CMS 得到cms.urlsL143X_FRAME_OPTIONSDENY防点击劫持设为ALLOW可关闭L1413.2 缓存与数据库CACHES 定义了 7 个缓存别名default、general、configuration、staticfiles、course_structure_cache超时 1 周、celery超时 7200 秒、mongo_metadata_inheritance超时 300 秒全部默认使用PyMemcacheCache指向localhost:11211并统一使用common.djangoapps.util.memcache.safe_key作为 KEY_FUNCTION、ignore_exc: True缓存故障不阻断业务。DATABASES 默认声明三个 MySQL 连接default库名edxapp开启ATOMIC_REQUESTS、read_replica读副本、student_module_history库名edxapp_csmh存放学习进度历史。配套的DATABASE_ROUTERS使用 StudentModuleHistoryExtendedRouter 把StudentModuleHistory相关表路由到独立库。注释中说明edxapp-migrate脚本保证除read_replica外的库会同时为 LMS 和 CMS 执行迁移。3.3 模板系统Django 与 Mako 双引擎TEMPLATES 同时注册了两个后端django后端APP_DIRS: False模板目录为PROJECT_ROOT/templates、common/templates等loader 链中特意加入 Mako 感知的 loaderThemeTemplateLoader→MakoFilesystemLoader→MakoAppDirectoriesLoader以便在 Django 模板中 include Mako 模板如main_django.html。mako后端BACKEND为common.djangoapps.edxmako.backend.Mako其DIRS是一个Derived(make_mako_template_dirs)——该函数 会在启用综合主题ENABLE_COMPREHENSIVE_THEMING时把各主题的模板目录插入MAKO_TEMPLATE_DIRS_BASE头部。相关配套设置MAKO_MODULE_DIRMako 编译产物目录L504 也是Derived按SERVICE_VARIANT区分 LMS/CMS 的临时目录、CONTEXT_PROCESSORSL520-L530包含帮助系统的help_tokens.context_processor与站点配置的configuration_context。3.4 其他主要分区openedx/envs/common.py 后半部分按主题划分的分区源码中的分区头注释包括Optional Apps可选项INSTALLED_APPS扩展、Django Rest Framework、Celery、RedirectMiddleware、Django Debug Toolbar、JWT、Features、CAPA External Code Evaluation、CSRF、Cross-domain Requests、Social Media、Google Analytics、Block Structures、Bulk Email、Video含图片/字幕存储与视频管线、Parental Controls、Instructor Downloads、Registration、Course Enrollment Modes、Enterprise Api Client、ModuleStore、Micro-frontends、Swift、SAML、django-fernet-fields、django-simple-history、Django OAuth Toolkit、Profile Image、XBlock、Built-in Blocks Extraction 等。这些分区的设置都会出现在文档构建产物中开发调试时可直接在源码中按分区名定位。四、核心机制一Derived派生设置Derived是理解整套配置体系的钥匙。定义在 openedx/core/lib/derived.pyclass Derived(t.Generic[T]): A temporary Django setting value, defined with a function which generates the settings eventual value. Said function (calculate_value) should accept a Django settings module, and return a calculated value. To ensure that application code does not encounter an instance of this class in your settings, be sure to call derive_settings somewhere in your terminal settings file. def __init__(self, calculate_value: t.Callable[[Settings], T]): self.calculate_value calculate_value工作方式是延迟求值设置先被赋值为一个Derived(calculate_value)占位对象而不是具体值所有设置模块shared → service → 下游覆盖全部加载完成后终端设置文件调用derive_settings(module_name)derive_settings 遍历该模块所有大写字母开头的顶层变量正则^[A-Z][A-Z0-9_]*$递归评估其中嵌套在 dict/list/tuple/set 里的Derived对象见 _derive_recursively用calculate_value(settings)的返回值就地替换。这样设计解决的问题是某个设置的合理默认值依赖另一个设置的最终值而后者可能被你下游覆盖。典型实例ROOT_URLCONF Derived(lambda settings: f{settings.SERVICE_VARIANT}.urls)openedx/envs/common.py#L143只有等SERVICE_VARIANT被最终确定后才计算LOCALE_PATHS Derived(_make_locale_paths)L222依赖PREPEND_LOCALE_PATHS与主题设置LOCALE_PATHS的推导函数 _make_locale_paths 会先取PREPEND_LOCALE_PATHS再追加conf/locale启用主题时继续追加主题 locale 路径。两条硬约束源码 docstring 明确你的终端设置文件必须调用derive_settings(__name__)否则应用代码会拿到Derived实例而非真实值。仓库内现有调用点见 lms/envs/test.py#L339 与 cms/envs/test.py#L193Derived值可以被直接赋成一个普通值来覆盖——此时它不再参与推导等价于手工指定最终值。五、核心机制二FEATURES特性开关代理LMS 与 CMS 的common.py都不再用裸字典管理开关而是FEATURES FeaturesProxy(globals())lms/envs/common.py#L71-L72。FeaturesProxy是 openedx/core/lib/features_setting_proxy.py 中实现的MutableMapping它以所在设置模块的globals()为数据源把settings.FEATURES[ENABLE_MASQUERADE]这样的字典访问映射回模块级变量ENABLE_MASQUERADE的读写。这带来两个实际后果覆盖开关的标准写法仍是直接重赋模块级变量如ENABLE_MASQUERADE Falsesettings.FEATURES[...]只是读取语法糖由于代理绑定在globals()上LMS 与 CMS 各自维护独立的FEATURES命名空间修改互不干扰。带# .. toggle_name:注释块的开关如 lms/envs/common.py#L129-L138 的ENABLE_DJANGO_ADMIN_SITE会被文档管线收集到 featuretoggles.rst 页面注释块中的toggle_default、toggle_description、toggle_warning字段即页面展示内容。六、LMS 与 CMS 服务级设置要点6.1 lms/envs/common.py除继承自平台级的全部设置外LMS 层还定义了PLATFORM_NAME、COURSE_IDT_REGEX、课程/使用键的正则常量、COURSES_API_*、PAYMENT_PROCESSOR_*、邮件/SMTP、ENTERPRISE_*角色常量导入lms/envs/common.py#L48-L62、CACHES扩展如bulk_email别名等。文件头部 lms/envs/common.py#L14-L32 还写明了一条重要惯例——扩展列表类设置优先使用EXTRA后缀的新变量如CELERY_EXTRA_IMPORTS、XBLOCK_EXTRA_MIXINS而不是就地替换整个列表以便平台后续合并时不丢失你的条目。6.2 cms/envs/common.pyCMS 层聚焦 Studio 侧能力代表性设置cms/envs/common.py#L62-L160设置默认说明STUDIO_NAME/STUDIO_SHORT_NAMEYour Platform Studio/Studio品牌名SECRET_KEYdev key再次覆盖为占位值生产必须替换ENABLE_CREATOR_GROUPTrue开启后仅课程创建者组可建课ENABLE_CONTENT_LIBRARIESTrue内容库仅 split mongo 课程支持ALLOW_COURSE_RERUNSTrue控制 Studio 首页 Re-run Course 入口ENABLE_SEPARATE_ARCHIVED_COURSESTrue归档课程单独列表展示ENABLE_GRADE_DOWNLOADSTrue支持成绩下载GITHUB_PUSH/STUDIO_REQUEST_EMAILFalse/Git 推送、开课申请邮箱ENABLE_MAX_FAILED_LOGIN_ATTEMPTSFalse失败登录锁定七、实操指南查看最终配置与自定义覆盖7.1 查看某设置模块的完整生效值ADR 计划引入的dump_settings管理命令已落地openedx/core/djangoapps/util/management/commands/dump_settings.py对应测试在 test_dump_settings.py。用法示例在 venv 中以 LMS 测试设置为前提DJANGO_SETTINGS_MODULElms.envs.test ./manage.py lms dump_settings它会以 JSON 输出当前DJANGO_SETTINGS_MODULE加载后的全部顶层设置适合在调整覆盖链后验证最终值到底是什么。7.2 编写自定义生产设置模块按 ADR 的目标结构自定义设置模块例如部署工具生成的lms_prod.py应遵循三步# your/lms_prod.py示例骨架 from lms.envs.common import * # 1. 继承服务级公共默认 # 2. 用生产值替换所有明显错误占位SECRET_KEY、ALLOWED_HOSTS、 # CSRF_COOKIE_SECURE、SECURE_PROXY_SSL_HEADER 前提条件…… from openedx.core.lib.derived import derive_settings derive_settings(__name__) # 3. 渲染所有 Derived 值要点回顾必须覆盖明显错误默认值否则会带着SECRET_KEYdev key这类占位值上线必须调用derive_settings(__name__)否则Derived占位不会计算修改共享可变值前先深拷贝见 openedx/envs/common.py 的 WARNING对列表类设置优先使用XXX_EXTRA_YYY变量扩展而非整表替换。7.3 测试环境配置单测使用的 openedx/envs/test.py 集中了 LMS/CMS 共享的测试值如把ENABLE_DISCUSSION_SERVICE置为False加速测试服务级测试模块 lms/envs/test.py 与 cms/envs/test.py 分别在其末尾执行derive_settings(__name__)完成派生设置渲染——这也是终端设置文件负责调用derive_settings这一约束在仓库内的直接范例。八、延伸阅读与限制说明配置简化工程的背景、动机与完整行动路线含对 Tutor 间接层问题的剖析见 ADRdocs/decisions/0022-settings-simplification.rst功能开关完整列表见 docs/references/featuretoggles.rst各环境模块的职责分工common.py默认值→production.py加载LMS_CFG/CMS_CFG指向的 YAML 覆盖→test.py单测。当前仓库中 YAML 覆盖路径仍在演进具体取舍以 ADR 所述两条路线保留简化版 YAML schema或完全转向自定义DJANGO_SETTINGS_MODULE为准本文所有行号与取值均基于当前仓库快照openedx/envs/common.py3062 行、lms/envs/common.py3306 行、cms/envs/common.py1359 行升级平台后请以对应版本的源码为准。【免费下载链接】openedx-platformThe Open edX LMS Studio, powering education sites around the world!项目地址: https://gitcode.com/GitHub_Trending/ed/openedx-platform创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
