我正在使用Django:
>>> django.VERSION
(1, 11, 15, u'final', 0)
MPTT:
django-mptt 0.9.1
在型号中:
from mptt.models import MPTTModel, TreeForeignKey
class Location(MPTTModel):
id = models.AutoField(primary_key=True)
name = models.CharField(max_length=75,null=False)
parent = TreeForeignKey('self', on_delete=models.PROTECT, null=True, blank=True)
我可以按照django-mptt文档正确查看和添加。但是我无法删除子节点。它弄乱了所有的树形结构。 这是在视图中使用删除的方式:
Location.objects.get(id=loc_id).delete()
其中loc_id是我要删除的节点的ID。 我不确定如何正确使用Delete或mptt中存在错误。 我在其官方文档中查找了任何示例。该主题仅说明以下内容:
mptt.models.MPTTModel类(* args,** kwargs)
MPTTModel.delete(* args,** kwargs)
在节点上调用delete将删除它以及它的完整子树,而不是重新附加所有 子节点到其父节点。没有特定于 MPTT模型,所有参数都将直接传递给Django的 删除模型。删除将不返回任何内容。
谢谢
答案 0 :(得分:0)
好吧,事实证明,暂时只是为了获得我可以使用的健全表结构
Location.objects.rebuild()
这将重建整个表结构,即其lft,rght列。所以我把树弄糟了。删除节点后,我使用此行。
这可能不是完美的解决方案。
我仍在寻找适当的删除代码,因为为大型数据集重建树可能很耗时。
希望有人在这方面仍然可以提供帮助。
答案 1 :(得分:0)
有一次我遇到了受保护儿童删除的问题(django-mptt==0.9.1)。 经过一番搜索,我发现了下一个问题: 问题发生在 MPTTodel 的 delete() 方法中。 首先它尝试更新树结构,然后删除对象。所以如果我们有受保护的关系,我们的树可能会搞砸。
tree_width = (self._mpttfield('right') -
self._mpttfield('left') + 1)
target_right = self._mpttfield('right')
tree_id = self._mpttfield('tree_id')
self._tree_manager._close_gap(tree_width, target_right, tree_id)
parent = cached_field_value(self, self._mptt_meta.parent_attr)
if parent:
right_shift = -self.get_descendant_count() - 2
self._tree_manager._post_insert_update_cached_parent_right(parent, right_shift)
return super(MPTTModel, self).delete(*args, **kwargs)
我已经使用事务解决了这个问题。类似的东西:
from django.db import transaction
def delete(self, *args, **kwargs):
with transaction.atomic():
super().delete(*args, **kwargs)
在 shell 中测试(django 3.1.7 和 django-mptt 0.12.0)
from mptt.models import MPTTModel, TreeForeignKey
from django.db import models, transaction
class Test(MPTTModel):
name = models.TextField()
parent = TreeForeignKey(
'self',
on_delete=models.PROTECT,
null=True,
blank=True,
related_name='children'
)
from testing.models import Test
a = Test.objects.create(name='a')
b = Test.objects.create(name='b', parent=a)
c = Test.objects.create(name='c', parent=b)
print(a.get_descendants())
print(c.get_ancestors())
b.delete()
# refresh from db
a = Test.objects.get(pk=a.pk)
c = Test.objects.get(pk=c.pk)
print(a.get_descendants())
print(c.get_ancestors())
>>> print(a.get_descendants())
<TreeQuerySet [<Test: Test object (20)>, <Test: Test object (21)>]>
>>> print(c.get_ancestors())
<TreeQuerySet [<Test: Test object (19)>, <Test: Test object (20)>]>
>>>
>>> b.delete()
Traceback (most recent call last):
File "<console>", line 1, in <module>
File "/home/vladimir/Desktop/test/.venv/lib/python3.8/site-packages/mptt/models.py", line 1138, in delete
return super().delete(*args, **kwargs)
File "/home/vladimir/Desktop/test/.venv/lib/python3.8/site-packages/django/db/models/base.py", line 946, in delete
collector.collect([self], keep_parents=keep_parents)
File "/home/vladimir/Desktop/test/.venv/lib/python3.8/site-packages/django/db/models/deletion.py", line 302, in collect
raise ProtectedError(
django.db.models.deletion.ProtectedError: ("Cannot delete some instances of model 'Test' because they are referenced through protected foreign keys: 'Test.parent'.", {<Test: Test object (21)>})
>>>
>>> # refresh from db
>>> a = Test.objects.get(pk=a.pk)
>>> c = Test.objects.get(pk=c.pk)
>>>
>>> print(a.get_descendants())
<TreeQuerySet []>
>>> print(c.get_ancestors())
<TreeQuerySet [<Test: Test object (20)>]>
>>> print(a.get_descendants())
<TreeQuerySet [<Test: Test object (23)>, <Test: Test object (24)>]>
>>> print(c.get_ancestors())
<TreeQuerySet [<Test: Test object (22)>, <Test: Test object (23)>]>
>>>
>>> b.delete()
Traceback (most recent call last):
File "<console>", line 1, in <module>
File "/home/vladimir/Desktop/test/someproject/testing/models.py", line 16, in delete
super().delete(*args, **kwargs)
File "/home/vladimir/Desktop/test/.venv/lib/python3.8/site-packages/mptt/models.py", line 1138, in delete
return super().delete(*args, **kwargs)
File "/home/vladimir/Desktop/test/.venv/lib/python3.8/site-packages/django/db/models/base.py", line 946, in delete
collector.collect([self], keep_parents=keep_parents)
File "/home/vladimir/Desktop/test/.venv/lib/python3.8/site-packages/django/db/models/deletion.py", line 302, in collect
raise ProtectedError(
django.db.models.deletion.ProtectedError: ("Cannot delete some instances of model 'Test' because they are referenced through protected foreign keys: 'Test.parent'.", {<Test: Test object (24)>})
>>>
>>> # refresh from db
>>> a = Test.objects.get(pk=a.pk)
>>> c = Test.objects.get(pk=c.pk)
>>>
>>> print(a.get_descendants())
<TreeQuerySet [<Test: Test object (23)>, <Test: Test object (24)>]>
>>> print(c.get_ancestors())
<TreeQuerySet [<Test: Test object (22)>, <Test: Test object (23)>]>