Commit 11dcf12f by Calen Pennington

Make XModule use the same get_children that XModuleDescriptor and XBlock do, and…

Make XModule use the same get_children that XModuleDescriptor and XBlock do, and make it returned the same CombinedSystem
parent 8a73a736
...@@ -206,6 +206,7 @@ class ConditionalModuleXmlTest(unittest.TestCase): ...@@ -206,6 +206,7 @@ class ConditionalModuleXmlTest(unittest.TestCase):
location = descriptor location = descriptor
descriptor = self.modulestore.get_item(location, depth=None) descriptor = self.modulestore.get_item(location, depth=None)
descriptor.xmodule_runtime = get_test_system() descriptor.xmodule_runtime = get_test_system()
descriptor.xmodule_runtime.descriptor_runtime = descriptor._runtime # pylint: disable=protected-access
descriptor.xmodule_runtime.get_module = inner_get_module descriptor.xmodule_runtime.get_module = inner_get_module
return descriptor return descriptor
......
...@@ -560,7 +560,7 @@ class XModuleMixin(XBlockMixin): ...@@ -560,7 +560,7 @@ class XModuleMixin(XBlockMixin):
continue continue
if field.scope.user == UserScope.ONE: if field.scope.user == UserScope.ONE:
field._del_cached_value(self) field._del_cached_value(self) # pylint: disable=protected-access
# Set the new xmodule_runtime and field_data (which are user-specific) # Set the new xmodule_runtime and field_data (which are user-specific)
self.xmodule_runtime = xmodule_runtime self.xmodule_runtime = xmodule_runtime
...@@ -644,10 +644,19 @@ class XModule(XModuleMixin, HTMLSnippet, XBlock): # pylint: disable=abstract-me ...@@ -644,10 +644,19 @@ class XModule(XModuleMixin, HTMLSnippet, XBlock): # pylint: disable=abstract-me
# Set the descriptor first so that we can proxy to it # Set the descriptor first so that we can proxy to it
self.descriptor = descriptor self.descriptor = descriptor
super(XModule, self).__init__(*args, **kwargs)
self._loaded_children = None self._loaded_children = None
self._runtime = None
super(XModule, self).__init__(*args, **kwargs)
self.runtime.xmodule_instance = self self.runtime.xmodule_instance = self
@property
def runtime(self):
return CombinedSystem(self._runtime, self.descriptor._runtime) # pylint: disable=protected-access
@runtime.setter
def runtime(self, value): # pylint: disable=arguments-differ
self._runtime = value
def __unicode__(self): def __unicode__(self):
return u'<x_module(id={0})>'.format(self.id) return u'<x_module(id={0})>'.format(self.id)
...@@ -688,26 +697,6 @@ class XModule(XModuleMixin, HTMLSnippet, XBlock): # pylint: disable=abstract-me ...@@ -688,26 +697,6 @@ class XModule(XModuleMixin, HTMLSnippet, XBlock): # pylint: disable=abstract-me
response_data = self.handle_ajax(suffix, request_post) response_data = self.handle_ajax(suffix, request_post)
return Response(response_data, content_type='application/json') return Response(response_data, content_type='application/json')
def get_children(self):
"""
Return module instances for all the children of this module.
"""
if self._loaded_children is None:
child_descriptors = self.get_child_descriptors()
# This deliberately uses system.get_module, rather than runtime.get_block,
# because we're looking at XModule children, rather than XModuleDescriptor children.
# That means it can use the deprecated XModule apis, rather than future XBlock apis
# TODO: Once we're in a system where this returns a mix of XModuleDescriptors
# and XBlocks, we're likely to have to change this more
children = [self.system.get_module(descriptor) for descriptor in child_descriptors]
# get_module returns None if the current user doesn't have access
# to the location.
self._loaded_children = [c for c in children if c is not None]
return self._loaded_children
def get_child_descriptors(self): def get_child_descriptors(self):
""" """
Returns the descriptors of the child modules Returns the descriptors of the child modules
......
...@@ -62,7 +62,6 @@ class FieldDataCache(object): ...@@ -62,7 +62,6 @@ class FieldDataCache(object):
asides: The list of aside types to load, or None to prefetch no asides. asides: The list of aside types to load, or None to prefetch no asides.
''' '''
self.cache = {} self.cache = {}
self.descriptors = descriptors
self.select_for_update = select_for_update self.select_for_update = select_for_update
if asides is None: if asides is None:
...@@ -74,24 +73,27 @@ class FieldDataCache(object): ...@@ -74,24 +73,27 @@ class FieldDataCache(object):
self.course_id = course_id self.course_id = course_id
self.user = user self.user = user
if user.is_authenticated(): self.add_descriptors_to_cache(descriptors)
for scope, fields in self._fields_to_cache().items():
for field_object in self._retrieve_fields(scope, fields): def add_descriptors_to_cache(self, descriptors):
"""
Add all `descriptors` to this FieldDataCache.
"""
if self.user.is_authenticated():
for scope, fields in self._fields_to_cache(descriptors).items():
for field_object in self._retrieve_fields(scope, fields, descriptors):
self.cache[self._cache_key_from_field_object(scope, field_object)] = field_object self.cache[self._cache_key_from_field_object(scope, field_object)] = field_object
@classmethod def add_descriptor_descendents(self, descriptor, depth=None, descriptor_filter=lambda descriptor: True):
def cache_for_descriptor_descendents(cls, course_id, user, descriptor, depth=None,
descriptor_filter=lambda descriptor: True,
select_for_update=False, asides=None):
""" """
course_id: the course in the context of which we want StudentModules. Add all descendents of `descriptor` to this FieldDataCache.
user: the django user for whom to load modules.
descriptor: An XModuleDescriptor Arguments:
depth is the number of levels of descendent modules to load StudentModules for, in addition to descriptor: An XModuleDescriptor
the supplied descriptor. If depth is None, load all descendent StudentModules depth is the number of levels of descendent modules to load StudentModules for, in addition to
descriptor_filter is a function that accepts a descriptor and return wether the StudentModule the supplied descriptor. If depth is None, load all descendent StudentModules
should be cached descriptor_filter is a function that accepts a descriptor and return wether the StudentModule
select_for_update: Flag indicating whether the rows should be locked until end of transaction should be cached
""" """
def get_child_descriptors(descriptor, depth, descriptor_filter): def get_child_descriptors(descriptor, depth, descriptor_filter):
...@@ -120,7 +122,25 @@ class FieldDataCache(object): ...@@ -120,7 +122,25 @@ class FieldDataCache(object):
with modulestore().bulk_operations(descriptor.location.course_key): with modulestore().bulk_operations(descriptor.location.course_key):
descriptors = get_child_descriptors(descriptor, depth, descriptor_filter) descriptors = get_child_descriptors(descriptor, depth, descriptor_filter)
return FieldDataCache(descriptors, course_id, user, select_for_update, asides=asides) self.add_descriptors_to_cache(descriptors)
@classmethod
def cache_for_descriptor_descendents(cls, course_id, user, descriptor, depth=None,
descriptor_filter=lambda descriptor: True,
select_for_update=False, asides=None):
"""
course_id: the course in the context of which we want StudentModules.
user: the django user for whom to load modules.
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
descriptor_filter is a function that accepts a descriptor and return wether the StudentModule
should be cached
select_for_update: Flag indicating whether the rows should be locked until end of transaction
"""
cache = FieldDataCache([], course_id, user, select_for_update, asides=asides)
cache.add_descriptor_descendents(descriptor, depth, descriptor_filter)
return cache
def _query(self, model_class, **kwargs): def _query(self, model_class, **kwargs):
""" """
...@@ -147,14 +167,13 @@ class FieldDataCache(object): ...@@ -147,14 +167,13 @@ class FieldDataCache(object):
) )
return res return res
@property def _all_usage_ids(self, descriptors):
def _all_usage_ids(self):
""" """
Return a set of all usage_ids for the descriptors that this FieldDataCache is caching Return a set of all usage_ids for the descriptors that this FieldDataCache is caching
against, and well as all asides for those descriptors. against, and well as all asides for those descriptors.
""" """
usage_ids = set() usage_ids = set()
for descriptor in self.descriptors: for descriptor in descriptors:
usage_ids.add(descriptor.scope_ids.usage_id) usage_ids.add(descriptor.scope_ids.usage_id)
for aside_type in self.asides: for aside_type in self.asides:
...@@ -162,13 +181,12 @@ class FieldDataCache(object): ...@@ -162,13 +181,12 @@ class FieldDataCache(object):
return usage_ids return usage_ids
@property def _all_block_types(self, descriptors):
def _all_block_types(self):
""" """
Return a set of all block_types that are cached by this FieldDataCache. Return a set of all block_types that are cached by this FieldDataCache.
""" """
block_types = set() block_types = set()
for descriptor in self.descriptors: for descriptor in descriptors:
block_types.add(BlockTypeKeyV1(descriptor.entry_point, descriptor.scope_ids.block_type)) block_types.add(BlockTypeKeyV1(descriptor.entry_point, descriptor.scope_ids.block_type))
for aside_type in self.asides: for aside_type in self.asides:
...@@ -176,7 +194,7 @@ class FieldDataCache(object): ...@@ -176,7 +194,7 @@ class FieldDataCache(object):
return block_types return block_types
def _retrieve_fields(self, scope, fields): def _retrieve_fields(self, scope, fields, descriptors):
""" """
Queries the database for all of the fields in the specified scope Queries the database for all of the fields in the specified scope
""" """
...@@ -184,7 +202,7 @@ class FieldDataCache(object): ...@@ -184,7 +202,7 @@ class FieldDataCache(object):
return self._chunked_query( return self._chunked_query(
StudentModule, StudentModule,
'module_state_key__in', 'module_state_key__in',
self._all_usage_ids, self._all_usage_ids(descriptors),
course_id=self.course_id, course_id=self.course_id,
student=self.user.pk, student=self.user.pk,
) )
...@@ -192,14 +210,14 @@ class FieldDataCache(object): ...@@ -192,14 +210,14 @@ class FieldDataCache(object):
return self._chunked_query( return self._chunked_query(
XModuleUserStateSummaryField, XModuleUserStateSummaryField,
'usage_id__in', 'usage_id__in',
self._all_usage_ids, self._all_usage_ids(descriptors),
field_name__in=set(field.name for field in fields), field_name__in=set(field.name for field in fields),
) )
elif scope == Scope.preferences: elif scope == Scope.preferences:
return self._chunked_query( return self._chunked_query(
XModuleStudentPrefsField, XModuleStudentPrefsField,
'module_type__in', 'module_type__in',
self._all_block_types, self._all_block_types(descriptors),
student=self.user.pk, student=self.user.pk,
field_name__in=set(field.name for field in fields), field_name__in=set(field.name for field in fields),
) )
...@@ -212,12 +230,12 @@ class FieldDataCache(object): ...@@ -212,12 +230,12 @@ class FieldDataCache(object):
else: else:
return [] return []
def _fields_to_cache(self): def _fields_to_cache(self, descriptors):
""" """
Returns a map of scopes to fields in that scope that should be cached Returns a map of scopes to fields in that scope that should be cached
""" """
scope_map = defaultdict(set) scope_map = defaultdict(set)
for descriptor in self.descriptors: for descriptor in descriptors:
for field in descriptor.fields.values(): for field in descriptor.fields.values():
scope_map[field.scope].add(field) scope_map[field.scope].add(field)
return scope_map return scope_map
......
...@@ -489,8 +489,8 @@ def _index_bulk_op(request, course_key, chapter, section, position): ...@@ -489,8 +489,8 @@ def _index_bulk_op(request, course_key, chapter, section, position):
# Load all descendants of the section, because we're going to display its # Load all descendants of the section, because we're going to display its
# html, which in general will need all of its children # html, which in general will need all of its children
section_field_data_cache = FieldDataCache.cache_for_descriptor_descendents( field_data_cache.add_descriptor_descendents(
course_key, user, section_descriptor, depth=None, asides=XBlockAsidesConfig.possible_asides() section_descriptor, depth=None
) )
# Verify that position a string is in fact an int # Verify that position a string is in fact an int
...@@ -504,7 +504,7 @@ def _index_bulk_op(request, course_key, chapter, section, position): ...@@ -504,7 +504,7 @@ def _index_bulk_op(request, course_key, chapter, section, position):
request.user, request.user,
request, request,
section_descriptor, section_descriptor,
section_field_data_cache, field_data_cache,
course_key, course_key,
position position
) )
......
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