如何使用类似的 Django 模型方法避免代码重复?

How to avoid code duplication with similar Django model methods?

以下模型包含两个几乎相同的函数list_ancestorslist_descendants。什么是只编写一次此代码的好方法?

class Node(models.Model):
    name = models.CharField(max_length=120, blank=True, null=True)
    parents = models.ManyToManyField('self', blank=True, symmetrical=False)

    def list_parents(self):
        return self.parents.all()

    def list_children(self):
        return Node.objects.filter(parents=self.id)

    def list_ancestors(self):
        parents = self.list_parents()
        ancestors = set(parents)
        for p in parents:
            ancestors |= set(p.list_ancestors())  # set union
        return list(ancestors)

    def list_descendants(self):
        children = self.list_children()
        descendants = set(children)
        for c in children:
            descendants |= set(c.list_descendants())  # set union
        return list(descendants)

    def __str__(self):
        return self.name

编辑:从以下答案得出的解决方案:

def list_withindirect(self, arg):
    direct = getattr(self, arg)()
    withindirect = set(direct)
    for d in direct:
         withindirect |= set(d.list_withindirect(arg))
    return list(withindirect)

def list_ancestors(self):
     return self.list_withindirect('list_parents')

def list_descendants(self):
     return self.list_withindirect('list_children')

使用字符串并在对象上调用 getattr 以获取可调用函数。

def list_withindirect(self, fn1):
    direct = getattr(self, fn1)()
    withindirect = set(direct)
    for d in direct:
         withindirect |= set(d.list_withindirect(fn1))

    return list(withindirect)

def list_ancestors(self):
     return self.list_withindirect('list_parents')

这看起来像是 boundunbound 方法问题中的问题。

当您最初将 self.list_parents 传递给 self.list_withindirect(list_direct) 时,一切正常。

但是当你递归传递相同的! self.list_parentsd.list_withindirect(即后代),你不小心用最顶层调用者对象的父代填充了你的 direct 变量,而不是 d.

例如,它可以使用getattr来解决,就像2ps 回答的那样(更新:他的原始代码中的错误是在那里的评论中找到).