Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/362.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 理解Django'中的规范化表;s ORM_Python_Django_Orm_Normalization - Fatal编程技术网

Python 理解Django'中的规范化表;s ORM

Python 理解Django'中的规范化表;s ORM,python,django,orm,normalization,Python,Django,Orm,Normalization,我试图从自己直接编写数据库模式的背景中学习Django。我想了解我应该如何有效地使用数据库抽象工具进行规范化 作为一个人为的例子,假设我有一个对话,可以问3个主题的问题,每个问题都很复杂,足以保证自己的课程 Class Conversation(models.Model): partner = models.CharField() Class Weather_q(models.Model): #stuff Class Health_q(models.Model): #stuff Cl

我试图从自己直接编写数据库模式的背景中学习Django。我想了解我应该如何有效地使用数据库抽象工具进行规范化

作为一个人为的例子,假设我有一个对话,可以问3个主题的问题,每个问题都很复杂,足以保证自己的课程

Class Conversation(models.Model):
  partner = models.CharField()
Class Weather_q(models.Model):
  #stuff
Class Health_q(models.Model):
  #stuff
Class Family_q(models.Model):
  #stuff
假设我想进行两次对话:

  • 对话1:问两个不同的天气问题和一个关于他的健康的问题
  • 与爱丽丝对话2:询问天气和她的家庭情况
通常,我会为自己编写一个规范化表:

INSERT INTO Conversation (partner) values ("Bob", "Alice"); --primary keys = 1 and 2
INSERT INTO NormalizationTable (fk_Conversation, fk_Weather_q, fk_Health_q,  fk_Family_q) VALUES 
  (1,1,0,0), -- Bob weather#1
  (1,2,0,0), -- Bob weather#2
  (1,0,1,0), -- Bob health#1
  (2,1,0,0), -- Alice weather#1
  (2,0,0,1); -- Alice family#1
我需要显式地创建这个规范化表吗?还是不鼓励这样做

Class NormalizationTable(models.Model):
  fk_Conversation = models.ForeignKey(Conversation)
  fk_Weather_q = models.ForeignKey(Weather)
  fk_Health_q = models.ForeignKey(Health)
  fk_Family_q = models.ForeignKey(Family)
然后我想执行对话。我写了这样一个视图(跳过异常捕获和逻辑,在每次对话中迭代多个问题):


从整体上看,这是解决此类规范化问题的“Django”方法吗(与容器对象关联的N个对象)?我能更好地利用Django的内置ORM或其他工具吗?

我不熟悉术语规范化表,但我知道您在尝试做什么

在我看来,您所描述的并不是一种非常令人满意的数据库建模方法。最简单的方法是使所有问题都成为同一个表的一部分,带有一个“类型”字段,可能还有一些其他可选字段,这些字段在不同类型之间有所不同。在这种情况下,这在Django变得非常简单

但是,好吧,你说“让我们假设……每个问题都足够复杂,足以证明自己的类别。”Django确实有一个解决方案,这就是。它看起来像这样:

class ConversationQuestion(models.Model):
    conversation = models.ForeignKey(Conversation)
    content_type = models.ForeignKey(ContentType)
    question_id = models.PositiveIntegerField()
    question = GenericForeignKey('content_type', 'question_id')

# you can use prefetch_related("question") for efficiency
cqs = ConversationQuestion.objects.filter(conversation=conversation)
for cq in cqs:
    # do something with the question
    # you can look at the content_type if, as above, you need to choose
    # a separate template for each type.
    print(cq.question)
from myapp.models import Question

def converse(request, partner_id):
    question = Question.objects.filter(partner=partner_id).select_subclasses().first()
    question_type = question._meta.object_name.lower()

    return render(
        "questions/{}.html".format(question_type),
        {'question': question}
    )
因为它是Django的一部分,所以您可以在管理、表单等方面获得一些(但不是全部)支持


或者你也可以像上面那样做,但是,正如你所注意到的,这很难看,似乎没有抓住使用ORM的优势。

我不熟悉术语规范化表,但我知道你在尝试做什么

在我看来,您所描述的并不是一种非常令人满意的数据库建模方法。最简单的方法是使所有问题都成为同一个表的一部分,带有一个“类型”字段,可能还有一些其他可选字段,这些字段在不同类型之间有所不同。在这种情况下,这在Django变得非常简单

但是,好吧,你说“让我们假设……每个问题都足够复杂,足以证明自己的类别。”Django确实有一个解决方案,这就是。它看起来像这样:

class ConversationQuestion(models.Model):
    conversation = models.ForeignKey(Conversation)
    content_type = models.ForeignKey(ContentType)
    question_id = models.PositiveIntegerField()
    question = GenericForeignKey('content_type', 'question_id')

# you can use prefetch_related("question") for efficiency
cqs = ConversationQuestion.objects.filter(conversation=conversation)
for cq in cqs:
    # do something with the question
    # you can look at the content_type if, as above, you need to choose
    # a separate template for each type.
    print(cq.question)
from myapp.models import Question

def converse(request, partner_id):
    question = Question.objects.filter(partner=partner_id).select_subclasses().first()
    question_type = question._meta.object_name.lower()

    return render(
        "questions/{}.html".format(question_type),
        {'question': question}
    )
因为它是Django的一部分,所以您可以在管理、表单等方面获得一些(但不是全部)支持

或者你可以像上面那样做,但是,正如你所注意到的,这很难看,而且似乎没有抓住使用ORM的优势。

抛开“规范化表”(这个术语我不熟悉),这就是我认为解决问题的“djangish”方法。请注意,我同意你的说法“每个问题都很复杂,足以证明自己的类别”。对我来说,这意味着每种类型的问题都有其独特的领域和方法。否则,我将创建一个
问题
模型,通过
外键
连接到
类别
模型

class Partner(models.Model):
    name = models.CharField()


class Question(models.Model):
    # Fields and methods common to all kinds of questions
    partner = models.ForeignKey(Partner)
    label = models.CharField()  # example field


class WeatherQuestion(Question):
    # Fields and methods for weather questions only


class HealthQuestion(Question):
    # Fields and methods for health questions only


class FamilyQuestion(Question):
    # Fields and methods for family questions only
这样,您将拥有一个基本的
问题
模型,用于所有问题通用的所有字段和方法,以及一组用于描述不同类型问题的子模型。基本模型和它的子模型之间有一种隐式关系,由Django维护。这使您能够创建一个包含不同问题的查询集,无论其类型如何。此查询集中的项目默认为
Question
类型,但可以通过访问特殊属性(例如
HealtQuestion
HealtQuestion
属性)将其转换为特定的问题类型。这将在中详细描述

然后在视图中,您可以获得(不同类型)问题的列表,然后检测其特定类型:

from myapp.models import Question

def converse(request, partner_id):
    question = Question.objects.filter(partner=partner_id).first()

    # Detect question type
    question_type = "other"
    question_obj = question
    # in real life the list of types below would probably live in the settings
    for current_type in ['weather', 'health', 'family']:
        if hasattr(question, current_type + 'question'):
            question_type = current_type
            question_obj = getattr(question, current_type + 'question')
            break

    return render(
        "questions/{}.html".format(question_type),
        {'question': question_obj}
    )
检测问题类型的代码非常难看和复杂。使用from包可以使它更简单、更通用。您需要安装软件包并将该行添加到
问题
型号:

objects = InheritanceManager()
然后,视图将如下所示:

class ConversationQuestion(models.Model):
    conversation = models.ForeignKey(Conversation)
    content_type = models.ForeignKey(ContentType)
    question_id = models.PositiveIntegerField()
    question = GenericForeignKey('content_type', 'question_id')

# you can use prefetch_related("question") for efficiency
cqs = ConversationQuestion.objects.filter(conversation=conversation)
for cq in cqs:
    # do something with the question
    # you can look at the content_type if, as above, you need to choose
    # a separate template for each type.
    print(cq.question)
from myapp.models import Question

def converse(request, partner_id):
    question = Question.objects.filter(partner=partner_id).select_subclasses().first()
    question_type = question._meta.object_name.lower()

    return render(
        "questions/{}.html".format(question_type),
        {'question': question}
    )
两个视图仅选择一个问题-第一个问题。这就是您示例中的视图的行为方式,因此我选择了它。您可以轻松地将这些示例转换为返回问题列表(不同类型)。

抛开“规范化表”(我不熟悉这个术语),这就是我认为解决问题的“djangish”方法。请注意,我同意你的说法“每个问题都很复杂,足以证明自己的类别”。对我来说,这意味着每种类型的问题都有其独特的领域和方法。否则,我将创建一个
问题
模型,通过
外键
连接到
类别
模型

class Partner(models.Model):
    name = models.CharField()


class Question(models.Model):
    # Fields and methods common to all kinds of questions
    partner = models.ForeignKey(Partner)
    label = models.CharField()  # example field


class WeatherQuestion(Question):
    # Fields and methods for weather questions only


class HealthQuestion(Question):
    # Fields and methods for health questions only


class FamilyQuestion(Question):
    # Fields and methods for family questions only
这样,您将拥有一个基本的
问题
模型,用于所有问题通用的所有字段和方法,以及一组用于描述不同类型问题的子模型。基本模型和它的子模型之间有一种隐式关系,由Django维护。这使您能够创建一个包含不同问题的查询集,无论其类型如何。此查询集中的项目默认为
Question
类型,但可以通过访问特殊属性(例如
HealtQuestion
HealtQuestion
属性)将其转换为特定的问题类型。这将在中详细描述

然后在视图中,您可以获得(不同类型)问题的列表,然后检测其特定类型:

from myapp.models import Question

def converse(request, partner_id):
    question = Question.objects.filter(partner=partner_id).first()

    # Detect question type
    question_type = "other"
    question_obj = question
    # in real life the list of types below would probably live in the settings
    for current_type in ['weather', 'health', 'family']:
        if hasattr(question, current_type + 'question'):
            question_type = current_type
            question_obj = getattr(question, current_type + 'question')
            break

    return render(
        "questions/{}.html".format(question_type),
        {'question': question_obj}
    )
检测问题类型的代码非常难看和复杂。