3

django内でツリー構造をモデル化しようとしています。これは私が持っているものの縮小版です:

from django.db import models

class Node(models.Model):
    parent = models.ForeignKey("Node", null=True)
    name = models.CharField(max_length=20)

    def child_cnt(self):
        return self.node_set.count()

    def __unicode__(self):
        return self.name

ここまでは順調ですね。できます。しかし、今、そのような階層を作成し始めると、次のようになります。

from ....models import Node
root = Node()
root.name = "ROOT"
root.parent = None
root.save()

n = Node()
print n.child_cnt()
>> 1
print n.node_set.all()
[<Node: ROOT>]

では、ルートノードは内部の子として何を作成しnますか?そして、どうすればそれを回避できますか?

電話をかけると問題は解決しますが、管理サイト内でn.save()ノードが1で初期化されているのを見るのはちょっと厄介です。child_cnt

4

2 に答える 2

1

さて、いくつかの調査の後-ここに結果があります:

まず、注意-漸化式でForeignKeyを使用する場合は、クラス名の代わりに「self」を使用する必要があります: https ://docs.djangoproject.com/en/dev/ref/models/fields/#django.db.models 。外部キー

次に-ForeignKeyはOneToOneリレーションです。親ノードを列挙しているときにノードの子を列挙するのは正しくありません...質問に戻ります-node_set.all()を呼び出すと-Node.objects.all()として実行されているように見えます。そのため、次のように表示されます。新しく作成されたノードインスタンスのアイテム(DBに保存されません)。実際、ここではnode.node_setを使用してノードの外部キーを取得することはできません。ノードに複数の子を含めるには、ManyToManyFieldを使用する必要があります。例:

children = models.ManyToManyField('self', null=True)

次に、次を使用して呼び出します。

node.children.all() # for all children

また

node.children.count()

編集

簡単な分析:

class A(model):
    parent = ForeignKey(B)

それから

a = A()
b = B()
b.parent_set.all() 

親としてBを持つすべてのA、またはparent_id=b.idを持つすべてのAを返します。あなたの場合、あなたは実際に以下を持っています:

a = A()
b = A()
b.parent_set.all() 

b(== a)を親として持つすべてのAを返します。その場合、a.parent_id = b.idですが、b.idはNone(保存されていない)なので、parent_id =を持つすべてのノード(b)を取得します。なし。

実際、この動作は非再帰的な関係でも同じです。最初の例では、A()をparent = Noneで保存し、保存されていないすべてのBについてb.parent_set.all()で取得します。

于 2012-06-11T14:58:03.357 に答える
1

私はそれがおかしなことに聞こえることを知っています、しかし私はあなたの問題を解決するために数分を費やしました、そしてそれは私が試みたどんな試みでもうまくいきませんでした。とにかく、Tree ForeignKeyについては、このタイプのキーを処理するライブラリ全体である別のソリューションをオンラインで見つけます。https://github.com/django-mptt/django-mptt 試してみることができます。あなたにぴったりです。このような小さなもののためにライブラリを追加するのは嫌いですが、これ以上のものは見つかりませんでした。

また、ライブラリ全体をインポートしたくない場合は、TreeForeignKeyだけをコードに取り込むことができます。

于 2012-06-11T14:43:21.323 に答える