I'm using google app engine with django 1.0.2 (and the django-helper) and wonder how people go about doing recursive delete. Suppose you have a model that's something like this:
我正在使用django 1.0.2(以及django-helper)的谷歌应用引擎,并想知道人们如何进行递归删除。假设你有一个类似这样的模型:
class Top(BaseModel): pass class Bottom(BaseModel): daddy = db.ReferenceProperty(Top)
Now, when I delete an object of type 'Top', I want all the associated 'Bottom' objects to be deleted as well.
现在,当我删除“Top”类型的对象时,我希望删除所有关联的“Bottom”对象。
As things are now, when I delete a 'Top' object, the 'Bottom' objects stay and then I get data that doesn't belong anywhere. When accessing the datastore in a view, I end up with:
就像现在一样,当我删除'Top'对象时,'Bottom'对象保持不变,然后我得到的数据不属于任何地方。在视图中访问数据存储区时,我最终得到:
Caught an exception while rendering: ReferenceProperty failed to be resolved.
I could of course find all objects and delete them, but since my real model is at least 5 levels deep, I'm hoping there's a way to make sure this can be done automatically.
我当然可以找到所有对象并删除它们,但由于我的真实模型至少有5个级别,我希望有一种方法可以确保自动完成。
I've found this article about how it works with Java and that seems to be pretty much what I want as well.
我发现这篇文章关于它如何与Java一起工作,这似乎也是我想要的。
Anyone know how I could get that behavior in django as well?
任何人都知道如何在django中获得这种行为?
4 个解决方案
#1
6
You need to implement this manually, by looking up affected records and deleting them at the same time as you delete the parent record. You can simplify this, if you wish, by overriding the .delete() method on your parent class to automatically delete all related records.
您需要手动实现此操作,方法是查找受影响的记录并在删除父记录的同时删除它们。如果您愿意,可以通过覆盖父类的.delete()方法来自动删除所有相关记录。
For performance reasons, you almost certainly want to use key-only queries (allowing you to get the keys of entities to be deleted without having to fetch and decode the actual entities), and batch deletes. For example:
出于性能原因,您几乎肯定希望使用仅键查询(允许您删除实体的键,而无需获取和解码实际实体)和批量删除。例如:
db.delete(Bottom.all(keys_only=True).filter("daddy =", top).fetch(1000))
#2
2
Actually that behavior is GAE-specific. Django's ORM simulates "ON DELETE CASCADE" on .delete().
实际上,这种行为是针对GAE的。 Django的ORM在.delete()上模拟“ON DELETE CASCADE”。
I know that this is not an answer to your question, but maybe it can help you from looking in the wrong places.
我知道这不是你问题的答案,但也许它可以帮助你找错地方。
#3
2
Reconsider the data structure. If the relationship will never change on the record lifetime, you could use "ancestors" feature of GAE:
重新考虑数据结构。如果关系在记录生命周期中永远不会改变,您可以使用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]
Then querying for ancestor=top will find all the records from all levels. So it will be easy to delete them.
然后查询ancestor = top将查找所有级别的所有记录。因此删除它们很容易。
descendants = list(db.Query().ancestor(top))
# should return [top] + middles + bottoms
#4
1
If your hierarchy is only a small number of levels deep, then you might be able to do something with a field that looks like a file path:
如果您的层次结构只有少量级别,那么您可以使用看起来像文件路径的字段执行某些操作:
daddy.ancestry = "greatgranddaddy/granddaddy/daddy/"
me.ancestry = daddy.ancestry + me.uniquename + "/"
sort of thing. You do need unique names, at least unique among siblings.
那类的东西。你确实需要独特的名字,至少在兄弟姐妹中是独一无二的。
The path in object IDs sort of does this already, but IIRC that's bound up with entity groups, which you're advised not to use to express relationships in the data domain.
对象ID中的路径已经这样做,但IIRC与实体组绑定,建议您不要使用它来表达数据域中的关系。
Then you can construct a query to return all of granddaddy's descendants using the initial substring trick, like this:
然后你可以构造一个查询来使用初始子字符串技巧返回所有granddaddy的后代,如下所示:
query = Person.all()
query.filter("ancestry >", gdaddy.ancestry + "\U0001")
query.filter("ancestry <", gdaddy.ancestry + "\UFFFF")
Obviously this is no use if you can't fit the ancestry into a 500 byte StringProperty.
显然,如果你不能将祖先放入500字节的StringProperty中,这是没用的。
#1
6
You need to implement this manually, by looking up affected records and deleting them at the same time as you delete the parent record. You can simplify this, if you wish, by overriding the .delete() method on your parent class to automatically delete all related records.
您需要手动实现此操作,方法是查找受影响的记录并在删除父记录的同时删除它们。如果您愿意,可以通过覆盖父类的.delete()方法来自动删除所有相关记录。
For performance reasons, you almost certainly want to use key-only queries (allowing you to get the keys of entities to be deleted without having to fetch and decode the actual entities), and batch deletes. For example:
出于性能原因,您几乎肯定希望使用仅键查询(允许您删除实体的键,而无需获取和解码实际实体)和批量删除。例如:
db.delete(Bottom.all(keys_only=True).filter("daddy =", top).fetch(1000))
#2
2
Actually that behavior is GAE-specific. Django's ORM simulates "ON DELETE CASCADE" on .delete().
实际上,这种行为是针对GAE的。 Django的ORM在.delete()上模拟“ON DELETE CASCADE”。
I know that this is not an answer to your question, but maybe it can help you from looking in the wrong places.
我知道这不是你问题的答案,但也许它可以帮助你找错地方。
#3
2
Reconsider the data structure. If the relationship will never change on the record lifetime, you could use "ancestors" feature of GAE:
重新考虑数据结构。如果关系在记录生命周期中永远不会改变,您可以使用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]
Then querying for ancestor=top will find all the records from all levels. So it will be easy to delete them.
然后查询ancestor = top将查找所有级别的所有记录。因此删除它们很容易。
descendants = list(db.Query().ancestor(top))
# should return [top] + middles + bottoms
#4
1
If your hierarchy is only a small number of levels deep, then you might be able to do something with a field that looks like a file path:
如果您的层次结构只有少量级别,那么您可以使用看起来像文件路径的字段执行某些操作:
daddy.ancestry = "greatgranddaddy/granddaddy/daddy/"
me.ancestry = daddy.ancestry + me.uniquename + "/"
sort of thing. You do need unique names, at least unique among siblings.
那类的东西。你确实需要独特的名字,至少在兄弟姐妹中是独一无二的。
The path in object IDs sort of does this already, but IIRC that's bound up with entity groups, which you're advised not to use to express relationships in the data domain.
对象ID中的路径已经这样做,但IIRC与实体组绑定,建议您不要使用它来表达数据域中的关系。
Then you can construct a query to return all of granddaddy's descendants using the initial substring trick, like this:
然后你可以构造一个查询来使用初始子字符串技巧返回所有granddaddy的后代,如下所示:
query = Person.all()
query.filter("ancestry >", gdaddy.ancestry + "\U0001")
query.filter("ancestry <", gdaddy.ancestry + "\UFFFF")
Obviously this is no use if you can't fit the ancestry into a 500 byte StringProperty.
显然,如果你不能将祖先放入500字节的StringProperty中,这是没用的。