diff --git a/common/lib/xmodule/xmodule/x_module.py b/common/lib/xmodule/xmodule/x_module.py index 3406bcb99c..30522b871c 100644 --- a/common/lib/xmodule/xmodule/x_module.py +++ b/common/lib/xmodule/xmodule/x_module.py @@ -501,11 +501,11 @@ class XModuleDescriptor(Plugin, HTMLSnippet): all(getattr(self, attr, None) == getattr(other, attr, None) for attr in self.equality_attributes)) - if not eq: - for attr in self.equality_attributes: - print(getattr(self, attr, None), - getattr(other, attr, None), - getattr(self, attr, None) == getattr(other, attr, None)) + # if not eq: + # for attr in self.equality_attributes: + # print(getattr(self, attr, None), + # getattr(other, attr, None), + # getattr(self, attr, None) == getattr(other, attr, None)) return eq diff --git a/lms/djangoapps/courseware/grades.py b/lms/djangoapps/courseware/grades.py index e522468f45..7cb928e648 100644 --- a/lms/djangoapps/courseware/grades.py +++ b/lms/djangoapps/courseware/grades.py @@ -20,6 +20,7 @@ def get_graded_sections(course_descriptor): "section_descriptor" : The section descriptor "xmoduledescriptors" : An array of xmoduledescriptors that could possibly be in the section, for any student """ + all_descriptors = [] graded_sections = {} for c in course_descriptor.get_children(): @@ -35,8 +36,11 @@ def get_graded_sections(course_descriptor): section_format = s.metadata.get('format', "") graded_sections[ section_format ] = graded_sections.get( section_format, [] ) + [section_description] + + all_descriptors.extend(xmoduledescriptors) + all_descriptors.append(s) - return graded_sections + return graded_sections, all_descriptors def yield_descriptor_descendents(module_descriptor): for child in module_descriptor.get_children(): diff --git a/lms/djangoapps/courseware/models.py b/lms/djangoapps/courseware/models.py index 3b0ca7fdcf..79617e428d 100644 --- a/lms/djangoapps/courseware/models.py +++ b/lms/djangoapps/courseware/models.py @@ -67,17 +67,30 @@ class StudentModuleCache(object): """ A cache of StudentModules for a specific student """ - def __init__(self, user, descriptor, depth=None): + def __init__(self, user, descriptor=None, depth=None, descriptors=None, descriptor_filter=lambda descriptor: True): ''' Find any StudentModule objects that are needed by any child modules of the - supplied descriptor. Avoids making multiple queries to the database - - descriptor: An XModuleDescriptor - depth is the number of levels of descendent modules to load StudentModules for, in addition to - the supplied descriptor. If depth is None, load all descendent StudentModules + supplied descriptor, or caches only the StudentModule objects specifically + for every descriptor in descriptors. Avoids making multiple queries to the + database. + + There are two ways to init: + descriptor: An XModuleDescriptor + depth is the number of levels of descendent modules to load StudentModules for, in addition to + the supplied descriptor. If depth is None, load all descendent StudentModules + OR + descriptors: An array of XModuleDescriptors. + + descriptor_filter is a function that accepts a descriptor and return wether the StudentModule + should be cached ''' if user.is_authenticated(): - module_ids = self._get_module_state_keys(descriptor, depth) + if not (descriptor == None) != (descriptors == None): #An xor on the descriptor and descriptors parameters. + raise ValueError("Either the descriptor or descriptors must be supplied to StudentModuleCache.") + + if descriptor != None: + descriptors = self._get_child_descriptors(descriptor, depth) + module_ids = self._get_module_state_keys(descriptors, descriptor_filter) # This works around a limitation in sqlite3 on the number of parameters # that can be put into a single query @@ -91,27 +104,39 @@ class StudentModuleCache(object): else: self.cache = [] - - def _get_module_state_keys(self, descriptor, depth): - ''' - Get a list of the state_keys needed for StudentModules - required for this module descriptor - + + def _get_child_descriptors(self, descriptor, depth): + """ descriptor: An XModuleDescriptor depth is the number of levels of descendent modules to load StudentModules for, in addition to the supplied descriptor. If depth is None, load all descendent StudentModules - ''' - keys = [descriptor.location.url()] - - shared_state_key = getattr(descriptor, 'shared_state_key', None) - if shared_state_key is not None: - keys.append(shared_state_key) - + """ + descriptors = [descriptor] + if depth is None or depth > 0: new_depth = depth - 1 if depth is not None else depth for child in descriptor.get_children(): - keys.extend(self._get_module_state_keys(child, new_depth)) + descriptors.extend(self._get_child_descriptors(child, new_depth)) + + return descriptors + + def _get_module_state_keys(self, descriptors, descriptor_filter): + ''' + Get a list of the state_keys needed for StudentModules + required for this module descriptor + + descriptor_filter is a function that accepts a descriptor and return wether the StudentModule + should be cached + ''' + keys = [] + for descriptor in descriptors: + if descriptor_filter(descriptor): + keys.append(descriptor.location.url()) + + shared_state_key = getattr(descriptor, 'shared_state_key', None) + if shared_state_key is not None: + keys.append(shared_state_key) return keys diff --git a/lms/djangoapps/courseware/views.py b/lms/djangoapps/courseware/views.py index 423d436087..c8939c0b75 100644 --- a/lms/djangoapps/courseware/views.py +++ b/lms/djangoapps/courseware/views.py @@ -38,9 +38,8 @@ template_imports = {'urllib': urllib} def test_grading(request, course_id): course = check_course(course_id) - sections = grades.get_graded_sections(course) - - student_module_cache = StudentModuleCache(request.user, course) + sections, all_descriptors = grades.get_graded_sections(course) + student_module_cache = StudentModuleCache(request.user, descriptors=all_descriptors) grade_result = grades.fast_grade(request.user, request, sections, course.grader, student_module_cache)