2013-02-09 44 views
5

我想模擬使用閉包表作爲分層樹組織的數據。將表示樹中節點的條目不是什麼幻想,並且定義如下。Django的ORM和閉包表

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這將是非常感謝。

+0

不確定是否有很多幫助,因爲它是一種不同的語言(php/codeigniter),但我有一個實現閉包表的玩法,也許它會給你一些想法。 https://gist.github.com/dazld/2174233 – dmp 2013-02-09 14:27:31

+0

感謝您的鏈接,但我不認爲這對我有幫助。我可以計算查詢的邏輯,如果需要,可以在原始SQL中編寫查詢。我被Django QuerySet API難住了。 – CadentOrange 2013-02-09 16:24:33

+0

你有什麼特別的理由需要在這裏使用閉包表嗎?例如,有一個很好的[MPTT] Django實現(https://github.com/django-mptt/django-mptt),它解決了同樣的問題。 – 2013-02-09 19:31:48

回答

1

通過添加related_name的外鍵,像這樣:

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()來減少查詢。