def test_archiving_does_not_change_results(self): results = calculate_average_grades_and_deviation(self.course) self.semester.archive() self.refresh_course() cache.clear() self.assertEqual(calculate_average_grades_and_deviation(self.course), results)
def semester_detail(request, semester_id): semester = get_object_or_404(Semester, id=semester_id) courses = list(semester.course_set.filter(state="published").prefetch_related("degrees")) # Annotate each course object with its grades. for course in courses: course.avg_grade, course.avg_deviation = calculate_average_grades_and_deviation(course) CourseTuple = namedtuple('CourseTuple', ('courses', 'single_results')) courses_by_degree = OrderedDict() for degree in Degree.objects.all(): courses_by_degree[degree] = CourseTuple([], []) for course in courses: if course.is_single_result: for degree in course.degrees.all(): section = calculate_results(course)[0] result = section.results[0] courses_by_degree[degree].single_results.append((course, result)) else: for degree in course.degrees.all(): courses_by_degree[degree].courses.append(course) template_data = dict(semester=semester, courses_by_degree=courses_by_degree, staff=request.user.is_staff) return render(request, "results_semester_detail.html", template_data)
def semester_detail(request, semester_id): semester = get_object_or_404(Semester, id=semester_id) courses = list(semester.course_set.filter(state="published").prefetch_related("degrees")) # annotate each course object with its grades for course in courses: course.avg_grade, course.avg_deviation = calculate_average_grades_and_deviation(course) CourseTuple = namedtuple('CourseTuple', ('courses', 'single_results')) courses_by_degree = OrderedDict() for degree in Degree.objects.all(): courses_by_degree[degree] = CourseTuple([], []) for course in courses: if course.is_single_result(): for degree in course.degrees.all(): section = calculate_results(course)[0] result = section.results[0] courses_by_degree[degree].single_results.append((course, result)) else: for degree in course.degrees.all(): courses_by_degree[degree].courses.append(course) template_data = dict(semester=semester, courses_by_degree=courses_by_degree, staff=request.user.is_staff) return render(request, "results_semester_detail.html", template_data)
def test_average_grades(self): contributor1 = mommy.make(UserProfile) contributor2 = mommy.make(UserProfile) course = mommy.make(Course) questionnaire = mommy.make(Questionnaire) question_grade = mommy.make(Question, questionnaire=questionnaire, type="G") question_likert = mommy.make(Question, questionnaire=questionnaire, type="L") general_contribution = mommy.make(Contribution, contributor=None, course=course, questionnaires=[questionnaire]) contribution1 = mommy.make(Contribution, contributor=contributor1, course=course, questionnaires=[questionnaire]) contribution2 = mommy.make(Contribution, contributor=contributor2, course=course, questionnaires=[questionnaire]) mommy.make(RatingAnswerCounter, question=question_grade, contribution=contribution1, answer=1, count=1) mommy.make(RatingAnswerCounter, question=question_grade, contribution=contribution2, answer=4, count=2) mommy.make(RatingAnswerCounter, question=question_likert, contribution=contribution1, answer=3, count=4) mommy.make(RatingAnswerCounter, question=question_likert, contribution=general_contribution, answer=5, count=3) total_likert = settings.CONTRIBUTION_PERCENTAGE * 3 + (1 - settings.CONTRIBUTION_PERCENTAGE) * 5 total_grade = 2.5 total = settings.GRADE_PERCENTAGE * total_grade + (1 - settings.GRADE_PERCENTAGE) * total_likert average, deviation = calculate_average_grades_and_deviation(course) self.assertAlmostEqual(average, total) self.assertAlmostEqual(deviation, 0)
def course_detail(request, semester_id, course_id): semester = get_object_or_404(Semester, id=semester_id) course = get_object_or_404(semester.course_set, id=course_id) if not course.can_user_see_results(request.user): raise PermissionDenied sections = calculate_results(course) public_view = request.GET.get('public_view', 'false') # default: show own view public_view = {'true': True, 'false': False}.get(public_view.lower()) # convert parameter to boolean for section in sections: results = [] for result in section.results: if isinstance(result, TextResult): answers = [answer for answer in result.answers if user_can_see_text_answer(request.user, answer, public_view)] if answers: results.append(TextResult(question=result.question, answers=answers)) else: results.append(result) section.results[:] = results # filter empty sections and group by contributor course_sections = [] contributor_sections = OrderedDict() for section in sections: if not section.results: continue if section.contributor is None: course_sections.append(section) else: contributor_sections.setdefault(section.contributor, []).append(section) # show a warning if course is still in evaluation (for staff preview) evaluation_warning = course.state != 'published' # results for a course might not be visible because there are not enough answers # but it can still be "published" e.g. to show the comment results to contributors. # users who can open the results page see a warning message in this case sufficient_votes_warning = not course.can_publish_grades show_grades = request.user.is_staff or course.can_publish_grades course.avg_grade, course.avg_deviation = calculate_average_grades_and_deviation(course) template_data = dict( course=course, course_sections=course_sections, contributor_sections=contributor_sections, evaluation_warning=evaluation_warning, sufficient_votes_warning=sufficient_votes_warning, show_grades=show_grades, staff=request.user.is_staff, contributor=course.is_user_contributor_or_delegate(request.user), can_download_grades=request.user.can_download_grades, public_view=public_view) return render(request, "results_course_detail.html", template_data)
def semester_raw_export(request, semester_id): semester = get_object_or_404(Semester, id=semester_id) filename = "Evaluation-{}-{}_raw.csv".format(semester.name, get_language()) response = HttpResponse(content_type="text/csv") response["Content-Disposition"] = "attachment; filename=\"{}\"".format(filename) writer = csv.writer(response, delimiter=";") writer.writerow([_('Name'), _('Degrees'), _('Type'), _('Single result'), _('State'), _('#Voters'), _('#Participants'), _('#Comments'), _('Average grade')]) for course in semester.course_set.all(): degrees = ", ".join([degree.name for degree in course.degrees.all()]) course.avg_grade, course.avg_deviation = calculate_average_grades_and_deviation(course) if course.state in ['evaluated', 'reviewed', 'published'] and course.avg_grade is not None: avg_grade = "{:.1f}".format(course.avg_grade) else: avg_grade = "" writer.writerow([course.name, degrees, course.type.name, course.is_single_result, course.state, course.num_voters, course.num_participants, course.textanswer_set.count(), avg_grade]) return response
def export(self, response, ignore_not_enough_answers=False): courses_with_results = list() for course in self.semester.course_set.filter(state="published").all(): results = OrderedDict() for questionnaire, contributor, label, data, section_warning in calculate_results(course): results.setdefault(questionnaire.id, []).extend(data) courses_with_results.append((course, results)) courses_with_results.sort(key=lambda cr: cr[0].type) qn_frequencies = defaultdict(int) for course, results in courses_with_results: for questionnaire, results in results.items(): qn_frequencies[questionnaire] += 1 qn_relevant = list(qn_frequencies.items()) qn_relevant.sort(key=lambda t: -t[1]) questionnaires = [Questionnaire.objects.get(id=t[0]) for t in qn_relevant] self.workbook = xlwt.Workbook() self.sheet = self.workbook.add_sheet(_("Results")) self.row = 0 self.col = 0 self.init_styles(self.workbook) writec(self, _("Evaluation {0} - created on {1}").format(self.semester.name, datetime.date.today()), "headline") for course, results in courses_with_results: if course.state == "published": writec(self, course.name, "course", cols=2) else: writec(self, course.name, "course_unfinished", cols=2) writen(self) for course, results in courses_with_results: writec(self, "Average", "avg") writec(self, "Deviation", "border_top_bottom_right") for questionnaire in questionnaires: writen(self, questionnaire.name, "bold") for course, results in courses_with_results: self.write_two_empty_cells_with_borders() for question in questionnaire.question_set.all(): if question.is_text_question: continue writen(self, question.text) for course, results in courses_with_results: qn_results = results.get(questionnaire.id, None) if qn_results: values = [] deviations = [] for grade_result in qn_results: if grade_result.question.id == question.id: if grade_result.average: values.append(grade_result.average) deviations.append(grade_result.deviation) break enough_answers = course.can_publish_grades if values and (enough_answers or ignore_not_enough_answers): avg = sum(values) / len(values) writec(self, avg, self.grade_to_style(avg)) dev = sum(deviations) / len(deviations) writec(self, dev, self.deviation_to_style(dev)) else: self.write_two_empty_cells_with_borders() else: self.write_two_empty_cells_with_borders() writen(self, None) for course, results in courses_with_results: self.write_two_empty_cells_with_borders() writen(self, _("Overall Average Grade"), "bold") for course, results in courses_with_results: avg, dev = calculate_average_grades_and_deviation(course) if avg: writec(self, avg, self.grade_to_style(avg), cols=2) else: self.write_two_empty_cells_with_borders() writen(self, _("Overall Average Standard Deviation"), "bold") for course, results in courses_with_results: avg, dev = calculate_average_grades_and_deviation(course) if dev is not None: writec(self, dev, self.deviation_to_style(dev), cols=2) else: self.write_two_empty_cells_with_borders() writen(self, _("Total Voters/Total Participants"), "bold") for course, results in courses_with_results: percent_participants = float(course.num_voters)/float(course.num_participants) writec(self, "{}/{} ({:.0%})".format(course.num_voters, course.num_participants, percent_participants), "total_voters", cols=2) self.workbook.save(response)
def course_detail(request, semester_id, course_id): semester = get_object_or_404(Semester, id=semester_id) course = get_object_or_404(semester.course_set, id=course_id, semester=semester) if not course.can_user_see_results(request.user): raise PermissionDenied sections = calculate_results(course) public_view = request.GET.get('public_view', 'false') # Default: show own view. public_view = {'true': True, 'false': False}.get(public_view.lower()) # Convert parameter to boolean. represented_users = list(request.user.represented_users.all()) represented_users.append(request.user) for section in sections: results = [] for result in section.results: if isinstance(result, TextResult): answers = [answer for answer in result.answers if user_can_see_text_answer(request.user, represented_users, answer, public_view)] if answers: results.append(TextResult(question=result.question, answers=answers)) else: results.append(result) section.results[:] = results # Filter empty sections and group by contributor. course_sections = [] contributor_sections = OrderedDict() for section in sections: if not section.results: continue if section.contributor is None: course_sections.append(section) else: contributor_sections.setdefault(section.contributor, {'total_votes': 0, 'sections': []})['sections'].append(section) # Sum up all Sections for this contributor. # If section is not a RatingResult: # Add 1 as we assume it is a TextResult or something similar that should be displayed. contributor_sections[section.contributor]['total_votes'] +=\ sum([s.total_count if isinstance(s, RatingResult) else 1 for s in section.results]) # Show a warning if course is still in evaluation (for staff preview). evaluation_warning = course.state != 'published' # Results for a course might not be visible because there are not enough answers # but it can still be "published" e.g. to show the comment results to contributors. # Users who can open the results page see a warning message in this case. sufficient_votes_warning = not course.can_publish_grades show_grades = request.user.is_staff or course.can_publish_grades course.avg_grade, course.avg_deviation = calculate_average_grades_and_deviation(course) template_data = dict( course=course, course_sections=course_sections, contributor_sections=contributor_sections, evaluation_warning=evaluation_warning, sufficient_votes_warning=sufficient_votes_warning, show_grades=show_grades, staff=request.user.is_staff, contributor=course.is_user_contributor_or_delegate(request.user), can_download_grades=request.user.can_download_grades, public_view=public_view) return render(request, "results_course_detail.html", template_data)
def export(self, response, course_types_list, ignore_not_enough_answers=False, include_unpublished=False): self.workbook = xlwt.Workbook() self.init_styles(self.workbook) counter = 1 for course_types in course_types_list: self.sheet = self.workbook.add_sheet("Sheet " + str(counter)) counter += 1 self.row = 0 self.col = 0 courses_with_results = list() course_states = ['published'] if include_unpublished: course_states.extend(['evaluated', 'reviewed']) used_questionnaires = set() for course in self.semester.course_set.filter(state__in=course_states, type__in=course_types).all(): if course.is_single_result(): continue results = OrderedDict() for questionnaire, contributor, label, data, section_warning in calculate_results(course): if has_no_rating_answers(course, contributor, questionnaire): continue results.setdefault(questionnaire.id, []).extend(data) used_questionnaires.add(questionnaire) courses_with_results.append((course, results)) courses_with_results.sort(key=lambda cr: cr[0].type) used_questionnaires = sorted(used_questionnaires) writec(self, _("Evaluation {0}\n\n{1}").format(self.semester.name, ", ".join(course_types)), "headline") for course, results in courses_with_results: writec(self, course.name, "course", cols=2) writen(self) for course, results in courses_with_results: writec(self, "Average", "avg") writec(self, "Deviation", "border_top_bottom_right") for questionnaire in used_questionnaires: writen(self, questionnaire.name, "bold") for course, results in courses_with_results: self.write_two_empty_cells_with_borders() for question in questionnaire.question_set.all(): if question.is_text_question: continue writen(self, question.text) for course, results in courses_with_results: if questionnaire.id not in results: self.write_two_empty_cells_with_borders() continue qn_results = results[questionnaire.id] values = [] deviations = [] total_count = 0 for grade_result in qn_results: if grade_result.question.id == question.id: if grade_result.average: values.append(grade_result.average * grade_result.total_count) deviations.append(grade_result.deviation * grade_result.total_count) total_count += grade_result.total_count enough_answers = course.can_publish_grades if values and (enough_answers or ignore_not_enough_answers): avg = sum(values) / total_count writec(self, avg, self.grade_to_style(avg)) dev = sum(deviations) / total_count writec(self, dev, self.deviation_to_style(dev)) else: self.write_two_empty_cells_with_borders() writen(self, None) for course, results in courses_with_results: self.write_two_empty_cells_with_borders() writen(self, _("Overall Average Grade"), "bold") for course, results in courses_with_results: avg, dev = calculate_average_grades_and_deviation(course) if avg: writec(self, avg, self.grade_to_style(avg, total=True), cols=2) else: self.write_two_empty_cells_with_borders() writen(self, _("Overall Average Standard Deviation"), "bold") for course, results in courses_with_results: avg, dev = calculate_average_grades_and_deviation(course) if dev is not None: writec(self, dev, self.deviation_to_style(dev, total=True), cols=2) else: self.write_two_empty_cells_with_borders() writen(self, _("Total Voters/Total Participants"), "bold") for course, results in courses_with_results: percent_participants = float(course.num_voters)/float(course.num_participants) if course.num_participants > 0 else 0 writec(self, "{}/{} ({:.0%})".format(course.num_voters, course.num_participants, percent_participants), "total_voters", cols=2) self.workbook.save(response)
def course_detail(request, semester_id, course_id): semester = get_object_or_404(Semester, id=semester_id) course = get_object_or_404(semester.course_set, id=course_id, semester=semester) if not course.can_user_see_results(request.user): raise PermissionDenied sections = calculate_results(course) public_view = request.GET.get('public_view', 'false') # Default: show own view. public_view = { 'true': True, 'false': False }.get(public_view.lower()) # Convert parameter to boolean. represented_users = list(request.user.represented_users.all()) represented_users.append(request.user) for section in sections: results = [] for result in section.results: if isinstance(result, TextResult): answers = [ answer for answer in result.answers if user_can_see_text_answer( request.user, represented_users, answer, public_view) ] if answers: results.append( TextResult(question=result.question, answers=answers)) else: results.append(result) section.results[:] = results # Filter empty sections and group by contributor. course_sections = [] contributor_sections = OrderedDict() for section in sections: if not section.results: continue if section.contributor is None: course_sections.append(section) else: contributor_sections.setdefault(section.contributor, { 'total_votes': 0, 'sections': [] })['sections'].append(section) # Sum up all Sections for this contributor. # If section is not a RatingResult: # Add 1 as we assume it is a TextResult or something similar that should be displayed. contributor_sections[section.contributor]['total_votes'] +=\ sum([s.total_count if isinstance(s, RatingResult) else 1 for s in section.results]) # Show a warning if course is still in evaluation (for staff preview). evaluation_warning = course.state != 'published' # Results for a course might not be visible because there are not enough answers # but it can still be "published" e.g. to show the comment results to contributors. # Users who can open the results page see a warning message in this case. sufficient_votes_warning = not course.can_publish_grades show_grades = request.user.is_staff or course.can_publish_grades course.avg_grade, course.avg_deviation = calculate_average_grades_and_deviation( course) template_data = dict(course=course, course_sections=course_sections, contributor_sections=contributor_sections, evaluation_warning=evaluation_warning, sufficient_votes_warning=sufficient_votes_warning, show_grades=show_grades, staff=request.user.is_staff, contributor=course.is_user_contributor_or_delegate( request.user), can_download_grades=request.user.can_download_grades, public_view=public_view) return render(request, "results_course_detail.html", template_data)