我有一个模特:
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
除了第一个(初始)循环中的值外,再没有其他值。
我该如何解决此问题或解决该问题?
答案 0 :(得分:1)
问题在于,加载了Vertex
的{{1}}对象与prefetch_related
中的对象不同。是的,这两个对象将相等,vertices
检查将成功。这是因为Django检查模型是否相同以及主键,而不是其他值。对v1 == v2
对象之一所做的更改不会反映在另一个模型中。
我们可以通过维护将Vertex
映射到相应顶点的字典来解决此问题,例如:
pk
您可能还忘记了写class PMap(models.Model):
# ...
def compute_flux(self, save=False):
vertices = self.vertex_set.order_by('-elevation')
ver_dic = { v.pk: v for v in vertices }
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
而不是 :后者将无效,因为我们已经将该值分配给了顶点。+=
因此,我们在这里将=
对象缓存在字典中,而不是使用预取值的结果,而是使用字典值。
在这里我们假设所有顶点都是Vertex
查询集的一部分,如果不是这种情况,我们仍然可以通过构造一个字典来工作,即当新条目到达时“懒惰地”填充该字典:>
vertices
请注意,但是,如果您不保存对象,则设置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
将无效,并且如果以后再获取顶点,则这些顶点当然仍将具有旧值。