访问预取自递归集中的更新值
Access updated values in prefetched self recursion set
我有一个模型:
class Vertex(models.Model):
pmap = models.ForeignKey('PMap',on_delete=models.CASCADE)
elevation = models.FloatField(default=0)
flow_sink = models.ForeignKey(
'Vertex',
on_delete=models.CASCADE,
related_name='upstream',
null=True)
还有一个具有以下功能的模型:
class PMap(models.Model):
def compute_flux(self, save=False):
vertices = self.vertex_set.order_by('-elevation').prefetch_related('flow_sink')
# Init flux
for vert in vertices:
vert.flux = 1.0 / len(vertices)
# Add flux from current to the downstream node.
for vert in vertices:
if vert.id != vert.flow_sink.id:
vert.flow_sink.flux = vert.flux
函数compute_flux()
应该将flux
值从当前访问的顶点添加到它的flow_sink
(这又是另一个顶点)。它应该递归地执行此操作,以便当它到达之前已更新其 flux
的顶点时,它应该将该值生成为它自己的 flow_sink
.
遗憾的是,这不起作用。所有顶点都以初始 flux = 1.0 / len(vertices)
结束。我认为原因是我们正在更新预取集 prefetch_related('flow_sink')
中的顶点,而不是 vertices
集中的顶点。因此,最后一个循环中的 vert.flux
将永远不会有任何其他值而不是第一个(初始)循环中设置的值。
我该如何解决或解决这个问题?
问题是您使用 prefetch_related
加载的 Vertex
对象与 vertices
中的 对象 不同。是的,这两个对象将相等,v1 == v2
检查将成功。这是因为 Django 检查模型和主键是否相同,而不是其他值。对其中一个 Vertex
对象所做的更改不会反映在另一个模型中。
我们可以通过维护一个将 pk
映射到相应顶点的字典来解决这个问题,例如:
class PMap(models.Model):
# ...
def compute_flux(self, save=False):
vertices = self.vertex_set.order_by('-elevation')
<b>ver_dic = { v.pk: v for v in vertices }</b>
for vert in vertices:
vert.flux = 1.0 / len(vertices)
# Add flux from current to the downstream node.
for vert in vertices:
if vert.flow_sink_id != vert.pk:
<b>vertices[flow_sink_id]</b>.flux += vert.flux
您可能还忘记写 +=
而不是 =
:后者将无效,因为我们已经将该值分配给顶点.
因此我们在这里将 Vertex
对象缓存在字典中,而不是使用预取值的结果,我们使用字典值。
这里我们假设所有的顶点都是vertices
查询集的一部分,如果不是这样,我们仍然可以这样工作,通过构造一个字典,将"lazily"填充为新项到达:
class PMap(models.Model):
# ...
def compute_flux(self, save=False):
vertices = self.vertex_set.order_by('-elevation').prefetch_related('flow_sink')
ver_dic = { v.pk: v for v in vertices }
# if some flow_sink vertices are not part of the PMap
for vert in vertices:
if vert.flow_sink_id not in ver_dic:
ver_dic[vert.flow_sink_id] = vert.flow_sink
for vert in vertices:
vert.flux = 1.0 / len(vertices)
# Add flux from current to the downstream node.
for vert in vertices:
if vert.flow_sink_id != vert.pk:
vertices[flow_sink_id].flux += vert.flux
请注意,如果您不保存对象,那么设置 .flux
将无效,如果您稍后再次获取顶点,那么这些顶点当然仍然具有旧值。
我有一个模型:
class Vertex(models.Model):
pmap = models.ForeignKey('PMap',on_delete=models.CASCADE)
elevation = models.FloatField(default=0)
flow_sink = models.ForeignKey(
'Vertex',
on_delete=models.CASCADE,
related_name='upstream',
null=True)
还有一个具有以下功能的模型:
class PMap(models.Model):
def compute_flux(self, save=False):
vertices = self.vertex_set.order_by('-elevation').prefetch_related('flow_sink')
# Init flux
for vert in vertices:
vert.flux = 1.0 / len(vertices)
# Add flux from current to the downstream node.
for vert in vertices:
if vert.id != vert.flow_sink.id:
vert.flow_sink.flux = vert.flux
函数compute_flux()
应该将flux
值从当前访问的顶点添加到它的flow_sink
(这又是另一个顶点)。它应该递归地执行此操作,以便当它到达之前已更新其 flux
的顶点时,它应该将该值生成为它自己的 flow_sink
.
遗憾的是,这不起作用。所有顶点都以初始 flux = 1.0 / len(vertices)
结束。我认为原因是我们正在更新预取集 prefetch_related('flow_sink')
中的顶点,而不是 vertices
集中的顶点。因此,最后一个循环中的 vert.flux
将永远不会有任何其他值而不是第一个(初始)循环中设置的值。
我该如何解决或解决这个问题?
问题是您使用 prefetch_related
加载的 Vertex
对象与 vertices
中的 对象 不同。是的,这两个对象将相等,v1 == v2
检查将成功。这是因为 Django 检查模型和主键是否相同,而不是其他值。对其中一个 Vertex
对象所做的更改不会反映在另一个模型中。
我们可以通过维护一个将 pk
映射到相应顶点的字典来解决这个问题,例如:
class PMap(models.Model):
# ...
def compute_flux(self, save=False):
vertices = self.vertex_set.order_by('-elevation')
<b>ver_dic = { v.pk: v for v in vertices }</b>
for vert in vertices:
vert.flux = 1.0 / len(vertices)
# Add flux from current to the downstream node.
for vert in vertices:
if vert.flow_sink_id != vert.pk:
<b>vertices[flow_sink_id]</b>.flux += vert.flux
您可能还忘记写 +=
而不是 :后者将无效,因为我们已经将该值分配给顶点.=
因此我们在这里将 Vertex
对象缓存在字典中,而不是使用预取值的结果,我们使用字典值。
这里我们假设所有的顶点都是vertices
查询集的一部分,如果不是这样,我们仍然可以这样工作,通过构造一个字典,将"lazily"填充为新项到达:
class PMap(models.Model):
# ...
def compute_flux(self, save=False):
vertices = self.vertex_set.order_by('-elevation').prefetch_related('flow_sink')
ver_dic = { v.pk: v for v in vertices }
# if some flow_sink vertices are not part of the PMap
for vert in vertices:
if vert.flow_sink_id not in ver_dic:
ver_dic[vert.flow_sink_id] = vert.flow_sink
for vert in vertices:
vert.flux = 1.0 / len(vertices)
# Add flux from current to the downstream node.
for vert in vertices:
if vert.flow_sink_id != vert.pk:
vertices[flow_sink_id].flux += vert.flux
请注意,如果您不保存对象,那么设置 .flux
将无效,如果您稍后再次获取顶点,那么这些顶点当然仍然具有旧值。