3

我有一个类似于以下的多表继承架构:

class NodeData(models.Model):
    node = models.ForeignKey(Node, db_index = True)
    value = models.FloatField(default = 0)
    name = models.TextField(unique=True, blank=True)

class Node(models.Model):
    name = models.CharField(max_length=50, blank=True)
    description = models.TextField(blank=True)
    node_tree = models.ForeignKey(NodeTree, db_index = True)
    unique_name = models.TextField(unique=True, blank=True)
    last_updated_timestamp = models.DateTimeField('date last updated', blank=True)

class ConceptNode(Node):
    node_parent = models.ForeignKey(Node, related_name="nodeParent", null=True, blank=True)

class DerivedNode(Node):
    node_source = models.ForeignKey(Node, related_name="nodeSource")
    node_target = models.ForeignKey(Node, related_name="nodeTarget")

出于性能原因,每当我获取大量 NodeData 元素时,我都会使用 select_related(depth = 2)。但是,select_related 不遵循与子类的关系,因此以下代码* 导致调用 myFunction 的 ConceptNode 实现,而该函数中使用的 ConceptNode 对象没有预取数据:

nd = NodeData.objects.get(id = 1)
nd.node.conceptnode.myFunction()

这使得 select_related 没那么有用,因为有很多这样调用的函数,它们并没有从 select_related 缓存的数据中获益。

我的问题是:我可以获取 select_related 来为我获取此信息,以便我获取的每个 NodeData 对象都缓存了 Node 和 ConceptNode/DerivedNode 实例吗?*

注意:这实际上是使用我在这里询问的访问器函数模型完成的

注意:我正在尝试做的是类似于this,但有点不同,因为我有多个子类。

编辑:感谢 chris-platt 的提示,我发现以下内容可以满足我的需要:

nd = NodeData.objects.select_related('conceptnode','derivednode').get(id = 1)
nd.node.conceptnode.myFunction()

第一行将 DerivedNode 或 ConceptNode 实例预取到相关的缓存对象中。

4

2 回答 2

2

如果您执行类似ConceptNode.objects.get(...)的操作,Node则将同时获取实例,以便您拥有实例的完整数据。但是,当您执行诸如等子类中Node.objects.get(...)的数据之类的操作时,包括在内。要选择这些,您需要使用,并且要获得多个子类,您只需将s 添加为逗号分隔的列表,例如:ConceptNodeselect_related(<related_name>)related_name

Node.objects.select_related('nodeParent', 'nodeSource', 'nodeTarget')
于 2012-07-27T22:02:13.397 回答
0

我认为这里对如何select_related工作有一点误解。它不适用于所有关系,它适用于外键或一对一关系 - 其中相关数据是单个记录,并且可以使用连接修改原始查询以获取它。所以这个例子不起作用:

nd = NodeData.objects.get(id = 1)
nd.node.conceptnode.myFunction()

...因为 Node 是 ConceptNode 的父级,所以它可以有许多相关的。事实上,我认为你会得到一个属性错误nd.node.conceptnode。我认为您可以通过以下方式访问这些子概念节点:

nd = NodeData.objects.get(id = 1)
nd.node.nodeParent.all() # Loop through this and do stuff with the children...

我在这里使用'nodeParent',因为你已经设置了related_name(你可能想把它改成更合适的东西,比如'nodeChildren'或其他东西),但默认情况下它是'conceptnode_set',例如:nd.node.conceptnode_set.all()

如果您使用的是 Django 1.4,则有一个名为 QuerySet 的新方法[prefetch_related][1],我没有使用过,但它应该是针对这种确切情况(减少对“许多”类型关系的查询),理论上你应该能够做到就像是:

nd = NodeData.objects.get(id = 1).prefetch_related('conceptnode')

...尽管您必须使用“conceptnode”参数,并且通常使用 prefetch_related 来查看它是否可以满足您的需求。

于 2012-07-27T22:29:02.790 回答