diff --git a/courseware/content_parser.py b/courseware/content_parser.py index 07ad98a64b..0954f60489 100644 --- a/courseware/content_parser.py +++ b/courseware/content_parser.py @@ -168,17 +168,23 @@ def course_xml_process(tree): return tree def course_file(user): - ''' Given a user, return course.xml - ''' - # TODO: Cache. + ''' Given a user, return course.xml''' filename = user.profile_cache.courseware # UserProfile.objects.get(user=user).courseware - groups = user_groups(user) - options = {'dev_content':settings.DEV_CONTENT, 'groups' : groups} - tree = course_xml_process(etree.XML(render_to_string(filename, options, namespace = 'course'))) + + cache_key = filename + "_processed?dev_content:" + str(options['dev_content']) + "&groups:" + str(sorted(groups)) + tree_string = cache.get(cache_key) + if not tree_string: + tree = course_xml_process(etree.XML(render_to_string(filename, options, namespace = 'course'))) + tree_string = etree.tostring(tree) + + cache.set(cache_key, tree_string, 60) + else: + tree = etree.XML(tree_string) + return tree def section_file(user, section): diff --git a/courseware/models.py b/courseware/models.py index 3fdaabe4d8..24c212366a 100644 --- a/courseware/models.py +++ b/courseware/models.py @@ -8,12 +8,19 @@ file and check it in at the same time as your model changes. To do that, 2. ./manage.py schemamigration courseware --auto description_of_your_change 3. Add the migration file created in mitx/courseware/migrations/ + +ASSUMPTIONS: modules have unique IDs, even across different module_types + """ from django.db import models +from django.db.models.signals import post_save, post_delete +from django.core.cache import cache from django.contrib.auth.models import User from cache_toolbox import cache_model, cache_relation +CACHE_TIMEOUT = 60 * 60 * 4 # Set the cache timeout to be four hours + class StudentModule(models.Model): # For a homework problem, contains a JSON # object consisting of state @@ -51,5 +58,35 @@ class StudentModule(models.Model): def __unicode__(self): return self.module_type+'/'+self.student.username+"/"+self.module_id+'/'+str(self.state)[:20] + @classmethod + def get_with_caching(cls, student, module_id): + k = cls.key_for(student, module_id) + student_module = cache.get(k) + if student_module is None: + student_module = StudentModule.objects.filter(student=student, + module_id=module_id)[0] + # It's possible it really doesn't exist... + if student_module is not None: + cache.set(k, student_module, CACHE_TIMEOUT) + + return student_module + + @classmethod + def key_for(cls, student, module_id): + return "StudentModule-student_id:{0};module_id:{1}".format(student.id, module_id) + + +def clear_cache_by_student_and_module_id(sender, instance, *args, **kwargs): + k = sender.key_for(instance.student, instance.module_id) + cache.delete(k) + +def update_cache_by_student_and_module_id(sender, instance, *args, **kwargs): + k = sender.key_for(instance.student, instance.module_id) + cache.set(k, instance, CACHE_TIMEOUT) + + +post_save.connect(update_cache_by_student_and_module_id, sender=StudentModule, weak=False) +post_delete.connect(clear_cache_by_student_and_module_id, sender=StudentModule, weak=False) + +cache_model(StudentModule) -cache_model(StudentModule) \ No newline at end of file diff --git a/courseware/module_render.py b/courseware/module_render.py index 99e13031af..59660ad687 100644 --- a/courseware/module_render.py +++ b/courseware/module_render.py @@ -48,13 +48,13 @@ def make_track_function(request): def modx_dispatch(request, module=None, dispatch=None, id=None): ''' Generic view for extensions. ''' # Grab the student information for the module from the database - s = StudentModule.objects.filter(student=request.user, - module_id=id) - if len(s) == 0: + #s = StudentModule.objects.filter(student=request.user, + # module_id=id) + s = StudentModule.get_with_caching(request.user, id) + if s is None: log.debug("Couldnt find module for user and id " + str(module) + " " + str(request.user) + " "+ str(id)) raise Http404 - s=s[0] oldgrade = s.grade oldstate = s.state