Commit 541d4247 by Dennis Jen

Updated engagement ranges fields.

* new fields: class_rank_bottom, class_rank_average, class_rank_top
parent 7fe4fa66
......@@ -424,23 +424,23 @@ class DateRangeSerializer(serializers.Serializer):
class EnagementRangeMetricSerializer(serializers.Serializer):
"""
Serializes ModuleEngagementMetricRanges ('low', 'normal', and 'high') into
the below_average, average, and above_average ranges represented as arrays.
If any one of the ranges is not defined, it is not included in the
serialized output.
Serializes ModuleEngagementMetricRanges ('bottom', 'average', and 'top') into
the class_rank_bottom, class_rank_average, and class_rank_top ranges
represented as arrays. If any one of the ranges is not defined, it is not
included in the serialized output.
"""
below_average = serializers.SerializerMethodField('get_below_average_range')
average = serializers.SerializerMethodField('get_average_range')
above_average = serializers.SerializerMethodField('get_above_average_range')
class_rank_bottom = serializers.SerializerMethodField('get_class_rank_bottom')
class_rank_average = serializers.SerializerMethodField('get_class_rank_average')
class_rank_top = serializers.SerializerMethodField('get_class_rank_top')
def get_average_range(self, obj):
return self._transform_range(obj['normal_range'])
def get_class_rank_average(self, obj):
return self._transform_range(obj['average'])
def get_below_average_range(self, obj):
return self._transform_range(obj['low_range'])
def get_class_rank_bottom(self, obj):
return self._transform_range(obj['bottom'])
def get_above_average_range(self, obj):
return self._transform_range(obj['high_range'])
def get_class_rank_top(self, obj):
return self._transform_range(obj['top'])
def _transform_range(self, metric_range):
return [metric_range.low_value, metric_range.high_value] if metric_range else None
......@@ -459,15 +459,20 @@ class CourseLearnerMetadataSerializer(serializers.Serializer):
}
for metric in engagement_events.EVENTS:
low_range_queryset = query_set.filter(metric=metric, range_type='low')
normal_range_queryset = query_set.filter(metric=metric, range_type='normal')
high_range_queryset = query_set.filter(metric=metric, range_type='high')
# construct the range type to class rank pairs
ranges_ranks = [('normal', 'average')]
if metric == 'problem_attempts_per_completed':
ranges_ranks.extend([('low', 'top'), ('high', 'bottom')])
else:
ranges_ranks.extend([('high', 'top'), ('low', 'bottom')])
# put together data to be serialized
serializer_kwargs = {}
for range_type, class_rank_type in ranges_ranks:
range_queryset = query_set.filter(metric=metric, range_type=range_type)
serializer_kwargs[class_rank_type] = range_queryset[0] if len(range_queryset) else None
engagement_ranges.update({
metric: EnagementRangeMetricSerializer({
'low_range': low_range_queryset[0] if len(low_range_queryset) else None,
'normal_range': normal_range_queryset[0] if len(normal_range_queryset) else None,
'high_range': high_range_queryset[0] if len(high_range_queryset) else None,
}).data
metric: EnagementRangeMetricSerializer(serializer_kwargs).data
})
return engagement_ranges
......@@ -569,7 +569,7 @@ class CourseLearnerMetadataTests(DemoCourseMixin, VerifyCourseIdMixin,
}
}
empty_range = {
range_type: None for range_type in ['below_average', 'average', 'above_average']
range_type: None for range_type in ['class_rank_bottom', 'class_rank_average', 'class_rank_top']
}
for metric in engagement_events.EVENTS:
empty_engagement_ranges['engagement_ranges'][metric] = copy.deepcopy(empty_range)
......@@ -593,9 +593,9 @@ class CourseLearnerMetadataTests(DemoCourseMixin, VerifyCourseIdMixin,
'end': '2015-07-21'
},
metric_type: {
'below_average': None,
'average': [90.0, 6120.0],
'above_average': None
'class_rank_bottom': None,
'class_rank_average': [90.0, 6120.0],
'class_rank_top': None
}
})
......@@ -625,11 +625,20 @@ class CourseLearnerMetadataTests(DemoCourseMixin, VerifyCourseIdMixin,
normal_floor = 800.8
G(ModuleEngagementMetricRanges, course_id=self.course_id, start_date=start_date, end_date=end_date,
metric=metric_type, range_type='normal', low_value=normal_floor, high_value=max_value)
expected['engagement_ranges'][metric_type] = {
'below_average': [0.0, low_ceil],
'average': [normal_floor, max_value],
'above_average': None
'class_rank_average': [normal_floor, max_value],
}
if metric_type == 'problem_attempts_per_completed':
expected['engagement_ranges'][metric_type].update({
'class_rank_top': [0.0, low_ceil],
'class_rank_bottom': None
})
else:
expected['engagement_ranges'][metric_type].update({
'class_rank_bottom': [0.0, low_ceil],
'class_rank_top': None
})
return expected
......
......@@ -347,8 +347,8 @@ class CourseLearnerMetadata(CourseViewMixin, generics.RetrieveAPIView):
tracks in the course to the number of learners belonging to those
tracks. Examples include "audit" and "verified".
* engagement_ranges: An object containing ranges of learner
engagement with the courseware. Each range has 'below_average',
'average', and 'above_average' keys. These keys map to
engagement with the courseware. Each range has 'class_rank_bottom',
'class_rank_average', and 'class_rank_top' keys. These keys map to
two-element arrays, in which the first element is the lower bound
(inclusive) and the second element is the upper bound
(exclusive). It has the following keys.
......
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