全解析:从数据模型、生成流程到证书管理实战)
Open edX 课程证书模块Certificates App全解析从数据模型、生成流程到证书管理实战【免费下载链接】openedx-platformThe Open edX LMS Studio, powering education sites around the world!项目地址: https://gitcode.com/GitHub_Trending/ed/openedx-platform导读Open edX 平台的课程证书功能并非只存在于单一目录而是横跨 LMS、StudioCMS与 Credentials 等多个子系统。本文以lms/djangoapps/certificates为核心系统讲解该应用的职责边界、核心数据模型、证书状态机、证书生成与撤销的完整调用链并结合cms/djangoapps/contentstore/views/certificates.py与openedx/core/djangoapps/credentials等关联代码帮助你理解证书配置 → 证书生成 → 证书展示 → 证书撤销的端到端实现掌握通过源码定位证书问题、通过管理命令批量发证的能力。仓库定位本应用当前状态为Maintenance维护中即功能已基本稳定新功能开发优先考虑 Credentials 等外部服务本模块以维护为主。Open edX 课程证书生成流程架构图一、应用职责证书的创建与管理中枢根据 lms/djangoapps/certificates/README.rstCertificates 应用负责创建和管理课程证书course certificates其职责覆盖三个层面证书设置certificate settings——课程的证书启用开关、显示行为、生效日期等配置课程证书模板course certificate templates——Web 端自定义证书的 Django 模板及其配套资源已生成的学习者课程证书generated learner course certificates——每位学习者在某次课程运行course run下实际获得的证书记录。同时该应用提供了两类关键数据模型能力证书无效化invalidating certificates与白名单管理managing the allowlist。1.1 功能散布在多个子系统证书相关功能分散在多处理解哪里改什么是排查问题的第一步位置职责lms/djangoapps/certificates核心证书数据模型、生成逻辑、任务、信号、API 与 Web 展示openedx/core/djangoapps/credentials学习者的项目证书Program Certificates记录系统system of record与课程证书联动cms/djangoapps/contentstore/views/certificates.pyStudio 侧证书配置的 CRUD API创建/编辑/删除证书及签名人各前端静态模板证书列表页Backbone 应用、证书 Web 视图等 UI值得特别说明的是Credentials 服务它是学习者项目证书的权威记录system of record系统。在本仓库中对应openedx/core/djangoapps/credentials课程证书在生成或状态变化时会通过COURSE_CERT_CHANGED、COURSE_CERT_AWARDED等信号通知 Credentials由其判断是否可以授予项目级证书。二、核心数据模型models.py证书模块的数据模型全部定义在lms/djangoapps/certificates/models.py下面按学习者证书 → 例外与撤销 → 配置 → 模板四类介绍。2.1 GeneratedCertificate学习者证书主模型这是全模块最核心的模型一条记录代表一个学生在一次课程运行中获得的证书。关键字段字段说明user关联用户course_id课程运行 keyCourseKeyFieldverify_uuid证书唯一标识32 位 UUID用于证书校验 URLgrade生成证书时的成绩快照注意该成绩不会随课程成绩变化更新权威成绩应使用 PersistentCourseGradekey证书标识符PDF 证书时代使用distinction是否荣誉通过当前未使用status证书状态见下文状态机mode课程运行模式verified、honor、audit、masters 等name证书上显示的用户姓名PII 字段download_uuid/download_url/error_reason遗留的 PDF 证书字段已不再使用见 ADR 008-certificate-model-remnants.rst模型内置了三个 Managerobjects默认管理器包含不合格证书如 audit 模式的新证书eligible_certificates自动排除audit_passing、audit_notpassing状态防止意外给未注册证书模式的学生发证eligible_available_certificates在 eligible 基础上仅返回存在对应CourseOverview的证书。# 使用示例查询某学生在某课程的证书 cert GeneratedCertificate.certificate_for_student(student, course_id)2.2 例外与撤销类模型CertificateAllowlist证书白名单记录某个课程运行下被特批发证的学生allowlistTrue时生效get_certificate_allowlist(course_id, student)会返回包含id/user_id/user_name/user_email/course_id/created/notes/certificate_generated的字典列表。CertificateInvalidation证书无效化记录对某张证书的无效化操作activeTrue表示当前生效提供get_certificate_invalidations()与has_certificate_invalidation(student, course_key)查询接口。CertificateDateOverride证书日期覆盖手动将某张证书的展示日期覆盖为指定日期date字段时间建议设为 00:00:00并记录reason与overridden_by保存/删除时会通过COURSE_CERT_CHANGED信号通知 Credentials 刷新。2.3 配置类模型CertificateGenerationConfiguration全局开关控制自助生成证书功能关闭时进度页隐藏生成证书按钮CertificateGenerationCourseSetting按课程配置包括self_generation_enabled允许学生自助生成、language_specific_templates_enabled多语言模板、include_hours_of_effort展示学时投入需 Discovery 提供weeks_to_complete与max_effortCertificateHtmlViewConfigurationHTML 证书视图的静态上下文参数JSON支持default与按 mode 覆盖CertificateGenerationCommandConfiguration / ModifiedCertificateTemplateCommandConfiguration / PurgeReferencestoPDFCertificatesCommandConfiguration分别对应三条管理命令的参数存储可配合--args-from-database使用ExampleCertificateSet / ExampleCertificate示例证书用于在启用自助发证前验证模板与生成链路是否正常示例证书不关联真实用户姓名固定为John Doë。2.4 模板类模型CertificateTemplate自定义 Web 证书模板字段包括templateDjango 模板 HTML、organization_id、course_key、mode、language、is_active。唯一性约束为(organization_id, course_key, mode, language)CertificateTemplateAsset模板配套资源图片、CSS 等上传至MEDIA_ROOT/certificate_template_assets/id/通过asset_slug在模板中引用。三、证书状态机data.py所有状态常量定义在CertificateStatuses类中。当前代码实际会写入的状态有四种状态含义设置入口downloadable已授予且可下载generation.py中的生成流程notpassing未达到通过成绩GeneratedCertificate.mark_notpassing()unavailable证书已被无效化GeneratedCertificate.invalidate()unverified身份验证未通过GeneratedCertificate.mark_unverified()其余状态generating、error、requesting、deleted、audit_passing等为 PDF 证书时代的遗留值仅用于兼容历史数据。两个派生常量值得注意PASSED_STATUSES (downloadable, generating)——判断学生是否通过课程NON_REFUNDABLE_STATUSES (downloadable, generating, unavailable)——用于退款资格判断is_refundable_status。GeneratedCertificate.invalidate()/mark_notpassing()/mark_unverified()最终都汇聚到私有方法_revoke_certificate()它会清空download_uuid与download_url、更新状态随后依次发送COURSE_CERT_REVOKED信号用于联动撤销项目证书发送 Open edX 事件org.openedx.learning.certificate.revoked.v1CERTIFICATE_REVOKED若撤销前状态为downloadable额外发出edx.certificate.revoked埋点事件。四、证书生成流程从信号到 Celery 的完整链路证书生成采用信号触发 → 资格校验 → 异步任务的架构相关代码集中在 generation_handler.py 与 tasks.py。4.1 触发信号signals.py证书生成的触发源包括COURSE_GRADE_NOW_PASSED学生成绩变为通过自动发证模式下COURSE_GRADE_NOW_FAILED成绩变为不通过标记notpassing白名单学生除外LEARNER_SSO_VERIFIED/PHOTO_VERIFICATION_APPROVED/IDV_ATTEMPT_APPROVED身份验证通过后补发证书ENROLLMENT_TRACK_UPDATED选课模式变为可发证模式如升级到 verifiedpost_save(CertificateAllowlist)学生被加入白名单后自动尝试发证。4.2 资格校验generation_handler.py入口函数generate_certificate_task(user, course_key, generation_mode, delay_seconds)会先判断学生是否在白名单上分流到两条路径白名单路径generate_allowlist_certificate_task()不要求通过成绩但仍需满足公共校验常规路径_generate_regular_certificate_task()额外要求非 CCX 课程、非 Beta 测试者、成绩通过。两条路径共享公共校验_can_generate_certificate_common()其检查项依次为是否在证书无效化列表CertificateInvalidation.has_certificate_invalidation——是则拒绝是否存在选课记录enrollment_mode 为空则拒绝选课模式是否可发证modes_api.is_eligible_for_certificate若课程强制身份验证ENABLE_CERTIFICATES_IDV_REQUIREMENT且用户未验证且模式不属于NON_VERIFIED_MODEShonor、no-id-professional 等——则拒绝已有证书状态是否允许生成downloadable且当前模式未升级为可发证模式则拒绝课程是否存在CourseOverview是否已启用 HTML 证书has_html_certificates_enabled。校验通过后调用_generate_certificate_task()其中会触发 Open edX 过滤器CertificateCreationRequested类型org.openedx.learning.certificate.creation.requested.v1允许插件在生成前拦截抛出PreventCertificateCreation则中止。4.3 异步任务执行tasks.py / generation.py# tasks.py 中的任务定义节选 shared_task(baseLoggedPersistOnFailureTask, bindTrue, default_retry_delay30, max_retries2) def generate_certificate(self, **kwargs): student User.objects.get(idkwargs.pop(student)) course_key CourseKey.from_string(kwargs.pop(course_key)) status kwargs.pop(status, CertificateStatuses.downloadable) enrollment_mode kwargs.pop(enrollment_mode) course_grade kwargs.pop(course_grade, ) generation_mode kwargs.pop(generation_mode, batch) generate_course_certificate(userstudent, course_keycourse_key, statusstatus, enrollment_modeenrollment_mode, course_gradecourse_grade, generation_modegeneration_mode)任务参数说明参数必填默认值说明student是—学生用户 IDcourse_key是—课程运行 keystatus否downloadable目标证书状态enrollment_mode是—选课模式course_grade否课程成绩generation_mode否batch事件模式self用户自助/batch批量等任务默认延迟CERTIFICATE_DELAY_SECONDS 2秒执行防止调用方在 post-save 阶段仍有未提交改动失败时最多重试 2 次、间隔 30 秒。真正落库的逻辑在 generation.py 的generate_course_certificate()若已存在证书则复用其verify_uuid保证学习者证书 URL 不变否则新生成 UUID通过GeneratedCertificate.objects.update_or_create(user, course_id, ...)创建或更新记录若状态为通过类状态downloadable/generating发出edx.certificate.created埋点事件若状态为unverified调用mark_unverified()落库。同时GeneratedCertificate.save()的重写会在保存后发出COURSE_CERT_CHANGED、CERTIFICATE_CHANGED事件以及通过状态时COURSE_CERT_AWARDED、CERTIFICATE_CREATED事件供 Credentials 与事件总线消费——这正是架构图中信号 → Celery → 数据库 → Credentials/Event Bus的实现对应。五、Studio 侧的证书配置 API证书的配置而非具体某张证书存储在课程 Modulestore 的course.certificates字段中由 Studio 管理对应 cms/djangoapps/contentstore/views/certificates.py。其数据契约如下course.certificates: { certificates: [ { version: 1, // 数据契约版本 id: 12345, // 自动生成的标识符 name: Certificate 1, description: Certificate 1 Description, course_title: course title, signatories: [ { id: 24680, // 自动生成的标识符 name: Dr. Bob Smith, title: Dean of the College, organization: Awesome College } ] } ] }提供的接口能力证书列表/创建certificates_list_handlerGET/POST返回证书列表页Backbone 应用或 JSON 列表POST 时通过CertificateManager.deserialize_certificate()校验并追加新证书证书详情CertificateDetailAPIViewPOST/PUT/DELETE创建、更新、删除单条证书配置删除处于激活状态的证书需要 GlobalStaff 权限签名人管理signatory_detail_handler删除证书签名人证书激活/停用CertificateActivationAPIViewPOST{ is_active: true/false }切换证书配置的激活状态假设每个课程只有一条激活证书配置。所有接口都先通过has_studio_write_access(user, course_key)做权限校验因此仅具备 Studio 写权限的用户可管理证书配置。六、HTML 证书的展示views/webview.py现代 Open edX 使用Web 证书HTML 证书替代 PDF 证书。渲染入口为render_html_view()其判断链为全局开关settings.CERTIFICATES_HTML_VIEW关闭 → 返回 invalid 页课程cert_html_view_enabled为假 → 返回 invalid 页学生无downloadable状态证书 → 返回 invalid 页课程无激活证书配置get_active_web_certificate→ 返回 invalid 页。渲染时支持两种模板路径标准模板certificates/valid.html上下文由CertificateHtmlViewConfiguration.get_config()提供默认值并按user_certificate.mode覆盖自定义模板启用CUSTOM_CERTIFICATE_TEMPLATES_ENABLED后按组织课程模式语言四级匹配CertificateTemplateget_certificate_template()并使用模板自带语言渲染。此外渲染前会触发过滤器CertificateRenderStartedorg.openedx.learning.certificate.render.started.v1插件可借此替换为自定义响应视图还支持?previewverified等参数实现 CMS 侧的证书预览。证书的显示日期由display_date_for_certificate()api.py决定优先使用CertificateDateOverride覆盖日期否则按课程的certificates_display_behaviorEND_WITH_DATE/END/EARLY_NO_INFO选择证书可用日期 / 课程结束日期 / 证书修改日期。七、证书的撤销与无效化证书撤销的核心入口单张无效化GeneratedCertificate.invalidate(mode, source)将状态置为unavailableAPI 级无效化api.invalidate_certificate(user_id, course_key, source)白名单学生豁免事件驱动撤销EXAM_ATTEMPT_REJECTED事件考试作弊被拒会触发invalidate_certificate(sourceexam_event)见 signals.py白名单移除联动remove_allowlist_entry()在把学生移出白名单前会先无效化其证书sourceallowlist_removal。Open edX 课程证书撤销流程架构图八、管理命令批量发证与模板维护lms/djangoapps/certificates/management/commands/下提供多条运维命令8.1 cert_generation为指定用户批量生成证书./manage.py lms cert_generation -u 123 456 -c course-v1:edXDemoXDemo_Course参数说明参数说明-u, --user用户 ID可传多个空格分隔-c, --course-key课程运行 key--args-from-database从CertificateGenerationCommandConfiguration配置读取参数如-u user_id -c course_run_key命令内部对每个用户调用generate_certificate_task()不存在的用户或不允许生成的情况仅记录日志。8.2 其余命令modify_cert_template批量修改CertificateTemplate中的文本--old-text/--new-text/--template_ids/--dry-run支持ModifiedCertificateTemplateCommandConfiguration存储参数purge_references_to_pdf_certificates清理 PDF 证书遗留引用--certificate_idspurge_pii_from_generatedcertificates清理已生成证书中的个人隐私信息PII。九、测试与设计决策参考单元测试位于 lms/djangoapps/certificates/tests/覆盖生成test_generation.py、处理器test_generation_handler.py、信号test_signals.py、任务test_tasks.py、模型test_models.py、Web 视图test_webview_views.py等管理命令测试位于 management/commands/tests/设计决策ADR位于 docs/decisions/推荐重点阅读003-web-certs.rstWeb 证书、004-cert-status.rst状态机、006-cert-date-override.rst日期覆盖、008-certificate-model-remnants.rstPDF 遗留字段去留流程图源码PlantUML DSL位于 docs/diagrams/可在仓库内直接查看生成与撤销两条流程的完整组件交互。十、排查指引小结症状排查入口学生未自动获证检查CertificateGenerationConfiguration全局开关、课程self_generation_enabled、CourseOverview、cert_html_view_enabled、ENABLE_CERTIFICATES_IDV_REQUIREMENT及信号日志证书显示 invalid依次核对CERTIFICATES_HTML_VIEW、cert_html_view_enabled、证书状态是否downloadable、get_active_web_certificate是否有激活配置需要给未通过学生发证使用CertificateAllowlist白名单APIcreate_or_update_certificate_allowlist_entry加入后自动触发发证需批量补发证书./manage.py lms cert_generation -u ... -c course_key某学生证书需作废invalidate_certificate()/CertificateInvalidation记录 GeneratedCertificate.invalidate()证书日期需修正Django Admin 中维护CertificateDateOverride保存后自动广播COURSE_CERT_CHANGED综上Open edX 的证书体系以GeneratedCertificate为核心、以信号和 Celery 为纽带、以 Credentials 为下游权威记录将配置Studio→ 生成LMS→ 展示Web 证书→ 撤销串联为完整闭环。理解这条链路即可从容应对证书相关的绝大多数开发与运维场景。【免费下载链接】openedx-platformThe Open edX LMS Studio, powering education sites around the world!项目地址: https://gitcode.com/GitHub_Trending/ed/openedx-platform创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考