def spoc_gradebook(request, course_id): """ Show the gradebook for this course: - Only shown for courses with enrollment < settings.FEATURES.get("MAX_ENROLLMENT_INSTR_BUTTONS") - Only displayed to course staff """ course_key = SlashSeparatedCourseKey.from_deprecated_string(course_id) course = get_course_with_access(request.user, 'staff', course_key, depth=None) enrolled_students = User.objects.filter( courseenrollment__course_id=course_key, courseenrollment__is_active=1 ).order_by('username').select_related("profile") # possible extension: implement pagination to show to large courses student_info = [ { 'username': student.username, 'id': student.id, 'email': student.email, 'grade_summary': student_grades(student, request, course), 'realname': student.profile.name, } for student in enrolled_students ] return render_to_response('courseware/gradebook.html', { 'students': student_info, 'course': course, 'course_id': course_key, # Checked above 'staff_access': True, 'ordered_grades': sorted(course.grade_cutoffs.items(), key=lambda i: i[1], reverse=True), })
def get_grade_book_page(request, course, course_key): """ Get student records per page along with page information i.e current page, total pages and offset information. """ # Unsanitized offset current_offset = request.GET.get('offset', 0) enrolled_students = User.objects.filter( courseenrollment__course_id=course_key, courseenrollment__is_active=1 ).order_by('username').select_related("profile") total_students = enrolled_students.count() page = calculate_page_info(current_offset, total_students) offset = page["offset"] total_pages = page["total_pages"] if total_pages > 1: # Apply limit on queryset only if total number of students are greater then MAX_STUDENTS_PER_PAGE_GRADE_BOOK. enrolled_students = enrolled_students[offset: offset + MAX_STUDENTS_PER_PAGE_GRADE_BOOK] student_info = [ { 'username': student.username, 'id': student.id, 'email': student.email, 'grade_summary': student_grades(student, request, course), 'realname': student.profile.name, } for student in enrolled_students ] return student_info, page
def ccx_gradebook(request, course, ccx=None): """ Show the gradebook for this CCX. """ if not ccx: raise Http404 ccx_key = CCXLocator.from_course_locator(course.id, ccx.id) with ccx_course(ccx_key) as course: prep_course_for_grading(course, request) enrolled_students = User.objects.filter( courseenrollment__course_id=ccx_key, courseenrollment__is_active=1 ).order_by('username').select_related("profile") student_info = [ { 'username': student.username, 'id': student.id, 'email': student.email, 'grade_summary': student_grades(student, request, course), 'realname': student.profile.name, } for student in enrolled_students ] return render_to_response('courseware/gradebook.html', { 'students': student_info, 'course': course, 'course_id': course.id, 'staff_access': request.user.is_staff, 'ordered_grades': sorted( course.grade_cutoffs.items(), key=lambda i: i[1], reverse=True), })
def grade(request, course_id): """ Show the gradebook for this course: - Only shown for courses with enrollment < settings.FEATURES.get("MAX_ENROLLMENT_INSTR_BUTTONS") - Only displayed to course staff """ course_key = SlashSeparatedCourseKey.from_deprecated_string(course_id) course = get_course_with_access(request.user, 'staff', course_key, depth=None) enrolled_students = User.objects.filter( courseenrollment__course_id=course_key, courseenrollment__is_active=1 ).order_by('username').select_related("profile") grading_filter = Grading.objects.filter( course_id=course_id ) grading = [ { 'problem_number': grade.problem_number, 'deadline': grade.deadline, 'min_grade': grade.min_grade } for grade in grading_filter ] # possible extension: implement pagination to show to large courses print course.grader.sections[0][0].short_label student_info = [ { 'username': enrolled_students[0].username, 'id': enrolled_students[0].id, 'email': enrolled_students[0].email, 'grade_summary': student_grades(enrolled_students[0], request, course), 'realname': enrolled_students[0].profile.name, } #for student in enrolled_students ] print student_info[0]['grade_summary']['section_breakdown'][0]['detail'].split(' - ')[2] return render_to_response('easyGradebook.html', { 'url': request.path, 'students': student_info, 'course': course, 'course_id': course_key, 'course_raw_id':course_id, 'grading': grading, # Checked above 'staff_access': True, 'ordered_grades': sorted(course.grade_cutoffs.items(), key=lambda i: i[1], reverse=True), })
def ccx_gradebook(request, course): """ Show the gradebook for this CCX. """ # Need course module for overrides to function properly field_data_cache = FieldDataCache.cache_for_descriptor_descendents( course.id, request.user, course, depth=2) course = get_module_for_descriptor(request.user, request, course, field_data_cache, course.id) ccx = get_ccx_for_coach(course, request.user) with ccx_context(ccx): # The grading policy for the MOOC is probably already cached. We need # to make sure we have the CCX grading policy loaded. course._field_data_cache = {} # pylint: disable=protected-access course.set_grading_policy(course.grading_policy) enrolled_students = User.objects.filter( ccxmembership__ccx=ccx, ccxmembership__active=1).order_by( 'username').select_related("profile") student_info = [{ 'username': student.username, 'id': student.id, 'email': student.email, 'grade_summary': student_grades(student, request, course), 'realname': student.profile.name, } for student in enrolled_students] return render_to_response( 'courseware/gradebook.html', { 'students': student_info, 'course': course, 'course_id': course.id, 'staff_access': request.user.is_staff, 'ordered_grades': sorted(course.grade_cutoffs.items(), key=lambda i: i[1], reverse=True), })
def get(self, request, **kwargs): username = self.kwargs.get('username') enrolled_students = CourseEnrollment.objects.users_enrolled_in(self.course_key).filter(username=username) course = courses.get_course(self.course_key) student_info = [ { 'username': student.username, 'id': student.id, 'email': student.email, 'grade_summary': student_grades(student, request, course), 'realname': student.profile.name, } for student in enrolled_students ] return Response(student_info)
def get(self, request, **kwargs): username = self.kwargs.get('username') enrolled_students = CourseEnrollment.objects.users_enrolled_in( self.course_key).filter(username=username) course = courses.get_course(self.course_key) student_info = [{ 'username': student.username, 'id': student.id, 'email': student.email, 'grade_summary': student_grades(student, request, course), 'realname': student.profile.name, } for student in enrolled_students] return Response(student_info)
def ccx_gradebook(request, course): """ Show the gradebook for this CCX. """ # Need course module for overrides to function properly field_data_cache = FieldDataCache.cache_for_descriptor_descendents(course.id, request.user, course, depth=2) course = get_module_for_descriptor(request.user, request, course, field_data_cache, course.id) ccx = get_ccx_for_coach(course, request.user) with ccx_context(ccx): # The grading policy for the MOOC is probably already cached. We need # to make sure we have the CCX grading policy loaded. course._field_data_cache = {} # pylint: disable=protected-access course.set_grading_policy(course.grading_policy) enrolled_students = ( User.objects.filter(ccxmembership__ccx=ccx, ccxmembership__active=1) .order_by("username") .select_related("profile") ) student_info = [ { "username": student.username, "id": student.id, "email": student.email, "grade_summary": student_grades(student, request, course), "realname": student.profile.name, } for student in enrolled_students ] return render_to_response( "courseware/gradebook.html", { "students": student_info, "course": course, "course_id": course.id, "staff_access": request.user.is_staff, "ordered_grades": sorted(course.grade_cutoffs.items(), key=lambda i: i[1], reverse=True), }, )
def get(self, request, **kwargs): username = self.kwargs.get('username') enrolled_students = CourseEnrollment.objects.users_enrolled_in(self.course_key).filter(username=username) course = courses.get_course(self.course_key) if not enrolled_students: return Response({ "error_description": "User is not enrolled for the course", "error": "invalid_request" }) student_info = [ { 'username': student.username, 'id': student.id, 'email': student.email, 'grade_summary': student_grades(student, request, course), 'realname': student.profile.name, } for student in enrolled_students ] return Response(student_info)
def ccx_gradebook(request, course, ccx=None): """ Show the gradebook for this CCX. """ if not ccx: raise Http404 ccx_key = CCXLocator.from_course_locator(course.id, ccx.id) with ccx_course(ccx_key) as course: prep_course_for_grading(course, request) enrolled_students = ( User.objects.filter(courseenrollment__course_id=ccx_key, courseenrollment__is_active=1) .order_by("username") .select_related("profile") ) student_info = [ { "username": student.username, "id": student.id, "email": student.email, "grade_summary": student_grades(student, request, course), "realname": student.profile.name, } for student in enrolled_students ] return render_to_response( "courseware/gradebook.html", { "students": student_info, "course": course, "course_id": course.id, "staff_access": request.user.is_staff, "ordered_grades": sorted(course.grade_cutoffs.items(), key=lambda i: i[1], reverse=True), }, )
def gendata(request): data = {} for course in modulestore().get_courses(): data[course.id] = {} print("Loading info for course {courseid}".format(courseid = course.id)) enrolled_students = User.objects.filter( courseenrollment__course_id=course.id, ).prefetch_related("groups").order_by('username') enrolled_students = [st for st in enrolled_students if not _has_staff_access_to_course_id(st, course.id)] if len(enrolled_students) <= 0: continue #Category weights gradeset = student_grades(enrolled_students[0], request, course, keep_raw_scores=False, use_offline=False) category_weights = {} for section in gradeset['grade_breakdown']: category_weights[section['category']] = section['weight'] for user in enrolled_students: data[course.id][user.email] = {} #User data[course.id][user.email]["user"] = user #Raw statistic by problems gradeset = student_grades(user, request, course, keep_raw_scores=True, use_offline=False) statprob = [(getattr(score, 'earned', '') or score[0]) for score in gradeset['raw_scores']] #By subsection statsec = [] complition = 0 complition_cnt = 0 try: courseware_summary = grades.progress_summary(user, request, course); for chapter in courseware_summary: total = 0 flag = False for section in chapter['sections']: if not section['graded'] or len(section['format']) < 1: continue flag = True statsec += [((section['section_total'].earned / section['section_total'].possible) if section['section_total'].possible else 0)] total += ((section['section_total'].earned / section['section_total'].possible) if section['section_total'].possible else 0) * category_weights.get(section['format'], 0.0) statsec += [total] if flag: complition += total complition_cnt += 1 except: pass if complition_cnt == 0: complition = 0 else: complition = complition / complition_cnt if complition > 0.7: data[course.id][user.email]["0.7"] = True else: data[course.id][user.email]["0.7"] = False if complition > 0.99: data[course.id][user.email]["1.0"] = True else: data[course.id][user.email]["1.0"] = False data[course.id][user.email]["prob_info"] = statprob data[course.id][user.email]["sec_info"] = statsec print("Loading info for course {courseid} - COMPLETE - total {users}".format(courseid = course.id, users = len (data[course.id]) )) return data
def csv_out(request, course_id): response = HttpResponse(content_type='text/csv') response['Content-Disposition'] = 'attachment; filename="wellgraded_students.csv"' writer = csv.writer(response) course_key = SlashSeparatedCourseKey.from_deprecated_string(course_id) course = get_course_with_access(request.user, 'staff', course_key, depth=None) enrolled_students = User.objects.filter( courseenrollment__course_id=course_key, courseenrollment__is_active=1 ).order_by('username').select_related("profile") grading_filter = Grading.objects.filter( course_id=course_id ) grading = {} for el in grading_filter: grading[el.problem_number-1] = el.min_grade, el.deadline subsections = {} grading_context = course.grading_context for section_format, sections in grading_context['graded_sections'].iteritems(): for section in sections: if(subsections.get(section['section_descriptor'].format)): subsections[section['section_descriptor'].format].append(section['xmoduledescriptors']) else: subsections[section['section_descriptor'].format] = [section['xmoduledescriptors']] for student in enrolled_students: j = 0 grade_summary = student_grades(student, request, course) good_student = True for section in grade_summary['section_breakdown']: if(section['label'][-3:] != 'Avg'): try: if(len(subsections[section['category']]) > 1): subsection = subsections[section['category']][int(section['label'][-2:])-1] else: subsection = subsections[section['category']][0] problems = StudentModule.objects.filter( student=student, module_state_key__in=[ descriptor.location for descriptor in subsection ] ) for problem in problems: if(problem.modified.now().date() > grading[j][1]): good_student = False break if(not good_student): break except IndexError: pass if(grading.get(j) and section['percent'] <= grading[j][0]): good_student = False break j += 1 if(grading.get(j) and grade_summary['percent'] <= grading[j][0]): good_student = False if(good_student): result = [section['label']+'='+str(section['percent']) for section in grade_summary['section_breakdown']] writer.writerow([student.username]+result) return response
def stats(request, course_id): course_key = SlashSeparatedCourseKey.from_deprecated_string(course_id) course = get_course_with_access(request.user, 'staff', course_key, depth=None) enrolled_students = User.objects.filter( courseenrollment__course_id=course_key, courseenrollment__is_active=1 ).order_by('username').select_related("profile") grading_filter = Grading.objects.filter( course_id=course_id ) grading = {} for el in grading_filter: grading[el.problem_number-1] = el.min_grade subsections = {} grading_context = course.grading_context for section_format, sections in grading_context['graded_sections'].iteritems(): for section in sections: if(subsections.get(section['section_descriptor'].format)): subsections[section['section_descriptor'].format].append(section['xmoduledescriptors']) else: subsections[section['section_descriptor'].format] = [section['xmoduledescriptors']] """ all_stats [0] - Total [1] - Tried [2] - OverZero [3] - OverMin [4] - Max [5] - Zero """ all_stats = [] for section in student_grades(enrolled_students[0], request, course)['section_breakdown']: all_stats.append([section['label'], [0,0,0,0,0,0]]) all_stats.append(['Total', [0,0,0,0,0,0]]) for student in enrolled_students: j = 0 grade_summary = student_grades(student, request, course) for section in grade_summary['section_breakdown']: if(section['label'][-3:] != 'Avg'): try: if(len(subsections[section['category']]) > 1): subsection = subsections[section['category']][int(section['label'][-2:])-1] else: subsection = subsections[section['category']][0] problems = StudentModule.objects.filter( student=student, module_state_key__in=[ descriptor.location for descriptor in subsection ] ) for problem in problems: if(problem.modified != problem.created): all_stats[j][1][0] += 1 all_stats[j][1][1] += 1 else: all_stats[j][1][0] += 1 except IndexError: pass if(section['percent'] > 0): all_stats[j][1][2] += 1 if(grading.get(j) and section['percent'] >= grading[j]): all_stats[j][1][3] += 1 if(section['percent'] == 1.0): all_stats[j][1][4] += 1 if(section['percent'] == 0): all_stats[j][1][5] += 1 j += 1 if(grade_summary['percent'] > 0): all_stats[j][1][2] += 1 if(grading.get(j) and grade_summary['percent'] >= grading[j]): all_stats[j][1][3] += 1 if(grade_summary['percent'] == 1.0): all_stats[j][1][4] += 1 if(grade_summary['percent'] == 0): all_stats[j][1][5] += 1 return render_to_response('stats.html', { 'url': request.path, 'course': course, 'course_id': course_key, 'all_stats': all_stats, 'staff_access': True, })
def get_student_grade_summary_data( request, course, get_grades=True, get_raw_scores=False, use_offline=False, get_score_max=False ): """ Return data arrays with student identity and grades for specified course. course = CourseDescriptor course_key = course ID Note: both are passed in, only because instructor_dashboard already has them already. returns datatable = dict(header=header, data=data) where header = list of strings labeling the data fields data = list (one per student) of lists of data corresponding to the fields If get_raw_scores=True, then instead of grade summaries, the raw grades for all graded modules are returned. If get_score_max is True, two values will be returned for each grade -- the total number of points earned and the total number of points possible. For example, if two points are possible and one is earned, (1, 2) will be returned instead of 0.5 (the default). """ course_key = course.id enrolled_students = User.objects.filter( courseenrollment__course_id=course_key, courseenrollment__is_active=1, ).prefetch_related("groups").order_by('username') header = [_('ID'), _('Username'), _('Full Name'), _('edX email'), _('External email')] datatable = {'header': header, 'students': enrolled_students} data = [] gtab = GradeTable() for student in enrolled_students: datarow = [student.id, student.username, student.profile.name, student.email] try: datarow.append(student.externalauthmap.external_email) except Exception: # pylint: disable=broad-except datarow.append('') if get_grades: gradeset = student_grades(student, request, course, keep_raw_scores=get_raw_scores, use_offline=use_offline) log.debug(u'student=%s, gradeset=%s', student, gradeset) with gtab.add_row(student.id) as add_grade: if get_raw_scores: # The following code calls add_grade, which is an alias # for the add_row method on the GradeTable class. This adds # a grade for each assignment. Depending on whether # get_score_max is True, it will return either a single # value as a float between 0 and 1, or a two-tuple # containing the earned score and possible score for # the assignment (see docstring). for score in gradeset['raw_scores']: if get_score_max is True: add_grade(score.section, score.earned, score.possible) else: add_grade(score.section, score.earned) else: for grade_item in gradeset['section_breakdown']: add_grade(grade_item['label'], grade_item['percent']) student.grades = gtab.get_grade(student.id) data.append(datarow) # if getting grades, need to do a second pass, and add grades to each datarow; # on the first pass we don't know all the graded components if get_grades: for datarow in data: # get grades for student sgrades = gtab.get_grade(datarow[0]) datarow += sgrades # get graded components and add to table header assignments = gtab.get_graded_components() header += assignments datatable['assignments'] = assignments datatable['data'] = data return datatable
def get_student_grade_summary_data(request, course, get_grades=True, get_raw_scores=False, use_offline=False): """ Return data arrays with student identity and grades for specified course. course = CourseDescriptor course_key = course ID Note: both are passed in, only because instructor_dashboard already has them already. returns datatable = dict(header=header, data=data) where header = list of strings labeling the data fields data = list (one per student) of lists of data corresponding to the fields If get_raw_scores=True, then instead of grade summaries, the raw grades for all graded modules are returned. """ course_key = course.id enrolled_students = User.objects.filter( courseenrollment__course_id=course_key, courseenrollment__is_active=1, ).prefetch_related("groups").order_by('username') header = [_('ID'), _('Username'), _('Full Name'), _('edX email'), _('External email')] datatable = {'header': header, 'students': enrolled_students} data = [] gtab = GradeTable() for student in enrolled_students: datarow = [student.id, student.username, student.profile.name, student.email] try: datarow.append(student.externalauthmap.external_email) except Exception: # pylint: disable=broad-except datarow.append('') if get_grades: gradeset = student_grades(student, request, course, keep_raw_scores=get_raw_scores, use_offline=use_offline) log.debug('student={0}, gradeset={1}'.format(student, gradeset)) with gtab.add_row(student.id) as add_grade: if get_raw_scores: # TODO (ichuang) encode Score as dict instead of as list, so score[0] -> score['earned'] for score in gradeset['raw_scores']: add_grade(score.section, getattr(score, 'earned', score[0])) else: for grade_item in gradeset['section_breakdown']: add_grade(grade_item['label'], grade_item['percent']) student.grades = gtab.get_grade(student.id) data.append(datarow) # if getting grades, need to do a second pass, and add grades to each datarow; # on the first pass we don't know all the graded components if get_grades: for datarow in data: # get grades for student sgrades = gtab.get_grade(datarow[0]) datarow += sgrades # get graded components and add to table header assignments = gtab.get_graded_components() header += assignments datatable['assignments'] = assignments datatable['data'] = data return datatable
def fullstat(request = None): request = DummyRequest() header = [u'ФИО', u'ФИО (измененное)', u'логин школы', u'email', u'email (измененное)', u'курс', u'зарег. в пакет рег.', u"дата рег. на курс", u'2/3', u'100%', u'Задачи/Задания(Модули)'] assignments = [] datatablefull = {'header': header, 'assignments': assignments, 'students': []} datafull = [] for course in modulestore().get_courses(): datarow = [u'-', u'-', u'-', u'-', u'-', course.id, u'-', u'-', u'-'] assignments = [] enrolled_students = User.objects.filter( courseenrollment__course_id=course.id, ).prefetch_related("groups").order_by('username') enrolled_students = [st for st in enrolled_students if not _has_staff_access_to_course_id(st, course.id)] if len(enrolled_students) <= 0: continue gradeset = student_grades(enrolled_students[0], request, course, keep_raw_scores=True, use_offline=False) courseware_summary = grades.progress_summary(enrolled_students[0], request, course); if courseware_summary is None: continue assignments += [score.section for score in gradeset['raw_scores']] for chapter in courseware_summary: for section in chapter['sections']: if not section['graded'] or len(section['format']) < 1: continue assignments += [section['format']] assignments += [chapter['display_name']] datarow += assignments datafull.append(datarow) edxdata = gendata(request) print("Dumping fullstat") f = open("/opt/data.csv") if f is None: return False; ff = UnicodeDictReader(f, delimiter=';', quoting=csv.QUOTE_NONE) usermap = {} idx = 0 for row in ff: idx += 1 usermap.setdefault(row['email'],[]).append(row) for course in modulestore().get_courses(): enrolled_students = User.objects.filter( courseenrollment__course_id=course.id, courseenrollment__is_active=1, ).prefetch_related("groups").order_by('username') enrolled_students = [st for st in enrolled_students if not _has_staff_access_to_course_id(st, course.id)] idx = 0 for user in enrolled_students: try: idx += 1 datarow = [] found = False rows = [] try: for elem in user.profile.get_meta().get('old_emails',[])[::-1]: if usermap[elem[0]]: found = True rows = usermap[elem[0]] break if not found and usermap[user.email]: found = True rows = usermap[user.email] except: pass off_reg = False try: for row in rows: found = False for course_id, course_name in coursemap.iteritems(): if course_name in row['subject']: found = True off_reg = True break if found: break except: pass #User name = '' try: name = rows[0]['second-name'] + ' ' + rows[0]['first-name'] + ' ' + rows[0]['patronymic'] except: pass datarow += [name] if user.profile.name != name: datarow += [user.profile.name] else: datarow += [u''] try: datarow += [rows[0]['login']] except: datarow += [''] email = '' try: datarow += [rows[0]['email']] email = rows[0]['email'] except: datarow += [''] if user.email != email: datarow += [user.email] else: datarow += [u''] #Course datarow += [course.display_name] if off_reg: datarow += [u'Да'] else: datarow += [u'Нет'] try: courseenrollment = user.courseenrollment_set.filter(course_id = course.id)[0] datarow += [courseenrollment.created.strftime('%d/%m/%Y')] except: continue #Raw statistic by problems statprob = edxdata[course.id][user.email]["prob_info"] #By subsection statsec = edxdata[course.id][user.email]["sec_info"] if edxdata[course.id][user.email]["0.7"]: datarow += [u"Да"] else: datarow += [u"Нет"] if edxdata[course.id][user.email]["1.0"]: datarow += [u"Да"] else: datarow += [u"Нет"] if len(statsec) > 0 and len(statprob) > 0: datarow += statprob datarow += statsec datafull.append(datarow) except: logging.exception("Something awful happened in fullstat!") pass datatablefull['data'] = datafull return_csv('full_stat.csv',datatablefull, open("/var/www/edx/fullstat.csv", "wb")) for course in modulestore().get_courses(): print("Dumping course {courseid}".format(courseid = course.id)) assignments = [] enrolled_students = User.objects.filter( courseenrollment__course_id=course.id, ).prefetch_related("groups").order_by('username') enrolled_students = [st for st in enrolled_students if not _has_staff_access_to_course_id(st, course.id)] if len(enrolled_students) <= 0: continue gradeset = student_grades(enrolled_students[0], request, course, keep_raw_scores=True, use_offline=False) courseware_summary = grades.progress_summary(enrolled_students[0], request, course); if courseware_summary is None: print "No courseware_summary" continue assignments += [score.section for score in gradeset['raw_scores']] for chapter in courseware_summary: for section in chapter['sections']: if not section['graded'] or len(section['format']) < 1: continue assignments += [section['format']] assignments += [chapter['display_name']] header = [u'ФИО', u'логин школы', u'email', u"дата регистрации на курс", u'2/3', u'100%'] header += assignments datatable = {'header': header, 'assignments': assignments, 'students': []} data = [] for user in enrolled_students: try: datarow = [] #User name = user.profile.name datarow += [name] datarow += [user.profile.work_login] datarow += [user.email] courseenrollment = user.courseenrollment_set.filter(course_id = course.id)[0] datarow += [courseenrollment.created.strftime('%d/%m/%Y')] #Raw statistic by problems statprob = edxdata[course.id][user.email]["prob_info"] #By subsection statsec = edxdata[course.id][user.email]["sec_info"] if edxdata[course.id][user.email]["0.7"]: datarow += [u"Да"] else: datarow += [u"Нет"] if edxdata[course.id][user.email]["1.0"]: datarow += [u"Да"] else: datarow += [u"Нет"] if len(statsec) > 0 and len(statprob) > 0: datarow += statprob datarow += statsec else: datarow += [0] * len(assignments) data.append(datarow) except: logging.exception("Something awful happened in {course_id}!".format(course_id = course.id)) pass datatable['data'] = data return_csv(course.id,datatable, open("/var/www/edx/" + course.id.replace('/','_') + ".xls", "wb"), encoding="cp1251", dialect="excel-tab") return_csv(course.id,datatable, open("/var/www/edx/" + course.id.replace('/','_') + ".csv", "wb")) return True