【问题标题】:Recursive delete in google app engine谷歌应用引擎中的递归删除
【发布时间】:2009-06-28 12:48:36
【问题描述】:

我正在使用带有 django 1.0.2(和 django-helper)的谷歌应用引擎,想知道人们是如何进行递归删除的。 假设你有一个类似这样的模型:

类顶级(BaseModel): 经过 类底部(BaseModel): 爸爸 = db.ReferenceProperty(顶部)

现在,当我删除“顶部”类型的对象时,我希望也删除所有关联的“底部”对象。

就像现在一样,当我删除“顶部”对象时,“底部”对象会保留下来,然后我会得到不属于任何地方的数据。在视图中访问数据存储时,我最终得到:

渲染时遇到异常:ReferenceProperty 解析失败。

我当然可以找到所有对象并删除它们,但由于我的真实模型至少有 5 层深,我希望有一种方法可以确保这可以自动完成。

我发现这个article 是关于它如何与 Java 一起工作的,这似乎也是我想要的。

有人知道我如何在 django 中获得这种行为吗?

【问题讨论】:

    标签: python django google-app-engine


    【解决方案1】:

    您需要手动执行此操作,方法是查找受影响的记录并在删除父记录的同时删除它们。如果您愿意,您可以通过覆盖父类的 .delete() 方法来自动删除所有相关记录来简化此操作。

    出于性能原因,您几乎肯定希望使用仅键查询(允许您获取要删除的实体的键,而无需获取和解码实际实体)和批量删除。例如:

    db.delete(Bottom.all(keys_only=True).filter("daddy =", top).fetch(1000))
    

    【讨论】:

    • 出于兴趣,db.delete 是否在每个实体上调用 delete()?它进行了极其优化,所以我有点怀疑你不能将这两个技巧结合起来。不过,keys_only 很好。
    • 不,db.delete() 直接对应一个RPC,并行发送所有要删除的key。 Entity.delete() 只是调用 db.delete(self) 的语法糖。
    • 是的,它会 - 虽然 db.delete(top.bottom_set.fetch(1000)) 会更快(假设少于 1000 个实体)。
    • 我无法让它工作,但这个答案已经快 4 年了,所以可能就是这样。 GAE 是否仍然支持按键查询(jgeewax 的解决方案运行良好)?搜过了,不清楚。
    【解决方案2】:

    实际上,这种行为是 GAE 特有的。 Django 的 ORM 在 .delete() 上模拟“ON DELETE CASCADE”。

    我知道这不是您问题的答案,但也许它可以帮助您避免找错地方。

    【讨论】:

      【解决方案3】:

      重新考虑数据结构。如果关系在记录生命周期内永远不会改变,您可以使用 GAE 的“祖先”功能:

      class Top(db.Model): pass
      class Middle(db.Model): pass
      class Bottom(db.Model): pass
      
      top = Top()
      middles = [Middle(parent=top) for i in range(0,10)]
      bottoms = [Bottom(parent=middle) for i in range(0,10) for middle in middles]
      

      然后查询祖先=top 将找到所有级别的所有记录。所以很容易删除它们。

      descendants = list(db.Query().ancestor(top))
      # should return [top] + middles + bottoms
      

      【讨论】:

      • 美丽。很好地使用列表推导。我第一次看到有两个循环的!不过,它们似乎是另一个顺序,外部循环首先出现。
      【解决方案4】:

      如果您的层次结构只有少数几个层次,那么您也许可以对一个看起来像文件路径的字段做一些事情:

      daddy.ancestry = "greatgranddaddy/granddaddy/daddy/"
      me.ancestry = daddy.ancestry + me.uniquename + "/"
      

      之类的。您确实需要唯一的名称,至少在兄弟姐妹中是唯一的。

      对象 ID 中的路径已经这样做了,但 IIRC 与实体组绑定,建议您不要使用它来表达数据域中的关系。

      然后您可以使用初始子字符串技巧构造一个查询以返回所有祖父的后代,如下所示:

      query = Person.all()
      query.filter("ancestry >", gdaddy.ancestry + "\U0001")
      query.filter("ancestry <", gdaddy.ancestry + "\UFFFF")
      

      如果你不能将祖先放入一个 500 字节的 StringProperty 中,这显然是没有用的。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2012-06-10
        • 2011-12-16
        • 1970-01-01
        • 2014-07-24
        • 2011-05-06
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多