Reputation: 1397
I am creating quiz app in django, my django model for questions is like this,
class Question(models.Model):
questions = models.CharField(max_length=50, unique=True)
choice1 = models.CharField(max_length=50, unique=True)
choice2 = models.CharField(max_length=50, unique=True)
choice3 = models.CharField(max_length=50, unique=True)
choice4 = models.CharField(max_length=50, unique=True)
correct_answer = models.CharField(max_length=50, unique=True)
is this fine or save the four options in postgres array or save the choices in separate table.
Upvotes: 2
Views: 12658
Reputation: 225
The best way is:
ANSWER_CHOICES = (
("choice_1", "Answer_1"),
("choice_2", "Answer_2"),
("choice_3", "Answer_3"),
("choice_4", "Answer_4"),
("choice_5", "Answer_5"),
("choice_6", "Answer_6"),
)
class Question(models.Model):
questions = models.CharField
(
max_length=50,
unique=True,
choices=ANSWER_CHOICES
)
correct_answer = models.CharField(max_length=50, unique=True)
Upvotes: 0
Reputation: 106
you can use arryfield if you are using postgres sql
class QuizMcqDetail(BaseModel):
title = models.CharField(max_length=255, null=True, blank=True)
time_limit = models.TimeField()
start_date = models.DateTimeField(null=True, blank=True)
end_date = models.DateTimeField(null=True, blank=True)
available_languages = models.ManyToManyField(QuizLanguage, related_name='available_language', blank=True)
question_count = models.PositiveIntegerField(default=10)
is_active = models.BooleanField(default=True)
def __str__(self):
return self.title
class QuizMcqQuestion(BaseModel):
s_no = models.PositiveIntegerField()
quiz = models.ForeignKey(QuizMcqDetail, on_delete=models.CASCADE, related_name='quiz_mcq')
question_text = models.TextField(max_length=200)
options = ArrayField(models.CharField(max_length=200))
answer_position = ArrayField(models.IntegerField())
explanation = models.TextField(null=True)
language = models.ForeignKey(QuizLanguage, related_name='question_language', on_delete=models.SET_NULL, null=True)
def __str__(self):
return self.question_text
class QuizMcqSelect(BaseModel):
quiz_question = models.ForeignKey(QuizMcqQuestion, related_name="select_quiz_mcq", on_delete=models.CASCADE)
user = models.ForeignKey(User, related_name="user_select_quiz_mcq", on_delete=models.CASCADE)
answer = models.BooleanField(default=False)
selected_answer = ArrayField(models.IntegerField())
def __str__(self):
return f"{self.quiz_question} {self.user} {self.answer}"
def save(self, *args, **kwargs):
if self.quiz_question.answer_position == self.selected_answer:
self.answer = True
else:
self.answer = False
super().save(*args, **kwargs)
Upvotes: 0
Reputation: 810
This tutorial shows it all https://medium.com/@nsjcorps/create-a-quiz-application-with-django-rest-framework-react-redux-part-one-f0fcae5103fd
This is the summary of it though:
from django.db import models
from django.contrib.auth.models import User
from django.template.defaultfilters import slugify
from django.db.models.signals import post_save, pre_save
from django.dispatch import receiver
class Quiz(models.Model):
name = models.CharField(max_length=1000)
questions_count = models.IntegerField(default=0)
description = models.CharField(max_length=70)
created = models.DateTimeField(auto_now_add=True,null=True,blank=True)
slug = models.SlugField()
roll_out = models.BooleanField(default=False)
class Meta:
ordering = [‘created’,]
verbose_name_plural =”Quizzes”
def __str__(self):
return self.name
class Question(models.Model):
quiz = models.ForeignKey(Quiz, on_delete=models.CASCADE)
label = models.CharField(max_length=1000)
order = models.IntegerField(default=0)
def __str__(self):
return self.label
class Answer(models.Model):
question = models.ForeignKey(Question, on_delete=models.CASCADE)
text = models.CharField(max_length=1000)
is_correct = models.BooleanField(default=False)
def __str__(self):
return self.text
class QuizTakers(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
quiz = models.ForeignKey(Quiz, on_delete=models.CASCADE)
correct_answers = models.IntegerField(default=0)
completed = models.BooleanField(default=False)
timestamp = models.DateTimeField(auto_now_add=True)
def __str__(self):
return self.user.username
class Response(models.Model):
quiztaker = models.ForeignKey(QuizTakers, on_delete=models.CASCADE)
question = models.ForeignKey(Question, on_delete=models.CASCADE)
answer = models.ForeignKey(Answer,on_delete=models.CASCADE,null=True,blank=True)
def __str__(self):
return self.question.label
@receiver(post_save, sender=Quiz)
def set_default_quiz(sender, instance, created,**kwargs):
quiz = Quiz.objects.filter(id = instance.id)
quiz.update(questions_count=instance.question_set.filter(quiz=instance.pk).count())
@receiver(post_save, sender=Question)
def set_default(sender, instance, created,**kwargs):
quiz = Quiz.objects.filter(id = instance.quiz.id)
quiz.update(questions_count=instance.quiz.question_set.filter(quiz=instance.quiz.pk).count())
@receiver(pre_save, sender=Quiz)
def slugify_title(sender, instance, *args, **kwargs):
instance.slug = slugify(instance.name)
Upvotes: 0
Reputation: 77912
For a properly normalized relational database schema, you want a distinct Choice
model with a foreign key on Question
:
class Question(models.Model):
question = models.CharField(...)
class Choice(models.Model):
question = models.ForeignKey("Question", related_name="choices")
choice = modelsCharField("Choice", max_length=50)
position = models.IntegerField("position")
class Meta:
unique_together = [
# no duplicated choice per question
("question", "choice"),
# no duplicated position per question
("question", "position")
]
ordering = ("position",)
And then you can get at a Question
's choices with myquestion.choices.all()
(and get the question from a Choice
with mychoice.question
).
Note that this won't impose any limitation on the number of choices for a Question, not even mandates that a Question has at least one related Choice.
Unless you have a very compelling reason to do otherwise, a properly normalized schema is what you want when using a relational database (rdbms are much more than mere bitbuckets, they offer a lot of useful features - as long as you do have a proper schema, that is).
Upvotes: 10