Skip to content

Commit 666ae68

Browse files
committed
fix: remove container hierarchy information from publish api
1 parent 559eee8 commit 666ae68

7 files changed

Lines changed: 119 additions & 14 deletions

File tree

openedx_learning/apps/authoring/publishing/api.py

Lines changed: 23 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1283,6 +1283,7 @@ def get_entities_in_container(
12831283
container: Container,
12841284
*,
12851285
published: bool,
1286+
select_related_version: str | None = None,
12861287
) -> list[ContainerEntityListEntry]:
12871288
"""
12881289
[ 🛑 UNSTABLE ]
@@ -1293,23 +1294,34 @@ def get_entities_in_container(
12931294
container: The Container, e.g. returned by `get_container()`
12941295
published: `True` if we want the published version of the container, or
12951296
`False` for the draft version.
1297+
select_related_version: An optional optimization; specify a relationship
1298+
on ContainerVersion, like `componentversion` or `containerversion__x`
1299+
to preload via select_related.
12961300
"""
12971301
assert isinstance(container, Container)
1298-
container_version = container.versioning.published if published else container.versioning.draft
1302+
if published:
1303+
# Very minor optimization: reload the container with related 1:1 entities
1304+
container = Container.objects.select_related(
1305+
"publishable_entity__published__version__containerversion__entity_list").get(pk=container.pk)
1306+
container_version = container.versioning.published
1307+
select_related = ["entity__published__version"]
1308+
if select_related_version:
1309+
select_related.append(f"entity__published__version__{select_related_version}")
1310+
else:
1311+
# Very minor optimization: reload the container with related 1:1 entities
1312+
container = Container.objects.select_related(
1313+
"publishable_entity__draft__version__containerversion__entity_list").get(pk=container.pk)
1314+
container_version = container.versioning.draft
1315+
select_related = ["entity__draft__version"]
1316+
if select_related_version:
1317+
select_related.append(f"entity__draft__version__{select_related_version}")
12991318
if container_version is None:
13001319
raise ContainerVersion.DoesNotExist # This container has not been published yet, or has been deleted.
13011320
assert isinstance(container_version, ContainerVersion)
1302-
entity_list = []
1321+
entity_list: list[ContainerEntityListEntry] = []
13031322
for row in container_version.entity_list.entitylistrow_set.select_related(
1304-
"entity_version__componentversion__component",
1305-
"entity_version__containerversion__container",
1306-
"entity__published__version__containerversion__unitversion__container__unit",
1307-
"entity__published__version__containerversion__subsectionversion__container__subsection",
1308-
"entity__published__version__containerversion__sectionversion__container__section",
1309-
"entity__draft__version__componentversion__component",
1310-
"entity__draft__version__containerversion__unitversion__container__unit",
1311-
"entity__draft__version__containerversion__subsectionversion__container__subsection",
1312-
"entity__draft__version__containerversion__sectionversion__container__section",
1323+
"entity_version",
1324+
*select_related,
13131325
).order_by("order_num"):
13141326
entity_version = row.entity_version # This will be set if pinned
13151327
if not entity_version: # If this entity is "unpinned", use the latest published/draft version:

openedx_learning/apps/authoring/sections/api.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -257,7 +257,12 @@ def get_subsections_in_section(
257257
"""
258258
assert isinstance(section, Section)
259259
subsections = []
260-
for entry in publishing_api.get_entities_in_container(section, published=published):
260+
entries = publishing_api.get_entities_in_container(
261+
section,
262+
published=published,
263+
select_related_version="containerversion__subsectionversion",
264+
)
265+
for entry in entries:
261266
# Convert from generic PublishableEntityVersion to SubsectionVersion:
262267
subsection_version = entry.entity_version.containerversion.subsectionversion
263268
assert isinstance(subsection_version, SubsectionVersion)

openedx_learning/apps/authoring/subsections/api.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -256,7 +256,12 @@ def get_units_in_subsection(
256256
"""
257257
assert isinstance(subsection, Subsection)
258258
units = []
259-
for entry in publishing_api.get_entities_in_container(subsection, published=published):
259+
entries = publishing_api.get_entities_in_container(
260+
subsection,
261+
published=published,
262+
select_related_version="containerversion__unitversion",
263+
)
264+
for entry in entries:
260265
# Convert from generic PublishableEntityVersion to UnitVersion:
261266
unit_version = entry.entity_version.containerversion.unitversion
262267
assert isinstance(unit_version, UnitVersion)

openedx_learning/apps/authoring/units/api.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -257,7 +257,12 @@ def get_components_in_unit(
257257
"""
258258
assert isinstance(unit, Unit)
259259
components = []
260-
for entry in publishing_api.get_entities_in_container(unit, published=published):
260+
entries = publishing_api.get_entities_in_container(
261+
unit,
262+
published=published,
263+
select_related_version="componentversion",
264+
)
265+
for entry in entries:
261266
# Convert from generic PublishableEntityVersion to ComponentVersion:
262267
component_version = entry.entity_version.componentversion
263268
assert isinstance(component_version, ComponentVersion)

tests/openedx_learning/apps/authoring/sections/test_api.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -993,6 +993,32 @@ def test_sections_containing(self):
993993
]
994994
assert result2 == [section4_unpinned]
995995

996+
def test_get_subsections_in_section_queries(self):
997+
"""
998+
Test the query count of get_subsections_in_section()
999+
This also tests the generic method get_entities_in_container()
1000+
"""
1001+
section = self.create_section_with_subsections([
1002+
self.subsection_1,
1003+
self.subsection_2,
1004+
self.subsection_2_v1,
1005+
])
1006+
with self.assertNumQueries(4):
1007+
result = authoring_api.get_subsections_in_section(section, published=False)
1008+
assert result == [
1009+
Entry(self.subsection_1.versioning.draft),
1010+
Entry(self.subsection_2.versioning.draft),
1011+
Entry(self.subsection_2.versioning.draft, pinned=True),
1012+
]
1013+
authoring_api.publish_all_drafts(self.learning_package.id)
1014+
with self.assertNumQueries(4):
1015+
result = authoring_api.get_subsections_in_section(section, published=True)
1016+
assert result == [
1017+
Entry(self.subsection_1.versioning.draft),
1018+
Entry(self.subsection_2.versioning.draft),
1019+
Entry(self.subsection_2.versioning.draft, pinned=True),
1020+
]
1021+
9961022
def test_add_remove_container_children(self):
9971023
"""
9981024
Test adding and removing children subsections from sections.

tests/openedx_learning/apps/authoring/subsections/test_api.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1024,6 +1024,32 @@ def test_subsections_containing(self):
10241024
]
10251025
assert result2 == [subsection4_unpinned]
10261026

1027+
def test_get_units_in_subsection_queries(self):
1028+
"""
1029+
Test the query count of get_units_in_subsection()
1030+
This also tests the generic method get_entities_in_container()
1031+
"""
1032+
subsection = self.create_subsection_with_units([
1033+
self.unit_1,
1034+
self.unit_2,
1035+
self.unit_2_v1,
1036+
])
1037+
with self.assertNumQueries(4):
1038+
result = authoring_api.get_units_in_subsection(subsection, published=False)
1039+
assert result == [
1040+
Entry(self.unit_1.versioning.draft),
1041+
Entry(self.unit_2.versioning.draft),
1042+
Entry(self.unit_2.versioning.draft, pinned=True),
1043+
]
1044+
authoring_api.publish_all_drafts(self.learning_package.id)
1045+
with self.assertNumQueries(4):
1046+
result = authoring_api.get_units_in_subsection(subsection, published=True)
1047+
assert result == [
1048+
Entry(self.unit_1.versioning.draft),
1049+
Entry(self.unit_2.versioning.draft),
1050+
Entry(self.unit_2.versioning.draft, pinned=True),
1051+
]
1052+
10271053
def test_add_remove_container_children(self):
10281054
"""
10291055
Test adding and removing children units from subsections.

tests/openedx_learning/apps/authoring/units/test_api.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1012,6 +1012,32 @@ def test_units_containing(self):
10121012
]
10131013
assert result2 == [unit4_unpinned, unit7_several]
10141014

1015+
def test_get_components_in_unit_queries(self):
1016+
"""
1017+
Test the query count of get_components_in_unit()
1018+
This also tests the generic method get_entities_in_container()
1019+
"""
1020+
unit = self.create_unit_with_components([
1021+
self.component_1,
1022+
self.component_2,
1023+
self.component_2_v1,
1024+
])
1025+
with self.assertNumQueries(3):
1026+
result = authoring_api.get_components_in_unit(unit, published=False)
1027+
assert result == [
1028+
Entry(self.component_1.versioning.draft),
1029+
Entry(self.component_2.versioning.draft),
1030+
Entry(self.component_2.versioning.draft, pinned=True),
1031+
]
1032+
authoring_api.publish_all_drafts(self.learning_package.id)
1033+
with self.assertNumQueries(3):
1034+
result = authoring_api.get_components_in_unit(unit, published=True)
1035+
assert result == [
1036+
Entry(self.component_1.versioning.draft),
1037+
Entry(self.component_2.versioning.draft),
1038+
Entry(self.component_2.versioning.draft, pinned=True),
1039+
]
1040+
10151041
def test_add_remove_container_children(self):
10161042
"""
10171043
Test adding and removing children components from containers.

0 commit comments

Comments
 (0)