Seite 1 von 1

Django acts as tree

Verfasst: Sonntag 31. Mai 2009, 09:50
von sma
Rails kann ein Modell relativ einfach zu einem Knoten in einem Baum machen, indem man das `acts_as_tree`-Plugin wie folgt benutzt:

Code: Alles auswählen

    class Page
      acts_as_tree
    end
Ich finde diese pseudo-deklarative Form eigentlich gar nicht schlecht, auch wenn man nicht so recht weiß, was da nun eigentlich passiert. Ein Blick in den Quelltext zeigt, dass die Methoden `roots`, `root`, `ancestors` und `siblings` sowie zwei Relationen `parent` und `children` definiert werden. Optional kann man auch noch eine Sortierreihenfolge definieren, aber das soll hier keine Rolle spielen.

Wie sähe die Django-Lösung aus? Ich biete

Code: Alles auswählen

    class Page(models.Model):
        parent = acts_as.Tree(related_name='children')
Ich mache die beiden Namen `parent` und `children` explizit, auch wenn sie eigentlich nicht ohne weiteres änderbar sind. Alternativ ginge auch so etwas:

class Page(models.Model):
acts_as = Tree()

Ich nutze in beiden Fällen aus, dass Django automatisch die Methode `contribute_to_class` für ein Objekt aufruft, das im Kontext eines `Model` einem Attribut zugewiesen wird. Dort kann ich nun alle weiteren Attribute definieren, einen Manager zu weisen und weitere Methoden erzeugen. Funktioniert ausgezeichnet :)

Code: Alles auswählen

    class Tree(object):
        def contribute_to_class(self, model, name):
            TreeManager().contribute_to_class(model, 'objects')
            models.ForeignKey('self', related_name='children', blank=True, null=True)\
                .contribute_to_class(model, 'parent')
            model.ancestors = Tree.ancestors
            ...
        
        @staticmethod
        def ancestors(self):
            ...
Spricht etwas dagegen? Hat jemand noch eine bessere Idee für die Benamsung?

Stefan

Verfasst: Mittwoch 10. Juni 2009, 21:35
von bracki
Sehr elegante Lösung.

Was IHMO dagegen spricht ist, das Model-Attribute eigentlich immer vom Typ model.Field sind. Evtl. könnte es da zur Verwirrung kommen wieso hier plötzlich ein Nicht-Field als Attribut verwendet wird. Könnte es nicht auch eine Lösung über einen Decorator geben?
Oder vielleicht in die Meta-Klasse eintragen?

Verfasst: Donnerstag 11. Juni 2009, 13:17
von sma
Mich hat es nicht verwirrt ;) Einen Decorator erst kann ich ja nicht an Attribute schreiben, sondern nur Funktionen. Nur, wenn ich Python 2.6 voraussetze, könnte ich auch noch Klassen als Ziel haben. Ich sehe daher nicht, wie ich diesen elegant benutzen könnte. Und Metaklassen zu definieren sieht IMHO nicht nur hässlich aus, sondern käme möglicherweise auch in Konflikt mit der Metaklasse von `django.db.models.Model`. Aber ich lasse mich gerne überraschen, wie es doch elegant gehen könnte.

Stefan

Verfasst: Donnerstag 11. Juni 2009, 13:57
von Dauerbaustelle
Was macht das jetzt genau?!

Verfasst: Donnerstag 11. Juni 2009, 14:28
von sma
Was macht was?

Stefan

Verfasst: Donnerstag 11. Juni 2009, 15:43
von hinnerk
wie baust Du denn die Hierarchie auf, benutzt Du z.B. MPTT?


Hinnerk

Verfasst: Donnerstag 11. Juni 2009, 20:13
von Dauerbaustelle
Das acts as tree. Was macht das und wozu brauch ich das ;-)

Verfasst: Freitag 12. Juni 2009, 08:35
von sma
Rails' acts as tree baut auf naive Weise (kein MPTT) eine hierarchische Struktur, indem jedes Modell einen Papa kennt und damit jeder Papa seine Kinderchen. Außerdem kann man (mit Aufwand O(n)) die Vorfahren und die vaterlosen Urväter erfragen.

Stefan

Verfasst: Dienstag 16. Juni 2009, 20:59
von bracki
Das hier gibt's ja auch noch: http://code.google.com/p/django-mptt/

Mit einem bisschen Herumspielen habe ich herausgefunden, dass das Subclassen von models.ModelBase keine Probleme bereitet. Man sollte sich nur an die Metaclasses-Doku halten.

Unabhängig davon fände folgendes sonst auch gut:

Code: Alles auswählen

class TreeModel(models.Model):
       parent = models.TreeField
       objects = TreeManager
       
       class Meta:
              abstract = True

class MyTreeModel(TreeModel):
       pass

Verfasst: Donnerstag 18. Juni 2009, 21:47
von sma
Ich finde es nicht so gut, `objects` zu überschreiben, denn was, wenn ich nicht nur Baum-Verhalten will, sondern auch noch Listen-Verhalten (`acts_as_list`), wo ich Objekte nach einer Position anordnen kann oder weitere besondere Eigenschaften ergänzen will, die dann ebenfalls ein eigenes `objects` brauchen würden.

Stefan

Verfasst: Freitag 19. Juni 2009, 08:06
von jens
Interessantes Thema.

In PyLucid hab ich auch ein einfaches parent-tree model. In der alten v0.8 Version erstelle ich seperat vom Modell den "internen" Baum: In v0.9 soll das anders werden. Das parent-tree model bleibt, aber es wäre schön, wenn das Modell selber direkt einen Node Baum zurück liefern könnte. Wie, weiß ich aber noch nicht :(

EDIT: neben django-mptt gibt auch auch noch andere Dinge:
http://django-treebeard.googlecode.com/ ... index.html
parent-tree: http://code.google.com/p/django-treemenus/

Auch interessant, wie man ein parent-tree model aufbauen kann:
http://www.eflorenzano.com/blog/post/ex ... heritance/

Gibt sicherlich noch mehr, wenn man mal sucht: http://www.google.de/search?hl=de&q=django+tree+model

Verfasst: Dienstag 7. Juli 2009, 11:23
von jens
Wie sieht es denn bei euch zu dem Thema aus?