Skip to content

feat!: Add Container.container_code field#545

Merged
kdmccormick merged 5 commits intomainfrom
kdmccormick/keys-container
Apr 20, 2026
Merged

feat!: Add Container.container_code field#545
kdmccormick merged 5 commits intomainfrom
kdmccormick/keys-container

Conversation

@kdmccormick
Copy link
Copy Markdown
Member

@kdmccormick kdmccormick commented Apr 15, 2026

Description

Adds a container_code field (code_field) and a learning_package FK to the
Container model. Also adds a UniqueConstraint on (learning_package,
container_code), which is stricter than Component's constraint (no type scoping
-- container codes must be unique across all container types within a given
LearningPackage).

For existing containers, container_code is backfilled from the entity key via a
data migration. Future containers will have container_code set explicitly by the
caller.

BREAKING CHANGE: In create_container() and create_container_and_version(), the
key argument has been renamed to container_code. The same applies to
create_unit_and_version(), create_subsection_and_version(), and
create_section_and_version().

Backup-restore format is unchanged. container_code will be set to the value of
the entity key. This may change in a future "v2" backup format.

Part of: #322

Full series of PRs:

  1. feat!: Collection.key -> Collection.collection_code #542
  2. feat!: Component.local_key -> Component.component_code #544
  3. feat!: Add Container.container_code field #545
  4. feat!: Package and Entity keys are now opaque refs #546
  5. feat!: ComponentVersionMedia.key -> ComponentVersionMedia.path #547

Testing, AI Usage, and Merge Considerations

See #322

Comment thread src/openedx_content/applets/containers/api.py
@kdmccormick kdmccormick force-pushed the kdmccormick/keys-component branch from fbe4b4b to f4d32b8 Compare April 16, 2026 18:18
@kdmccormick kdmccormick force-pushed the kdmccormick/keys-container branch from 266d7f3 to 5283857 Compare April 16, 2026 20:47
@kdmccormick kdmccormick force-pushed the kdmccormick/keys-component branch from f4d32b8 to 0f875ed Compare April 17, 2026 13:40
@kdmccormick kdmccormick force-pushed the kdmccormick/keys-container branch from 5283857 to c32f78c Compare April 17, 2026 14:28
@kdmccormick kdmccormick force-pushed the kdmccormick/keys-component branch from 0f875ed to 2bf60ff Compare April 17, 2026 16:35
@kdmccormick kdmccormick force-pushed the kdmccormick/keys-container branch 2 times, most recently from 8434cbf to 64f0eeb Compare April 17, 2026 16:56
@kdmccormick kdmccormick marked this pull request as ready for review April 17, 2026 17:57
@kdmccormick kdmccormick force-pushed the kdmccormick/keys-component branch from 2bf60ff to 382a7b3 Compare April 17, 2026 18:45
@kdmccormick kdmccormick force-pushed the kdmccormick/keys-container branch from 64f0eeb to f67afa4 Compare April 17, 2026 18:47
Comment thread src/openedx_content/applets/containers/models.py
Copy link
Copy Markdown
Contributor

@bradenmacdonald bradenmacdonald left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm fine with this, assuming it's immediately followed by the proper removal of the key field, but I'd prefer to replace key more 1 for 1 as mentioned. Did not run the code, just read.

Comment thread src/openedx_content/applets/containers/models.py
Comment thread src/openedx_content/applets/units/api.py Outdated
Comment thread tests/openedx_content/applets/publishing/test_api.py Outdated
Copy link
Copy Markdown
Contributor

@ormsbee ormsbee left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just a sanity check question, but otherwise LGTM.

Comment on lines +18 to +22
Container = apps.get_model("openedx_content", "Container")
for container in Container.objects.select_related("publishable_entity__learning_package").all():
container.learning_package = container.publishable_entity.learning_package
container.container_code = container.publishable_entity.key
container.save(update_fields=["learning_package", "container_code"])
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Comment, no action needed] It's really unfortunate that we can't use F() across relations. I feel like this is one of the few cases where I'd be tempted to use raw SQL.

Comment thread src/openedx_content/migrations/0010_add_container_code.py
@kdmccormick kdmccormick force-pushed the kdmccormick/keys-component branch 2 times, most recently from d7dc148 to 13cad83 Compare April 20, 2026 16:52
Base automatically changed from kdmccormick/keys-component to main April 20, 2026 18:14
Adds a container_code field (code_field) and a learning_package FK to the
Container model. Also adds a UniqueConstraint on (learning_package,
container_code), which is stricter than Component's constraint
(no type scoping -- container codes must be unique across all container
types within a given LearningPackage).

For existing containers, container_code is backfilled from the entity key
via a data migration. Future containers will have container_code set
explicitly by the caller.

Backup/restore now writes container_code into the [entity.container]
section (Verawood and later). Archives created in Ulmo (which have no
container_code) fall back to using the entity key as the container_code
on restore.

BREAKING CHANGE: create_container() and create_container_and_version()
now require a container_code keyword argument. The same applies to
create_unit_and_version(), create_subsection_and_version(), and
create_section_and_version().

Part of: #322

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@kdmccormick kdmccormick force-pushed the kdmccormick/keys-container branch from f67afa4 to ed3aadc Compare April 20, 2026 18:50
@kdmccormick kdmccormick force-pushed the kdmccormick/keys-container branch from bdbebec to f42b544 Compare April 20, 2026 19:39
@kdmccormick
Copy link
Copy Markdown
Member Author

Thanks for the review @bradenmacdonald . I've applied all your suggestions except the denormalization check. Could you take another look?

Comment on lines +190 to +191
# Unlike component_code, it is unique across all container types within
# the same LearningPackage.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will requiring this code to be unique across all containers in a [course] bite us later when we try to migrate old courses to Learning Core, since they may have e.g. a section and unit with the same container_code ?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hard to say.

On one hand, we'll likely have multiple course runs per learning package. So, we'll need to handle collisions between container block url_names anyway. I'm imagining that there'll have to be a table which maps CourseRunUsages to Entities, rather than a simple mapping function between {component,container}_{type,code} and CourseRunUsageKeys.

On the other hand, it's weird to me that container_code and component_code have different uniqueness constraints. I have a feeling that the inconsistency will make consuming code more complicated rather than having any benefit to us.

We're riding the line now, but maybe we can sneak a fix to this in before the cutoff.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I'd prefer to make container_code work like component_code if we can.

Copy link
Copy Markdown
Contributor

@bradenmacdonald bradenmacdonald left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks great! I read through the code, but didn't test; let me know if you want any testing on these PRs.

@kdmccormick
Copy link
Copy Markdown
Member Author

@bradenmacdonald all set for now, but if you if you have time on Wednesday I could use a hand testing the openedx-platform PR.

@kdmccormick kdmccormick merged commit 1511a5b into main Apr 20, 2026
6 checks passed
@kdmccormick kdmccormick deleted the kdmccormick/keys-container branch April 20, 2026 21:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants