Commit eee6250f by Usman Khalid

Use RequestCache to cache cohorts information.

TNL-1258
parent d382f569
...@@ -14,7 +14,9 @@ from django.utils.translation import ugettext as _ ...@@ -14,7 +14,9 @@ from django.utils.translation import ugettext as _
from courseware import courses from courseware import courses
from eventtracking import tracker from eventtracking import tracker
from request_cache.middleware import RequestCache
from student.models import get_user_by_username_or_email from student.models import get_user_by_username_or_email
from .models import CourseUserGroup, CourseCohort, CourseCohortsSettings, CourseUserGroupPartitionGroup from .models import CourseUserGroup, CourseCohort, CourseCohortsSettings, CourseUserGroupPartitionGroup
...@@ -177,6 +179,10 @@ def get_cohort(user, course_key, assign=True, use_cached=False): ...@@ -177,6 +179,10 @@ def get_cohort(user, course_key, assign=True, use_cached=False):
Given a Django user and a CourseKey, return the user's cohort in that Given a Django user and a CourseKey, return the user's cohort in that
cohort. cohort.
The cohort for the user is cached for the duration of a request. Pass
use_cached=True to use the cached value instead of fetching from the
database.
Arguments: Arguments:
user: a Django User object. user: a Django User object.
course_key: CourseKey course_key: CourseKey
...@@ -190,35 +196,37 @@ def get_cohort(user, course_key, assign=True, use_cached=False): ...@@ -190,35 +196,37 @@ def get_cohort(user, course_key, assign=True, use_cached=False):
Raises: Raises:
ValueError if the CourseKey doesn't exist. ValueError if the CourseKey doesn't exist.
""" """
# pylint: disable=protected-access request_cache = RequestCache.get_request_cache()
# We cache the cohort on the user object so that we do not have to repeatedly cache_key = u"cohorts.get_cohort.{}.{}".format(user.id, course_key)
# query the database during a request. If the cached value exists, just return it.
if use_cached and hasattr(user, '_cohort'): if use_cached and cache_key in request_cache.data:
return user._cohort return request_cache.data[cache_key]
request_cache.data.pop(cache_key, None)
# First check whether the course is cohorted (users shouldn't be in a cohort # First check whether the course is cohorted (users shouldn't be in a cohort
# in non-cohorted courses, but settings can change after course starts) # in non-cohorted courses, but settings can change after course starts)
course = courses.get_course(course_key) course_cohort_settings = get_course_cohort_settings(course_key)
course_cohort_settings = get_course_cohort_settings(course.id)
if not course_cohort_settings.is_cohorted: if not course_cohort_settings.is_cohorted:
user._cohort = None return request_cache.data.setdefault(cache_key, None)
return user._cohort
# If course is cohorted, check if the user already has a cohort.
try: try:
user._cohort = CourseUserGroup.objects.get( cohort = CourseUserGroup.objects.get(
course_id=course_key, course_id=course_key,
group_type=CourseUserGroup.COHORT, group_type=CourseUserGroup.COHORT,
users__id=user.id, users__id=user.id,
) )
return user._cohort return request_cache.data.setdefault(cache_key, cohort)
except CourseUserGroup.DoesNotExist: except CourseUserGroup.DoesNotExist:
# Didn't find the group. We'll go on to create one if needed. # Didn't find the group. If we do not want to assign, return here.
if not assign: if not assign:
# Do not cache the cohort here, because in the next call assign # Do not cache the cohort here, because in the next call assign
# may be True, and we will have to assign the user a cohort. # may be True, and we will have to assign the user a cohort.
return None return None
# Otherwise assign the user a cohort.
course = courses.get_course(course_key)
cohorts = get_course_cohorts(course, assignment_type=CourseCohort.RANDOM) cohorts = get_course_cohorts(course, assignment_type=CourseCohort.RANDOM)
if cohorts: if cohorts:
cohort = local_random().choice(cohorts) cohort = local_random().choice(cohorts)
...@@ -231,8 +239,7 @@ def get_cohort(user, course_key, assign=True, use_cached=False): ...@@ -231,8 +239,7 @@ def get_cohort(user, course_key, assign=True, use_cached=False):
user.course_groups.add(cohort) user.course_groups.add(cohort)
user._cohort = cohort return request_cache.data.setdefault(cache_key, cohort)
return user._cohort
def migrate_cohort_settings(course): def migrate_cohort_settings(course):
...@@ -406,23 +413,26 @@ def get_group_info_for_cohort(cohort, use_cached=False): ...@@ -406,23 +413,26 @@ def get_group_info_for_cohort(cohort, use_cached=False):
If the cohort has not been linked to any group/partition, both values in the If the cohort has not been linked to any group/partition, both values in the
tuple will be None. tuple will be None.
The partition group info is cached for the duration of a request. Pass
use_cached=True to use the cached value instead of fetching from the
database.
""" """
# pylint: disable=protected-access request_cache = RequestCache.get_request_cache()
# We cache the partition group on the cohort object so that we do not have to repeatedly cache_key = u"cohorts.get_group_info_for_cohort.{}".format(cohort.id)
# query the database during a request.
if not use_cached and hasattr(cohort, '_partition_group'):
delattr(cohort, '_partition_group')
if not hasattr(cohort, '_partition_group'): if use_cached and cache_key in request_cache.data:
try: return request_cache.data[cache_key]
cohort._partition_group = CourseUserGroupPartitionGroup.objects.get(course_user_group=cohort)
except CourseUserGroupPartitionGroup.DoesNotExist:
cohort._partition_group = None
if cohort._partition_group: request_cache.data.pop(cache_key, None)
return cohort._partition_group.group_id, cohort._partition_group.partition_id
try:
partition_group = CourseUserGroupPartitionGroup.objects.get(course_user_group=cohort)
return request_cache.data.setdefault(cache_key, (partition_group.group_id, partition_group.partition_id))
except CourseUserGroupPartitionGroup.DoesNotExist:
pass
return None, None return request_cache.data.setdefault(cache_key, (None, None))
def set_assignment_type(user_group, assignment_type): def set_assignment_type(user_group, assignment_type):
......
...@@ -176,7 +176,7 @@ class TestCohorts(ModuleStoreTestCase): ...@@ -176,7 +176,7 @@ class TestCohorts(ModuleStoreTestCase):
self.assertEqual(cohorts.get_cohort_id(user, course.id), cohort.id) self.assertEqual(cohorts.get_cohort_id(user, course.id), cohort.id)
self.assertRaises( self.assertRaises(
ValueError, Http404,
lambda: cohorts.get_cohort_id(user, SlashSeparatedCourseKey("course", "does_not", "exist")) lambda: cohorts.get_cohort_id(user, SlashSeparatedCourseKey("course", "does_not", "exist"))
) )
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment