Commit dd809dfd by sanfordstudent Committed by GitHub

Merge pull request #13961 from edx/sstudent/TNL-5895

Add first_attempted to subsection grades data model
parents 48507af2 6d50044e
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('grades', '0007_add_passed_timestamp_column'),
]
operations = [
migrations.AddField(
model_name='persistentsubsectiongrade',
name='first_attempted',
field=models.DateTimeField(null=True, blank=True),
),
]
...@@ -236,6 +236,11 @@ class PersistentSubsectionGrade(TimeStampedModel): ...@@ -236,6 +236,11 @@ class PersistentSubsectionGrade(TimeStampedModel):
earned_graded = models.FloatField(blank=False) earned_graded = models.FloatField(blank=False)
possible_graded = models.FloatField(blank=False) possible_graded = models.FloatField(blank=False)
# timestamp for the learner's first attempt at content in
# this subsection. If null, indicates no attempt
# has yet been made.
first_attempted = models.DateTimeField(null=True, blank=True)
# track which blocks were visible at the time of grade calculation # track which blocks were visible at the time of grade calculation
visible_blocks = models.ForeignKey(VisibleBlocks, db_column='visible_blocks_hash', to_field='hashed') visible_blocks = models.ForeignKey(VisibleBlocks, db_column='visible_blocks_hash', to_field='hashed')
...@@ -253,7 +258,9 @@ class PersistentSubsectionGrade(TimeStampedModel): ...@@ -253,7 +258,9 @@ class PersistentSubsectionGrade(TimeStampedModel):
""" """
Returns a string representation of this model. Returns a string representation of this model.
""" """
return u"{} user: {}, course version: {}, subsection {} ({}). {}/{} graded, {}/{} all".format( return (
u"{} user: {}, course version: {}, subsection: {} ({}). {}/{} graded, {}/{} all, first_attempted: {}"
).format(
type(self).__name__, type(self).__name__,
self.user_id, self.user_id,
self.course_version, self.course_version,
...@@ -263,6 +270,7 @@ class PersistentSubsectionGrade(TimeStampedModel): ...@@ -263,6 +270,7 @@ class PersistentSubsectionGrade(TimeStampedModel):
self.possible_graded, self.possible_graded,
self.earned_all, self.earned_all,
self.possible_all, self.possible_all,
self.first_attempted,
) )
@classmethod @classmethod
......
...@@ -210,6 +210,7 @@ class PersistentSubsectionGradeTest(GradesModelTestCase): ...@@ -210,6 +210,7 @@ class PersistentSubsectionGradeTest(GradesModelTestCase):
"earned_graded": 6.0, "earned_graded": 6.0,
"possible_graded": 8.0, "possible_graded": 8.0,
"visible_blocks": self.block_records, "visible_blocks": self.block_records,
"first_attempted": "2016-08-01 18:53:24.354741",
} }
def test_create(self): def test_create(self):
...@@ -235,10 +236,27 @@ class PersistentSubsectionGradeTest(GradesModelTestCase): ...@@ -235,10 +236,27 @@ class PersistentSubsectionGradeTest(GradesModelTestCase):
with self.assertRaises(IntegrityError): with self.assertRaises(IntegrityError):
PersistentSubsectionGrade.create_grade(**self.params) PersistentSubsectionGrade.create_grade(**self.params)
def test_course_version_is_optional(self): @ddt.data("course_version", "first_attempted")
del self.params["course_version"] def test_optional_fields(self, field):
del self.params[field]
PersistentSubsectionGrade.create_grade(**self.params) PersistentSubsectionGrade.create_grade(**self.params)
@ddt.data(
("user_id", IntegrityError),
("usage_key", KeyError),
("subtree_edited_timestamp", IntegrityError),
("earned_all", IntegrityError),
("possible_all", IntegrityError),
("earned_graded", IntegrityError),
("possible_graded", IntegrityError),
("visible_blocks", KeyError),
)
@ddt.unpack
def test_non_optional_fields(self, field, error):
del self.params[field]
with self.assertRaises(error):
PersistentSubsectionGrade.create_grade(**self.params)
@ddt.data(True, False) @ddt.data(True, False)
def test_update_or_create_grade(self, already_created): def test_update_or_create_grade(self, already_created):
created_grade = PersistentSubsectionGrade.create_grade(**self.params) if already_created else None created_grade = PersistentSubsectionGrade.create_grade(**self.params) if already_created else None
......
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