32

自己参照する外部キー関係を持つこのモデルがあります。

class Person(TimeStampedModel):
    name = models.CharField(max_length=32)
    parent = models.ForeignKey('self', null=True, blank=True, related_name='children')

今、私は人のマルチレベルの子供をすべて取得したいと考えています。Django クエリを作成するにはどうすればよいですか? 再帰関数のように振る舞う必要があります。

4

9 に答える 9

42

モデルにはいつでも再帰関数を追加できます。

編集:SeomGiHanに従って修正

def get_all_children(self, include_self=True):
    r = []
    if include_self:
        r.append(self)
    for c in Person.objects.filter(parent=self):
        _r = c.get_all_children(include_self=True)
        if 0 < len(_r):
            r.extend(_r)
    return r

(再帰やデータが多い場合は、これを使用しないでください...)

errxによって提案されたようにmpttをまだ推奨しています。

編集:この答えはまだ注目を集めているので2021:/

代わりにdjango-tree-queriesを使用してください!

于 2011-01-18T16:25:17.870 に答える
18

Modified preorder tree traversal について読む必要があります。これがdjangoの実装です。 https://github.com/django-mptt/django-mptt/

于 2011-01-18T14:56:47.303 に答える
8

sunn0 の提案は素晴らしいアイデアですが、get_all_children() は奇妙な結果を返します。[Person1, [Person3, Person4], []] のようなものを返します。以下のように変更する必要があります。

def get_all_children(self, include_self=True):
    r = []
    if include_self:
        r.append(self)
    for c in Person.objects.filter(parent=self):
        _r = c.get_all_children(include_self=True)
        if 0 < len(_r):
            r.extend(_r)
    return r
于 2016-04-19T12:23:27.973 に答える
5

ツリーの最大深度がわかっている場合は、次のようなものを試すことができます(テストされていません)。

Person.objects.filter(Q(parent=my_person)|Q(parent__parent=my_person)| Q(parent__parent__parent=my_person))
于 2011-01-18T21:50:56.823 に答える
1

私はこれが古いことを知っていますが、誰かが助けられるかもしれません.

     def get_all_children(self, container=None):
         if container is None:
             container = []
         result = container
         for child in self.children.all():
             result.append(child)
             if child.children.count() > 0:
                 child.get_all_children(result)
         return result

次に、モデルでこれを a property(または、cached_propertyそれが機能する場合は a) にして、任意のインスタンスで呼び出すことができるようにします。

于 2018-01-11T06:26:08.320 に答える