Commit 4442754a by Piotr Mitros

Redundant DB queries eliminated. We're at about 5 hits per sequence w/o Askbot, and 10 with

parent 98e9d96c
......@@ -45,15 +45,25 @@ class StudentModule(models.Model):
('video','video'),
('html','html'),
)
## These three are the key for the object
module_type = models.CharField(max_length=32, choices=MODULE_TYPES, default='problem')
module_id = models.CharField(max_length=255) # Filename for homeworks, etc.
student = models.ForeignKey(User)
class Meta:
unique_together = (('student', 'module_id', 'module_type'),)
## Internal state of the object
state = models.TextField(null=True, blank=True)
## Grade, and are we done?
grade = models.FloatField(null=True, blank=True)
#max_grade = models.FloatField(null=True, blank=True)
# DONE_TYPES = (('done','DONE'), # Finished
# ('incomplete','NOTDONE'), # Not finished
# ('na','NA')) # Not applicable (e.g. vertical)
# done = models.CharField(max_length=16, choices=DONE_TYPES)
created = models.DateTimeField(auto_now_add=True)
modified = models.DateTimeField(auto_now=True)
......
......@@ -4,6 +4,7 @@ from djangomako.shortcuts import render_to_response, render_to_string
import json, os, sys
from django.core.context_processors import csrf
from django.db import connection
from django.template import Context
from django.contrib.auth.models import User
from auth.models import UserProfile
......@@ -44,6 +45,16 @@ modx_modules={'problem':courseware.modules.capa_module.LoncapaModule,
'sequential':courseware.modules.seq_module.SequentialModule,
'schematic':courseware.modules.schematic_module.SchematicModule}
def object_cache(cache, user, module_type, module_id):
# We don't look up on user -- all queries include user
# Additional lookup would require a DB hit the way Django
# is broken.
for o in cache:
if o.module_type == module_type and \
o.module_id == module_id:
return o
return None
def make_track_function(request):
def f(event_type, event):
return track.views.server_track(request, event_type, event, page='x_module')
......@@ -52,7 +63,6 @@ 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
print module, request.user, id
s = StudentModule.objects.filter(module_type=module,
student=request.user,
module_id=id)
......@@ -77,8 +87,7 @@ def modx_dispatch(request, module=None, dispatch=None, id=None):
ajax_url=ajax_url,
state=s.state,
track_function = make_track_function(request),
render_function = render_module,
meta = request)
render_function = None)
# Let the module handle the AJAX
ajax_return=instance.handle_ajax(dispatch, request.POST)
# Save the state back to the database
......@@ -89,7 +98,7 @@ def modx_dispatch(request, module=None, dispatch=None, id=None):
# Return whatever the module wanted to return to the client/caller
return HttpResponse(ajax_return)
def render_x_module(request, xml_module):
def render_x_module(user, request, xml_module, module_object_preload):
''' Generic module for extensions. This renders to HTML. '''
# Check if problem has an instance in DB
module_type=xml_module.tag
......@@ -97,13 +106,16 @@ def render_x_module(request, xml_module):
module_id=xml_module.get('id') #module_class.id_attribute) or ""
# Grab state from database
s = StudentModule.objects.filter(student=request.user,
module_id=module_id,
module_type = module_type)
if len(s) == 0: # If nothing in the database...
s = object_cache(module_object_preload,
user,
module_type,
module_id)#student=request.user,
#module_id=module_id,
#module_type = module_type)
if s == None: # If nothing in the database...
state=None
else:
smod = s[0]
smod = s
state = smod.state
# Create a new instance
......@@ -113,27 +125,25 @@ def render_x_module(request, xml_module):
ajax_url=ajax_url,
state=state,
track_function = make_track_function(request),
render_function = render_module,
meta = request)
render_function = lambda x: render_module(user, request, x, module_object_preload))
# If instance wasn't already in the database, create it
if len(s) == 0:
smod=StudentModule(student=request.user,
if s == None:
smod=StudentModule(student=user,
module_type = module_type,
module_id=module_id,
state=instance.get_state())
smod.save() # This may be optional (at least in the case of no instance in the dB)
# Grab content
content = {'content':instance.get_html(),
"destroy_js":instance.get_destroy_js(),
'init_js':instance.get_init_js(),
'type':module_type}
smod.save() # This may be optional (at least in the case of no instance in the dB)
return content
def render_module(request, module):
def render_module(user, request, module, module_object_preload):
''' Generic dispatch for internal modules. '''
if module==None :
return {"content":""}
return render_x_module(request, module)
return render_x_module(user, request, module, module_object_preload)
......@@ -25,7 +25,7 @@ class HtmlModule(XModule):
textlist=[i for i in textlist if type(i)==str]
return "".join(textlist)
def __init__(self, xml, item_id, ajax_url=None, track_url=None, state=None, track_function=None, render_function = None, meta = None):
def __init__(self, xml, item_id, ajax_url=None, track_url=None, state=None, track_function=None, render_function = None):
XModule.__init__(self, xml, item_id, ajax_url, track_url, state, track_function, render_function)
xmltree=etree.fromstring(xml)
self.filename = None
......
......@@ -18,6 +18,6 @@ class SchematicModule(XModule):
def get_html(self):
return '<input type="hidden" class="schematic" name="{item_id}" height="480" width="640">'.format(item_id=self.item_id)
def __init__(self, xml, item_id, ajax_url=None, track_url=None, state=None, render_function = None, meta = None):
def __init__(self, xml, item_id, ajax_url=None, track_url=None, state=None, render_function = None):
XModule.__init__(self, xml, item_id, ajax_url, track_url, state, render_function)
......@@ -36,7 +36,7 @@ class SequentialModule(XModule):
return json.dumps({'success':True})
raise Http404()
def __init__(self, xml, item_id, ajax_url=None, track_url=None, state=None, track_function=None, render_function = None, meta = None):
def __init__(self, xml, item_id, ajax_url=None, track_url=None, state=None, track_function=None, render_function = None):
XModule.__init__(self, xml, item_id, ajax_url, track_url, state, track_function, render_function)
xmltree=etree.fromstring(xml)
......@@ -60,7 +60,7 @@ class SequentialModule(XModule):
'init_js':m['init_js'],
'type':m['type']}
contents=[(e.get("name"),j(render_function(meta, e))) \
contents=[(e.get("name"),j(render_function(e))) \
for e in xmltree]
js=""
......
......@@ -25,10 +25,10 @@ class VerticalModule(XModule):
def get_destroy_js(self):
return self.destroy_js_text
def __init__(self, xml, item_id, ajax_url=None, track_url=None, state=None, track_function=None, render_function = None, meta = None):
def __init__(self, xml, item_id, ajax_url=None, track_url=None, state=None, track_function=None, render_function = None):
XModule.__init__(self, xml, item_id, ajax_url, track_url, state, track_function, render_function)
xmltree=etree.fromstring(xml)
self.contents=[(e.get("name"),self.render_function(meta, e)) \
self.contents=[(e.get("name"),self.render_function(e)) \
for e in xmltree]
self.init_js_text="".join([e[1]['init_js'] for e in self.contents if 'init_js' in e[1]])
self.destroy_js_text="".join([e[1]['destroy_js'] for e in self.contents if 'destroy_js' in e[1]])
......@@ -51,7 +51,7 @@ class VideoModule(XModule):
def get_destroy_js(self):
return "videoDestroy(\""+self.item_id+"\");"
def __init__(self, xml, item_id, ajax_url=None, track_url=None, state=None, track_function=None, render_function = None, meta = None):
def __init__(self, xml, item_id, ajax_url=None, track_url=None, state=None, track_function=None, render_function = None):
XModule.__init__(self, xml, item_id, ajax_url, track_url, state, track_function, render_function)
self.youtube = etree.XML(xml).get('youtube')
self.position = 0
......
......@@ -39,7 +39,7 @@ class XModule(object):
get is a dictionary-like object '''
return ""
def __init__(self, xml, item_id, ajax_url=None, track_url=None, state=None, track_function=None, render_function = None, meta = None):
def __init__(self, xml, item_id, ajax_url=None, track_url=None, state=None, track_function=None, render_function = None):
''' In most cases, you must pass state or xml'''
self.xml = xml
self.item_id = item_id
......@@ -48,4 +48,4 @@ class XModule(object):
self.state = state
self.tracker = track_function
self.render_function = render_function
self.meta = meta
......@@ -13,6 +13,8 @@ from django.http import HttpResponse, Http404
from django.shortcuts import redirect
from django.template import Context, loader
from djangomako.shortcuts import render_to_response, render_to_string
from django.db import connection
from lxml import etree
from auth.models import UserProfile
......@@ -105,7 +107,8 @@ def render_accordion(request,course,chapter,section):
def index(request, course="6.002 Spring 2012", chapter="Using the System", section="Hints"):
''' Displays courseware accordion, and any associated content.
'''
if not settings.COURSEWARE_ENABLED or not request.user.is_authenticated():
user = request.user
if not settings.COURSEWARE_ENABLED or not user.is_authenticated():
return redirect('/')
# Fixes URLs -- we don't get funny encoding characters from spaces
......@@ -120,7 +123,7 @@ def index(request, course="6.002 Spring 2012", chapter="Using the System", secti
if course!="6.002 Spring 2012":
return redirect('/')
dom = content_parser.course_file(request.user)
dom = content_parser.course_file(user)
dom_module = dom.xpath("//course[@name=$course]/chapter[@name=$chapter]//section[@name=$section]/*[1]",
course=course, chapter=chapter, section=section)
if len(dom_module) == 0:
......@@ -130,17 +133,21 @@ def index(request, course="6.002 Spring 2012", chapter="Using the System", secti
accordion=render_accordion(request, course, chapter, section)
module=render_module(request, module)
module_ids = dom.xpath("//course[@name=$course]/chapter[@name=$chapter]//section[@name=$section]//@id",
course=course, chapter=chapter, section=section)
module_object_preload = StudentModule.objects.filter(student=user,
module_id__in=module_ids)
module=render_module(user, request, module, module_object_preload)
if 'init_js' not in module:
module['init_js']=''
context={'init':accordion['init_js']+module['init_js'],
'accordion':accordion['content'],
'content':module['content'],
'csrf':csrf(request)['csrf_token']}
return render_to_response('courseware.html', context)
result = render_to_response('courseware.html', context)
return result
ASKBOT_ENABLED = False
execfile("settings.py")
execfile("settings_old_askbot.py")
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