2013-02-09 22 views
5

Sto provando a modellare i dati che sono organizzati come un albero gerarchico usando una tabella di chiusura. Le voci che rappresenteranno i nodi nell'albero non sono fantasiose e sono definite come segue.Django ORM e Tabelle di chiusura

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' 

I percorsi tra i nodi sono definiti utilizzando la seguente tabella di chiusura. Si compone di un FK al nodo antenato, FK al nodo discendente e la lunghezza del percorso (cioè il numero di nodi) tra Ancestor e Decrescente:

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' 

Ora come avrei recuperare tutte Region righe e rispettivo nodo genitore (cioè dove RegionPath.PathLength = 1)? Il mio SQL è un po 'arrugginito, ma penso che la query SQL dovrebbe essere simile a questa.

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 

Qualsiasi aiuto nell'esprimere questo utilizzando l'API QuerySet di Django sarebbe molto apprezzato.

+0

non so se molto di aiuto in quanto è una lingua diversa (php/codeigniter) ma ho avuto un gioco con l'implementazione di tabelle di chiusura, e forse ti darà alcune idee. https://gist.github.com/dazld/2174233 – dmp

+0

Grazie per il link, ma non penso che questo mi aiuti. Posso elaborare la logica della query e posso scrivere la query se in SQL raw se necessario. Sono solo perplesso dall'API di Django QuerySet. – CadentOrange

+0

C'è qualche ragione particolare per cui devi usare i tavoli di chiusura qui? C'è un'implementazione molto bella di Django di [MPTT] (https://github.com/django-mptt/django-mptt), ad esempio, che risolve lo stesso problema. –

risposta

1

Aggiungendo related_name alle chiavi esterne in questo modo:

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' 

È possibile effettuare le query per entrambi i confronti:

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

ho fatto la mia prova su un modello molto simile. Potrebbe essere necessario aggiungere .distinct(), potrebbe essere necessario selezionare_related() per ridurre le query.