Commit 6d650d18 by Bridger Maxwell

Got the gradebook working again with the new fast grading method.

parent 694520eb
...@@ -52,6 +52,7 @@ def certificate_request(request): ...@@ -52,6 +52,7 @@ def certificate_request(request):
return return_error(survey_response['error']) return return_error(survey_response['error'])
grade = None grade = None
# TODO: (bridger) Update this to use the faster grade instead of grade_sheet
student_gradesheet = grades.grade_sheet(request.user) student_gradesheet = grades.grade_sheet(request.user)
grade = student_gradesheet['grade'] grade = student_gradesheet['grade']
...@@ -65,6 +66,7 @@ def certificate_request(request): ...@@ -65,6 +66,7 @@ def certificate_request(request):
else: else:
#This is not a POST, we should render the page with the form #This is not a POST, we should render the page with the form
# TODO: (bridger) Update this to use the faster grade instead of grade_sheet
grade_sheet = grades.grade_sheet(request.user) grade_sheet = grades.grade_sheet(request.user)
certificate_state = certificate_state_for_student(request.user, grade_sheet['grade']) certificate_state = certificate_state_for_student(request.user, grade_sheet['grade'])
......
...@@ -30,6 +30,7 @@ def get_graded_sections(course_descriptor): ...@@ -30,6 +30,7 @@ def get_graded_sections(course_descriptor):
xmoduledescriptors = [] xmoduledescriptors = []
for module in yield_descriptor_descendents(s): for module in yield_descriptor_descendents(s):
# TODO: Only include modules that have a score here
xmoduledescriptors.append(module) xmoduledescriptors.append(module)
section_description = { 'section_descriptor' : s, 'xmoduledescriptors' : xmoduledescriptors} section_description = { 'section_descriptor' : s, 'xmoduledescriptors' : xmoduledescriptors}
...@@ -73,19 +74,20 @@ def fast_grade(student, request, course_graded_sections, grader, student_module_ ...@@ -73,19 +74,20 @@ def fast_grade(student, request, course_graded_sections, grader, student_module_
scores = [] scores = []
section_module = get_module(student, request, section_descriptor.location, student_module_cache) section_module = get_module(student, request, section_descriptor.location, student_module_cache)
for module in yield_descriptor_descendents(section_module): # TODO: We may be able to speed this up by only getting a list of children IDs from section_module
# Then, we may not need to instatiate any problems if they are already in the database
for module in yield_module_descendents(section_module):
(correct, total) = get_score(student, module, student_module_cache) (correct, total) = get_score(student, module, student_module_cache)
graded = module.metadata.get("graded", False)
if correct is None and total is None: if correct is None and total is None:
continue continue
if settings.GENERATE_PROFILE_SCORES: if settings.GENERATE_PROFILE_SCORES:
if total > 1: if total > 1:
correct = random.randrange(max(total - 2, 1), total + 1) correct = random.randrange(max(total - 2, 1), total + 1)
else: else:
correct = total correct = total
graded = module.metadata.get("graded", False)
if not total > 0: if not total > 0:
#We simply cannot grade a problem that is 12/0, because we might need it as a percentage #We simply cannot grade a problem that is 12/0, because we might need it as a percentage
graded = False graded = False
...@@ -110,20 +112,18 @@ def fast_grade(student, request, course_graded_sections, grader, student_module_ ...@@ -110,20 +112,18 @@ def fast_grade(student, request, course_graded_sections, grader, student_module_
def grade_sheet(student, course, grader, student_module_cache): def grade_sheet(student, course, grader, student_module_cache):
""" """
This pulls a summary of all problems in the course. It returns a dictionary with two datastructures: This pulls a summary of all problems in the course.
Returns
- courseware_summary is a summary of all sections with problems in the course. It is organized as an array of chapters, - courseware_summary is a summary of all sections with problems in the course. It is organized as an array of chapters,
each containing an array of sections, each containing an array of scores. This contains information for graded and ungraded each containing an array of sections, each containing an array of scores. This contains information for graded and ungraded
problems, and is good for displaying a course summary with due dates, etc. problems, and is good for displaying a course summary with due dates, etc.
- grade_summary is the output from the course grader. More information on the format is in the docstring for CourseGrader.
Arguments: Arguments:
student: A User object for the student to grade student: A User object for the student to grade
course: An XModule containing the course to grade course: An XModule containing the course to grade
student_module_cache: A StudentModuleCache initialized with all instance_modules for the student student_module_cache: A StudentModuleCache initialized with all instance_modules for the student
""" """
totaled_scores = {}
chapters = [] chapters = []
for c in course.get_children(): for c in course.get_children():
sections = [] sections = []
...@@ -132,30 +132,13 @@ def grade_sheet(student, course, grader, student_module_cache): ...@@ -132,30 +132,13 @@ def grade_sheet(student, course, grader, student_module_cache):
scores = [] scores = []
for module in yield_module_descendents(s): for module in yield_module_descendents(s):
(correct, total) = get_score(student, module, student_module_cache) (correct, total) = get_score(student, module, student_module_cache)
if correct is None and total is None: if correct is None and total is None:
continue continue
if settings.GENERATE_PROFILE_SCORES:
if total > 1:
correct = random.randrange(max(total - 2, 1), total + 1)
else:
correct = total
if not total > 0:
#We simply cannot grade a problem that is 12/0, because we might need it as a percentage
graded = False
scores.append(Score(correct, total, graded, module.metadata.get('display_name'))) scores.append(Score(correct, total, graded, module.metadata.get('display_name')))
section_total, graded_total = graders.aggregate_scores(scores, s.metadata.get('display_name')) section_total, graded_total = graders.aggregate_scores(scores, s.metadata.get('display_name'))
#Add the graded total to totaled_scores
format = s.metadata.get('format', "") format = s.metadata.get('format', "")
if format and graded_total.possible > 0:
format_scores = totaled_scores.get(format, [])
format_scores.append(graded_total)
totaled_scores[format] = format_scores
sections.append({ sections.append({
'section': s.metadata.get('display_name'), 'section': s.metadata.get('display_name'),
'scores': scores, 'scores': scores,
...@@ -169,10 +152,7 @@ def grade_sheet(student, course, grader, student_module_cache): ...@@ -169,10 +152,7 @@ def grade_sheet(student, course, grader, student_module_cache):
'chapter': c.metadata.get('display_name'), 'chapter': c.metadata.get('display_name'),
'sections': sections}) 'sections': sections})
grade_summary = grader.grade(totaled_scores) return chapters
return {'courseware_summary': chapters,
'grade_summary': grade_summary}
def get_score(user, problem, student_module_cache): def get_score(user, problem, student_module_cache):
......
...@@ -86,18 +86,20 @@ def gradebook(request, course_id): ...@@ -86,18 +86,20 @@ def gradebook(request, course_id):
if 'course_admin' not in user_groups(request.user): if 'course_admin' not in user_groups(request.user):
raise Http404 raise Http404
course = check_course(course_id) course = check_course(course_id)
sections, all_descriptors = grades.get_graded_sections(course)
student_objects = User.objects.all()[:100] student_objects = User.objects.all()[:100]
student_info = [] student_info = []
for student in student_objects: for student in student_objects:
student_module_cache = StudentModuleCache(student, course) student_module_cache = StudentModuleCache(student, descriptors=all_descriptors)
course = get_module(request.user, request, course.location, student_module_cache)
student_info.append({ student_info.append({
'username': student.username, 'username': student.username,
'id': student.id, 'id': student.id,
'email': student.email, 'email': student.email,
'grade_info': grades.grade_sheet(student, course, student_module_cache), 'grade_summary': grades.fast_grade(student, request, sections, course.grader, student_module_cache),
'realname': UserProfile.objects.get(user=student).name 'realname': UserProfile.objects.get(user=student).name
}) })
...@@ -123,16 +125,21 @@ def profile(request, course_id, student_id=None): ...@@ -123,16 +125,21 @@ def profile(request, course_id, student_id=None):
student_module_cache = StudentModuleCache(request.user, course) student_module_cache = StudentModuleCache(request.user, course)
course_module = get_module(request.user, request, course.location, student_module_cache) course_module = get_module(request.user, request, course.location, student_module_cache)
courseware_summary = grades.grade_sheet(student, course_module, course.grader, student_module_cache)
sections, _ = grades.get_graded_sections(course)
grade_summary = grades.fast_grade(request.user, request, sections, course.grader, student_module_cache)
context = {'name': user_info.name, context = {'name': user_info.name,
'username': student.username, 'username': student.username,
'location': user_info.location, 'location': user_info.location,
'language': user_info.language, 'language': user_info.language,
'email': student.email, 'email': student.email,
'course': course, 'course': course,
'format_url_params': format_url_params, 'csrf': csrf(request)['csrf_token'],
'csrf': csrf(request)['csrf_token'] 'courseware_summary' : courseware_summary,
'grade_summary' : grade_summary
} }
context.update(grades.grade_sheet(student, course_module, course.grader, student_module_cache)) context.update()
return render_to_response('profile.html', context) return render_to_response('profile.html', context)
...@@ -157,6 +164,7 @@ def render_accordion(request, course, chapter, section): ...@@ -157,6 +164,7 @@ def render_accordion(request, course, chapter, section):
('toc', toc), ('toc', toc),
('course_name', course.title), ('course_name', course.title),
('course_id', course.id), ('course_id', course.id),
#TODO: Do we need format_url_params anymore? What is a better way to create the reversed links?
('format_url_params', format_url_params), ('format_url_params', format_url_params),
('csrf', csrf(request)['csrf_token'])] + template_imports.items()) ('csrf', csrf(request)['csrf_token'])] + template_imports.items())
return render_to_string('accordion.html', context) return render_to_string('accordion.html', context)
......
...@@ -41,7 +41,7 @@ PERFSTATS = False ...@@ -41,7 +41,7 @@ PERFSTATS = False
MITX_FEATURES = { MITX_FEATURES = {
'SAMPLE' : False, 'SAMPLE' : False,
'USE_DJANGO_PIPELINE' : True, 'USE_DJANGO_PIPELINE' : True,
'DISPLAY_HISTOGRAMS_TO_STAFF' : True, 'DISPLAY_HISTOGRAMS_TO_STAFF' : False,
'REROUTE_ACTIVATION_EMAIL' : False, # nonempty string = address for all activation emails 'REROUTE_ACTIVATION_EMAIL' : False, # nonempty string = address for all activation emails
'DEBUG_LEVEL' : 0, # 0 = lowest level, least verbose, 255 = max level, most verbose 'DEBUG_LEVEL' : 0, # 0 = lowest level, least verbose, 255 = max level, most verbose
......
...@@ -65,5 +65,7 @@ DEBUG_TOOLBAR_PANELS = ( ...@@ -65,5 +65,7 @@ DEBUG_TOOLBAR_PANELS = (
# Django=1.3.1/1.4 where requests to views get duplicated (your method gets # Django=1.3.1/1.4 where requests to views get duplicated (your method gets
# hit twice). So you can uncomment when you need to diagnose performance # hit twice). So you can uncomment when you need to diagnose performance
# problems, but you shouldn't leave it on. # problems, but you shouldn't leave it on.
# 'debug_toolbar.panels.profiling.ProfilingDebugPanel', 'debug_toolbar.panels.profiling.ProfilingDebugPanel',
) )
#PIPELINE = True
...@@ -28,7 +28,7 @@ ...@@ -28,7 +28,7 @@
%if len(students) > 0: %if len(students) > 0:
<table> <table>
<% <%
templateSummary = students[0]['grade_info']['grade_summary'] templateSummary = students[0]['grade_summary']
%> %>
...@@ -58,10 +58,10 @@ ...@@ -58,10 +58,10 @@
%for student in students: %for student in students:
<tr> <tr>
<td><a href="/profile/${student['id']}/">${student['username']}</a></td> <td><a href="/profile/${student['id']}/">${student['username']}</a></td>
%for section in student['grade_info']['grade_summary']['section_breakdown']: %for section in student['grade_summary']['section_breakdown']:
${percent_data( section['percent'] )} ${percent_data( section['percent'] )}
%endfor %endfor
<th>${percent_data( student['grade_info']['grade_summary']['percent'])}</th> <th>${percent_data( student['grade_summary']['percent'])}</th>
</tr> </tr>
%endfor %endfor
</table> </table>
......
...@@ -105,7 +105,6 @@ if settings.COURSEWARE_ENABLED: ...@@ -105,7 +105,6 @@ if settings.COURSEWARE_ENABLED:
# TODO: These views need to be updated before they work # TODO: These views need to be updated before they work
# url(r'^calculate$', 'util.views.calculate'), # url(r'^calculate$', 'util.views.calculate'),
# url(r'^gradebook$', 'courseware.views.gradebook'),
# TODO: We should probably remove the circuit package. I believe it was only used in the old way of saving wiki circuits for the wiki # TODO: We should probably remove the circuit package. I believe it was only used in the old way of saving wiki circuits for the wiki
# url(r'^edit_circuit/(?P<circuit>[^/]*)$', 'circuit.views.edit_circuit'), # url(r'^edit_circuit/(?P<circuit>[^/]*)$', 'circuit.views.edit_circuit'),
# url(r'^save_circuit/(?P<circuit>[^/]*)$', 'circuit.views.save_circuit'), # url(r'^save_circuit/(?P<circuit>[^/]*)$', 'circuit.views.save_circuit'),
...@@ -139,6 +138,10 @@ if settings.COURSEWARE_ENABLED: ...@@ -139,6 +138,10 @@ if settings.COURSEWARE_ENABLED:
'courseware.views.profile', name="profile"), 'courseware.views.profile', name="profile"),
url(r'^courses/(?P<course_id>[^/]+/[^/]+/[^/]+)/profile/(?P<student_id>[^/]*)/$', url(r'^courses/(?P<course_id>[^/]+/[^/]+/[^/]+)/profile/(?P<student_id>[^/]*)/$',
'courseware.views.profile'), 'courseware.views.profile'),
# For the instructor
url(r'^courses/(?P<course_id>[^/]+/[^/]+/[^/]+)/gradebook$',
'courseware.views.gradebook'),
) )
# Multicourse wiki # Multicourse wiki
......
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