From e72a5629085211e3f27fd7c77b30a4fafabf6a64 Mon Sep 17 00:00:00 2001 From: Eric Fischer Date: Wed, 24 May 2017 09:20:38 -0400 Subject: [PATCH] Add passing_users to course summary (#170) EDU-153 --- AUTHORS | 1 + .../commands/generate_fake_course_data.py | 6 ++++-- analytics_data_api/v0/models.py | 1 + analytics_data_api/v0/serializers.py | 1 + .../v0/tests/views/test_course_summaries.py | 13 ++++++++++++- analytics_data_api/v0/views/course_summaries.py | 7 ++++++- 6 files changed, 25 insertions(+), 4 deletions(-) diff --git a/AUTHORS b/AUTHORS index 72661636..dc3a9771 100644 --- a/AUTHORS +++ b/AUTHORS @@ -8,3 +8,4 @@ Gabe Mulley Jason Bau John Jarvis Dmitry Viskov +Eric Fischer diff --git a/analytics_data_api/management/commands/generate_fake_course_data.py b/analytics_data_api/management/commands/generate_fake_course_data.py index 20d1681e..9f5b82f6 100644 --- a/analytics_data_api/management/commands/generate_fake_course_data.py +++ b/analytics_data_api/management/commands/generate_fake_course_data.py @@ -161,15 +161,17 @@ def generate_daily_data(self, course_id, start_date, end_date): progress.update(1) date = date + datetime.timedelta(days=1) - for mode, ratio in enrollment_mode_ratios.iteritems(): + for index, (mode, ratio) in enumerate(enrollment_mode_ratios.iteritems()): count = int(ratio * daily_total) + pass_rate = min(random.normalvariate(.45 + (.1 * index), .15), 1.0) cumulative_count = count + random.randint(0, 100) models.CourseMetaSummaryEnrollment.objects.create( course_id=course_id, catalog_course_title='Demo Course', catalog_course='Demo_Course', start_time=timezone.now() - datetime.timedelta(weeks=6), end_time=timezone.now() + datetime.timedelta(weeks=10), pacing_type='self_paced', availability='Starting Soon', enrollment_mode=mode, count=count, - cumulative_count=cumulative_count, count_change_7_days=random.randint(-50, 50)) + cumulative_count=cumulative_count, count_change_7_days=random.randint(-50, 50), + passing_users=int(cumulative_count * pass_rate)) models.CourseProgramMetadata.objects.create(course_id=course_id, program_id='Demo_Program', program_type='Demo', program_title='Demo Program') diff --git a/analytics_data_api/v0/models.py b/analytics_data_api/v0/models.py index 2f8151ac..9a5ca6fc 100644 --- a/analytics_data_api/v0/models.py +++ b/analytics_data_api/v0/models.py @@ -78,6 +78,7 @@ class CourseMetaSummaryEnrollment(BaseCourseModel): count = models.IntegerField(null=False) cumulative_count = models.IntegerField(null=False) count_change_7_days = models.IntegerField(default=0) + passing_users = models.IntegerField(default=0) class Meta(BaseCourseModel.Meta): db_table = 'course_meta_summary_enrollment' diff --git a/analytics_data_api/v0/serializers.py b/analytics_data_api/v0/serializers.py index 11e1cbe9..55101733 100644 --- a/analytics_data_api/v0/serializers.py +++ b/analytics_data_api/v0/serializers.py @@ -561,6 +561,7 @@ class CourseMetaSummaryEnrollmentSerializer(ModelSerializerWithCreatedField, Dyn count = serializers.IntegerField(default=0) cumulative_count = serializers.IntegerField(default=0) count_change_7_days = serializers.IntegerField(default=0) + passing_users = serializers.IntegerField(default=0) enrollment_modes = serializers.SerializerMethodField() programs = serializers.SerializerMethodField() diff --git a/analytics_data_api/v0/tests/views/test_course_summaries.py b/analytics_data_api/v0/tests/views/test_course_summaries.py index 61ceff02..9032cb3a 100644 --- a/analytics_data_api/v0/tests/views/test_course_summaries.py +++ b/analytics_data_api/v0/tests/views/test_course_summaries.py @@ -36,7 +36,7 @@ def create_model(self, model_id, **kwargs): start_time=datetime.datetime(2016, 10, 11, tzinfo=pytz.utc), end_time=datetime.datetime(2016, 12, 18, tzinfo=pytz.utc), pacing_type='instructor', availability=kwargs['availability'], enrollment_mode=mode, - count=5, cumulative_count=10, count_change_7_days=1, create=self.now,) + count=5, cumulative_count=10, count_change_7_days=1, passing_users=1, create=self.now,) if 'programs' in kwargs and kwargs['programs']: # Create a link from this course to a program G(models.CourseProgramMetadata, course_id=model_id, program_id=CourseSamples.program_ids[0], @@ -70,6 +70,7 @@ def expected_result(self, item_id, modes=None, availability='Current', programs= ('count', count_factor * num_modes), ('cumulative_count', cumulative_count_factor * num_modes), ('count_change_7_days', count_change_factor * num_modes), + ('passing_users', count_change_factor * num_modes), ('enrollment_modes', {}), ]) summary['enrollment_modes'].update({ @@ -77,6 +78,7 @@ def expected_result(self, item_id, modes=None, availability='Current', programs= 'count': count_factor, 'cumulative_count': cumulative_count_factor, 'count_change_7_days': count_change_factor, + 'passing_users': count_change_factor, } for mode in modes }) summary['enrollment_modes'].update({ @@ -84,6 +86,7 @@ def expected_result(self, item_id, modes=None, availability='Current', programs= 'count': 0, 'cumulative_count': 0, 'count_change_7_days': 0, + 'passing_users': 0, } for mode in set(enrollment_modes.ALL) - set(modes) }) no_prof = summary['enrollment_modes'].pop(enrollment_modes.PROFESSIONAL_NO_ID) @@ -92,6 +95,7 @@ def expected_result(self, item_id, modes=None, availability='Current', programs= 'count': prof['count'] + no_prof['count'], 'cumulative_count': prof['cumulative_count'] + no_prof['cumulative_count'], 'count_change_7_days': prof['count_change_7_days'] + no_prof['count_change_7_days'], + 'passing_users': prof['passing_users'] + no_prof['passing_users'], }) if programs: summary['programs'] = [CourseSamples.program_ids[0]] @@ -159,3 +163,10 @@ def test_programs(self): response = self.authenticated_get(self.path(exclude=self.always_exclude[:1], programs=['True'])) self.assertEquals(response.status_code, 200) self.assertItemsEqual(response.data, self.all_expected_results(programs=True)) + + @ddt.data('passing_users', ) + def test_exclude(self, field): + self.generate_data() + response = self.authenticated_get(self.path(exclude=[field])) + self.assertEquals(response.status_code, 200) + self.assertEquals(str(response.data).count(field), 0) diff --git a/analytics_data_api/v0/views/course_summaries.py b/analytics_data_api/v0/views/course_summaries.py index 85cecf05..1e725b20 100644 --- a/analytics_data_api/v0/views/course_summaries.py +++ b/analytics_data_api/v0/views/course_summaries.py @@ -54,7 +54,8 @@ class CourseSummariesView(APIListView): model = models.CourseMetaSummaryEnrollment model_id_field = 'course_id' programs_model = models.CourseProgramMetadata - count_fields = ('count', 'cumulative_count', 'count_change_7_days') # are initialized to 0 by default + count_fields = ('count', 'cumulative_count', 'count_change_7_days', + 'passing_users') # are initialized to 0 by default summary_meta_fields = ['catalog_course_title', 'catalog_course', 'start_time', 'end_time', 'pacing_type', 'availability'] # fields to extract from summary model @@ -120,6 +121,10 @@ def postprocess_field_dict(self, field_dict): # don't do expensive looping for programs if we are just going to throw it away field_dict = self.add_programs(field_dict) + for field in self.exclude: + for mode in field_dict['enrollment_modes']: + _ = field_dict['enrollment_modes'][mode].pop(field, None) + return field_dict def add_programs(self, field_dict):