openedx-learning 0.23.1__tar.gz → 0.26.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {openedx_learning-0.23.1/openedx_learning.egg-info → openedx_learning-0.26.0}/PKG-INFO +4 -4
- {openedx_learning-0.23.1 → openedx_learning-0.26.0}/openedx_learning/__init__.py +1 -1
- {openedx_learning-0.23.1 → openedx_learning-0.26.0}/openedx_learning/api/authoring.py +2 -0
- {openedx_learning-0.23.1 → openedx_learning-0.26.0}/openedx_learning/api/authoring_models.py +2 -0
- {openedx_learning-0.23.1 → openedx_learning-0.26.0}/openedx_learning/apps/authoring/publishing/api.py +14 -12
- {openedx_learning-0.23.1 → openedx_learning-0.26.0}/openedx_learning/apps/authoring/publishing/migrations/0008_alter_draftchangelogrecord_options_and_more.py +1 -2
- openedx_learning-0.26.0/openedx_learning/apps/authoring/sections/api.py +310 -0
- openedx_learning-0.26.0/openedx_learning/apps/authoring/sections/apps.py +25 -0
- openedx_learning-0.26.0/openedx_learning/apps/authoring/sections/migrations/0001_initial.py +36 -0
- openedx_learning-0.26.0/openedx_learning/apps/authoring/sections/models.py +50 -0
- openedx_learning-0.26.0/openedx_learning/apps/authoring/subsections/api.py +309 -0
- openedx_learning-0.26.0/openedx_learning/apps/authoring/subsections/apps.py +25 -0
- openedx_learning-0.26.0/openedx_learning/apps/authoring/subsections/migrations/0001_initial.py +36 -0
- openedx_learning-0.26.0/openedx_learning/apps/authoring/subsections/models.py +50 -0
- {openedx_learning-0.23.1 → openedx_learning-0.26.0/openedx_learning.egg-info}/PKG-INFO +4 -4
- {openedx_learning-0.23.1 → openedx_learning-0.26.0}/openedx_learning.egg-info/SOURCES.txt +12 -0
- openedx_learning-0.26.0/openedx_tagging/core/tagging/migrations/__init__.py +0 -0
- openedx_learning-0.26.0/openedx_tagging/core/tagging/rest_api/__init__.py +0 -0
- openedx_learning-0.26.0/openedx_tagging/core/tagging/rest_api/v1/__init__.py +0 -0
- {openedx_learning-0.23.1 → openedx_learning-0.26.0}/openedx_tagging/core/tagging/rules.py +2 -2
- openedx_learning-0.26.0/openedx_tagging/py.typed +0 -0
- {openedx_learning-0.23.1 → openedx_learning-0.26.0}/CHANGELOG.rst +0 -0
- {openedx_learning-0.23.1 → openedx_learning-0.26.0}/LICENSE.txt +0 -0
- {openedx_learning-0.23.1 → openedx_learning-0.26.0}/MANIFEST.in +0 -0
- {openedx_learning-0.23.1 → openedx_learning-0.26.0}/README.rst +0 -0
- {openedx_learning-0.23.1 → openedx_learning-0.26.0}/openedx_learning/api/__init__.py +0 -0
- {openedx_learning-0.23.1 → openedx_learning-0.26.0}/openedx_learning/apps/__init__.py +0 -0
- {openedx_learning-0.23.1 → openedx_learning-0.26.0}/openedx_learning/apps/authoring/__init__.py +0 -0
- {openedx_learning-0.23.1 → openedx_learning-0.26.0}/openedx_learning/apps/authoring/collections/__init__.py +0 -0
- {openedx_learning-0.23.1 → openedx_learning-0.26.0}/openedx_learning/apps/authoring/collections/admin.py +0 -0
- {openedx_learning-0.23.1 → openedx_learning-0.26.0}/openedx_learning/apps/authoring/collections/api.py +0 -0
- {openedx_learning-0.23.1 → openedx_learning-0.26.0}/openedx_learning/apps/authoring/collections/apps.py +0 -0
- {openedx_learning-0.23.1 → openedx_learning-0.26.0}/openedx_learning/apps/authoring/collections/migrations/0001_initial.py +0 -0
- {openedx_learning-0.23.1 → openedx_learning-0.26.0}/openedx_learning/apps/authoring/collections/migrations/0002_remove_collection_name_collection_created_by_and_more.py +0 -0
- {openedx_learning-0.23.1 → openedx_learning-0.26.0}/openedx_learning/apps/authoring/collections/migrations/0003_collection_entities.py +0 -0
- {openedx_learning-0.23.1 → openedx_learning-0.26.0}/openedx_learning/apps/authoring/collections/migrations/0004_collection_key.py +0 -0
- {openedx_learning-0.23.1 → openedx_learning-0.26.0}/openedx_learning/apps/authoring/collections/migrations/0005_alter_collection_options_alter_collection_enabled.py +0 -0
- {openedx_learning-0.23.1 → openedx_learning-0.26.0}/openedx_learning/apps/authoring/collections/migrations/__init__.py +0 -0
- {openedx_learning-0.23.1 → openedx_learning-0.26.0}/openedx_learning/apps/authoring/collections/models.py +0 -0
- {openedx_learning-0.23.1 → openedx_learning-0.26.0}/openedx_learning/apps/authoring/components/__init__.py +0 -0
- {openedx_learning-0.23.1 → openedx_learning-0.26.0}/openedx_learning/apps/authoring/components/admin.py +0 -0
- {openedx_learning-0.23.1 → openedx_learning-0.26.0}/openedx_learning/apps/authoring/components/api.py +0 -0
- {openedx_learning-0.23.1 → openedx_learning-0.26.0}/openedx_learning/apps/authoring/components/apps.py +0 -0
- {openedx_learning-0.23.1 → openedx_learning-0.26.0}/openedx_learning/apps/authoring/components/management/__init__.py +0 -0
- {openedx_learning-0.23.1 → openedx_learning-0.26.0}/openedx_learning/apps/authoring/components/management/commands/__init__.py +0 -0
- {openedx_learning-0.23.1 → openedx_learning-0.26.0}/openedx_learning/apps/authoring/components/management/commands/add_assets_to_component.py +0 -0
- {openedx_learning-0.23.1 → openedx_learning-0.26.0}/openedx_learning/apps/authoring/components/migrations/0001_initial.py +0 -0
- {openedx_learning-0.23.1 → openedx_learning-0.26.0}/openedx_learning/apps/authoring/components/migrations/0002_alter_componentversioncontent_key.py +0 -0
- {openedx_learning-0.23.1 → openedx_learning-0.26.0}/openedx_learning/apps/authoring/components/migrations/0003_remove_componentversioncontent_learner_downloadable.py +0 -0
- {openedx_learning-0.23.1 → openedx_learning-0.26.0}/openedx_learning/apps/authoring/components/migrations/__init__.py +0 -0
- {openedx_learning-0.23.1 → openedx_learning-0.26.0}/openedx_learning/apps/authoring/components/models.py +0 -0
- {openedx_learning-0.23.1 → openedx_learning-0.26.0}/openedx_learning/apps/authoring/contents/__init__.py +0 -0
- {openedx_learning-0.23.1 → openedx_learning-0.26.0}/openedx_learning/apps/authoring/contents/admin.py +0 -0
- {openedx_learning-0.23.1 → openedx_learning-0.26.0}/openedx_learning/apps/authoring/contents/api.py +0 -0
- {openedx_learning-0.23.1 → openedx_learning-0.26.0}/openedx_learning/apps/authoring/contents/apps.py +0 -0
- {openedx_learning-0.23.1 → openedx_learning-0.26.0}/openedx_learning/apps/authoring/contents/migrations/0001_initial.py +0 -0
- {openedx_learning-0.23.1 → openedx_learning-0.26.0}/openedx_learning/apps/authoring/contents/migrations/__init__.py +0 -0
- {openedx_learning-0.23.1 → openedx_learning-0.26.0}/openedx_learning/apps/authoring/contents/models.py +0 -0
- {openedx_learning-0.23.1 → openedx_learning-0.26.0}/openedx_learning/apps/authoring/publishing/__init__.py +0 -0
- {openedx_learning-0.23.1 → openedx_learning-0.26.0}/openedx_learning/apps/authoring/publishing/admin.py +0 -0
- {openedx_learning-0.23.1 → openedx_learning-0.26.0}/openedx_learning/apps/authoring/publishing/apps.py +0 -0
- {openedx_learning-0.23.1 → openedx_learning-0.26.0}/openedx_learning/apps/authoring/publishing/contextmanagers.py +0 -0
- {openedx_learning-0.23.1 → openedx_learning-0.26.0}/openedx_learning/apps/authoring/publishing/migrations/0001_initial.py +0 -0
- {openedx_learning-0.23.1 → openedx_learning-0.26.0}/openedx_learning/apps/authoring/publishing/migrations/0002_alter_learningpackage_key_and_more.py +0 -0
- {openedx_learning-0.23.1 → openedx_learning-0.26.0}/openedx_learning/apps/authoring/publishing/migrations/0003_containers.py +0 -0
- {openedx_learning-0.23.1 → openedx_learning-0.26.0}/openedx_learning/apps/authoring/publishing/migrations/0004_publishableentity_can_stand_alone.py +0 -0
- {openedx_learning-0.23.1 → openedx_learning-0.26.0}/openedx_learning/apps/authoring/publishing/migrations/0005_alter_entitylistrow_options.py +0 -0
- {openedx_learning-0.23.1 → openedx_learning-0.26.0}/openedx_learning/apps/authoring/publishing/migrations/0006_draftchangelog.py +0 -0
- {openedx_learning-0.23.1 → openedx_learning-0.26.0}/openedx_learning/apps/authoring/publishing/migrations/0007_bootstrap_draftchangelog.py +0 -0
- {openedx_learning-0.23.1 → openedx_learning-0.26.0}/openedx_learning/apps/authoring/publishing/migrations/__init__.py +0 -0
- {openedx_learning-0.23.1 → openedx_learning-0.26.0}/openedx_learning/apps/authoring/publishing/models/__init__.py +0 -0
- {openedx_learning-0.23.1 → openedx_learning-0.26.0}/openedx_learning/apps/authoring/publishing/models/container.py +0 -0
- {openedx_learning-0.23.1 → openedx_learning-0.26.0}/openedx_learning/apps/authoring/publishing/models/draft_log.py +0 -0
- {openedx_learning-0.23.1 → openedx_learning-0.26.0}/openedx_learning/apps/authoring/publishing/models/entity_list.py +0 -0
- {openedx_learning-0.23.1 → openedx_learning-0.26.0}/openedx_learning/apps/authoring/publishing/models/learning_package.py +0 -0
- {openedx_learning-0.23.1 → openedx_learning-0.26.0}/openedx_learning/apps/authoring/publishing/models/publish_log.py +0 -0
- {openedx_learning-0.23.1 → openedx_learning-0.26.0}/openedx_learning/apps/authoring/publishing/models/publishable_entity.py +0 -0
- {openedx_learning-0.23.1/openedx_learning/apps/authoring/units → openedx_learning-0.26.0/openedx_learning/apps/authoring/sections}/__init__.py +0 -0
- {openedx_learning-0.23.1/openedx_learning/apps/authoring/units → openedx_learning-0.26.0/openedx_learning/apps/authoring/sections}/migrations/__init__.py +0 -0
- {openedx_learning-0.23.1/openedx_learning/contrib → openedx_learning-0.26.0/openedx_learning/apps/authoring/subsections}/__init__.py +0 -0
- {openedx_learning-0.23.1/openedx_learning/lib → openedx_learning-0.26.0/openedx_learning/apps/authoring/subsections/migrations}/__init__.py +0 -0
- {openedx_learning-0.23.1/openedx_tagging/core → openedx_learning-0.26.0/openedx_learning/apps/authoring/units}/__init__.py +0 -0
- {openedx_learning-0.23.1 → openedx_learning-0.26.0}/openedx_learning/apps/authoring/units/api.py +0 -0
- {openedx_learning-0.23.1 → openedx_learning-0.26.0}/openedx_learning/apps/authoring/units/apps.py +0 -0
- {openedx_learning-0.23.1 → openedx_learning-0.26.0}/openedx_learning/apps/authoring/units/migrations/0001_initial.py +0 -0
- {openedx_learning-0.23.1/openedx_tagging/core/tagging → openedx_learning-0.26.0/openedx_learning/apps/authoring/units/migrations}/__init__.py +0 -0
- {openedx_learning-0.23.1 → openedx_learning-0.26.0}/openedx_learning/apps/authoring/units/models.py +0 -0
- {openedx_learning-0.23.1/openedx_tagging/core/tagging/migrations → openedx_learning-0.26.0/openedx_learning/contrib}/__init__.py +0 -0
- {openedx_learning-0.23.1 → openedx_learning-0.26.0}/openedx_learning/contrib/media_server/__init__.py +0 -0
- {openedx_learning-0.23.1 → openedx_learning-0.26.0}/openedx_learning/contrib/media_server/apps.py +0 -0
- {openedx_learning-0.23.1 → openedx_learning-0.26.0}/openedx_learning/contrib/media_server/urls.py +0 -0
- {openedx_learning-0.23.1 → openedx_learning-0.26.0}/openedx_learning/contrib/media_server/views.py +0 -0
- {openedx_learning-0.23.1/openedx_tagging/core/tagging/rest_api → openedx_learning-0.26.0/openedx_learning/lib}/__init__.py +0 -0
- {openedx_learning-0.23.1 → openedx_learning-0.26.0}/openedx_learning/lib/admin_utils.py +0 -0
- {openedx_learning-0.23.1 → openedx_learning-0.26.0}/openedx_learning/lib/cache.py +0 -0
- {openedx_learning-0.23.1 → openedx_learning-0.26.0}/openedx_learning/lib/collations.py +0 -0
- {openedx_learning-0.23.1 → openedx_learning-0.26.0}/openedx_learning/lib/fields.py +0 -0
- {openedx_learning-0.23.1 → openedx_learning-0.26.0}/openedx_learning/lib/managers.py +0 -0
- {openedx_learning-0.23.1 → openedx_learning-0.26.0}/openedx_learning/lib/test_utils.py +0 -0
- {openedx_learning-0.23.1 → openedx_learning-0.26.0}/openedx_learning/lib/validators.py +0 -0
- {openedx_learning-0.23.1 → openedx_learning-0.26.0}/openedx_learning/py.typed +0 -0
- {openedx_learning-0.23.1 → openedx_learning-0.26.0}/openedx_learning.egg-info/dependency_links.txt +0 -0
- {openedx_learning-0.23.1 → openedx_learning-0.26.0}/openedx_learning.egg-info/not-zip-safe +0 -0
- {openedx_learning-0.23.1 → openedx_learning-0.26.0}/openedx_learning.egg-info/requires.txt +3 -3
- {openedx_learning-0.23.1 → openedx_learning-0.26.0}/openedx_learning.egg-info/top_level.txt +0 -0
- {openedx_learning-0.23.1 → openedx_learning-0.26.0}/openedx_tagging/__init__.py +0 -0
- {openedx_learning-0.23.1/openedx_tagging/core/tagging/rest_api/v1 → openedx_learning-0.26.0/openedx_tagging/core}/__init__.py +0 -0
- /openedx_learning-0.23.1/openedx_tagging/py.typed → /openedx_learning-0.26.0/openedx_tagging/core/tagging/__init__.py +0 -0
- {openedx_learning-0.23.1 → openedx_learning-0.26.0}/openedx_tagging/core/tagging/admin.py +0 -0
- {openedx_learning-0.23.1 → openedx_learning-0.26.0}/openedx_tagging/core/tagging/api.py +0 -0
- {openedx_learning-0.23.1 → openedx_learning-0.26.0}/openedx_tagging/core/tagging/apps.py +0 -0
- {openedx_learning-0.23.1 → openedx_learning-0.26.0}/openedx_tagging/core/tagging/data.py +0 -0
- {openedx_learning-0.23.1 → openedx_learning-0.26.0}/openedx_tagging/core/tagging/import_export/__init__.py +0 -0
- {openedx_learning-0.23.1 → openedx_learning-0.26.0}/openedx_tagging/core/tagging/import_export/actions.py +0 -0
- {openedx_learning-0.23.1 → openedx_learning-0.26.0}/openedx_tagging/core/tagging/import_export/api.py +0 -0
- {openedx_learning-0.23.1 → openedx_learning-0.26.0}/openedx_tagging/core/tagging/import_export/exceptions.py +0 -0
- {openedx_learning-0.23.1 → openedx_learning-0.26.0}/openedx_tagging/core/tagging/import_export/import_plan.py +0 -0
- {openedx_learning-0.23.1 → openedx_learning-0.26.0}/openedx_tagging/core/tagging/import_export/parsers.py +0 -0
- {openedx_learning-0.23.1 → openedx_learning-0.26.0}/openedx_tagging/core/tagging/import_export/tasks.py +0 -0
- {openedx_learning-0.23.1 → openedx_learning-0.26.0}/openedx_tagging/core/tagging/import_export/template.csv +0 -0
- {openedx_learning-0.23.1 → openedx_learning-0.26.0}/openedx_tagging/core/tagging/import_export/template.json +0 -0
- {openedx_learning-0.23.1 → openedx_learning-0.26.0}/openedx_tagging/core/tagging/migrations/0001_initial.py +0 -0
- {openedx_learning-0.23.1 → openedx_learning-0.26.0}/openedx_tagging/core/tagging/migrations/0001_squashed.py +0 -0
- {openedx_learning-0.23.1 → openedx_learning-0.26.0}/openedx_tagging/core/tagging/migrations/0002_auto_20230718_2026.py +0 -0
- {openedx_learning-0.23.1 → openedx_learning-0.26.0}/openedx_tagging/core/tagging/migrations/0003_auto_20230721_1238.py +0 -0
- {openedx_learning-0.23.1 → openedx_learning-0.26.0}/openedx_tagging/core/tagging/migrations/0004_auto_20230723_2001.py +0 -0
- {openedx_learning-0.23.1 → openedx_learning-0.26.0}/openedx_tagging/core/tagging/migrations/0005_language_taxonomy.py +0 -0
- {openedx_learning-0.23.1 → openedx_learning-0.26.0}/openedx_tagging/core/tagging/migrations/0006_alter_objecttag_unique_together.py +0 -0
- {openedx_learning-0.23.1 → openedx_learning-0.26.0}/openedx_tagging/core/tagging/migrations/0006_auto_20230802_1631.py +0 -0
- {openedx_learning-0.23.1 → openedx_learning-0.26.0}/openedx_tagging/core/tagging/migrations/0007_tag_import_task_log_null_fix.py +0 -0
- {openedx_learning-0.23.1 → openedx_learning-0.26.0}/openedx_tagging/core/tagging/migrations/0008_taxonomy_description_not_null.py +0 -0
- {openedx_learning-0.23.1 → openedx_learning-0.26.0}/openedx_tagging/core/tagging/migrations/0009_alter_objecttag_object_id.py +0 -0
- {openedx_learning-0.23.1 → openedx_learning-0.26.0}/openedx_tagging/core/tagging/migrations/0010_cleanups.py +0 -0
- {openedx_learning-0.23.1 → openedx_learning-0.26.0}/openedx_tagging/core/tagging/migrations/0011_remove_required.py +0 -0
- {openedx_learning-0.23.1 → openedx_learning-0.26.0}/openedx_tagging/core/tagging/migrations/0012_language_taxonomy.py +0 -0
- {openedx_learning-0.23.1 → openedx_learning-0.26.0}/openedx_tagging/core/tagging/migrations/0013_tag_parent_blank.py +0 -0
- {openedx_learning-0.23.1 → openedx_learning-0.26.0}/openedx_tagging/core/tagging/migrations/0014_minor_fixes.py +0 -0
- {openedx_learning-0.23.1 → openedx_learning-0.26.0}/openedx_tagging/core/tagging/migrations/0015_taxonomy_export_id.py +0 -0
- {openedx_learning-0.23.1 → openedx_learning-0.26.0}/openedx_tagging/core/tagging/migrations/0016_object_tag_export_id.py +0 -0
- {openedx_learning-0.23.1 → openedx_learning-0.26.0}/openedx_tagging/core/tagging/migrations/0017_alter_tagimporttask_status.py +0 -0
- {openedx_learning-0.23.1 → openedx_learning-0.26.0}/openedx_tagging/core/tagging/migrations/0018_objecttag_is_copied.py +0 -0
- {openedx_learning-0.23.1 → openedx_learning-0.26.0}/openedx_tagging/core/tagging/models/__init__.py +0 -0
- {openedx_learning-0.23.1 → openedx_learning-0.26.0}/openedx_tagging/core/tagging/models/base.py +0 -0
- {openedx_learning-0.23.1 → openedx_learning-0.26.0}/openedx_tagging/core/tagging/models/import_export.py +0 -0
- {openedx_learning-0.23.1 → openedx_learning-0.26.0}/openedx_tagging/core/tagging/models/system_defined.py +0 -0
- {openedx_learning-0.23.1 → openedx_learning-0.26.0}/openedx_tagging/core/tagging/models/utils.py +0 -0
- {openedx_learning-0.23.1 → openedx_learning-0.26.0}/openedx_tagging/core/tagging/rest_api/paginators.py +0 -0
- {openedx_learning-0.23.1 → openedx_learning-0.26.0}/openedx_tagging/core/tagging/rest_api/urls.py +0 -0
- {openedx_learning-0.23.1 → openedx_learning-0.26.0}/openedx_tagging/core/tagging/rest_api/utils.py +0 -0
- {openedx_learning-0.23.1 → openedx_learning-0.26.0}/openedx_tagging/core/tagging/rest_api/v1/permissions.py +0 -0
- {openedx_learning-0.23.1 → openedx_learning-0.26.0}/openedx_tagging/core/tagging/rest_api/v1/serializers.py +0 -0
- {openedx_learning-0.23.1 → openedx_learning-0.26.0}/openedx_tagging/core/tagging/rest_api/v1/urls.py +0 -0
- {openedx_learning-0.23.1 → openedx_learning-0.26.0}/openedx_tagging/core/tagging/rest_api/v1/views.py +0 -0
- {openedx_learning-0.23.1 → openedx_learning-0.26.0}/openedx_tagging/core/tagging/rest_api/v1/views_import.py +0 -0
- {openedx_learning-0.23.1 → openedx_learning-0.26.0}/openedx_tagging/core/tagging/urls.py +0 -0
- {openedx_learning-0.23.1 → openedx_learning-0.26.0}/requirements/base.in +0 -0
- {openedx_learning-0.23.1 → openedx_learning-0.26.0}/setup.cfg +0 -0
- {openedx_learning-0.23.1 → openedx_learning-0.26.0}/setup.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: openedx-learning
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.26.0
|
|
4
4
|
Summary: Open edX Learning Core and Tagging.
|
|
5
5
|
Home-page: https://github.com/openedx/openedx-learning
|
|
6
6
|
Author: David Ormsbee
|
|
@@ -19,12 +19,12 @@ Classifier: Programming Language :: Python :: 3.11
|
|
|
19
19
|
Classifier: Programming Language :: Python :: 3.12
|
|
20
20
|
Requires-Python: >=3.11
|
|
21
21
|
License-File: LICENSE.txt
|
|
22
|
+
Requires-Dist: djangorestframework<4.0
|
|
23
|
+
Requires-Dist: celery
|
|
24
|
+
Requires-Dist: edx-drf-extensions
|
|
22
25
|
Requires-Dist: attrs
|
|
23
26
|
Requires-Dist: Django
|
|
24
|
-
Requires-Dist: edx-drf-extensions
|
|
25
|
-
Requires-Dist: celery
|
|
26
27
|
Requires-Dist: rules<4.0
|
|
27
|
-
Requires-Dist: djangorestframework<4.0
|
|
28
28
|
Dynamic: author
|
|
29
29
|
Dynamic: author-email
|
|
30
30
|
Dynamic: classifier
|
|
@@ -13,6 +13,8 @@ from ..apps.authoring.collections.api import *
|
|
|
13
13
|
from ..apps.authoring.components.api import *
|
|
14
14
|
from ..apps.authoring.contents.api import *
|
|
15
15
|
from ..apps.authoring.publishing.api import *
|
|
16
|
+
from ..apps.authoring.sections.api import *
|
|
17
|
+
from ..apps.authoring.subsections.api import *
|
|
16
18
|
from ..apps.authoring.units.api import *
|
|
17
19
|
|
|
18
20
|
# This was renamed after the authoring API refactoring pushed this and other
|
{openedx_learning-0.23.1 → openedx_learning-0.26.0}/openedx_learning/api/authoring_models.py
RENAMED
|
@@ -11,4 +11,6 @@ from ..apps.authoring.collections.models import *
|
|
|
11
11
|
from ..apps.authoring.components.models import *
|
|
12
12
|
from ..apps.authoring.contents.models import *
|
|
13
13
|
from ..apps.authoring.publishing.models import *
|
|
14
|
+
from ..apps.authoring.sections.models import *
|
|
15
|
+
from ..apps.authoring.subsections.models import *
|
|
14
16
|
from ..apps.authoring.units.models import *
|
|
@@ -1203,6 +1203,7 @@ def get_container_by_key(learning_package_id: int, /, key: str) -> Container:
|
|
|
1203
1203
|
def get_containers(
|
|
1204
1204
|
learning_package_id: int,
|
|
1205
1205
|
container_cls: type[ContainerModel] = Container, # type: ignore[assignment]
|
|
1206
|
+
include_deleted: bool | None = False,
|
|
1206
1207
|
) -> QuerySet[ContainerModel]:
|
|
1207
1208
|
"""
|
|
1208
1209
|
[ 🛑 UNSTABLE ]
|
|
@@ -1211,12 +1212,17 @@ def get_containers(
|
|
|
1211
1212
|
Args:
|
|
1212
1213
|
learning_package_id: The primary key of the learning package
|
|
1213
1214
|
container_cls: The subclass of Container to use, if applicable
|
|
1215
|
+
include_deleted: If True, include deleted containers (with no draft version) in the result.
|
|
1214
1216
|
|
|
1215
1217
|
Returns:
|
|
1216
1218
|
A queryset containing the container associated with the given learning package.
|
|
1217
1219
|
"""
|
|
1218
1220
|
assert issubclass(container_cls, Container)
|
|
1219
|
-
|
|
1221
|
+
container_qset = container_cls.objects.filter(publishable_entity__learning_package=learning_package_id)
|
|
1222
|
+
if not include_deleted:
|
|
1223
|
+
container_qset = container_qset.filter(publishable_entity__draft__version__isnull=False)
|
|
1224
|
+
|
|
1225
|
+
return container_qset.order_by('pk')
|
|
1220
1226
|
|
|
1221
1227
|
|
|
1222
1228
|
def get_collection_containers(
|
|
@@ -1322,7 +1328,10 @@ def contains_unpublished_changes(container_id: int) -> bool:
|
|
|
1322
1328
|
return True
|
|
1323
1329
|
|
|
1324
1330
|
# We only care about children that are un-pinned, since published changes to pinned children don't matter
|
|
1325
|
-
entity_list = container.versioning.draft
|
|
1331
|
+
entity_list = getattr(container.versioning.draft, "entity_list", None)
|
|
1332
|
+
if entity_list is None:
|
|
1333
|
+
# This container has been soft-deleted, so it has no children.
|
|
1334
|
+
return False
|
|
1326
1335
|
|
|
1327
1336
|
# This is a naive and inefficient implementation but should be correct.
|
|
1328
1337
|
# TODO: Once we have expanded the containers system to support multiple levels (not just Units and Components but
|
|
@@ -1367,23 +1376,16 @@ def get_containers_with_entity(
|
|
|
1367
1376
|
ignore_pinned: if true, ignore any pinned references to the entity.
|
|
1368
1377
|
"""
|
|
1369
1378
|
if ignore_pinned:
|
|
1370
|
-
# TODO: Do we need to run distinct() on this? Will fix in https://github.com/openedx/openedx-learning/issues/303
|
|
1371
1379
|
qs = Container.objects.filter(
|
|
1372
1380
|
# Note: these two conditions must be in the same filter() call, or the query won't be correct.
|
|
1373
1381
|
publishable_entity__draft__version__containerversion__entity_list__entitylistrow__entity_id=publishable_entity_pk, # pylint: disable=line-too-long # noqa: E501
|
|
1374
1382
|
publishable_entity__draft__version__containerversion__entity_list__entitylistrow__entity_version_id=None, # pylint: disable=line-too-long # noqa: E501
|
|
1375
|
-
)
|
|
1383
|
+
)
|
|
1376
1384
|
else:
|
|
1377
1385
|
qs = Container.objects.filter(
|
|
1378
1386
|
publishable_entity__draft__version__containerversion__entity_list__entitylistrow__entity_id=publishable_entity_pk, # pylint: disable=line-too-long # noqa: E501
|
|
1379
|
-
)
|
|
1380
|
-
|
|
1381
|
-
# # Find all the EntityLists that contain the given entity:
|
|
1382
|
-
# lists = EntityList.objects.filter(entitylistrow__entity_id=publishable_entity_pk).values_list('pk', flat=True)
|
|
1383
|
-
# qs = Container.objects.filter(
|
|
1384
|
-
# publishable_entity__draft__version__containerversion__entity_list__in=lists
|
|
1385
|
-
# )
|
|
1386
|
-
return qs
|
|
1387
|
+
)
|
|
1388
|
+
return qs.order_by("pk").distinct() # Ordering is mostly for consistent test cases.
|
|
1387
1389
|
|
|
1388
1390
|
|
|
1389
1391
|
def get_container_children_count(
|
|
@@ -0,0 +1,310 @@
|
|
|
1
|
+
"""Sections API.
|
|
2
|
+
|
|
3
|
+
This module provides functions to manage sections.
|
|
4
|
+
"""
|
|
5
|
+
from dataclasses import dataclass
|
|
6
|
+
from datetime import datetime
|
|
7
|
+
|
|
8
|
+
from django.db.transaction import atomic
|
|
9
|
+
|
|
10
|
+
from openedx_learning.apps.authoring.subsections.models import Subsection, SubsectionVersion
|
|
11
|
+
|
|
12
|
+
from ..publishing import api as publishing_api
|
|
13
|
+
from .models import Section, SectionVersion
|
|
14
|
+
|
|
15
|
+
# 🛑 UNSTABLE: All APIs related to containers are unstable until we've figured
|
|
16
|
+
# out our approach to dynamic content (randomized, A/B tests, etc.)
|
|
17
|
+
__all__ = [
|
|
18
|
+
"create_section",
|
|
19
|
+
"create_section_version",
|
|
20
|
+
"create_next_section_version",
|
|
21
|
+
"create_section_and_version",
|
|
22
|
+
"get_section",
|
|
23
|
+
"get_section_version",
|
|
24
|
+
"get_latest_section_version",
|
|
25
|
+
"SectionListEntry",
|
|
26
|
+
"get_subsections_in_section",
|
|
27
|
+
"get_subsections_in_section",
|
|
28
|
+
"get_subsections_in_published_section_as_of",
|
|
29
|
+
]
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def create_section(
|
|
33
|
+
learning_package_id: int,
|
|
34
|
+
key: str,
|
|
35
|
+
created: datetime,
|
|
36
|
+
created_by: int | None,
|
|
37
|
+
*,
|
|
38
|
+
can_stand_alone: bool = True,
|
|
39
|
+
) -> Section:
|
|
40
|
+
"""
|
|
41
|
+
[ 🛑 UNSTABLE ] Create a new section.
|
|
42
|
+
|
|
43
|
+
Args:
|
|
44
|
+
learning_package_id: The learning package ID.
|
|
45
|
+
key: The key.
|
|
46
|
+
created: The creation date.
|
|
47
|
+
created_by: The user who created the section.
|
|
48
|
+
can_stand_alone: Set to False when created as part of containers
|
|
49
|
+
"""
|
|
50
|
+
return publishing_api.create_container(
|
|
51
|
+
learning_package_id,
|
|
52
|
+
key,
|
|
53
|
+
created,
|
|
54
|
+
created_by,
|
|
55
|
+
can_stand_alone=can_stand_alone,
|
|
56
|
+
container_cls=Section,
|
|
57
|
+
)
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
def create_section_version(
|
|
61
|
+
section: Section,
|
|
62
|
+
version_num: int,
|
|
63
|
+
*,
|
|
64
|
+
title: str,
|
|
65
|
+
entity_rows: list[publishing_api.ContainerEntityRow],
|
|
66
|
+
created: datetime,
|
|
67
|
+
created_by: int | None = None,
|
|
68
|
+
) -> SectionVersion:
|
|
69
|
+
"""
|
|
70
|
+
[ 🛑 UNSTABLE ] Create a new section version.
|
|
71
|
+
|
|
72
|
+
This is a very low-level API, likely only needed for import/export. In
|
|
73
|
+
general, you will use `create_section_and_version()` and
|
|
74
|
+
`create_next_section_version()` instead.
|
|
75
|
+
|
|
76
|
+
Args:
|
|
77
|
+
section_pk: The section ID.
|
|
78
|
+
version_num: The version number.
|
|
79
|
+
title: The title.
|
|
80
|
+
entity_rows: child entities/versions
|
|
81
|
+
created: The creation date.
|
|
82
|
+
created_by: The user who created the section.
|
|
83
|
+
"""
|
|
84
|
+
return publishing_api.create_container_version(
|
|
85
|
+
section.pk,
|
|
86
|
+
version_num,
|
|
87
|
+
title=title,
|
|
88
|
+
entity_rows=entity_rows,
|
|
89
|
+
created=created,
|
|
90
|
+
created_by=created_by,
|
|
91
|
+
container_version_cls=SectionVersion,
|
|
92
|
+
)
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
def _pub_entities_for_subsections(
|
|
96
|
+
subsections: list[Subsection | SubsectionVersion] | None,
|
|
97
|
+
) -> list[publishing_api.ContainerEntityRow] | None:
|
|
98
|
+
"""
|
|
99
|
+
Helper method: given a list of Subsection | SubsectionVersion, return the
|
|
100
|
+
lists of publishable_entities_pks and entity_version_pks needed for the
|
|
101
|
+
base container APIs.
|
|
102
|
+
|
|
103
|
+
SubsectionVersion is passed when we want to pin a specific version, otherwise
|
|
104
|
+
Subsection is used for unpinned.
|
|
105
|
+
"""
|
|
106
|
+
if subsections is None:
|
|
107
|
+
# When these are None, that means don't change the entities in the list.
|
|
108
|
+
return None
|
|
109
|
+
for u in subsections:
|
|
110
|
+
if not isinstance(u, (Subsection, SubsectionVersion)):
|
|
111
|
+
raise TypeError("Section subsections must be either Subsection or SubsectionVersion.")
|
|
112
|
+
return [
|
|
113
|
+
(
|
|
114
|
+
publishing_api.ContainerEntityRow(
|
|
115
|
+
entity_pk=s.container.publishable_entity_id,
|
|
116
|
+
version_pk=None,
|
|
117
|
+
) if isinstance(s, Subsection)
|
|
118
|
+
else publishing_api.ContainerEntityRow(
|
|
119
|
+
entity_pk=s.subsection.container.publishable_entity_id,
|
|
120
|
+
version_pk=s.container_version.publishable_entity_version_id,
|
|
121
|
+
)
|
|
122
|
+
)
|
|
123
|
+
for s in subsections
|
|
124
|
+
]
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
def create_next_section_version(
|
|
128
|
+
section: Section,
|
|
129
|
+
*,
|
|
130
|
+
title: str | None = None,
|
|
131
|
+
subsections: list[Subsection | SubsectionVersion] | None = None,
|
|
132
|
+
created: datetime,
|
|
133
|
+
created_by: int | None = None,
|
|
134
|
+
entities_action: publishing_api.ChildrenEntitiesAction = publishing_api.ChildrenEntitiesAction.REPLACE,
|
|
135
|
+
) -> SectionVersion:
|
|
136
|
+
"""
|
|
137
|
+
[ 🛑 UNSTABLE ] Create the next section version.
|
|
138
|
+
|
|
139
|
+
Args:
|
|
140
|
+
section_pk: The section ID.
|
|
141
|
+
title: The title. Leave as None to keep the current title.
|
|
142
|
+
subsections: The subsections, as a list of Subsections (unpinned) and/or SubsectionVersions (pinned).
|
|
143
|
+
Passing None will leave the existing subsections unchanged.
|
|
144
|
+
created: The creation date.
|
|
145
|
+
created_by: The user who created the section.
|
|
146
|
+
"""
|
|
147
|
+
entity_rows = _pub_entities_for_subsections(subsections)
|
|
148
|
+
section_version = publishing_api.create_next_container_version(
|
|
149
|
+
section.pk,
|
|
150
|
+
title=title,
|
|
151
|
+
entity_rows=entity_rows,
|
|
152
|
+
created=created,
|
|
153
|
+
created_by=created_by,
|
|
154
|
+
container_version_cls=SectionVersion,
|
|
155
|
+
entities_action=entities_action,
|
|
156
|
+
)
|
|
157
|
+
return section_version
|
|
158
|
+
|
|
159
|
+
|
|
160
|
+
def create_section_and_version(
|
|
161
|
+
learning_package_id: int,
|
|
162
|
+
key: str,
|
|
163
|
+
*,
|
|
164
|
+
title: str,
|
|
165
|
+
subsections: list[Subsection | SubsectionVersion] | None = None,
|
|
166
|
+
created: datetime,
|
|
167
|
+
created_by: int | None = None,
|
|
168
|
+
can_stand_alone: bool = True,
|
|
169
|
+
) -> tuple[Section, SectionVersion]:
|
|
170
|
+
"""
|
|
171
|
+
[ 🛑 UNSTABLE ] Create a new section and its version.
|
|
172
|
+
|
|
173
|
+
Args:
|
|
174
|
+
learning_package_id: The learning package ID.
|
|
175
|
+
key: The key.
|
|
176
|
+
created: The creation date.
|
|
177
|
+
created_by: The user who created the section.
|
|
178
|
+
can_stand_alone: Set to False when created as part of containers
|
|
179
|
+
"""
|
|
180
|
+
entity_rows = _pub_entities_for_subsections(subsections)
|
|
181
|
+
with atomic():
|
|
182
|
+
section = create_section(
|
|
183
|
+
learning_package_id,
|
|
184
|
+
key,
|
|
185
|
+
created,
|
|
186
|
+
created_by,
|
|
187
|
+
can_stand_alone=can_stand_alone,
|
|
188
|
+
)
|
|
189
|
+
section_version = create_section_version(
|
|
190
|
+
section,
|
|
191
|
+
1,
|
|
192
|
+
title=title,
|
|
193
|
+
entity_rows=entity_rows or [],
|
|
194
|
+
created=created,
|
|
195
|
+
created_by=created_by,
|
|
196
|
+
)
|
|
197
|
+
return section, section_version
|
|
198
|
+
|
|
199
|
+
|
|
200
|
+
def get_section(section_pk: int) -> Section:
|
|
201
|
+
"""
|
|
202
|
+
[ 🛑 UNSTABLE ] Get a section.
|
|
203
|
+
|
|
204
|
+
Args:
|
|
205
|
+
section_pk: The section ID.
|
|
206
|
+
"""
|
|
207
|
+
return Section.objects.get(pk=section_pk)
|
|
208
|
+
|
|
209
|
+
|
|
210
|
+
def get_section_version(section_version_pk: int) -> SectionVersion:
|
|
211
|
+
"""
|
|
212
|
+
[ 🛑 UNSTABLE ] Get a section version.
|
|
213
|
+
|
|
214
|
+
Args:
|
|
215
|
+
section_version_pk: The section version ID.
|
|
216
|
+
"""
|
|
217
|
+
return SectionVersion.objects.get(pk=section_version_pk)
|
|
218
|
+
|
|
219
|
+
|
|
220
|
+
def get_latest_section_version(section_pk: int) -> SectionVersion:
|
|
221
|
+
"""
|
|
222
|
+
[ 🛑 UNSTABLE ] Get the latest section version.
|
|
223
|
+
|
|
224
|
+
Args:
|
|
225
|
+
section_pk: The section ID.
|
|
226
|
+
"""
|
|
227
|
+
return Section.objects.get(pk=section_pk).versioning.latest
|
|
228
|
+
|
|
229
|
+
|
|
230
|
+
@dataclass(frozen=True)
|
|
231
|
+
class SectionListEntry:
|
|
232
|
+
"""
|
|
233
|
+
[ 🛑 UNSTABLE ]
|
|
234
|
+
Data about a single entity in a container, e.g. a subsection in a section.
|
|
235
|
+
"""
|
|
236
|
+
subsection_version: SubsectionVersion
|
|
237
|
+
pinned: bool = False
|
|
238
|
+
|
|
239
|
+
@property
|
|
240
|
+
def subsection(self):
|
|
241
|
+
return self.subsection_version.subsection
|
|
242
|
+
|
|
243
|
+
|
|
244
|
+
def get_subsections_in_section(
|
|
245
|
+
section: Section,
|
|
246
|
+
*,
|
|
247
|
+
published: bool,
|
|
248
|
+
) -> list[SectionListEntry]:
|
|
249
|
+
"""
|
|
250
|
+
[ 🛑 UNSTABLE ]
|
|
251
|
+
Get the list of entities and their versions in the draft or published
|
|
252
|
+
version of the given Section.
|
|
253
|
+
|
|
254
|
+
Args:
|
|
255
|
+
section: The Section, e.g. returned by `get_section()`
|
|
256
|
+
published: `True` if we want the published version of the section, or
|
|
257
|
+
`False` for the draft version.
|
|
258
|
+
"""
|
|
259
|
+
assert isinstance(section, Section)
|
|
260
|
+
subsections = []
|
|
261
|
+
for entry in publishing_api.get_entities_in_container(section, published=published):
|
|
262
|
+
# Convert from generic PublishableEntityVersion to SubsectionVersion:
|
|
263
|
+
subsection_version = entry.entity_version.containerversion.subsectionversion
|
|
264
|
+
assert isinstance(subsection_version, SubsectionVersion)
|
|
265
|
+
subsections.append(SectionListEntry(subsection_version=subsection_version, pinned=entry.pinned))
|
|
266
|
+
return subsections
|
|
267
|
+
|
|
268
|
+
|
|
269
|
+
def get_subsections_in_published_section_as_of(
|
|
270
|
+
section: Section,
|
|
271
|
+
publish_log_id: int,
|
|
272
|
+
) -> list[SectionListEntry] | None:
|
|
273
|
+
"""
|
|
274
|
+
[ 🛑 UNSTABLE ]
|
|
275
|
+
Get the list of entities and their versions in the published version of the
|
|
276
|
+
given container as of the given PublishLog version (which is essentially a
|
|
277
|
+
version for the entire learning package).
|
|
278
|
+
|
|
279
|
+
TODO: This API should be updated to also return the SectionVersion so we can
|
|
280
|
+
see the section title and any other metadata from that point in time.
|
|
281
|
+
TODO: accept a publish log UUID, not just int ID?
|
|
282
|
+
TODO: move the implementation to be a generic 'containers' implementation
|
|
283
|
+
that this sections function merely wraps.
|
|
284
|
+
TODO: optimize, perhaps by having the publishlog store a record of all
|
|
285
|
+
ancestors of every modified PublishableEntity in the publish.
|
|
286
|
+
"""
|
|
287
|
+
assert isinstance(section, Section)
|
|
288
|
+
section_pub_entity_version = publishing_api.get_published_version_as_of(
|
|
289
|
+
section.publishable_entity_id, publish_log_id
|
|
290
|
+
)
|
|
291
|
+
if section_pub_entity_version is None:
|
|
292
|
+
return None # This section was not published as of the given PublishLog ID.
|
|
293
|
+
container_version = section_pub_entity_version.containerversion
|
|
294
|
+
|
|
295
|
+
entity_list = []
|
|
296
|
+
rows = container_version.entity_list.entitylistrow_set.order_by("order_num")
|
|
297
|
+
for row in rows:
|
|
298
|
+
if row.entity_version is not None:
|
|
299
|
+
subsection_version = row.entity_version.containerversion.subsectionversion
|
|
300
|
+
assert isinstance(subsection_version, SubsectionVersion)
|
|
301
|
+
entity_list.append(SectionListEntry(subsection_version=subsection_version, pinned=True))
|
|
302
|
+
else:
|
|
303
|
+
# Unpinned subsection - figure out what its latest published version was.
|
|
304
|
+
# This is not optimized. It could be done in one query per section rather than one query per subsection.
|
|
305
|
+
pub_entity_version = publishing_api.get_published_version_as_of(row.entity_id, publish_log_id)
|
|
306
|
+
if pub_entity_version:
|
|
307
|
+
entity_list.append(SectionListEntry(
|
|
308
|
+
subsection_version=pub_entity_version.containerversion.subsectionversion, pinned=False
|
|
309
|
+
))
|
|
310
|
+
return entity_list
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Subsection Django application initialization.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from django.apps import AppConfig
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class SectionsConfig(AppConfig):
|
|
9
|
+
"""
|
|
10
|
+
Configuration for the subsections Django application.
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
name = "openedx_learning.apps.authoring.sections"
|
|
14
|
+
verbose_name = "Learning Core > Authoring > Sections"
|
|
15
|
+
default_auto_field = "django.db.models.BigAutoField"
|
|
16
|
+
label = "oel_sections"
|
|
17
|
+
|
|
18
|
+
def ready(self):
|
|
19
|
+
"""
|
|
20
|
+
Register Section and SectionVersion.
|
|
21
|
+
"""
|
|
22
|
+
from ..publishing.api import register_content_models # pylint: disable=import-outside-toplevel
|
|
23
|
+
from .models import Section, SectionVersion # pylint: disable=import-outside-toplevel
|
|
24
|
+
|
|
25
|
+
register_content_models(Section, SectionVersion)
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# Generated by Django 4.2.20 on 2025-04-11 12:53
|
|
2
|
+
|
|
3
|
+
import django.db.models.deletion
|
|
4
|
+
from django.db import migrations, models
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class Migration(migrations.Migration):
|
|
8
|
+
|
|
9
|
+
initial = True
|
|
10
|
+
|
|
11
|
+
dependencies = [
|
|
12
|
+
('oel_publishing', '0005_alter_entitylistrow_options'),
|
|
13
|
+
]
|
|
14
|
+
|
|
15
|
+
operations = [
|
|
16
|
+
migrations.CreateModel(
|
|
17
|
+
name='Section',
|
|
18
|
+
fields=[
|
|
19
|
+
('container', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='oel_publishing.container')),
|
|
20
|
+
],
|
|
21
|
+
options={
|
|
22
|
+
'abstract': False,
|
|
23
|
+
},
|
|
24
|
+
bases=('oel_publishing.container',),
|
|
25
|
+
),
|
|
26
|
+
migrations.CreateModel(
|
|
27
|
+
name='SectionVersion',
|
|
28
|
+
fields=[
|
|
29
|
+
('container_version', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='oel_publishing.containerversion')),
|
|
30
|
+
],
|
|
31
|
+
options={
|
|
32
|
+
'abstract': False,
|
|
33
|
+
},
|
|
34
|
+
bases=('oel_publishing.containerversion',),
|
|
35
|
+
),
|
|
36
|
+
]
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Models that implement sections
|
|
3
|
+
"""
|
|
4
|
+
from django.db import models
|
|
5
|
+
|
|
6
|
+
from ..publishing.models import Container, ContainerVersion
|
|
7
|
+
|
|
8
|
+
__all__ = [
|
|
9
|
+
"Section",
|
|
10
|
+
"SectionVersion",
|
|
11
|
+
]
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class Section(Container):
|
|
15
|
+
"""
|
|
16
|
+
A Section is type of Container that holds Units.
|
|
17
|
+
|
|
18
|
+
Via Container and its PublishableEntityMixin, Sections are also publishable
|
|
19
|
+
entities and can be added to other containers.
|
|
20
|
+
"""
|
|
21
|
+
container = models.OneToOneField(
|
|
22
|
+
Container,
|
|
23
|
+
on_delete=models.CASCADE,
|
|
24
|
+
parent_link=True,
|
|
25
|
+
primary_key=True,
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
class SectionVersion(ContainerVersion):
|
|
30
|
+
"""
|
|
31
|
+
A SectionVersion is a specific version of a Section.
|
|
32
|
+
|
|
33
|
+
Via ContainerVersion and its EntityList, it defines the list of Units
|
|
34
|
+
in this version of the Section.
|
|
35
|
+
"""
|
|
36
|
+
container_version = models.OneToOneField(
|
|
37
|
+
ContainerVersion,
|
|
38
|
+
on_delete=models.CASCADE,
|
|
39
|
+
parent_link=True,
|
|
40
|
+
primary_key=True,
|
|
41
|
+
)
|
|
42
|
+
|
|
43
|
+
@property
|
|
44
|
+
def section(self):
|
|
45
|
+
""" Convenience accessor to the Section this version is associated with """
|
|
46
|
+
return self.container_version.container.section # pylint: disable=no-member
|
|
47
|
+
|
|
48
|
+
# Note: the 'publishable_entity_version' field is inherited and will appear on this model, but does not exist
|
|
49
|
+
# in the underlying database table. It only exists in the ContainerVersion table.
|
|
50
|
+
# You can verify this by running 'python manage.py sqlmigrate oel_sections 0001_initial'
|