我有一个类似于以下内容的多表继承架构:
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实例吗?*
注意:这实际上是使用我询问here
的访问函数模型完成的注意:我尝试做的与this类似,但有点不同,因为我有多个子类。
编辑:感谢chris-platt的提示,我发现以下内容符合我的要求:
nd = NodeData.objects.select_related('conceptnode','derivednode').get(id = 1)
nd.node.conceptnode.myFunction()
第一行预先将DerivedNode或ConceptNode实例提取到相关的缓存对象中。
答案 0 :(得分:2)
如果您执行ConceptNode.objects.get(...)
之类的操作,则会同时获取Node
实例,以便获得实例的完整数据。但是,当您执行Node.objects.get(...)
之类的操作时,ConceptNode
等子类中的数据不包含 。要选择这些,您需要使用select_related(<related_name>)
,并且要获得多个子类,您只需将related_name
添加为逗号分隔列表,例如:
Node.objects.select_related('nodeParent', 'nodeSource', 'nodeTarget')
答案 1 :(得分:0)
我认为select_related
的工作方式存在轻微的误解。它不适用于所有关系,它适用于外键或一对一关系 - 其中相关数据是单个记录,并且可以使用连接修改原始查询以获取它。所以这个例子不起作用:
nd = NodeData.objects.get(id = 1)
nd.node.conceptnode.myFunction()
...因为Node是ConceptNode的父级,所以它可以有许多相关的。事实上,我认为你的nd.node.conceptnode
会出现属性错误。我想你可以通过以下方式访问这些孩子的ConceptNodes:
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,那么有一个名为[prefetch_related][1]
的新QuerySet方法,我还没有使用过,但它应该是针对这种情况(减少对'many'类型关系的查询),你理论上应该能够做到这样的事情:
nd = NodeData.objects.get(id = 1).prefetch_related('conceptnode')
...虽然您必须使用'conceptnode'参数,并且通常使用prefetch_related来查看它是否能满足您的需求。