Django 3 update value of a ManyToMany field Boolean

374 Views Asked by At

I'm creating an exam app, Many Questions to Many Exams. One of the parameters is 'is_correct', which is a bool.

for some reason, when i save the 'is_correct' on a question, the field changes globally (on the Question model) and become 'True' / 'False' to every one.

How can i update the specific question for the specific exam only?

Current code:

exam_data = Exam.objects.get(exam_token=exam_token)
if request.method == 'POST':
    choice = request.POST.get('answer')
    question_id = request.POST.get('question_id')
    correct_answer = exam_data.questions.get(id=question_id).answer
    if choice == correct_answer:
        question = exam_data.questions.get(id=question_id)
        question.is_correct = True # Change to True
        question.save() # After saving here, it changes for the model globally
    else:
        ...same but for False...

Model Question:

class Question(models.Model):
# Data
topic = models.CharField(max_length=50, choices=TOPICS)
title = models.CharField(max_length=50)
text = models.CharField(max_length=200)

LEVEL = (('EASY', 'EASY'), ('MEDIUM', 'MEDIUM'), ('HARD', 'HARD'))
level = models.CharField(max_length=10, choices=LEVEL)

# Answers
option1 = models.CharField(max_length=200, null=True)
option2 = models.CharField(max_length=200, null=True)
option3 = models.CharField(max_length=200, null=True)
option4 = models.CharField(max_length=200, null=True)
# Right answer
answer = models.CharField(max_length=200, null=True)

is_correct = models.BooleanField(default=False, editable=False)

def __str__(self):
    return f'{self.title} , {self.topic}, Question answered right: {self.is_correct}'

Model Exam:

class Exam(models.Model):
topic = models.CharField(max_length=50, choices=TOPICS)
grade = models.IntegerField(default=0, null=True)
STATUS = (('Pending', 'Pending'), ("Completed", "Completed"))
status = models.CharField(max_length=20, default='Pending', choices=STATUS)
questions = models.ManyToManyField(Question)
exam_taker = models.ForeignKey(Candidate, null=True, on_delete=models.SET_NULL)
exam_token = models.UUIDField(unique=True, default=uuid.uuid4, editable=False)
exam_start_date = models.DateTimeField(auto_now_add=True, null=True, editable=False)
exam_due_date = models.DateTimeField(null=True)

def __str__(self):
    return f'{self.topic} | {self.exam_taker} | {self.exam_token} | {self.grade} | {self.status} {self.questions}'
1

There are 1 best solutions below

1
On

You will have to model your relations properly, so instead of setting is_true on Question model you should have what user answered and is_correct in intermediate/pivot table set as through

class ExamQuestions(models.Model):
    exam = models.ForeignKey('Exam', on_delete=models.CASCADE)
    question = models.ForeignKey('Question', on_delete=models.CASCADE)
    answered_value = models.CharField(max_length=200, null=True)
    is_correct= models.BooleanField()

and set the pivot table in ManyToMany relationship

class Exam(models.Model):
    ...
    questions = models.ManyToManyField(Question, through='ExamQuestion')
    ....