def get(self, request, course_key): """ Returns a gradebook entry/entries (i.e. both course and subsection-level grade data) for all users enrolled in a course, or a single user enrolled in a course if a `username` parameter is provided. Args: request: A Django request object. course_key: The edx course opaque key of a course object. """ course = get_course_by_id(course_key, depth=None) # We fetch the entire course structure up-front, and use this when iterating # over users to determine their subsection grades. We purposely avoid fetching # the user-specific course structure for each user, because that is very expensive. course_data = CourseData(user=None, course=course) graded_subsections = list( grades_context.graded_subsections_for_course( course_data.collected_structure)) if request.GET.get('username'): with self._get_user_or_raise(request, course_key) as grade_user: course_grade = CourseGradeFactory().read(grade_user, course) entry = self._gradebook_entry(grade_user, course, graded_subsections, course_grade) serializer = StudentGradebookEntrySerializer(entry) return Response(serializer.data) else: q_objects = [] if request.GET.get('user_contains'): search_term = request.GET.get('user_contains') q_objects.append( Q(user__username__icontains=search_term) | Q(programcourseenrollment__program_enrollment__external_user_key__icontains =search_term) | Q(user__email__icontains=search_term)) if request.GET.get('username_contains'): q_objects.append( Q(user__username__icontains=request.GET.get( 'username_contains'))) if request.GET.get('cohort_id'): cohort = cohorts.get_cohort_by_id(course_key, request.GET.get('cohort_id')) if cohort: q_objects.append(Q(user__in=cohort.users.all())) else: q_objects.append(Q(user__in=[])) if request.GET.get('enrollment_mode'): q_objects.append(Q(mode=request.GET.get('enrollment_mode'))) entries = [] related_models = ['user'] users = self._paginate_users(course_key, q_objects, related_models) with bulk_gradebook_view_context(course_key, users): for user, course_grade, exc in CourseGradeFactory().iter( users, course_key=course_key, collected_block_structure=course_data. collected_structure): if not exc: entry = self._gradebook_entry(user, course, graded_subsections, course_grade) entries.append(entry) serializer = StudentGradebookEntrySerializer(entries, many=True) return self.get_paginated_response(serializer.data)
def get(self, request, course_key): """ Returns a gradebook entry/entries (i.e. both course and subsection-level grade data) for all users enrolled in a course, or a single user enrolled in a course if a `username` parameter is provided. Args: request: A Django request object. course_key: The edx course opaque key of a course object. """ course = get_course_by_id(course_key, depth=None) # We fetch the entire course structure up-front, and use this when iterating # over users to determine their subsection grades. We purposely avoid fetching # the user-specific course structure for each user, because that is very expensive. course_data = CourseData(user=None, course=course) graded_subsections = list(grades_context.graded_subsections_for_course(course_data.collected_structure)) if request.GET.get('username'): with self._get_user_or_raise(request, course_key) as grade_user: course_grade = CourseGradeFactory().read(grade_user, course) entry = self._gradebook_entry(grade_user, course, graded_subsections, course_grade) serializer = StudentGradebookEntrySerializer(entry) return Response(serializer.data) else: q_objects = [] annotations = {} if request.GET.get('user_contains'): search_term = request.GET.get('user_contains') q_objects.append( Q(user__username__icontains=search_term) | Q(programcourseenrollment__program_enrollment__external_user_key__icontains=search_term) | Q(user__email__icontains=search_term) ) if request.GET.get('username_contains'): q_objects.append(Q(user__username__icontains=request.GET.get('username_contains'))) if request.GET.get('cohort_id'): cohort = cohorts.get_cohort_by_id(course_key, request.GET.get('cohort_id')) if cohort: q_objects.append(Q(user__in=cohort.users.all())) else: q_objects.append(Q(user__in=[])) if request.GET.get('enrollment_mode'): q_objects.append(Q(mode=request.GET.get('enrollment_mode'))) if request.GET.get('assignment') and ( request.GET.get('assignment_grade_max') or request.GET.get('assignment_grade_min')): subqueryset = PersistentSubsectionGrade.objects.annotate( effective_grade_percentage=Case( When(override__isnull=False, then=( F('override__earned_graded_override') / F('override__possible_graded_override') ) * 100), default=(F('earned_graded') / F('possible_graded')) * 100 ) ) grade_conditions = { 'effective_grade_percentage__range': ( request.GET.get('assignment_grade_min', 0), request.GET.get('assignment_grade_max', 100) ) } annotations['selected_assignment_grade_in_range'] = Exists( subqueryset.filter( course_id=OuterRef('course'), user_id=OuterRef('user'), usage_key=UsageKey.from_string(request.GET.get('assignment')), **grade_conditions ) ) q_objects.append(Q(selected_assignment_grade_in_range=True)) if request.GET.get('course_grade_min') or request.GET.get('course_grade_max'): grade_conditions = {} q_object = Q() course_grade_min = request.GET.get('course_grade_min') if course_grade_min: course_grade_min = float(request.GET.get('course_grade_min')) / 100 grade_conditions['percent_grade__gte'] = course_grade_min if request.GET.get('course_grade_max'): course_grade_max = float(request.GET.get('course_grade_max')) / 100 grade_conditions['percent_grade__lte'] = course_grade_max if not course_grade_min or course_grade_min == 0: subquery_grade_absent = ~Exists( PersistentCourseGrade.objects.filter( course_id=OuterRef('course'), user_id=OuterRef('user_id'), ) ) annotations['course_grade_absent'] = subquery_grade_absent q_object |= Q(course_grade_absent=True) subquery_grade_in_range = Exists( PersistentCourseGrade.objects.filter( course_id=OuterRef('course'), user_id=OuterRef('user_id'), **grade_conditions ) ) annotations['course_grade_in_range'] = subquery_grade_in_range q_object |= Q(course_grade_in_range=True) q_objects.append(q_object) entries = [] related_models = ['user'] users = self._paginate_users(course_key, q_objects, related_models, annotations=annotations) users_counts = self._get_users_counts(course_key, q_objects, annotations=annotations) with bulk_gradebook_view_context(course_key, users): for user, course_grade, exc in CourseGradeFactory().iter( users, course_key=course_key, collected_block_structure=course_data.collected_structure ): if not exc: entry = self._gradebook_entry(user, course, graded_subsections, course_grade) entries.append(entry) serializer = StudentGradebookEntrySerializer(entries, many=True) return self.get_paginated_response(serializer.data, **users_counts)