【问题标题】:Django quiz application with different types of questions具有不同类型问题的 Django 测验应用程序
【发布时间】:2020-09-22 22:57:09
【问题描述】:

我正在构建 Django 测验应用程序,它将包含 3 种类型答案的问题:

  1. 单选答案;
  2. 多选答案;
  3. 文字回答;

我不确定我应该如何为这种模式设计 django 模型。

目前我的模型如下所示:

class Question(CoreModel, models.Model):
    TYPES = (
        (1, 'radio'),
        (2, 'checkbox'),
        (3, 'text'),
    )
    type = models.CharField(max_length=8, choices=TYPES, default='radio')
    text = models.CharField(max_length=2048, null=False, blank=False)

class Choice(CoreModel, models.Model):
    question = models.ForeignKey(Question, on_delete=models.DO_NOTHING)
    text = models.CharField(max_length=2048, null=False, blank=False)
    correct = models.BooleanField(default=False)

class Answer(CoreModel, models.Model):
    user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.DO_NOTHING)
    question = models.ForeignKey(Question, on_delete=models.DO_NOTHING)
    choice = models.ForeignKey(Choice, on_delete=models.DO_NOTHING)
    text = models.CharField(max_length=2048, null=False, blank=False)
    created = models.DateTimeField(auto_now_add=True)

但它似乎无法按预期工作。 我真的不喜欢在我的 Answer 模型中同时使用“选择”和“文本”字段,但这就是我能想到的。

有什么想法或建议吗?也许我需要更多其他模型来进一步逻辑?

【问题讨论】:

    标签: python django model-view-controller django-rest-framework


    【解决方案1】:

    感谢您的回答,所以这是我的解决方案:

    TYPES = (
        (1, 'One answer'),
        (2, 'Multiple answer'),
        (3, 'Text answer'),
    )
    
    
    class Quiz(CoreModel, models.Model):
        class Meta:
            verbose_name = 'Quiz'
            verbose_name_plural = 'Quizzes'
            ordering = ('id',)
    
        def __str__(self):
            return self.title
    
    
    class Question(models.Model):
        class Meta:
            verbose_name = 'Question'
            verbose_name_plural = 'Questions'
            ordering = ('id',)
    
        title = models.CharField('Title (must be unique)', max_length=256, blank=False, null=False, unique=True)
        active = models.BooleanField('Is active?', default=True, db_index=True)
        type = models.IntegerField(choices=TYPES, default=1, verbose_name='Question type')
        text = models.CharField(max_length=2048, null=False, blank=False, verbose_name='Question text')
        from_quiz = models.ForeignKey(Quiz, on_delete=models.DO_NOTHING, verbose_name='Quiz', null=True)
    
        def __str__(self):
            return self.title
    
    
    class Choice(CoreModel, models.Model):
        class Meta:
            verbose_name = 'Answer choice'
            verbose_name_plural = 'Answer choices'
            ordering = ('id',)
        from_question = models.ForeignKey(Question, on_delete=models.CASCADE, verbose_name='Question')
        text = models.CharField(max_length=2048, null=False, blank=False, verbose_name='Question text')
        correct = models.BooleanField(default=False, verbose_name='Is it right choice?')
    
        def __str__(self):
            return self.title
    
    
    class Answer(CoreModel, models.Model):
        class Meta:
            verbose_name = 'Answer'
            verbose_name_plural = 'Answers'
            ordering = ('id',)
        user_ip = models.CharField(max_length=2048, verbose_name='ip')
        user = models.ForeignKey(Account, on_delete=models.CASCADE, verbose_name='User', null=True)
        answered_question = models.ForeignKey(Question, on_delete=models.CASCADE, verbose_name='Question')
        answer_choice = models.ForeignKey(Choice, on_delete=models.CASCADE, verbose_name='Chosen option', null=True)
        answer_text = models.CharField(max_length=2048, null=True, verbose_name='Text answer')
        created = models.DateTimeField(auto_now_add=True, verbose_name='Answer time')
    
        def clean(self):
            super().clean()
            if self.answer_choice is None and self.answer_text is None:
                raise ValidationError('Field 'answer_choice' and 'answer_text' are empty! '
                                      'Must be filled at least one of')
    
        def __str__(self):
            return f'{self.answered_question} - {self.answer_choice or ""}{self.answer_text or ""}'
    

    答案模型包含 2 个答案字段:对选择和文本答案的 FK 以及检查是否至少填写了一个答案类型字段的清理方法。

    【讨论】:

      【解决方案2】:

      我会围绕以下几行做一些事情:

      class Quiz(CoreModel, models.Model):
          name = models.CharField(max_length=2048, null=False, blank=False)
      
      class Question(CoreModel, models.Model):
          TYPES = (
              (1, 'radio'),
              (2, 'checkbox'),
              (3, 'text'),
          )
          quiz = models.ForeignKey(Quiz)
          type = models.CharField(max_length=8, choices=TYPES, default='radio')
          prompt = models.CharField(max_length=2048, null=False, blank=False)
          correct_free_text = models.CharField(max_length=2048, null=True, blank=True)
          rank = models.SmallIntegerField(default=0)
      
      class Choice(CoreModel, models.Model):
          question = models.ForeignKey(Question, on_delete=models.DO_NOTHING)
          text = models.CharField(max_length=2048, null=False, blank=False)
          correct = models.BooleanField(default=False)
          rank = models.SmallIntegerField(default=0)
      
      class Answer(CoreModel, models.Model):
          user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.DO_NOTHING)
          question = models.ForeignKey(Question, on_delete=models.DO_NOTHING)
          choice = models.ForeignKey(Choice, null=True, on_delete=models.DO_NOTHING)
          free_text = models.CharField(max_length=2048, null=True, blank=True)
          created = models.DateTimeField(auto_now_add=True)
      

      我会尽量将“可重用性”保持在最低限度。我的意思是不要尝试在多个Quizes 中重复使用ChoiceQuestion,它们是否包含相同的信息并不重要,让它们不同。希望这会有所帮助,如果您有任何其他问题,请告诉我。

      【讨论】:

        【解决方案3】:

        答案应该可以有很多选择,在您当前的架构中Answerchoice 外键,即它指向一个选择。相反,我会在 Answers 上创建 choices 字段,该字段属于文本类型,并且应该包含以逗号分隔的选项 ID。

        您需要在创建答案时执行验证:如果问题是文本类型,则不应有选择,如果是单选则应为单个 ID,如果是多个则应有 1+ 个 ID。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2013-03-05
          • 1970-01-01
          • 2020-05-15
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2021-10-07
          相关资源
          最近更新 更多