访问预取的自递归集中的更新值

时间:2018-10-30 20:22:31

标签: django recursion updates prefetch django-2.0

我有一个模特:

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除了第一个(初始)循环中的值外,再没有其他值。

我该如何解决此问题或解决该问题?

1 个答案:

答案 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将无效,并且如果以后再获取顶点,则这些顶点当然仍将具有旧值。