Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
E
edx-analytics-data-api
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
edx
edx-analytics-data-api
Commits
3afb4103
Commit
3afb4103
authored
Oct 13, 2014
by
dylanrhodes
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Added REST API for grade_distribution and sequential_open_distribution tables and test cases
parent
29437878
Show whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
157 additions
and
0 deletions
+157
-0
analytics_data_api/v0/models.py
+26
-0
analytics_data_api/v0/serializers.py
+32
-0
analytics_data_api/v0/tests/test_views.py
+60
-0
analytics_data_api/v0/urls/problems.py
+5
-0
analytics_data_api/v0/views/problems.py
+34
-0
No files found.
analytics_data_api/v0/models.py
View file @
3afb4103
...
@@ -119,3 +119,29 @@ class CourseEnrollmentByCountry(BaseCourseEnrollment):
...
@@ -119,3 +119,29 @@ class CourseEnrollmentByCountry(BaseCourseEnrollment):
db_table
=
'course_enrollment_location_current'
db_table
=
'course_enrollment_location_current'
ordering
=
(
'date'
,
'course_id'
,
'country_code'
)
ordering
=
(
'date'
,
'course_id'
,
'country_code'
)
unique_together
=
[(
'course_id'
,
'date'
,
'country_code'
)]
unique_together
=
[(
'course_id'
,
'date'
,
'country_code'
)]
class
GradeDistribution
(
models
.
Model
):
""" Each row stores the count of a particular grade on a module for a given course. """
class
Meta
(
object
):
db_table
=
'grade_distribution'
module_id
=
models
.
CharField
(
db_index
=
True
,
max_length
=
255
,
db_column
=
'module_id'
)
course_id
=
models
.
CharField
(
db_index
=
True
,
max_length
=
255
,
db_column
=
'course_id'
)
grade
=
models
.
IntegerField
(
db_column
=
'grade'
)
max_grade
=
models
.
IntegerField
(
db_column
=
'max_grade'
)
count
=
models
.
IntegerField
(
db_column
=
'count'
)
created
=
models
.
DateTimeField
(
auto_now_add
=
True
,
db_column
=
'created'
)
class
SequentialOpenDistribution
(
models
.
Model
):
""" Each row stores the count of views a particular module has had in a given course. """
class
Meta
(
object
):
db_table
=
'sequential_open_distribution'
module_id
=
models
.
CharField
(
db_index
=
True
,
max_length
=
255
,
db_column
=
'module_id'
)
course_id
=
models
.
CharField
(
db_index
=
True
,
max_length
=
255
,
db_column
=
'course_id'
)
count
=
models
.
IntegerField
(
db_column
=
'count'
)
created
=
models
.
DateTimeField
(
auto_now_add
=
True
,
db_column
=
'created'
)
analytics_data_api/v0/serializers.py
View file @
3afb4103
...
@@ -54,6 +54,38 @@ class ProblemResponseAnswerDistributionSerializer(serializers.ModelSerializer):
...
@@ -54,6 +54,38 @@ class ProblemResponseAnswerDistributionSerializer(serializers.ModelSerializer):
)
)
class
GradeDistributionSerializer
(
serializers
.
ModelSerializer
):
"""
Representation of the grade_distribution table without id
"""
class
Meta
(
object
):
model
=
models
.
GradeDistribution
fields
=
(
'module_id'
,
'course_id'
,
'grade'
,
'max_grade'
,
'count'
,
'created'
)
class
SequentialOpenDistributionSerializer
(
serializers
.
ModelSerializer
):
"""
Representation of the sequential_open_distribution table without id
"""
class
Meta
(
object
):
model
=
models
.
SequentialOpenDistribution
fields
=
(
'module_id'
,
'course_id'
,
'count'
,
'created'
)
class
BaseCourseEnrollmentModelSerializer
(
serializers
.
ModelSerializer
):
class
BaseCourseEnrollmentModelSerializer
(
serializers
.
ModelSerializer
):
date
=
serializers
.
DateField
(
format
=
settings
.
DATE_FORMAT
)
date
=
serializers
.
DateField
(
format
=
settings
.
DATE_FORMAT
)
created
=
serializers
.
DateTimeField
(
format
=
settings
.
DATETIME_FORMAT
)
created
=
serializers
.
DateTimeField
(
format
=
settings
.
DATETIME_FORMAT
)
...
...
analytics_data_api/v0/tests/test_views.py
View file @
3afb4103
...
@@ -15,6 +15,8 @@ from analytics_data_api.v0 import models
...
@@ -15,6 +15,8 @@ from analytics_data_api.v0 import models
from
analytics_data_api.v0.constants
import
UNKNOWN_COUNTRY
,
UNKNOWN_COUNTRY_CODE
from
analytics_data_api.v0.constants
import
UNKNOWN_COUNTRY
,
UNKNOWN_COUNTRY_CODE
from
analytics_data_api.v0.models
import
CourseActivityWeekly
from
analytics_data_api.v0.models
import
CourseActivityWeekly
from
analytics_data_api.v0.serializers
import
ProblemResponseAnswerDistributionSerializer
from
analytics_data_api.v0.serializers
import
ProblemResponseAnswerDistributionSerializer
from
analytics_data_api.v0.serializers
import
GradeDistributionSerializer
from
analytics_data_api.v0.serializers
import
SequentialOpenDistributionSerializer
from
analytics_data_api.v0.tests.utils
import
flatten
from
analytics_data_api.v0.tests.utils
import
flatten
from
analyticsdataserver.tests
import
TestCaseWithAuthentication
from
analyticsdataserver.tests
import
TestCaseWithAuthentication
...
@@ -429,3 +431,61 @@ class CourseActivityWeeklyViewTests(CourseViewTestCaseMixin, TestCaseWithAuthent
...
@@ -429,3 +431,61 @@ class CourseActivityWeeklyViewTests(CourseViewTestCaseMixin, TestCaseWithAuthent
expected
=
self
.
format_as_response
(
*
self
.
model
.
objects
.
all
())
expected
=
self
.
format_as_response
(
*
self
.
model
.
objects
.
all
())
self
.
assertEqual
(
len
(
expected
),
2
)
self
.
assertEqual
(
len
(
expected
),
2
)
self
.
assertIntervalFilteringWorks
(
expected
,
self
.
interval_start
,
interval_end
+
datetime
.
timedelta
(
days
=
1
))
self
.
assertIntervalFilteringWorks
(
expected
,
self
.
interval_start
,
interval_end
+
datetime
.
timedelta
(
days
=
1
))
# pylint: disable=no-member,no-value-for-parameter
class
GradeDistributionTests
(
TestCaseWithAuthentication
):
path
=
'/grade_distribution'
maxDiff
=
None
@classmethod
def
setUpClass
(
cls
):
cls
.
course_id
=
"org/class/test"
cls
.
module_id
=
"i4x://org/class/test/problem/RANDOM_NUMBER"
cls
.
ad1
=
G
(
models
.
GradeDistribution
,
course_id
=
cls
.
course_id
,
module_id
=
cls
.
module_id
,
)
def
test_get
(
self
):
response
=
self
.
authenticated_get
(
'/api/v0/problems/
%
s
%
s'
%
(
self
.
module_id
,
self
.
path
))
self
.
assertEquals
(
response
.
status_code
,
200
)
expected_dict
=
GradeDistributionSerializer
(
self
.
ad1
)
.
data
actual_list
=
response
.
data
self
.
assertEquals
(
len
(
actual_list
),
1
)
self
.
assertDictEqual
(
actual_list
[
0
],
expected_dict
)
def
test_get_404
(
self
):
response
=
self
.
authenticated_get
(
'/api/v0/problems/
%
s
%
s'
%
(
"DOES-NOT-EXIST"
,
self
.
path
))
self
.
assertEquals
(
response
.
status_code
,
404
)
# pylint: disable=no-member,no-value-for-parameter
class
SequentialOpenDistributionTests
(
TestCaseWithAuthentication
):
path
=
'/sequential_open_distribution'
maxDiff
=
None
@classmethod
def
setUpClass
(
cls
):
cls
.
course_id
=
"org/class/test"
cls
.
module_id
=
"i4x://org/class/test/problem/RANDOM_NUMBER"
cls
.
ad1
=
G
(
models
.
SequentialOpenDistribution
,
course_id
=
cls
.
course_id
,
module_id
=
cls
.
module_id
,
)
def
test_get
(
self
):
response
=
self
.
authenticated_get
(
'/api/v0/problems/
%
s
%
s'
%
(
self
.
module_id
,
self
.
path
))
self
.
assertEquals
(
response
.
status_code
,
200
)
expected_dict
=
SequentialOpenDistributionSerializer
(
self
.
ad1
)
.
data
actual_list
=
response
.
data
self
.
assertEquals
(
len
(
actual_list
),
1
)
self
.
assertDictEqual
(
actual_list
[
0
],
expected_dict
)
def
test_get_404
(
self
):
response
=
self
.
authenticated_get
(
'/api/v0/problems/
%
s
%
s'
%
(
"DOES-NOT-EXIST"
,
self
.
path
))
self
.
assertEquals
(
response
.
status_code
,
404
)
analytics_data_api/v0/urls/problems.py
View file @
3afb4103
...
@@ -3,13 +3,18 @@ import re
...
@@ -3,13 +3,18 @@ import re
from
django.conf.urls
import
patterns
,
url
from
django.conf.urls
import
patterns
,
url
from
analytics_data_api.v0.views.problems
import
ProblemResponseAnswerDistributionView
from
analytics_data_api.v0.views.problems
import
ProblemResponseAnswerDistributionView
from
analytics_data_api.v0.views.problems
import
GradeDistributionView
from
analytics_data_api.v0.views.problems
import
SequentialOpenDistributionView
PROBLEM_URLS
=
[
PROBLEM_URLS
=
[
(
'answer_distribution'
,
ProblemResponseAnswerDistributionView
,
'answer_distribution'
),
(
'answer_distribution'
,
ProblemResponseAnswerDistributionView
,
'answer_distribution'
),
(
'grade_distribution'
,
GradeDistributionView
,
'grade_distribution'
),
]
]
urlpatterns
=
patterns
(
urlpatterns
=
patterns
(
''
,
''
,
url
(
r'^(?P<module_id>.+)/sequential_open_distribution$'
,
SequentialOpenDistributionView
.
as_view
(),
name
=
'sequential_open_distribution'
),
)
)
for
path
,
view
,
name
in
PROBLEM_URLS
:
for
path
,
view
,
name
in
PROBLEM_URLS
:
...
...
analytics_data_api/v0/views/problems.py
View file @
3afb4103
...
@@ -3,6 +3,12 @@ from rest_framework import generics
...
@@ -3,6 +3,12 @@ from rest_framework import generics
from
analytics_data_api.v0.models
import
ProblemResponseAnswerDistribution
from
analytics_data_api.v0.models
import
ProblemResponseAnswerDistribution
from
analytics_data_api.v0.serializers
import
ProblemResponseAnswerDistributionSerializer
from
analytics_data_api.v0.serializers
import
ProblemResponseAnswerDistributionSerializer
from
analytics_data_api.v0.models
import
GradeDistribution
from
analytics_data_api.v0.serializers
import
GradeDistributionSerializer
from
analytics_data_api.v0.models
import
SequentialOpenDistribution
from
analytics_data_api.v0.serializers
import
SequentialOpenDistributionSerializer
class
ProblemResponseAnswerDistributionView
(
generics
.
ListAPIView
):
class
ProblemResponseAnswerDistributionView
(
generics
.
ListAPIView
):
"""
"""
...
@@ -18,3 +24,31 @@ class ProblemResponseAnswerDistributionView(generics.ListAPIView):
...
@@ -18,3 +24,31 @@ class ProblemResponseAnswerDistributionView(generics.ListAPIView):
"""Select all the answer distribution response having to do with this usage of the problem."""
"""Select all the answer distribution response having to do with this usage of the problem."""
problem_id
=
self
.
kwargs
.
get
(
'problem_id'
)
problem_id
=
self
.
kwargs
.
get
(
'problem_id'
)
return
ProblemResponseAnswerDistribution
.
objects
.
filter
(
module_id
=
problem_id
)
return
ProblemResponseAnswerDistribution
.
objects
.
filter
(
module_id
=
problem_id
)
class
GradeDistributionView
(
generics
.
ListAPIView
):
"""
Distribution of grades for a particular module in a given course
"""
serializer_class
=
GradeDistributionSerializer
allow_empty
=
False
def
get_queryset
(
self
):
"""Select all grade distributions for a particular module"""
problem_id
=
self
.
kwargs
.
get
(
'problem_id'
)
return
GradeDistribution
.
objects
.
filter
(
module_id
=
problem_id
)
class
SequentialOpenDistributionView
(
generics
.
ListAPIView
):
"""
Distribution of view counts for a particular module in a given course
"""
serializer_class
=
SequentialOpenDistributionSerializer
allow_empty
=
False
def
get_queryset
(
self
):
"""Select the view count for a specific module"""
module_id
=
self
.
kwargs
.
get
(
'module_id'
)
return
SequentialOpenDistribution
.
objects
.
filter
(
module_id
=
module_id
)
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment