实现需要多层关系的Django模型的最佳方法

2024-03-29 10:24:18 发布

您现在位置:Python中文网/ 问答频道 /正文

我正在使用Django构建一个测验应用程序,但是我不知道在问题类别方面构建模型的最佳方法。你知道吗

一个问题将涉及一个领域,例如it、航空或科学等。这将是一个独特的领域。你知道吗

一个主题将涉及一个领域,例如气象学可以是航空领域的一部分,但也可以是科学领域的一部分。因此,这不能是唯一的字段。你知道吗

子主题将直接与主题(以及相应的领域)相关,例如气候或大气将是航空的一部分->;气象学

下面是一些类别组合的示例

航空->;气象->;气候

航空->;气象->;大气

航空->;质量与平衡

子主题是可选的,但所有组合必须是唯一的,即我不能有两个“航空->;气象->;气候”或两个“航空->;质量和平衡”

我不知道如何在模型中实现这一点,但我正在考虑执行下面两个解决方案之一

(一)

class Question(models.Model):
    question_text = models.TextField('What is the question?', max_length=4000)
    question_category = models.ForeignKey(Category) 
    question_type = models.CharField('Question Type', max_length=50)
    question_comment = models.TextField(('Question Comments/Explanations', max_length=4000)
    question_created = models.DateTimeField(auto_now_add=True)

class Category(models.Model):
    domain = models.CharField(max_length=255, unique=True)
    topic = models.CharField(max_length=255)
    sub_topic = models.CharField(max_length=255)

(二)

class Question(models.Model):
    question_text = models.TextField('What is the question?', max_length=4000)
    question_ sub_topic = models.ForeignKey(SubTopic) 
    question_type = models.CharField('Question Type', max_length=50)
    question_comment = models.TextField(('Question Comments/Explanations', max_length=4000)
    question_created = models.DateTimeField(auto_now_add=True)

class SubTopic(models.Model):
    sub_topic = models.CharField(max_length=255)
    topic = models.ForeignKey(Topic)

class Topic(models.Model):
    topic = models.CharField(max_length=255)
    domain = models.ForeignKey(Domain)

class Domain(models.Model):
    domain = models.CharField(max_length=255, unique=True)

如果子主题字段没有设置,我将被设置为default='none',blank=True

有人能告诉我以上两个解决方案中的任何一个是否能很好地实现我想要的目标吗?如果不是,什么是好的方法?你知道吗


Tags: gttrue航空主题topicmodelmodelslength
1条回答
网友
1楼 · 发布于 2024-03-29 10:24:18

正如我在对你的问题的评论中提到的,第二个例子比第一个更先进。这里的问题是副标题是可选的。可以这样显示:

域->;主题->;(副标题)

问题可以是副标题或主题的一部分。这意味着您不能简单地在Question中使用指向Subtopic的外键。我的方法是将问题与副标题或主题联系起来。为此,我建议使用Django^{}。你知道吗

模型Question可以如下所示:

from django.db import models
from django.contrib.contenttypes.fields import GenericForeignKey
from django.contrib.contenttypes.models import ContentType

class Question(models.Model):
    text = models.TextField('What is the question?', max_length=4000)
    type = models.CharField('Question Type', max_length=50)
    comment = models.TextField(('Question Comments/Explanations', max_length=4000)
    created = models.DateTimeField(auto_now_add=True)
    content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE)
    object_id = models.PositiveIntegerField()
    content_object = GenericForeignKey('content_type', 'object_id')

我们做了什么改变?首先,我们删除了class属性中的前缀question。它不是必需的,而且杂乱无章。
我们没有做的其他有意义的改变可能是减少max_lengthtextcomment。你真的认为一个问题需要4000个字符吗?相比之下,tweet的长度是140个字符。你知道吗

我们更改的最重要的是SubTopic的外键。我们创建了一个泛型关系(content_typeobject_idcontent_object)。
这意味着您可以将问题对象与您拥有的任何模型相关联。在实践中,这将是SubTopicTopic。你知道吗

其余部分可以稍作改动:

class SubTopic(models.Model):
    name = models.CharField(max_length=255)
    topic = models.ForeignKey(Topic)

class Topic(models.Model):
    name = models.CharField(max_length=255)
    domain = models.ManyToManyField(Domain)

class Domain(models.Model):
    name = models.CharField(max_length=255, unique=True)

我们现在将name作为每个类的属性,而不是将类名作为属性重复。想想这个:

  • 你知道吗副标题名称比…好副标题你知道吗
  • 你知道吗域名比…好域.Domain你知道吗

因为一个主题可以属于多个领域(主题气象学可以是航空领域的一部分,也可以是科学领域的一部分),所以我们将ForeignKey改为ManyToManyField。Django将负责在数据库中创建一个中间表。你知道吗

另一种方法是将模型SubTopic,在Question中创建一个ForeignKeyTopic,并将Topic更改为这样:

class Topic(models.Model):
    name = models.CharField(max_length=255)
    domain = models.ManyToManyField(Domain, related_name='topics')
    subtopic = models.ForeignKey('self', blank=True, null=True, related_name='subtopics')

编辑:

下面是另一种解决方案的进一步解释。在您的问题中,您给出了一些域、主题和子主题的示例:

  • 航空->;气象->;气候

  • 航空->;气象->;大气

  • 航空->;质量与平衡

气象学、气候、大气、质量和平衡都是主题。对于气候(与大气相似),您将具有以下特性:

Climate.name = 'Climate'
Climate.domains.all() = <QuerySet [<Domain: 'Aviation'>]>
Climate.subtopic = <Topic: 'Meteorology'>

属性名subtopic可能不是很有表现力,因为它在这里的意思是:气候是气象学的副标题。我还加了一个相关的名字,所以你可以得到这样的问题:

aviation = Domain.objects.get(name='Aviation')
meteorology = aviation.topics.get(name='Meteorology')
# if there is a subtopic you want to query
climate = meteorology.subtopics.get(name='Climate')
climate.questions.all() # you have to set related name questions
# in the model Question in the foreign key field
# if case there are no subtopics
mass_and_balance = aviation.topics.get(name='Mass and Balance')
mass_and_balance.questions.all()

我希望这有助于澄清方法。你知道吗

相关问题 更多 >