Skip to content
This repository was archived by the owner on May 1, 2024. It is now read-only.

Commit 90e861d

Browse files
authored
Merge pull request #130 from edx/dsjen/attempt-ratio
Updated engagement ranges fields.
2 parents 7fe4fa6 + 541d424 commit 90e861d

3 files changed

Lines changed: 44 additions & 30 deletions

File tree

analytics_data_api/v0/serializers.py

Lines changed: 26 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -424,23 +424,23 @@ class DateRangeSerializer(serializers.Serializer):
424424

425425
class EnagementRangeMetricSerializer(serializers.Serializer):
426426
"""
427-
Serializes ModuleEngagementMetricRanges ('low', 'normal', and 'high') into
428-
the below_average, average, and above_average ranges represented as arrays.
429-
If any one of the ranges is not defined, it is not included in the
430-
serialized output.
427+
Serializes ModuleEngagementMetricRanges ('bottom', 'average', and 'top') into
428+
the class_rank_bottom, class_rank_average, and class_rank_top ranges
429+
represented as arrays. If any one of the ranges is not defined, it is not
430+
included in the serialized output.
431431
"""
432-
below_average = serializers.SerializerMethodField('get_below_average_range')
433-
average = serializers.SerializerMethodField('get_average_range')
434-
above_average = serializers.SerializerMethodField('get_above_average_range')
432+
class_rank_bottom = serializers.SerializerMethodField('get_class_rank_bottom')
433+
class_rank_average = serializers.SerializerMethodField('get_class_rank_average')
434+
class_rank_top = serializers.SerializerMethodField('get_class_rank_top')
435435

436-
def get_average_range(self, obj):
437-
return self._transform_range(obj['normal_range'])
436+
def get_class_rank_average(self, obj):
437+
return self._transform_range(obj['average'])
438438

439-
def get_below_average_range(self, obj):
440-
return self._transform_range(obj['low_range'])
439+
def get_class_rank_bottom(self, obj):
440+
return self._transform_range(obj['bottom'])
441441

442-
def get_above_average_range(self, obj):
443-
return self._transform_range(obj['high_range'])
442+
def get_class_rank_top(self, obj):
443+
return self._transform_range(obj['top'])
444444

445445
def _transform_range(self, metric_range):
446446
return [metric_range.low_value, metric_range.high_value] if metric_range else None
@@ -459,15 +459,20 @@ def get_engagement_ranges(self, obj):
459459
}
460460

461461
for metric in engagement_events.EVENTS:
462-
low_range_queryset = query_set.filter(metric=metric, range_type='low')
463-
normal_range_queryset = query_set.filter(metric=metric, range_type='normal')
464-
high_range_queryset = query_set.filter(metric=metric, range_type='high')
462+
# construct the range type to class rank pairs
463+
ranges_ranks = [('normal', 'average')]
464+
if metric == 'problem_attempts_per_completed':
465+
ranges_ranks.extend([('low', 'top'), ('high', 'bottom')])
466+
else:
467+
ranges_ranks.extend([('high', 'top'), ('low', 'bottom')])
468+
469+
# put together data to be serialized
470+
serializer_kwargs = {}
471+
for range_type, class_rank_type in ranges_ranks:
472+
range_queryset = query_set.filter(metric=metric, range_type=range_type)
473+
serializer_kwargs[class_rank_type] = range_queryset[0] if len(range_queryset) else None
465474
engagement_ranges.update({
466-
metric: EnagementRangeMetricSerializer({
467-
'low_range': low_range_queryset[0] if len(low_range_queryset) else None,
468-
'normal_range': normal_range_queryset[0] if len(normal_range_queryset) else None,
469-
'high_range': high_range_queryset[0] if len(high_range_queryset) else None,
470-
}).data
475+
metric: EnagementRangeMetricSerializer(serializer_kwargs).data
471476
})
472477

473478
return engagement_ranges

analytics_data_api/v0/tests/views/test_learners.py

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -569,7 +569,7 @@ def empty_engagement_ranges(self):
569569
}
570570
}
571571
empty_range = {
572-
range_type: None for range_type in ['below_average', 'average', 'above_average']
572+
range_type: None for range_type in ['class_rank_bottom', 'class_rank_average', 'class_rank_top']
573573
}
574574
for metric in engagement_events.EVENTS:
575575
empty_engagement_ranges['engagement_ranges'][metric] = copy.deepcopy(empty_range)
@@ -593,9 +593,9 @@ def test_one_engagement_range(self):
593593
'end': '2015-07-21'
594594
},
595595
metric_type: {
596-
'below_average': None,
597-
'average': [90.0, 6120.0],
598-
'above_average': None
596+
'class_rank_bottom': None,
597+
'class_rank_average': [90.0, 6120.0],
598+
'class_rank_top': None
599599
}
600600
})
601601

@@ -625,11 +625,20 @@ def _get_full_engagement_ranges(self):
625625
normal_floor = 800.8
626626
G(ModuleEngagementMetricRanges, course_id=self.course_id, start_date=start_date, end_date=end_date,
627627
metric=metric_type, range_type='normal', low_value=normal_floor, high_value=max_value)
628+
628629
expected['engagement_ranges'][metric_type] = {
629-
'below_average': [0.0, low_ceil],
630-
'average': [normal_floor, max_value],
631-
'above_average': None
630+
'class_rank_average': [normal_floor, max_value],
632631
}
632+
if metric_type == 'problem_attempts_per_completed':
633+
expected['engagement_ranges'][metric_type].update({
634+
'class_rank_top': [0.0, low_ceil],
635+
'class_rank_bottom': None
636+
})
637+
else:
638+
expected['engagement_ranges'][metric_type].update({
639+
'class_rank_bottom': [0.0, low_ceil],
640+
'class_rank_top': None
641+
})
633642

634643
return expected
635644

analytics_data_api/v0/views/learners.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -347,8 +347,8 @@ class CourseLearnerMetadata(CourseViewMixin, generics.RetrieveAPIView):
347347
tracks in the course to the number of learners belonging to those
348348
tracks. Examples include "audit" and "verified".
349349
* engagement_ranges: An object containing ranges of learner
350-
engagement with the courseware. Each range has 'below_average',
351-
'average', and 'above_average' keys. These keys map to
350+
engagement with the courseware. Each range has 'class_rank_bottom',
351+
'class_rank_average', and 'class_rank_top' keys. These keys map to
352352
two-element arrays, in which the first element is the lower bound
353353
(inclusive) and the second element is the upper bound
354354
(exclusive). It has the following keys.

0 commit comments

Comments
 (0)