def _get_results_impl(evaluation: Evaluation, *, refetch_related_objects: bool = True): if refetch_related_objects: discard_cached_related_objects(evaluation) prefetch_related_objects([evaluation], *GET_RESULTS_PREFETCH_LOOKUPS) tas_per_contribution_question: Dict[Tuple[ int, int], List[TextAnswer]] = unordered_groupby( ((textanswer.contribution_id, textanswer.question_id), textanswer) for contribution in evaluation.contributions.all() for textanswer in contribution.textanswer_set.all() if textanswer.state in [TextAnswer.State.PRIVATE, TextAnswer.State.PUBLISHED]) racs_per_contribution_question: Dict[Tuple[ int, int], List[RatingAnswerCounter]] = unordered_groupby( ((counter.contribution_id, counter.question_id), counter) for contribution in evaluation.contributions.all() for counter in contribution.ratinganswercounter_set.all()) contributor_contribution_results = [] for contribution in evaluation.contributions.all(): questionnaire_results = [] for questionnaire in contribution.questionnaires.all(): results: List[Union[HeadingResult, TextResult, RatingResult]] = [] for question in questionnaire.questions.all(): if question.is_heading_question: results.append(HeadingResult(question=question)) continue text_result = None if question.can_have_textanswers and evaluation.can_publish_text_results: answers = tas_per_contribution_question.get( (contribution.id, question.id), []) text_result = TextResult( question=question, answers=answers, answers_visible_to=textanswers_visible_to( contribution)) if question.is_rating_question: if evaluation.can_publish_rating_results: answer_counters = racs_per_contribution_question.get( (contribution.id, question.id), []) else: answer_counters = None results.append( RatingResult(question, answer_counters, additional_text_result=text_result)) elif question.is_text_question and evaluation.can_publish_text_results: assert text_result is not None results.append(text_result) questionnaire_results.append( QuestionnaireResult(questionnaire, results)) contributor_contribution_results.append( ContributionResult(contribution.contributor, contribution.label, questionnaire_results)) return EvaluationResult(contributor_contribution_results)
def test_discard_cached_related_objects_discards_cached_m2m_instances( self): evaluation = baker.make(Evaluation) baker.make(Contribution, evaluation=evaluation) # M2M fields are not implicitly cached with self.assertNumQueries(1): self.assertEqual(len(list(evaluation.contributions.all())), 2) with self.assertNumQueries(1): self.assertEqual(len(list(evaluation.contributions.all())), 2) # Explicitly cached M2M fields (through prefetch_related_objects) are discarded prefetch_related_objects([evaluation], "contributions") with self.assertNumQueries(0): self.assertEqual(len(list(evaluation.contributions.all())), 2) discard_cached_related_objects(evaluation) with self.assertNumQueries(1): self.assertEqual(len(list(evaluation.contributions.all())), 2) # Explicitly cached M2M fields (through prefetch_related) are discarded evaluation = Evaluation.objects.filter( pk=evaluation.pk).prefetch_related("contributions").first() with self.assertNumQueries(0): self.assertEqual(len(list(evaluation.contributions.all())), 2) discard_cached_related_objects(evaluation) with self.assertNumQueries(1): self.assertEqual(len(list(evaluation.contributions.all())), 2)
def __init__( self, question: Question, answers: Iterable[TextAnswer], answers_visible_to: Optional[TextAnswerVisibility] = None, ): assert question.can_have_textanswers self.question = discard_cached_related_objects(copy(question)) self.answers = [ discard_cached_related_objects(copy(answer)) for answer in answers ] self.answers_visible_to = answers_visible_to
def __init__(self, visible_by_contribution: Iterable[UserProfile], visible_by_delegation_count: int): self.visible_by_contribution = [ discard_cached_related_objects(copy(user)) for user in visible_by_contribution ] self.visible_by_delegation_count = visible_by_delegation_count
def __init__(self, contributor: Optional[UserProfile], label: Optional[str], questionnaire_results: List[QuestionnaireResult]): self.contributor = discard_cached_related_objects( copy(contributor)) if contributor is not None else None self.label = label self.questionnaire_results = questionnaire_results
def test_discard_cached_related_objects_discards_cached_foreign_key_instances( self): evaluation = baker.make(Evaluation, course__name_en="old_name") discard_cached_related_objects(evaluation) # Instances are implicitly cached on access with self.assertNumQueries(1): self.assertEqual(evaluation.course.name_en, "old_name") Course.objects.filter(pk=evaluation.course.pk).update( name_en="new_name") with self.assertNumQueries(0): self.assertEqual(evaluation.course.name_en, "old_name") # method drops that cache discard_cached_related_objects(evaluation) with self.assertNumQueries(1): self.assertEqual(evaluation.course.name_en, "new_name") # Explicitly cached FK-fields (through select_related) are discarded evaluation = Evaluation.objects.filter( pk=evaluation.pk).select_related("course").first() Course.objects.filter(pk=evaluation.course.pk).update( name_en="even_newer_name") with self.assertNumQueries(0): self.assertEqual(evaluation.course.name_en, "new_name") discard_cached_related_objects(evaluation) with self.assertNumQueries(1): self.assertEqual(evaluation.course.name_en, "even_newer_name")
def test_discard_cached_related_objects_discards_cached_reverse_foreign_key_instances( self): course = baker.make(Course) baker.make(Evaluation, course=course) discard_cached_related_objects(course) # Reverse FK-relationships are not implicitly cached: with self.assertNumQueries(1): self.assertEqual(len(list(course.evaluations.all())), 1) with self.assertNumQueries(1): self.assertEqual(len(list(course.evaluations.all())), 1) # Explicitly cached reverse FK-fields (through prefetch_related_objects) are discarded prefetch_related_objects([course], "evaluations") with self.assertNumQueries(0): self.assertEqual(len(list(course.evaluations.all())), 1) discard_cached_related_objects(course) with self.assertNumQueries(1): self.assertEqual(len(list(course.evaluations.all())), 1) # Explicitly cached reverse FK-fields (through prefetch_related) are discarded course = Course.objects.filter( pk=course.pk).prefetch_related("evaluations").first() with self.assertNumQueries(0): self.assertEqual(len(list(course.evaluations.all())), 1) discard_cached_related_objects(course) with self.assertNumQueries(1): self.assertEqual(len(list(course.evaluations.all())), 1)
def __init__(self, question, answer_counters, additional_text_result=None): assert question.is_rating_question self.question = discard_cached_related_objects(copy(question)) self.additional_text_result = additional_text_result if answer_counters is not None: counts = OrderedDict((value, 0) for value in self.choices.values if value != NO_ANSWER) for answer_counter in answer_counters: counts[answer_counter.answer] = answer_counter.count self.counts = tuple(counts.values()) else: self.counts = None
def __init__(self, questionnaire: Questionnaire, question_results: List[QuestionResult]): self.questionnaire = discard_cached_related_objects( copy(questionnaire)) self.question_results = question_results
def __init__(self, question: Question): self.question = discard_cached_related_objects(copy(question))