2017-01-18 23 views
1

次のモデルには、2つのほぼ同じ機能list_ancestorslist_descendantsが含まれています。このコードを一度書くだけの良い方法は何でしょうか?同様のDjangoモデルメソッドでコードの重複を避けるには?

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 

EDIT:以下の回答から得られる解決策:

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') 
+0

@質問:私はあなたの質問を理解していません。祖先は親の一般化されたものなので、 'list_ancestors'は' list_parents'を使います。子孫は子どもの一般化されたものなので、 'list_descendants'は' list_children'を使います。 – Watchduck

+0

'list_ancestors'はまず親を取得し、次に親の祖先を再帰的に取得します。 'list_descendants'はまず子を取得し、子の子孫を再帰的に取得します。私が統合しようとするこれら2つの同様の関数が再帰的であるため、私の "解" list_withindirectも再帰的です。 – Watchduck

+0

ああ申し訳ありませんが、私はその部分を逃しました – Sayse

答えて

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') 
+0

それは動作しません。 'list_ancestors'を使用しようとすると、' ImportError'と 'TypeError:list_withindirect()は2つの位置引数をとりますが、3つは与えられます。あなたが 'getattr'で何をしようとしているのか分かりません。 – Watchduck

+1

@Watchduckは最後の行の2番目の 'self'を削除します – schwobaseggl

+0

それはそうしました。ありがとう! – Watchduck

0

これはバインドで問題と結合していない方法の問題のように見えます。

最初にself.list_parentsをに渡すときは、すべて問題ありません。

しかし、再帰的に同じものを渡すとき! self.list_parentsd.list_withindirect(つまり子孫)、dの代わりにdirect変数を一番上の呼び出し元オブジェクトの親に間違って設定しています。例えば

それは2PS(UPD:彼の元のコードに誤りがあったコメントで発見された)が応答したように、それは、getattrを使用して解決することができる

+1

'd.list_direct'は' AttributeError: 'Node'オブジェクトに属性 'list_direct'がありません。 – Watchduck

+0

だから、私はあなたがすでに答えを得ているので、私はそれが可能だと思うwo getaatrの解決策を見つけようとしないだろう。私は私のポストに元の問題の理由説明だけを残しています。 –

関連する問題