2013-02-09 12 views
5

私は、クロージャーテーブルを使って階層ツリーとして編成されたデータをモデル化しようとしています。ツリー内のノードを表すエントリは空想ではなく、次のように定義されます。Django ORMとClosureテーブル

class Region(models.Model): 
    RegionGuid = models.CharField(max_length=40, unique=True, db_column='RegionGUID', blank=True) 
    CustomerId = models.IntegerField(null=True, db_column='CustomerID', blank=True) 
    RegionName = models.CharField(max_length=256, db_column='RegionName', blank=True) 
    Description = models.TextField(db_column="Description", blank=True) 
    class Meta: 
     db_table = u'Region' 

ノード間のパスは、次のクロージャテーブルを使用して定義されます。これは、子孫ノードと祖先と子孫との間の経路長(ノードのすなわち数)に祖先ノード、FKにFKから構成されています

class RegionPath(models.Model): 
    Ancestor = models.ForeignKey(Region, null=True, db_column='Ancestor', blank=True) 
    Descendant = models.ForeignKey(Region, null=True, db_column='Descendant', blank=True) 
    PathLength = models.IntegerField(null=True, db_column='PathLength', blank=True) 
    class Meta: 
     db_table = u'RegionPath' 

今、私はすべてのRegion行とそれぞれの親ノードを取得する方法を(つまり、RegionPath.PathLength = 1の場合)?私のSQLはやや錆びていますが、SQLクエリーはこのように見えるはずです。

SELECT r.* from Region as r 
LEFT JOIN 
(SELECT r2.RegionName, p.Ancestor, p.Descendant from Region as r2 INNER JOIN RegionPath as p on r2.id = p.Ancestor WHERE p.PathLength = 1) AS Parent 
on r.id = Parent.Descendant 

DjangoのQuerySet APIを使用してこれを表現する際の助けがあれば幸いです。そのような外部キーにrelated_nameを追加することにより

+0

異なる言語(php/codeigniter)のヘルプがたくさんあるのかどうかわかりませんが、私はクロージャーテーブルを実装して遊んでいました。 https://gist.github.com/dazld/2174233 – dmp

+0

リンクをありがとうが、私はそれが私を助けるとは思わない。私はクエリのロジックを調べることができ、必要ならば生のSQLの場合はクエリを書くことができます。私はちょうどDjango QuerySet APIに困惑しています。 – CadentOrange

+0

ここでクロージャーテーブルを使用する特別な理由はありますか?たとえば、同じ問題を解決する、[MPTT](https://github.com/django-mptt/django-mptt)のDjangoの実装がとても素敵です。 –

答えて

1

class RegionPath(models.Model): 
    Ancestor = models.ForeignKey(Region, null=True, db_column='Ancestor', blank=True, related_name="ancestor") 
    Descendant = models.ForeignKey(Region, null=True, db_column='Descendant', blank=True, related_name="descendants") 
    PathLength = models.IntegerField(null=True, db_column='PathLength', blank=True) 
    class Meta: 
     db_table = u'RegionPath' 

あなたは関係のいずれかの照会を行うことができます。

children = Region.objects.filter(ancestors__PathLength=1) 
parents = Region.objects.filter(descendants__PathLength=1) 

は、私は非常によく似たモデルに私のテストを行いました。 .distinct()を追加する必要があるかもしれませんが、select_related()を使用してクエリを減らすことができます。