Commit fbaef361 by Clinton Blackburn

Removed Course Model

The pipeline does not yet support creating a courses table.
parent cd98dd07
...@@ -50,7 +50,7 @@ syncdb: ...@@ -50,7 +50,7 @@ syncdb:
$(foreach db_name,$(DATABASES),./manage.py syncdb --migrate --noinput --database=$(db_name);) $(foreach db_name,$(DATABASES),./manage.py syncdb --migrate --noinput --database=$(db_name);)
loaddata: syncdb loaddata: syncdb
python manage.py loaddata courses education_levels single_course_activity problem_response_answer_distribution --database=analytics python manage.py loaddata education_levels single_course_activity problem_response_answer_distribution --database=analytics
python manage.py generate_fake_enrollment_data python manage.py generate_fake_enrollment_data
demo: clean requirements loaddata demo: clean requirements loaddata
......
[
{
"pk": 1,
"model": "v0.course",
"fields": {
"course_id": "edX/DemoX/Demo_Course"
}
}
]
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
"pk": 40, "pk": 40,
"model": "v0.CourseActivityByWeek", "model": "v0.CourseActivityByWeek",
"fields": { "fields": {
"course": ["edX/DemoX/Demo_Course"], "course_id": "edX/DemoX/Demo_Course",
"interval_start": "2014-05-24T00:00:00Z", "interval_start": "2014-05-24T00:00:00Z",
"activity_type": "posted_forum", "activity_type": "posted_forum",
"count": 100, "count": 100,
...@@ -14,7 +14,7 @@ ...@@ -14,7 +14,7 @@
"pk": 106, "pk": 106,
"model": "v0.CourseActivityByWeek", "model": "v0.CourseActivityByWeek",
"fields": { "fields": {
"course": ["edX/DemoX/Demo_Course"], "course_id": "edX/DemoX/Demo_Course",
"interval_start": "2014-05-24T00:00:00Z", "interval_start": "2014-05-24T00:00:00Z",
"activity_type": "attempted_problem", "activity_type": "attempted_problem",
"count": 200, "count": 200,
...@@ -25,7 +25,7 @@ ...@@ -25,7 +25,7 @@
"pk": 201, "pk": 201,
"model": "v0.CourseActivityByWeek", "model": "v0.CourseActivityByWeek",
"fields": { "fields": {
"course": ["edX/DemoX/Demo_Course"], "course_id": "edX/DemoX/Demo_Course",
"interval_start": "2014-05-24T00:00:00Z", "interval_start": "2014-05-24T00:00:00Z",
"activity_type": "any", "activity_type": "any",
"count": 300, "count": 300,
...@@ -36,7 +36,7 @@ ...@@ -36,7 +36,7 @@
"pk": 725, "pk": 725,
"model": "v0.CourseActivityByWeek", "model": "v0.CourseActivityByWeek",
"fields": { "fields": {
"course": ["edX/DemoX/Demo_Course"], "course_id": "edX/DemoX/Demo_Course",
"interval_start": "2014-05-24T00:00:00Z", "interval_start": "2014-05-24T00:00:00Z",
"activity_type": "played_video", "activity_type": "played_video",
"count": 400, "count": 400,
......
# pylint: disable=line-too-long
import datetime import datetime
import random import random
...@@ -23,7 +25,7 @@ class Command(BaseCommand): ...@@ -23,7 +25,7 @@ class Command(BaseCommand):
def handle(self, *args, **options): def handle(self, *args, **options):
days = 120 days = 120
course = models.Course.objects.first() course_id = 'edX/DemoX/Demo_Course'
start_date = datetime.date(year=2014, month=1, day=1) start_date = datetime.date(year=2014, month=1, day=1)
genders = { genders = {
...@@ -65,29 +67,29 @@ class Command(BaseCommand): ...@@ -65,29 +67,29 @@ class Command(BaseCommand):
models.CourseEnrollmentByCountry]: models.CourseEnrollmentByCountry]:
model.objects.all().delete() model.objects.all().delete()
# Create new data data # Create new data
daily_total = 1500 daily_total = 1500
for i in range(days): for i in range(days):
daily_total = get_count(daily_total) daily_total = get_count(daily_total)
date = start_date + datetime.timedelta(days=i) date = start_date + datetime.timedelta(days=i)
models.CourseEnrollmentDaily.objects.create(course=course, date=date, count=daily_total) models.CourseEnrollmentDaily.objects.create(course_id=course_id, date=date, count=daily_total)
for gender, ratio in genders.iteritems(): for gender, ratio in genders.iteritems():
count = int(ratio * daily_total) count = int(ratio * daily_total)
models.CourseEnrollmentByGender.objects.create(course=course, date=date, count=count, gender=gender) models.CourseEnrollmentByGender.objects.create(course_id=course_id, date=date, count=count, gender=gender)
for short_name, ratio in education_levels.iteritems(): for short_name, ratio in education_levels.iteritems():
education_level = models.EducationLevel.objects.get(short_name=short_name) education_level = models.EducationLevel.objects.get(short_name=short_name)
count = int(ratio * daily_total) count = int(ratio * daily_total)
models.CourseEnrollmentByEducation.objects.create(course=course, date=date, count=count, models.CourseEnrollmentByEducation.objects.create(course_id=course_id, date=date, count=count,
education_level=education_level) education_level=education_level)
for country_code, ratio in countries.iteritems(): for country_code, ratio in countries.iteritems():
count = int(ratio * daily_total) count = int(ratio * daily_total)
models.CourseEnrollmentByCountry.objects.create(course=course, date=date, count=count, models.CourseEnrollmentByCountry.objects.create(course_id=course_id, date=date, count=count,
country_code=country_code) country_code=country_code)
for birth_year, ratio in birth_years.iteritems(): for birth_year, ratio in birth_years.iteritems():
count = int(ratio * daily_total) count = int(ratio * daily_total)
models.CourseEnrollmentByBirthYear.objects.create(course=course, date=date, count=count, models.CourseEnrollmentByBirthYear.objects.create(course_id=course_id, date=date, count=count,
birth_year=birth_year) birth_year=birth_year)
from django.db import models
class CourseManager(models.Manager):
def get_by_natural_key(self, course_id):
return self.get(course_id=course_id)
from collections import namedtuple from collections import namedtuple
from django.db import models from django.db import models
from iso3166 import countries from iso3166 import countries
from analytics_data_api.v0.managers import CourseManager
class Course(models.Model):
course_id = models.CharField(unique=True, max_length=255)
objects = CourseManager() # pylint: disable=no-value-for-parameter
class Meta(object):
db_table = 'courses'
class CourseActivityByWeek(models.Model): class CourseActivityByWeek(models.Model):
...@@ -19,7 +9,7 @@ class CourseActivityByWeek(models.Model): ...@@ -19,7 +9,7 @@ class CourseActivityByWeek(models.Model):
class Meta(object): class Meta(object):
db_table = 'course_activity' db_table = 'course_activity'
course = models.ForeignKey(Course, null=False) course_id = models.CharField(max_length=255)
interval_start = models.DateTimeField() interval_start = models.DateTimeField()
interval_end = models.DateTimeField() interval_end = models.DateTimeField()
activity_type = models.CharField(db_index=True, max_length=255) activity_type = models.CharField(db_index=True, max_length=255)
...@@ -28,11 +18,11 @@ class CourseActivityByWeek(models.Model): ...@@ -28,11 +18,11 @@ class CourseActivityByWeek(models.Model):
@classmethod @classmethod
def get_most_recent(cls, course_id, activity_type): def get_most_recent(cls, course_id, activity_type):
"""Activity for the week that was mostly recently computed.""" """Activity for the week that was mostly recently computed."""
return cls.objects.filter(course__course_id=course_id, activity_type=activity_type).latest('interval_end') return cls.objects.filter(course_id=course_id, activity_type=activity_type).latest('interval_end')
class BaseCourseEnrollment(models.Model): class BaseCourseEnrollment(models.Model):
course = models.ForeignKey(Course, null=False) course_id = models.CharField(max_length=255)
date = models.DateField(null=False, db_index=True) date = models.DateField(null=False, db_index=True)
count = models.IntegerField(null=False) count = models.IntegerField(null=False)
created = models.DateTimeField(auto_now_add=True) created = models.DateTimeField(auto_now_add=True)
...@@ -40,14 +30,14 @@ class BaseCourseEnrollment(models.Model): ...@@ -40,14 +30,14 @@ class BaseCourseEnrollment(models.Model):
class Meta(object): class Meta(object):
abstract = True abstract = True
get_latest_by = 'date' get_latest_by = 'date'
index_together = [('course', 'date',)] index_together = [('course_id', 'date',)]
class CourseEnrollmentDaily(BaseCourseEnrollment): class CourseEnrollmentDaily(BaseCourseEnrollment):
class Meta(BaseCourseEnrollment.Meta): class Meta(BaseCourseEnrollment.Meta):
db_table = 'course_enrollment_daily' db_table = 'course_enrollment_daily'
ordering = ('date', 'course') ordering = ('date', 'course_id')
unique_together = [('course', 'date',)] unique_together = [('course_id', 'date',)]
class CourseEnrollmentByBirthYear(BaseCourseEnrollment): class CourseEnrollmentByBirthYear(BaseCourseEnrollment):
...@@ -55,8 +45,8 @@ class CourseEnrollmentByBirthYear(BaseCourseEnrollment): ...@@ -55,8 +45,8 @@ class CourseEnrollmentByBirthYear(BaseCourseEnrollment):
class Meta(BaseCourseEnrollment.Meta): class Meta(BaseCourseEnrollment.Meta):
db_table = 'course_enrollment_birth_year_daily' db_table = 'course_enrollment_birth_year_daily'
ordering = ('date', 'course', 'birth_year') ordering = ('date', 'course_id', 'birth_year')
unique_together = [('course', 'date', 'birth_year')] unique_together = [('course_id', 'date', 'birth_year')]
class EducationLevel(models.Model): class EducationLevel(models.Model):
...@@ -75,8 +65,8 @@ class CourseEnrollmentByEducation(BaseCourseEnrollment): ...@@ -75,8 +65,8 @@ class CourseEnrollmentByEducation(BaseCourseEnrollment):
class Meta(BaseCourseEnrollment.Meta): class Meta(BaseCourseEnrollment.Meta):
db_table = 'course_enrollment_education_level_daily' db_table = 'course_enrollment_education_level_daily'
ordering = ('date', 'course', 'education_level') ordering = ('date', 'course_id', 'education_level')
unique_together = [('course', 'date', 'education_level')] unique_together = [('course_id', 'date', 'education_level')]
class CourseEnrollmentByGender(BaseCourseEnrollment): class CourseEnrollmentByGender(BaseCourseEnrollment):
...@@ -84,8 +74,8 @@ class CourseEnrollmentByGender(BaseCourseEnrollment): ...@@ -84,8 +74,8 @@ class CourseEnrollmentByGender(BaseCourseEnrollment):
class Meta(BaseCourseEnrollment.Meta): class Meta(BaseCourseEnrollment.Meta):
db_table = 'course_enrollment_gender_daily' db_table = 'course_enrollment_gender_daily'
ordering = ('date', 'course', 'gender') ordering = ('date', 'course_id', 'gender')
unique_together = [('course', 'date', 'gender')] unique_together = [('course_id', 'date', 'gender')]
class ProblemResponseAnswerDistribution(models.Model): class ProblemResponseAnswerDistribution(models.Model):
...@@ -119,5 +109,5 @@ class CourseEnrollmentByCountry(BaseCourseEnrollment): ...@@ -119,5 +109,5 @@ class CourseEnrollmentByCountry(BaseCourseEnrollment):
class Meta(BaseCourseEnrollment.Meta): class Meta(BaseCourseEnrollment.Meta):
db_table = 'course_enrollment_location_current' db_table = 'course_enrollment_location_current'
ordering = ('date', 'course', 'country_code') ordering = ('date', 'course_id', 'country_code')
unique_together = [('course', 'date', 'country_code')] unique_together = [('course_id', 'date', 'country_code')]
...@@ -3,16 +3,7 @@ from rest_framework import serializers ...@@ -3,16 +3,7 @@ from rest_framework import serializers
from analytics_data_api.v0 import models from analytics_data_api.v0 import models
class CourseIdMixin(object): class CourseActivityByWeekSerializer(serializers.ModelSerializer):
def get_course_id(self, obj):
return obj.course.course_id
class RequiredSerializerMethodField(serializers.SerializerMethodField):
required = True
class CourseActivityByWeekSerializer(serializers.ModelSerializer, CourseIdMixin):
""" """
Representation of CourseActivityByWeek that excludes the id field. Representation of CourseActivityByWeek that excludes the id field.
...@@ -20,8 +11,6 @@ class CourseActivityByWeekSerializer(serializers.ModelSerializer, CourseIdMixin) ...@@ -20,8 +11,6 @@ class CourseActivityByWeekSerializer(serializers.ModelSerializer, CourseIdMixin)
particular record is likely to change unexpectedly so we avoid exposing it. particular record is likely to change unexpectedly so we avoid exposing it.
""" """
course_id = RequiredSerializerMethodField('get_course_id')
class Meta(object): class Meta(object):
model = models.CourseActivityByWeek model = models.CourseActivityByWeek
fields = ('interval_start', 'interval_end', 'activity_type', 'count', 'course_id') fields = ('interval_start', 'interval_end', 'activity_type', 'count', 'course_id')
...@@ -51,8 +40,7 @@ class ProblemResponseAnswerDistributionSerializer(serializers.ModelSerializer): ...@@ -51,8 +40,7 @@ class ProblemResponseAnswerDistributionSerializer(serializers.ModelSerializer):
) )
class BaseCourseEnrollmentModelSerializer(serializers.ModelSerializer, CourseIdMixin): class BaseCourseEnrollmentModelSerializer(serializers.ModelSerializer):
course_id = RequiredSerializerMethodField('get_course_id')
date = serializers.DateField(format=settings.DATE_FORMAT) date = serializers.DateField(format=settings.DATE_FORMAT)
......
from django.core.exceptions import ObjectDoesNotExist
from django.test import TestCase
from django_dynamic_fixture import G
from analytics_data_api.v0.models import Course
class CourseManagerTests(TestCase):
def test_get_by_natural_key(self):
course_id = 'edX/DemoX/Demo_Course'
self.assertRaises(ObjectDoesNotExist, Course.objects.get_by_natural_key, course_id)
course = G(Course, course_id=course_id)
self.assertEqual(course, Course.objects.get_by_natural_key(course_id))
...@@ -4,7 +4,6 @@ ...@@ -4,7 +4,6 @@
import StringIO import StringIO
import csv import csv
import datetime import datetime
import random
from django.conf import settings from django.conf import settings
from django_dynamic_fixture import G from django_dynamic_fixture import G
...@@ -18,19 +17,19 @@ from analyticsdataserver.tests import TestCaseWithAuthentication ...@@ -18,19 +17,19 @@ from analyticsdataserver.tests import TestCaseWithAuthentication
class CourseActivityLastWeekTest(TestCaseWithAuthentication): class CourseActivityLastWeekTest(TestCaseWithAuthentication):
# pylint: disable=line-too-long
def setUp(self): def setUp(self):
super(CourseActivityLastWeekTest, self).setUp() super(CourseActivityLastWeekTest, self).setUp()
self.course_id = 'edX/DemoX/Demo_Course' self.course_id = 'edX/DemoX/Demo_Course'
self.course = G(models.Course, course_id=self.course_id)
interval_start = '2014-05-24T00:00:00Z' interval_start = '2014-05-24T00:00:00Z'
interval_end = '2014-06-01T00:00:00Z' interval_end = '2014-06-01T00:00:00Z'
G(models.CourseActivityByWeek, course=self.course, interval_start=interval_start, interval_end=interval_end, G(models.CourseActivityByWeek, course_id=self.course_id, interval_start=interval_start, interval_end=interval_end,
activity_type='posted_forum', count=100) activity_type='posted_forum', count=100)
G(models.CourseActivityByWeek, course=self.course, interval_start=interval_start, interval_end=interval_end, G(models.CourseActivityByWeek, course_id=self.course_id, interval_start=interval_start, interval_end=interval_end,
activity_type='attempted_problem', count=200) activity_type='attempted_problem', count=200)
G(models.CourseActivityByWeek, course=self.course, interval_start=interval_start, interval_end=interval_end, G(models.CourseActivityByWeek, course_id=self.course_id, interval_start=interval_start, interval_end=interval_end,
activity_type='any', count=300) activity_type='any', count=300)
G(models.CourseActivityByWeek, course=self.course, interval_start=interval_start, interval_end=interval_end, G(models.CourseActivityByWeek, course_id=self.course_id, interval_start=interval_start, interval_end=interval_end,
activity_type='played_video', count=400) activity_type='played_video', count=400)
def test_activity(self): def test_activity(self):
...@@ -87,27 +86,18 @@ class CourseEnrollmentViewTestCase(object): ...@@ -87,27 +86,18 @@ class CourseEnrollmentViewTestCase(object):
path = None path = None
order_by = [] order_by = []
def _get_non_existent_course_id(self):
course_id = random.randint(100, 9999)
if not models.Course.objects.filter(course_id=course_id).exists():
return course_id
return self._get_non_existent_course_id()
def get_expected_response(self, *args): def get_expected_response(self, *args):
raise NotImplementedError raise NotImplementedError
def test_get_not_found(self): def test_get_not_found(self):
""" Requests made against non-existent courses should return a 404 """ """ Requests made against non-existent courses should return a 404 """
course_id = self._get_non_existent_course_id() course_id = 'edX/DemoX/Non_Existent_Course'
self.assertFalse(self.model.objects.filter(course__course_id=course_id).exists())
response = self.authenticated_get('/api/v0/courses/%s%s' % (course_id, self.path)) response = self.authenticated_get('/api/v0/courses/%s%s' % (course_id, self.path))
self.assertEquals(response.status_code, 404) self.assertEquals(response.status_code, 404)
def test_get(self): def test_get(self):
# Validate the basic response status # Validate the basic response status
response = self.authenticated_get('/api/v0/courses/%s%s' % (self.course.course_id, self.path,)) response = self.authenticated_get('/api/v0/courses/%s%s' % (self.course_id, self.path,))
self.assertEquals(response.status_code, 200) self.assertEquals(response.status_code, 200)
# Validate the data is correct and sorted chronologically # Validate the data is correct and sorted chronologically
...@@ -115,7 +105,7 @@ class CourseEnrollmentViewTestCase(object): ...@@ -115,7 +105,7 @@ class CourseEnrollmentViewTestCase(object):
self.assertEquals(response.data, expected) self.assertEquals(response.data, expected)
def test_get_csv(self): def test_get_csv(self):
path = '/api/v0/courses/%s%s' % (self.course.course_id, self.path,) path = '/api/v0/courses/%s%s' % (self.course_id, self.path,)
csv_content_type = 'text/csv' csv_content_type = 'text/csv'
response = self.authenticated_get(path, HTTP_ACCEPT=csv_content_type) response = self.authenticated_get(path, HTTP_ACCEPT=csv_content_type)
...@@ -143,17 +133,15 @@ class CourseEnrollmentViewTestCase(object): ...@@ -143,17 +133,15 @@ class CourseEnrollmentViewTestCase(object):
self.assertIntervalFilteringWorks(expected, self.date, self.date + datetime.timedelta(days=1)) self.assertIntervalFilteringWorks(expected, self.date, self.date + datetime.timedelta(days=1))
def assertIntervalFilteringWorks(self, expected_response, start_date, end_date): def assertIntervalFilteringWorks(self, expected_response, start_date, end_date):
course = self.course
# If start date is after date of existing data, no data should be returned # If start date is after date of existing data, no data should be returned
date = (start_date + datetime.timedelta(days=30)).strftime(settings.DATE_FORMAT) date = (start_date + datetime.timedelta(days=30)).strftime(settings.DATE_FORMAT)
response = self.authenticated_get('/api/v0/courses/%s%s?start_date=%s' % (course.course_id, self.path, date)) response = self.authenticated_get('/api/v0/courses/%s%s?start_date=%s' % (self.course_id, self.path, date))
self.assertEquals(response.status_code, 200) self.assertEquals(response.status_code, 200)
self.assertListEqual([], response.data) self.assertListEqual([], response.data)
# If end date is before date of existing data, no data should be returned # If end date is before date of existing data, no data should be returned
date = (start_date - datetime.timedelta(days=30)).strftime(settings.DATE_FORMAT) date = (start_date - datetime.timedelta(days=30)).strftime(settings.DATE_FORMAT)
response = self.authenticated_get('/api/v0/courses/%s%s?end_date=%s' % (course.course_id, self.path, date)) response = self.authenticated_get('/api/v0/courses/%s%s?end_date=%s' % (self.course_id, self.path, date))
self.assertEquals(response.status_code, 200) self.assertEquals(response.status_code, 200)
self.assertListEqual([], response.data) self.assertListEqual([], response.data)
...@@ -161,7 +149,7 @@ class CourseEnrollmentViewTestCase(object): ...@@ -161,7 +149,7 @@ class CourseEnrollmentViewTestCase(object):
start_date = start_date.strftime(settings.DATE_FORMAT) start_date = start_date.strftime(settings.DATE_FORMAT)
end_date = end_date.strftime(settings.DATE_FORMAT) end_date = end_date.strftime(settings.DATE_FORMAT)
response = self.authenticated_get( response = self.authenticated_get(
'/api/v0/courses/%s%s?start_date=%s&end_date=%s' % (course.course_id, self.path, start_date, end_date)) '/api/v0/courses/%s%s?start_date=%s&end_date=%s' % (self.course_id, self.path, start_date, end_date))
self.assertEquals(response.status_code, 200) self.assertEquals(response.status_code, 200)
self.assertListEqual(response.data, expected_response) self.assertListEqual(response.data, expected_response)
...@@ -173,20 +161,20 @@ class CourseEnrollmentByBirthYearViewTests(TestCaseWithAuthentication, CourseEnr ...@@ -173,20 +161,20 @@ class CourseEnrollmentByBirthYearViewTests(TestCaseWithAuthentication, CourseEnr
@classmethod @classmethod
def setUpClass(cls): def setUpClass(cls):
cls.course = G(models.Course) cls.course_id = 'edX/DemoX/Demo_Course'
cls.date = datetime.date(2014, 1, 1) cls.date = datetime.date(2014, 1, 1)
G(cls.model, course=cls.course, date=cls.date, birth_year=1956) G(cls.model, course_id=cls.course_id, date=cls.date, birth_year=1956)
G(cls.model, course=cls.course, date=cls.date, birth_year=1986) G(cls.model, course_id=cls.course_id, date=cls.date, birth_year=1986)
G(cls.model, course=cls.course, date=cls.date - datetime.timedelta(days=10), birth_year=1956) G(cls.model, course_id=cls.course_id, date=cls.date - datetime.timedelta(days=10), birth_year=1956)
G(cls.model, course=cls.course, date=cls.date - datetime.timedelta(days=10), birth_year=1986) G(cls.model, course_id=cls.course_id, date=cls.date - datetime.timedelta(days=10), birth_year=1986)
def get_expected_response(self, *args): def get_expected_response(self, *args):
return [ return [
{'course_id': str(ce.course.course_id), 'count': ce.count, 'date': ce.date.strftime(settings.DATE_FORMAT), {'course_id': str(ce.course_id), 'count': ce.count, 'date': ce.date.strftime(settings.DATE_FORMAT),
'birth_year': ce.birth_year} for ce in args] 'birth_year': ce.birth_year} for ce in args]
def test_get(self): def test_get(self):
response = self.authenticated_get('/api/v0/courses/%s%s' % (self.course.course_id, self.path,)) response = self.authenticated_get('/api/v0/courses/%s%s' % (self.course_id, self.path,))
self.assertEquals(response.status_code, 200) self.assertEquals(response.status_code, 200)
expected = self.get_expected_response(*self.model.objects.filter(date=self.date)) expected = self.get_expected_response(*self.model.objects.filter(date=self.date))
...@@ -206,16 +194,16 @@ class CourseEnrollmentByEducationViewTests(TestCaseWithAuthentication, CourseEnr ...@@ -206,16 +194,16 @@ class CourseEnrollmentByEducationViewTests(TestCaseWithAuthentication, CourseEnr
def setUpClass(cls): def setUpClass(cls):
cls.el1 = G(models.EducationLevel, name='Doctorate', short_name='doctorate') cls.el1 = G(models.EducationLevel, name='Doctorate', short_name='doctorate')
cls.el2 = G(models.EducationLevel, name='Top Secret', short_name='top_secret') cls.el2 = G(models.EducationLevel, name='Top Secret', short_name='top_secret')
cls.course = G(models.Course) cls.course_id = 'edX/DemoX/Demo_Course'
cls.date = datetime.date(2014, 1, 1) cls.date = datetime.date(2014, 1, 1)
G(cls.model, course=cls.course, date=cls.date, education_level=cls.el1) G(cls.model, course_id=cls.course_id, date=cls.date, education_level=cls.el1)
G(cls.model, course=cls.course, date=cls.date, education_level=cls.el2) G(cls.model, course_id=cls.course_id, date=cls.date, education_level=cls.el2)
G(cls.model, course=cls.course, date=cls.date - datetime.timedelta(days=2), G(cls.model, course_id=cls.course_id, date=cls.date - datetime.timedelta(days=2),
education_level=cls.el2) education_level=cls.el2)
def get_expected_response(self, *args): def get_expected_response(self, *args):
return [ return [
{'course_id': str(ce.course.course_id), 'count': ce.count, 'date': ce.date.strftime(settings.DATE_FORMAT), {'course_id': str(ce.course_id), 'count': ce.count, 'date': ce.date.strftime(settings.DATE_FORMAT),
'education_level': {'name': ce.education_level.name, 'short_name': ce.education_level.short_name}} for 'education_level': {'name': ce.education_level.name, 'short_name': ce.education_level.short_name}} for
ce in args] ce in args]
...@@ -227,15 +215,15 @@ class CourseEnrollmentByGenderViewTests(TestCaseWithAuthentication, CourseEnroll ...@@ -227,15 +215,15 @@ class CourseEnrollmentByGenderViewTests(TestCaseWithAuthentication, CourseEnroll
@classmethod @classmethod
def setUpClass(cls): def setUpClass(cls):
cls.course = G(models.Course) cls.course_id = 'edX/DemoX/Demo_Course'
cls.date = datetime.date(2014, 1, 1) cls.date = datetime.date(2014, 1, 1)
G(cls.model, course=cls.course, gender='m', date=cls.date, count=34) G(cls.model, course_id=cls.course_id, gender='m', date=cls.date, count=34)
G(cls.model, course=cls.course, gender='f', date=cls.date, count=45) G(cls.model, course_id=cls.course_id, gender='f', date=cls.date, count=45)
G(cls.model, course=cls.course, gender='f', date=cls.date - datetime.timedelta(days=2), count=45) G(cls.model, course_id=cls.course_id, gender='f', date=cls.date - datetime.timedelta(days=2), count=45)
def get_expected_response(self, *args): def get_expected_response(self, *args):
return [ return [
{'course_id': str(ce.course.course_id), 'count': ce.count, 'date': ce.date.strftime(settings.DATE_FORMAT), {'course_id': str(ce.course_id), 'count': ce.count, 'date': ce.date.strftime(settings.DATE_FORMAT),
'gender': ce.gender} for ce in args] 'gender': ce.gender} for ce in args]
...@@ -276,14 +264,14 @@ class CourseEnrollmentViewTests(TestCaseWithAuthentication, CourseEnrollmentView ...@@ -276,14 +264,14 @@ class CourseEnrollmentViewTests(TestCaseWithAuthentication, CourseEnrollmentView
@classmethod @classmethod
def setUpClass(cls): def setUpClass(cls):
cls.course = G(models.Course) cls.course_id = 'edX/DemoX/Demo_Course'
cls.date = datetime.date(2014, 1, 1) cls.date = datetime.date(2014, 1, 1)
G(cls.model, course=cls.course, date=cls.date, count=203) G(cls.model, course_id=cls.course_id, date=cls.date, count=203)
G(cls.model, course=cls.course, date=cls.date - datetime.timedelta(days=5), count=203) G(cls.model, course_id=cls.course_id, date=cls.date - datetime.timedelta(days=5), count=203)
def get_expected_response(self, *args): def get_expected_response(self, *args):
return [ return [
{'course_id': str(ce.course.course_id), 'count': ce.count, 'date': ce.date.strftime(settings.DATE_FORMAT)} {'course_id': str(ce.course_id), 'count': ce.count, 'date': ce.date.strftime(settings.DATE_FORMAT)}
for ce in args] for ce in args]
...@@ -292,16 +280,16 @@ class CourseEnrollmentByLocationViewTests(TestCaseWithAuthentication, CourseEnro ...@@ -292,16 +280,16 @@ class CourseEnrollmentByLocationViewTests(TestCaseWithAuthentication, CourseEnro
model = models.CourseEnrollmentByCountry model = models.CourseEnrollmentByCountry
def get_expected_response(self, *args): def get_expected_response(self, *args):
args = sorted(args, key=lambda item: (item.date, item.course.course_id, item.country.code)) args = sorted(args, key=lambda item: (item.date, item.course_id, item.country.code))
return [ return [
{'course_id': str(ce.course.course_id), 'count': ce.count, 'date': ce.date.strftime(settings.DATE_FORMAT), {'course_id': str(ce.course_id), 'count': ce.count, 'date': ce.date.strftime(settings.DATE_FORMAT),
'country': {'code': ce.country.code, 'name': ce.country.name}} for ce in args] 'country': {'code': ce.country.code, 'name': ce.country.name}} for ce in args]
@classmethod @classmethod
def setUpClass(cls): def setUpClass(cls):
cls.course = G(models.Course) cls.course_id = 'edX/DemoX/Demo_Course'
cls.date = datetime.date(2014, 1, 1) cls.date = datetime.date(2014, 1, 1)
cls.country = countries.get('US') cls.country = countries.get('US')
G(cls.model, course=cls.course, country_code='US', count=455, date=cls.date) G(cls.model, course_id=cls.course_id, country_code='US', count=455, date=cls.date)
G(cls.model, course=cls.course, country_code='CA', count=356, date=cls.date) G(cls.model, course_id=cls.course_id, country_code='CA', count=356, date=cls.date)
G(cls.model, course=cls.course, country_code='IN', count=12, date=cls.date - datetime.timedelta(days=29)) G(cls.model, course_id=cls.course_id, country_code='IN', count=12, date=cls.date - datetime.timedelta(days=29))
...@@ -5,7 +5,6 @@ from django.core.exceptions import ObjectDoesNotExist ...@@ -5,7 +5,6 @@ from django.core.exceptions import ObjectDoesNotExist
from django.db.models import Max from django.db.models import Max
from django.http import Http404 from django.http import Http404
from rest_framework import generics from rest_framework import generics
from rest_framework.generics import get_object_or_404
from analytics_data_api.v0 import models, serializers from analytics_data_api.v0 import models, serializers
...@@ -53,8 +52,11 @@ class CourseActivityMostRecentWeekView(generics.RetrieveAPIView): ...@@ -53,8 +52,11 @@ class CourseActivityMostRecentWeekView(generics.RetrieveAPIView):
class BaseCourseEnrollmentView(generics.ListAPIView): class BaseCourseEnrollmentView(generics.ListAPIView):
def get_course_or_404(self): def verify_course_exists_or_404(self, course_id):
return get_object_or_404(models.Course, course_id=self.kwargs.get('course_id')) if self.model.objects.filter(course_id=course_id).exists():
return True
raise Http404
def apply_date_filtering(self, queryset): def apply_date_filtering(self, queryset):
if 'start_date' in self.request.QUERY_PARAMS or 'end_date' in self.request.QUERY_PARAMS: if 'start_date' in self.request.QUERY_PARAMS or 'end_date' in self.request.QUERY_PARAMS:
...@@ -77,8 +79,9 @@ class BaseCourseEnrollmentView(generics.ListAPIView): ...@@ -77,8 +79,9 @@ class BaseCourseEnrollmentView(generics.ListAPIView):
return queryset return queryset
def get_queryset(self): def get_queryset(self):
course = self.get_course_or_404() course_id = self.kwargs.get('course_id')
queryset = self.model.objects.filter(course=course) self.verify_course_exists_or_404(course_id)
queryset = self.model.objects.filter(course_id=course_id)
queryset = self.apply_date_filtering(queryset) queryset = self.apply_date_filtering(queryset)
return queryset return queryset
...@@ -185,9 +188,4 @@ class CourseEnrollmentByLocationView(BaseCourseEnrollmentView): ...@@ -185,9 +188,4 @@ class CourseEnrollmentByLocationView(BaseCourseEnrollmentView):
""" """
serializer_class = serializers.CourseEnrollmentByCountrySerializer serializer_class = serializers.CourseEnrollmentByCountrySerializer
model = models.CourseEnrollmentByCountry
def get_queryset(self):
course = self.get_course_or_404()
queryset = models.CourseEnrollmentByCountry.objects.filter(course=course)
queryset = self.apply_date_filtering(queryset)
return queryset
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