def create_update(self, user, indicator, action_date, value, is_skip, answer=None): 'Creates and returns a new Answer with the given parameters, or updates the given one' is_new_answer = False if not answer: try: answer = self.get( user = user, indicator_id = indicator.id, indicator_content_type = ContentType.objects.get_for_model(indicator), action_date = action_date ) except Answer.DoesNotExist: answer = Answer(user = user, action_date = action_date, is_skip = is_skip) answer.indicator = indicator is_new_answer = True if is_skip: answer.answer_num = None else: answer.answer_num = int( value ) answer.is_skip = is_skip answer.save() if is_new_answer: user.add_participation_points() try: Indicator.objects.next(user, indicator.campaign) is_last_indicator = False except Indicator.DoesNotExist: is_last_indicator = True if not is_skip: if is_last_indicator: # Worker won't have time before results screen comes up answer.update_averages() else: # Usual case, do out-of-band for performance messaging.send(messaging.SUBJECT_AVG, answer.id) return answer
def answers_with_average(self, from_user_or_group, to_user_or_group): """ Data for graphing. Tuple of four values, each one is a list of [date, value]: - from_data: From User or Group's answers to this indicator. - to_data: The To Users or Group's answers to this indicator. - from_avgs: Time average of from User or Group's answers - to_avgs: Time average of to User or Group's answers. """ def userize(user_or_group): """Takes a Profile or Group and returns a Profile. If given a Group, returns the system user that owns that groups averages""" if isinstance(user_or_group, Profile): return user_or_group elif isinstance(user_or_group, Group): return user_or_group.avg_user else: return None from_user = userize(from_user_or_group) to_user = userize(to_user_or_group) my_answers_iter = Answer.objects.by_indicator(from_user, self) my_answers = answer_map_by_date(my_answers_iter) average_answers_iter = Answer.objects.by_indicator(to_user, self) average_answers = answer_map_by_date(average_answers_iter) my_avgs = self._aggregate_averages(my_answers_iter) average_avgs = self._aggregate_averages(average_answers_iter) for action_date in my_answers.keys(): # This can happen if the back-end worker fell over or is slow if not action_date in average_answers: my_ans = Answer.objects.get( action_date=action_date, user=from_user, indicator_id=self.id) messaging.send(messaging.SUBJECT_AVG, my_ans.id) # No value for avg yet, so pretend avg has same value as user average_answers[action_date] = my_ans.num_value average_avgs[action_date] = my_ans.num_value answers = [] for action_date, average_value in average_answers.items(): me_value = my_answers[action_date] if action_date in my_answers else None my_avg = my_avgs[action_date] if action_date in my_avgs else None answers.append( (action_date, me_value, average_value, my_avg, average_avgs[action_date] ) ) answers.sort(key = lambda x: x[0]) # Sort by action_date me_data, average_data, me_avgs, average_avgs = [], [], [], [] for action_date, me_value, average_value, me_avg, average_avg in answers: if me_value or me_value == 0: me_data.append( [action_date, me_value] ) if average_value or average_value == 0: average_data.append( [action_date, average_value] ) if me_avg or me_avg == 0: me_avgs.append( [action_date, me_avg] ) if average_avg or average_avg == 0: average_avgs.append( [action_date, average_avg] ) return (me_data, average_data, me_avgs, average_avgs)