django-mptt:如何成功移动节点

发布于 2024-09-05 06:01:39 字数 1254 浏览 6 评论 0 原文

django-mptt 似乎决心要让我失去理智。我正在尝试做一些相对简单的事情:我要删除一个节点,并且需要对该节点的子节点做一些合理的事情。也就是说,我想将它们提升一级,这样它们就是当前父母的父母的孩子。

也就是说,如果树看起来像:

 Root
  |
Grandpa
  |
Father
|    |
C1   C2

我要删除父亲,并希望 C1 和 C2 成为祖父的孩子。

这是我正在使用的代码:

class Node(models.Model):
    first_name   = models.CharField(max_length=80, blank=True)
    parent       = models.ForeignKey('self', null=True, blank=True, related_name='children')

    def reparent_children(self, parent):
        print "Reparenting"
        for child in self.get_children():
            print "Working on", child.first_name, "to parent", parent.email
            parent = Node.objects.get(id=parent.id)
            child.move_to(parent, 'last-child')
            child.save()

所以我会调用:

father.reparent_children(grandpa)
father.parent = None
father.save()

这几乎有效。孩子们将他们的父母称为爷爷:

c1.parent == grandpa  # True

爷爷将 C1 和 C2 算在其孩子中。

c1 in grandpa.children.all()   # True

然而,Root 与这些孩子断绝关系。

c1.get_root() == father  # c1's root is father, instead of Root

c1 in root.get_descendants()  # False

怎样才能让孩子们动起来,而且他们的根不被腐蚀呢?

django-mptt seems determined to drive me out of my mind. I'm trying to do something relatively simple: I'm going to delete a node, and need to do something reasonable with the node's children. Namely, I'd like to move them up one level so they're children of their current parent's parent.

That is, if the tree looks like:

 Root
  |
Grandpa
  |
Father
|    |
C1   C2

I'm going to delete Father, and would like C1 and C2 to be children of Grandpa.

Here's the code I'm using:

class Node(models.Model):
    first_name   = models.CharField(max_length=80, blank=True)
    parent       = models.ForeignKey('self', null=True, blank=True, related_name='children')

    def reparent_children(self, parent):
        print "Reparenting"
        for child in self.get_children():
            print "Working on", child.first_name, "to parent", parent.email
            parent = Node.objects.get(id=parent.id)
            child.move_to(parent, 'last-child')
            child.save()

So I'd call:

father.reparent_children(grandpa)
father.parent = None
father.save()

This works - almost. The children report their parents as Grandpa:

c1.parent == grandpa  # True

Grandpa counts C1 and C2 among its children

c1 in grandpa.children.all()   # True

However, Root disowns these kids.

c1.get_root() == father  # c1's root is father, instead of Root

c1 in root.get_descendants()  # False

How do I get the children to move and their root not get corrupted?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

智商已欠费 2024-09-12 06:01:40

第一次保存子项时(即 reparent_children 方法的最后一行),内部 lftrght 值将会更改。 save() 不会更新您可能拥有的实例。我认为一种安全的方法是每次从数据库中重新获取它们,如下所示:

def reparent_children(self, parent):
    print "Reparenting"
    for child in self.get_children():
        print "Working on", child.first_name, "to parent", parent.email
        parent = Node.objects.get(id=parent.id)
        current_child = Node.objects.get(id = child.id)
        current_child.move_to(parent, 'last-child')
        current_child.save()

我有 类似问题不久前,这种方法解决了我的问题。

The internal lft and rght values will change the first time you save a child (i.e. the final line of your reparent_children method). save() doesn't update instances you may have lying around. I think a safe way to do this would be to refetch them from the database each time, like this:

def reparent_children(self, parent):
    print "Reparenting"
    for child in self.get_children():
        print "Working on", child.first_name, "to parent", parent.email
        parent = Node.objects.get(id=parent.id)
        current_child = Node.objects.get(id = child.id)
        current_child.move_to(parent, 'last-child')
        current_child.save()

I had similar problems a while back, and that approach solved my problem.

妄司 2024-09-12 06:01:40

最近几天这个库真的让我很困惑—— move_to 似乎并没有真正做到我想要的,而且我的树一直不同步。我想出了一个我更有信心的解决方案,但代价是速度和非传统性。

它围绕管理器方法 partial_rebuild 此处

def delete_node(self):
    if not self.parent:
        print("Should not delete root node, confusing behavior follows")
        return
    tree_id = self.tree_id
    parent = self.parent

    for child in self.get_children():
        child.parent = parent
        child.save()

    self.delete()
    Node.objects.partial_rebuild(tree_id)

如果您愿意,可以将 child.parent =parent 替换为 child.move_node(parent)

This library has really confused me these last few days -- move_to does not really seem to do what I want it to, and my tree keeps getting out of sync. I came up with a solution that I'm more confident in, at the expense of speed and nontraditional-ness.

It revolves around the manager method partial_rebuild here.

def delete_node(self):
    if not self.parent:
        print("Should not delete root node, confusing behavior follows")
        return
    tree_id = self.tree_id
    parent = self.parent

    for child in self.get_children():
        child.parent = parent
        child.save()

    self.delete()
    Node.objects.partial_rebuild(tree_id)

You can replace child.parent = parent with child.move_node(parent) if you'd like

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文