Commit f86ecabb by Clinton Blackburn Committed by Clinton Blackburn

Merge pull request #26 from edx/parts-unknown

Grouping and Returning Unknown Locations
parents a817d2c8 47c74d7f
......@@ -48,12 +48,13 @@ class Command(BaseCommand):
'doctorate': 0.0470
}
country_ratios = {
'US': 0.34,
'US': 0.33,
'GH': 0.12,
'IN': 0.10,
'CA': 0.14,
'CN': 0.22,
'DE': 0.08
'DE': 0.08,
'UNKNOWN': 0.01
}
# Generate birth year ratios
......
from django.db import models
from iso3166 import countries
from iso3166 import countries, Country
class CourseActivityWeekly(models.Model):
......@@ -99,6 +99,7 @@ class ProblemResponseAnswerDistribution(models.Model):
class CourseEnrollmentByCountry(BaseCourseEnrollment):
UNKNOWN_COUNTRY_CODE = 'UNKNOWN'
country_code = models.CharField(max_length=255, null=False, db_column='country_code')
@property
......@@ -107,6 +108,9 @@ class CourseEnrollmentByCountry(BaseCourseEnrollment):
Returns a Country object representing the country in this model's country_code.
"""
try:
if self.country_code == self.UNKNOWN_COUNTRY_CODE:
return Country(self.UNKNOWN_COUNTRY_CODE, None, None, None)
return countries.get(self.country_code)
except (KeyError, ValueError):
# Country code is not valid ISO-3166
......
......@@ -323,13 +323,27 @@ class CourseEnrollmentByLocationViewTests(CourseEnrollmentViewTestCaseMixin, Tes
model = models.CourseEnrollmentByCountry
def format_as_response(self, *args):
unknown = {'course_id': None, 'count': 0, 'date': None,
'country': {'alpha2': None, 'alpha3': None, 'name': u'UNKNOWN'}}
for arg in args:
if not arg.country:
unknown['course_id'] = arg.course_id
unknown['date'] = arg.date.strftime(settings.DATE_FORMAT)
unknown['count'] += arg.count
args = [arg for arg in args if arg.country_code not in ['', 'A1', 'A2', 'AP', 'EU', 'O1', 'UNKNOWN']]
args = sorted(args, key=lambda item: (item.date, item.course_id, item.country.alpha3))
return [
response = [
{'course_id': str(ce.course_id), 'count': ce.count, 'date': ce.date.strftime(settings.DATE_FORMAT),
'country': {'alpha2': ce.country.alpha2, 'alpha3': ce.country.alpha3, 'name': ce.country.name}} for ce in
args]
# Unknown comes last
response.append(unknown)
return response
def setUp(self):
super(CourseEnrollmentByLocationViewTests, self).setUp()
self.country = countries.get('US')
......
......@@ -313,7 +313,8 @@ class CourseEnrollmentByLocationView(BaseCourseEnrollmentView):
Course enrollment broken down by user location
Returns the enrollment of a course with users binned by their location. Location is calculated based on the user's
IP address.
IP address. Enrollment counts for users whose location cannot be determined will be included in an entry with
country.name set to UNKNOWN.
Countries are denoted by their <a href="http://www.iso.org/iso/country_codes/country_codes" target="_blank">ISO 3166 country code</a>.
......@@ -333,10 +334,36 @@ class CourseEnrollmentByLocationView(BaseCourseEnrollmentView):
def get_queryset(self):
queryset = super(CourseEnrollmentByLocationView, self).get_queryset()
# Remove all items where country is None
items = [item for item in queryset.all() if item.country is not None]
# Get all of the data from the database
items = queryset.all()
# Split into known and unknown
knowns = []
unknowns = []
for item in items:
if item.country:
knowns.append(item)
else:
unknowns.append(item)
# Group the unknowns by date and combine the counts
for key, group in groupby(unknowns, lambda x: (x.date, x.course_id)):
date = key[0]
course_id = key[1]
count = 0
for item in group:
count += item.count
# pylint: disable=unexpected-keyword-arg,no-value-for-parameter
knowns.append(models.CourseEnrollmentByCountry(
course_id=course_id,
date=date,
country_code=models.CourseEnrollmentByCountry.UNKNOWN_COUNTRY_CODE,
count=count
))
# Note: We are returning a list, instead of a queryset. This is
# acceptable since the consuming code simply expects the returned
# value to be iterable, not necessarily a queryset.
return items
return knowns
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