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 для узла-потомка и длины пути (т. Е. Количества узлов) между Ancestor и Descendant:

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

Любая помощь в выражении этого с помощью API QuerySet Django будет высоко ценится.

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(), чтобы уменьшить количество запросов.

Другие вопросы по тегам