【问题标题】:django quiz app model for multiple choice questions用于多项选择题的 django 测验应用程序模型
【发布时间】:2017-12-18 11:41:51
【问题描述】:

我正在 django 中创建测验应用程序,我的 django 问题模型是这样的,

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)

这样可以吗,或者将四个选项保存在 postgres 数组中,或者将选项保存在单独的表中。

【问题讨论】:

    标签: python django postgresql


    【解决方案1】:

    对于正确规范化的关系数据库架构,您需要一个独特的 Choice 模型,在 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",)
    

    然后您可以通过myquestion.choices.all() 获得Question 的选择(并通过mychoice.questionChoice 获得问题)。

    请注意,这不会对问题的选择数量施加任何限制,甚至不会强制问题至少有一个相关的选择。

    除非您有非常令人信服的理由不这样做,否则在使用关系数据库时您需要正确规范化的架构(rdbms 不仅仅是 bitbuckets,它们提供了 很多 有用的功能- 只要你有一个正确的模式,就是这样)。

    【讨论】:

    • 如何在单个字段中保存多项选择,如 postgres 数组,我还需要保存正确答案
    • 您要求提供有关设计模型的最佳方法的建议。我的建议是使用正确规范化的模式。如果您想改用一些非规范化模式,请这样做,但我不会回答这个问题,因为我认为这不会真正有帮助。如果您想知道为什么,请尝试这两种解决方案,看看哪一种可以让您在处理答案、分数以及您的问题/选择/答案的任何统计数据时更轻松。
    • 谢谢。现在只有我明白你想说的。
    【解决方案2】:

    本教程展示了这一切https://medium.com/@nsjcorps/create-a-quiz-application-with-django-rest-framework-react-redux-part-one-f0fcae5103fd

    这是它的摘要:

    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)
    

    【讨论】:

      【解决方案3】:

      如果你使用 postgres sql,你可以使用 arryfield

      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)
      

      【讨论】:

        【解决方案4】:

        最好的办法是:

        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)
        

        【讨论】:

          猜你喜欢
          • 2015-09-10
          • 1970-01-01
          • 2011-07-08
          • 2015-12-22
          • 2015-02-10
          • 2020-12-11
          • 2014-03-23
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多