Student Dashboard CourseOverviews with one query.

Pre-load the course overviews attached to CourseEnrollments on the
Student Dashboard, if possible. This will only grab the CourseOverviews
that already exist, and will not generate new ones. Any missing
CourseOverviews fall back to the lazily-created one-at-a-time behavior
they've always had. That's mostly because I wanted to optimize for the
common case in the least invasive way possible, and I don't want to get
caught up in locking issues.
This commit is contained in:
David Ormsbee
2017-02-20 11:27:50 -05:00
parent b91792145e
commit 8423ecb1c8
4 changed files with 76 additions and 1 deletions

View File

@@ -274,6 +274,27 @@ class CourseOverview(TimeStampedModel):
return course_overview or cls.load_from_module_store(course_id)
@classmethod
def get_from_ids_if_exists(cls, course_ids):
"""
Return a dict mapping course_ids to CourseOverviews, if they exist.
This method will *not* generate new CourseOverviews or delete outdated
ones. It exists only as a small optimization used when CourseOverviews
are known to exist, for common situations like the student dashboard.
Callers should assume that this list is incomplete and fall back to
get_from_id if they need to guarantee CourseOverview generation.
"""
return {
overview.id: overview
for overview
in cls.objects.select_related('image_set').filter(
id__in=course_ids,
version__gte=cls.VERSION
)
}
def clean_id(self, padding_char='='):
"""
Returns a unique deterministic base32-encoded ID for the course.

View File

@@ -515,6 +515,35 @@ class CourseOverviewTestCase(ModuleStoreTestCase):
"testing CourseOverview.get_all_courses with filter_={}".format(filter_),
)
def test_get_from_ids_if_exists(self):
course_with_overview_1 = CourseFactory.create(emit_signals=True)
course_with_overview_2 = CourseFactory.create(emit_signals=True)
course_without_overview = CourseFactory.create(emit_signals=False)
courses = [course_with_overview_1, course_with_overview_2, course_without_overview]
course_ids_to_overviews = CourseOverview.get_from_ids_if_exists(
course.id for course in courses
)
# We should see the ones that have published CourseOverviews
# (when the signals were emitted), but not the one that didn't issue
# a publish signal.
self.assertEqual(len(course_ids_to_overviews), 2)
self.assertIn(course_with_overview_1.id, course_ids_to_overviews)
self.assertIn(course_with_overview_2.id, course_ids_to_overviews)
self.assertNotIn(course_without_overview.id, course_ids_to_overviews)
# But if we set a CourseOverview to be an old version, it shouldn't be
# returned by get_from_ids_if_exists()
overview_2 = course_ids_to_overviews[course_with_overview_2.id]
overview_2.version = CourseOverview.VERSION - 1
overview_2.save()
course_ids_to_overviews = CourseOverview.get_from_ids_if_exists(
course.id for course in courses
)
self.assertEqual(len(course_ids_to_overviews), 1)
self.assertIn(course_with_overview_1.id, course_ids_to_overviews)
@attr(shard=3)
@ddt.ddt