Commit a5e721e4 by Eric Fischer Committed by Diana Huang

Use score summaries in data download

The submissions API has a get_score() method which, given a student item,
will look up the relevant ScoreSummary and return the latest Score it
contains. Our data download should do the same.

To avoid confusion, we have elected to hide scores that could not be
returned from api.get_score(). The other options are:
- include a score that may be for a different submission for the same
    student item, if using ScoreSummary.latest in all cases
- include scores that may not "count", because they'll never be the
    return value of api.get_score()

Test has been updated.
parent feb2ae3d
......@@ -414,7 +414,9 @@ def get_all_submissions(course_id, item_id, item_type, read_replica=True):
def get_all_course_submission_information(course_id, item_type, read_replica=True):
""" For the given course, get all the submissions, student items, and scores of the given item type.
""" For the given course, get all student items of the given item type, all the submissions for those itemes,
and the latest scores for each item. If a submission was given a score that is not the latest score for the
relevant student item, it will still be included but without score.
Args:
course_id (str): The course that we are getting submissions from.
......@@ -434,7 +436,8 @@ def get_all_course_submission_information(course_id, item_type, read_replica=Tru
submitted_at
created_at
answer
(3) a score with the following fields:
(3) a score with the following fields, if one exists and it is the latest score:
(if both conditions are not met, an empty dict is returned here)
student_item
submission
points_earned
......@@ -447,27 +450,26 @@ def get_all_course_submission_information(course_id, item_type, read_replica=Tru
if read_replica:
submission_qs = _use_read_replica(submission_qs)
query = submission_qs.select_related('student_item').prefetch_related('score_set').filter(
query = submission_qs.select_related('student_item__scoresummary__latest__submission').filter(
student_item__course_id=course_id,
student_item__item_type=item_type,
).iterator()
for submission in query:
student_item = submission.student_item
if submission.score_set.count() > 0:
for score in submission.score_set.all():
yield (
StudentItemSerializer(student_item).data,
SubmissionSerializer(submission).data,
ScoreSerializer(score).data
)
else:
# Make sure we return submission information even if there isn't a score associated with it.
yield (
StudentItemSerializer(student_item).data,
SubmissionSerializer(submission).data,
{}
)
serialized_score = {}
if hasattr(student_item, 'scoresummary'):
latest_score = student_item.scoresummary.latest
# Only include the score if it is not a reset score (is_hidden), and if the current submission is the same
# as the student_item's latest score's submission. This matches the behavior of the API's get_score method.
if (not latest_score.is_hidden()) and latest_score.submission.uuid == submission.uuid:
serialized_score = ScoreSerializer(latest_score).data
yield (
StudentItemSerializer(student_item).data,
SubmissionSerializer(submission).data,
serialized_score
)
def get_top_submissions(course_id, item_id, item_type, number_of_top_scores, use_cache=True, read_replica=True):
......
......@@ -101,16 +101,18 @@ class TestSubmissionsApi(TestCase):
self._assert_submission(submissions[1], ANSWER_TWO, student_item.pk, 2)
self.assertEqual(submissions[1]['student_id'], STUDENT_ITEM['student_id'])
def test_get_course_submissions(self):
@ddt.data(True, False)
def test_get_course_submissions(self, set_scores):
submission1 = api.create_submission(STUDENT_ITEM, ANSWER_ONE)
submission2 = api.create_submission(STUDENT_ITEM, ANSWER_TWO)
submission3 = api.create_submission(SECOND_STUDENT_ITEM, ANSWER_ONE)
submission4 = api.create_submission(SECOND_STUDENT_ITEM, ANSWER_TWO)
api.set_score(submission1['uuid'], 1, 4)
api.set_score(submission2['uuid'], 2, 4)
api.set_score(submission3['uuid'], 3, 4)
api.set_score(submission4['uuid'], 4, 4)
if set_scores:
api.set_score(submission1['uuid'], 1, 4)
api.set_score(submission2['uuid'], 2, 4)
api.set_score(submission3['uuid'], 3, 4)
api.set_score(submission4['uuid'], 4, 4)
submissions_and_scores = list(api.get_all_course_submission_information(
STUDENT_ITEM['course_id'],
......@@ -123,19 +125,26 @@ class TestSubmissionsApi(TestCase):
self.assertDictEqual(SECOND_STUDENT_ITEM, submissions_and_scores[0][0])
self._assert_submission(submissions_and_scores[0][1], submission4['answer'], student_item2.pk, 2)
self._assert_score(submissions_and_scores[0][2], 4, 4)
self.assertDictEqual(SECOND_STUDENT_ITEM, submissions_and_scores[1][0])
self._assert_submission(submissions_and_scores[1][1], submission3['answer'], student_item2.pk, 1)
self._assert_score(submissions_and_scores[1][2], 3, 4)
self.assertDictEqual(STUDENT_ITEM, submissions_and_scores[2][0])
self._assert_submission(submissions_and_scores[2][1], submission2['answer'], student_item1.pk, 2)
self._assert_score(submissions_and_scores[2][2], 2, 4)
self.assertDictEqual(STUDENT_ITEM, submissions_and_scores[3][0])
self._assert_submission(submissions_and_scores[3][1], submission1['answer'], student_item1.pk, 1)
self._assert_score(submissions_and_scores[3][2], 1, 4)
# These scores will always be empty
self.assertEqual(submissions_and_scores[1][2], {})
self.assertEqual(submissions_and_scores[3][2], {})
if set_scores:
self._assert_score(submissions_and_scores[0][2], 4, 4)
self._assert_score(submissions_and_scores[2][2], 2, 4)
else:
self.assertEqual(submissions_and_scores[0][2], {})
self.assertEqual(submissions_and_scores[2][2], {})
def test_get_submission(self):
# Test base case that we can create a submission and get it back
......
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