【问题标题】:Django create new object based on current object typeDjango 根据当前对象类型创建新对象
【发布时间】:2014-09-12 06:23:50
【问题描述】:

我有一个包含多种问题类型(即简答、多项选择)的测试设置。这些测试可以动态创建。我现在要做的是创建一个函数来为测试做出适当的响应集。我的模型是这样设置的:

class Test(models.Model):
    pass
class Question(models.Model):
    question = models.TextField()
    test = models.ForeignKey(Test)
class NumQ(Question):
    pass
class TextQ(Question):
    pass

class Response(models.Model):
    test = models.ForeignKey(Test)
class Answer(models.Model):
    pass
class NumA(Answer):
    question = models.ForeignKey(NumQ)
    answer = models.IntegerField(blank=True, null=True)
class TextA(Answer):
    question = models.ForeignKey(TextQ)
    answer = models.TextField(blank=True, null=True)

我正在创建一个函数来创建一个响应,在该函数中我循环遍历测试的所有问题并创建新的答案。但是,我想创建正确类型的答案。我发现我可以使用django-model-utils 获得实际的问题类型,但是由此,我可以弄清楚如何创建正确答案类型的唯一方法是使用一堆 if/elif 语句,这真的很难看(尤其是因为有超过 2 种问题类型)。

此时我能想到的最佳选择是为每个问题添加一个 answer_type 字段,但我不确定如何将该字段(CharField 或自定义 TypeField)转换为实际生成一个新对象,并为其赋予正确的表观类型 (Answer)。我想我可以使用eval,但这似乎是一个非常丑陋的解决方案。 (在这种情况下,我什至不需要额外的字段;我可以将 Q 替换为类型中的 A。)但是在这种情况下,有没有更好的替代 eval 的方法?

【问题讨论】:

  • 为什么你需要TextField以外的任何东西,即使答案是数字,因为你收到用户的所有输入作为文本?
  • TextQ 和 NumQ 只是示例。我有更复杂的问题类型,例如多项选择,但为了一个简单的示例,我只选择了 2 个没有其他模型依赖关系的问题类型。
  • 最简单的解决方案是简单地创建一个字典,将答案类型名称映射到其未绑定的类类型,例如:{'NumA':NumA,...}.但是这本字典很可能存在于 Django 的某个地方。不过,我似乎无法在文档中找到它。
  • 您是否建议使用现有字典添加字典?这本词典究竟是如何使用的?
  • 使用您的 aswer_type 字段。您实际上是在做您对eval 所做的事情,但要保护输入。但是,为什么你需要这样做呢?你能不能简单地从Question 模型中创建一个ForeignKeyAnswer 模型中,我假设它是多态加载的?我想我不明白在什么情况下会在没有Answer 的情况下创建Question,或者在创建Question 而不是实际的Answer 时会知道Answer 的类型。

标签: python django types


【解决方案1】:
class AnswerType(models.Model):
    name = models.CharField(max_length=200)
    value = models.CharField(max_length=200, blank=True, null=True)
    label = models.CharField(max_length=200, blank=True, null=True)

class Question(models.Model):
    title = models.CharField(max_length=300)
    answer = models.ManyToManyField(AnswerType)

class Result(models.Model):
    question = models.ForeignKey(Question)
    reponse = models.CharField(max_length=300)

class Attempts(models.Model):
    student = models.ForeignKey(User)
    taken_on = models.DateTimeField(auto_now=True)
    quiz = models.ForeignKey(Quiz)
    answer = models.ManyToMany(Result)

class Quiz(models.Model):
    title = models.CharField(max_length=300)
    questions = models.ManyToManyField(Question)
    results = models.ManyToManyField(Responses)
  1. 问题可以有多个答案(针对多项选择题)。
  2. 每个测验可以有多个问题。
  3. 每次尝试都会记录学生、测验和答案。
  4. 结果包含指向问题的链接,以及为一个测验输入的答案。
  5. 对于每个答案,您都有一个标签(显示在表格上)、一个名称(供您自己参考)和一个值(此答案的键/权重/分数) - 这通常用于加权测验。

我认为这样做可以使您的模型足够灵活。您唯一头疼的就是正确映射表单,我建议您使用 FormWizard 并创建自己的自定义表单。

【讨论】:

  • 为什么ManyToManyFields 有这么多这些字段?有什么优势吗,因为其中一些似乎没有必要(只需外键就足够了)。另外,这如何解决不同答案的问题?我仍然需要有不同的AnswerType 子类来适应不同类型的问题。
  • ForeignKey 会限制一个关系,所以当你想要多个关系时,你需要许多关系。所以一个测验 - 许多问题和许多结果;每个测验一次尝试,但每次尝试都有很多答案;一题可以一题或多题(多选题)。
  • 不过,并非每种问题类型都应该有多个答案。
  • 没关系,你可以有一个只有一个链接的多对多 - 这就是我说“一个或多个”的原因。
  • 但这如何解决不同类型答案的问题呢?一旦您到达AnswerType,该值始终是CharField
【解决方案2】:

我认为django-typed-models 可以解决您的问题。

即。对于NumQ,您需要设置answer_type='appname.numa',然后在创建答案时,您只需将type=answer_type 传递给答案构造函数。

不同的方法:如果要获取模型类表单字符串,请使用函数get_model from django.db.models.loading

【讨论】:

    猜你喜欢
    • 2014-01-06
    • 1970-01-01
    • 2015-07-26
    • 1970-01-01
    • 1970-01-01
    • 2014-07-25
    • 1970-01-01
    • 2017-02-19
    • 1970-01-01
    相关资源
    最近更新 更多