Foreach Ответ вычисляет количество баллов

У меня есть набор анкет, в каждой из которых есть вопросы, и каждый вопрос имеет ответ, значение ответа и вес ответа.

Нужно получить каждый ответ и умножить ответ value.count на answer weight value

Например, вопрос, 1 значение ответа --, которому присваивается значение -2 и вес 20, поэтому мне нужно рассчитать -2 x 20 и так далее для каждого вопроса, чтобы получить общий балл всех вопросов анкеты.

Мой взгляд на сегодняшний день

questionnaires = ProjectQuestionnaire.objects.all()

results = []
    for q in questionnaires:
        if ProjectQuestionnaireResponse.objects.filter(project_name_id=project_id, questionnaire_id = q.id).exists():     
            q_response = ProjectQuestionnaireResponse.objects.get(project_name_id=project_id, questionnaire_id = q.id)
            q_answered = ProjectQuestionnaireAnswer.objects.filter(response = q_response, answer__isnull=False).count()
            if q_answered > 1:
                q_count = (100 / ProjectQuestionnaireQuestion.objects.filter(questionnaire_id = q.id).count() * q_answered)
            else:
                q_count = 0

###### Trying to calculate here ######

            the_score = []
            for answer in q_answered:
                answer_score = ProjectQuestionnaireAnswer.objects.filter()

######  END of Calculation ######

Модели:

class ProjectQuestionnaire(models.Model):
    title = models.CharField(max_length=50, blank=False, unique=True)
    description = models.TextField(blank=True)


    def __str__(self):
        return str(self.title)
    

class ProjectQuestionnaireQuestion(models.Model):
    questionnaire = models.ForeignKey(ProjectQuestionnaire, on_delete=models.CASCADE)
    sequence = models.IntegerField()
    question = models.TextField()
    description = models.TextField(blank=True)

    def __str__(self):
        return str(self.question)

class ProjectQuestionnaireResponse(models.Model):
    project_name = models.ForeignKey(Project, on_delete=models.CASCADE)
    questionnaire = models.ForeignKey(ProjectQuestionnaire, on_delete=models.CASCADE)
    user = models.CharField(max_length=50, blank=True)

    class Meta:
        constraints = [
                models.UniqueConstraint(fields= ['project_name','questionnaire'], name='project_unique_response1'),
            ]
    def __str__(self):
        return str(self.project_name)

class Choice(models.Model):
    question = models.ForeignKey(ProjectQuestionnaireQuestion, on_delete=models.CASCADE)
    choice_text = models.CharField(max_length=200)
    choice_value = models.CharField(max_length=20, blank=True)
    choice_weight = models.IntegerField(blank=True, null=True)

    def __str__(self):
        return str(self.choice_text)

class ProjectQuestionnaireAnswer(models.Model):
    YN_Choices = [
        ('Yes', 'Yes'),
        ('No', 'No'),
        ('Unknown', 'Unknown')
    ]
    question = models.ForeignKey(ProjectQuestionnaireQuestion, on_delete=models.CASCADE)
    answer = models.ForeignKey(Choice, on_delete=models.CASCADE,null=True)
    value = models.CharField(max_length=20, blank=True)
    notes = models.TextField(blank=True)
    response = models.ForeignKey(ProjectQuestionnaireResponse, on_delete=models.CASCADE)
    
    class Meta:
        constraints = [
                models.UniqueConstraint(fields=['question','response'], name='project_unique_response2'),
            ]

    def __str__(self):
        return str(self.answer)

Я бы предложил добавить метод или свойство к модели. Вы могли бы повторно использовать расчет баллов в любом месте, где вы работаете с моделями.

choice_value_to_score_map = {
    '--': -2,
    '-': -1,
    'o': 0,
    '+': 1,
    '++': 2,
}

class ProjectQuestionnaireAnswer(models.Model):
    # your existing code ...

    @property
    def score(self):
        if not self.value:
            return None  # or maybe 0, this depends on how you like to calculate
        for choice in self.question.choice_set.all():
            if choice.value == self.value:
                return choice_value_to_score_map.get(self.value, 0) * choice.choice_weight
        return None  # or maybe 0, this depends on how you like to calculate

Или вы можете добавить свойство к Choice, чтобы получить оценку выбора, если нет необходимости включать Answer в расчет.

choice_value_to_score_map = {
    '--': -2,
    '-': -1,
    'o': 0,
    '+': 1,
    '++': 2,
}


class Choice(models.Model):
    question = models.ForeignKey(ProjectQuestionnaireQuestion, on_delete=models.CASCADE)
    choice_text = models.CharField(max_length=200)
    choice_value = models.CharField(max_length=20, blank=True)
    choice_weight = models.IntegerField(blank=True, null=True)

    def __str__(self):
        return str(self.choice_text)

    @property
    def raw_score(self):
        if not self.value:
            return 0
        return choice_value_to_score_map.get(self.value, 0)


    @property
    def weighted_score(self):
        return self.raw_score * self.choice_weight


class ProjectQuestionnaireAnswer(models.Model):
    # your existing code ...

    @property
    def score(self):
        if not self.value:
            return None  # or maybe 0, this depends on how you like to calculate
        for choice in self.question.choice_set.all():
            if choice.value == self.value:
                return choice.weighted_score
        return None  # or maybe 0, this depends on how you like to calculate
Вернуться на верх