Seite 1 von 1

[Django] ein Problem mit "models.ForeignKey"

Verfasst: Sonntag 10. Mai 2009, 13:49
von snoer
Hallo

Ich möchte eine Plattform schreiben auf der man verschiedene Dinge veröffentlichen kann.
Diese Dinge können ein Text, ein Bild, eine Datei, oder auch alles auf einmal sein.
Man hat Also ein Formular mit einem Textfeld, einem Filefield und einem Imagefield.
Jeder soll auf jeden Eintrag reagieren können, ähnlich wie in einem Usenetforum, oder auch
einen komplett neuen Beitrag ohne Bezug erstellen können.Auch diese Beiträge sollen Text, Bild, Datei oder alles auf einmal sein.

Also habe ich eine Klasse definiert die ich Objekt genannt habe.

Code: Alles auswählen

class Objekt (models.Model):
	titel = models.CharField('Titel', max_length = 100)
	nachricht = models.TextField('Nachricht', blank = True)
	datei = models.FileField('Datei', upload_to = '/media/ups/', blank = True)
	bild = models.ImageField('Bild', upload_to = '/media/ups/', blank = True)
	autor = models.CharField('Autor', max_length = 25)
	datum = models.CharField(max_length = 10)
	c_datum = models.CharField(max_length = 10)
	bezug = models.ForeignKey(Objekt, blank = True)

Jetzt meckert Django beim syncdb natürlich, dass die Klasse "Objekt" nicht definiert ist.
(letzte Zeile im Codeblock)
Wie kann ich dieses Problem umgehen ohne die verschiedenen Beiträge unterschiedlich zu klassifizieren?

Ich hoffe mein Problem ist klar geworden.

schöjn Gruß
snoer

Verfasst: Sonntag 10. Mai 2009, 14:49
von apollo13
Schau doch mal in die Dokumentation, dort wird exakt beschrieben, wie man Relations zum gleichen Objekt machen soll.

Verfasst: Sonntag 10. Mai 2009, 14:53
von snoer
oh..
okay werd ich machen, danke.
für ähnlich weit denkende die diesen thread auf der suche nach antwort lesen

Code: Alles auswählen

	bezug = models.ForeignKey('self', blank = True)

Verfasst: Sonntag 10. Mai 2009, 17:57
von sma
Noch ein paar Anmerkungen: `Objekt` scheint mir ein zu generischer Name zu sein. Von deutschen Namen würde ich persönlich sowieso Abstand nehmen, denn sie wirken fremd und erst ab Python 3.x (mit dem Django nicht funktioniert) kann man korrekte deutsche Namen mit Umlauten verwenden.

Etwas wie `datei` und `bild` würde ich jeweils als eigene Objekte modellieren, denn schnell gibt es hier den Wunsch nach weiteren Metadaten, etwa der Dimension eines Bildes. `author` sollte auch auf ein Modell verweisen und nicht nur ein String sein. Die beiden Datumse schließlich sollte `DateTimeField`s seinen.

Die Baumstruktur, die du ja mit dem Selbstbezug modellierst, würde ich durch einen eigenen `Manager` noch expliziter machen. Vielleicht so (gibt es bestimmt schon irgendwo noch besser, aber dieses hier ist nach Rails' `act_as_tree`-Plugin modelliert):

Code: Alles auswählen

class HierarchicalManager(models.Manager):
    @property
    def root(self):
        return self.get(parent__isnull=True)

    @property
    def roots(self):
        return self.filter(parent__isnull=True)

class HierarchicalModel(models.Model):
    objects = HierarchicalManager()

    parent = models.ForeignKey('self', related_name='children', null=True)

    def ancestors(self):
        node, nodes = self, []
        while node.parent:
            node = node.parent
            nodes.append(node)
        return nodes
    
    def root(self):
        return self.ancestors()[-1]

    def siblings(self, including_self=False):
        nodes = (self.parent.children if self.parent else self.objects.roots).all()
        if not including_self: 
            nodes = nodes.exclude(pk=self.pk)
        return nodes
Achtung: `ancestors` und das darauf basierende `root` sind sehr ineffizient, da Djangos ORM kein Caching kennt. Dafür ist's einfach und wenn er's mal kennt, wird's auch effizienter. Wenn man's für Breadcrumbs o.ä. nutzt, sollte man diese auf View-Ebene cachen.

Was fällt mir noch ein: Ich würde die Kinder noch anordnen, etwa durch eine Spalte `position`. Dann muss man noch ein `ordering` in einer `Meta`-Klasse definieren. Dieses sollte automatisch von den Relation-Managern aufgepickt werden. Das Einfügen und Verschieben von Elementen wird jetzt aber aufwendiger. Ein paar Anregungen kann man sich bei Rails' `acts_as_list` holen.

Stefan