Sakthi Panneerselvam
Sakthi Panneerselvam

Reputation: 1397

django quiz app model for multiple choice questions

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

Answers (4)

Manukumar
Manukumar

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

steve harvey
steve harvey

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

NduJay
NduJay

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

bruno desthuilliers
bruno desthuilliers

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

Related Questions