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

时间:2017-01-18 01:52:56

标签: django methods code-duplication

以下模型包含两个几乎相同的函数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')

2 个答案:

答案 0 :(得分:2)

使用字符串并在对象上调用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')

答案 1 :(得分:0)

这似乎是绑定未绑定方法问题中的问题。

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

但是当你以递归的方式通过时! self.list_parentsd.list_withindirect(即后代),您不小心将direct变量填充到最顶层调用者对象的父级,而不是d

例如,可以使用getattr进行解析,就像 2ps 一样(upd:他的原始代码中的错误在那里的评论中找到)