Wie sieht ein Datenmodell für ein Forum aus?

Sockets, TCP/IP, (XML-)RPC und ähnliche Themen gehören in dieses Forum
sma
User
Beiträge: 3018
Registriert: Montag 19. November 2007, 19:57
Wohnort: Kiel

Wie sieht eigentlich das Datenmodell einer typischen Forumsanwendung aus, speziell wenn ich es auf Django abbilden will? Mir geht es insbesondere darum, wie ich ungelesene und gelesene Beiträge verwalte. Dazu muss ich jedoch erstmal weiter ausholen.

Ein Forum (Forum) habe Themen (Topic) und jedes Thema habe Beiträge (Post). Ein Forum habe außerdem Benutzer (User), die Beiträge schreiben.

Code: Alles auswählen

class User(models.Model):
    """Represents a forum user who writes posts."""
    name = models.CharField()

class Forum(models.Model):
    """Represents a list of related conversations."""
    title = models.CharField()

class Topic(models.Model):
    """Represents a single conversation consisting of postings."""
    title = models.CharField()
    forum = models.ForeignKey(Forum, related_name='topics')

class Post(models.Model):
    body = models.TextField()
    date = models.DateTimeField()
    author = models.ForeignKey(User, related_name='all_posts')
    topic = models.ForeignKey(Topic, related_name='posts')
Anzeigen möchte ich gerne alle Foren in definierbarer Reihenfolge (hier egal), die Anzahl der Themen und Beiträge (auch egal, würde man wohl de-normalisieren und diese Zahlen im Forum speichern statt jedes mal zu zählen) und möglicherweise wer zuletzt was geschrieben hat (nochmal egal). Für jedes Forum möchte ich die Themen sortiert nach dem letzten Beitrag anzeigen, die Anzahl der Beiträge pro Thema und wer zuletzt was gechrieben hat (egal). Für jedes Thema möchte ich die Beiträge mit ihren Autoren anzeigen.

So weit, so gut.

Für jeden User möchte ich nun festhalten, welche Beiträge er gesehen hat bzw. welche noch neu für ihn sind. Wie mache ich dies und insbesondere, wie mache ich dies einigermaßen speichereffizient?

Der naive Ansatz wäre wohl, pro User und Thema einen Eintrag in einer speziellen Tabelle abzulegen. Entweder

Code: Alles auswählen

class Read(models.Model):
    topic = models.ForeignKey(Topic)
    user = models.ForeignKey(User)
oder

Code: Alles auswählen

class Unread(models.Model):
    topic = models.ForeignKey(Topic)
    user = models.ForeignKey(User)
Wenn aber wie in diesem Forum bereits über 12.000 Themen existieren und dann vielleicht noch 5.000 Anwender, hätte ich 60.000.000 Datensätze für gelesene Themen. Zu viel!

Speichere ich die ungelesenen Themen, müsste ich bei jeder Änderung hier pro Anwender einen Datensatz schreiben und später diese wieder löschen. Sagen wir einmal, das pro Tag 40 Beiträge geschrieben werden (was ungefähr für dieses Forum hinkommt) und User 1x pro Woche lesen, dann sind es noch 1.400.000 Datensätze. Hm.

Ich möchte allerdings nicht einfach nur ablegen, wann der letzte Login war, um dann alles, was seit diesem Zeitpunkt neu ist, zu markieren. Ich hasse, wenn Foren vergessen, was ich noch nicht gelesen habe (dieses Forum macht es auch manchmal).

Ich könnte die Menge der Datensätze reduzieren, indem ich die Informationen kompakt kodiere. Pro Forum könnte ich die Information, welche Themen bis zu welchen Beiträgen gelesen wurden, in einem String ablegen.

Code: Alles auswählen

12812:4522,12813:4598  # Topic:Post,Topic:Post,...
Bei etwa 200 Themen pro Forum und 12 Zeichen pro Paar kommen wir auf 2400 Zeichen pro Forum und Anwender. Letztlich die selbe Informationsmenge, aber vielleicht kann ich's so effizienter speichern als die Datenbank in Tabellen.

Wenn ich Beiträge nicht global durchnummeriere, sondern pro Forum, kann ich die Liste verkürzen, indem ich ausnutze, dass in der Regel das Gros der Beiträge bekannt ist und ich ein (offene) Intervale benutze, die Beiträge aufzuzählen:

Code: Alles auswählen

4528,4522-4518,4507-  # ID oder ID2-ID1 oder ID- 
Nun habe ich aber ein Problem mit Django, welches keine zusammengesetzten Primärschlüssel unterstützt und ich damit dann keine Beiträge mehr haben kann, die durch id + forum_id erst eindeutig werden.

Es muss doch einen besseren Ansatz geben!

Stefan
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Ein Forum in django ;)

Vielleicht hilft es dir weiter, zu sehen wie das andere gemacht haben. Such mal nach "Forum" auf der Seite: http://code.djangoproject.com/wiki/DjangoResources
(Wenn die überhaupt so eine Funktion implementiert haben)

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
sma
User
Beiträge: 3018
Registriert: Montag 19. November 2007, 19:57
Wohnort: Kiel

Ich finde es interessant, Problemstellungen theoretisch zu lösen (da kommt dann der Mathematiker in mir hoch) und wollte daher nicht einfach Quelltext studieren. Ich hatte gehofft, mit einem Posting einfach eine Diskussion der Diskussion wegen anregen zu können. Klappte nicht...

Bei django-forum und snapboard, die auch code.google.com gehostet werden und ich daher schnell auf die model.py-Datei schauen konnte kann ich vermelden, das keines von beidem (un)gelesene Beiträge trackt. Gleiches gilt für codepoint, diamanta aka MyghtyBoard, nyxcite und beastly so wie ich das auf die Schnelle sehe. Einige verschicken wohl Emails bei Änderungen, das ist dann aber auch schon alles.

Und nun?

Wie hast du's denn in deinem Forum implementiert, jens?

Stefan
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Auf pylucid.org nutzte ich, mangels Alternativen, noch immer phpBB2, so wie hier. Wenn dein Forum brauchbar ist, würde ich gern wechseln ;)

Die Frage könntest du ans pocoo Team richten, vielleicht haben die sich dazu schon Gedanken gemacht, die dir weiterhelfen.

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
burli
User
Beiträge: 1156
Registriert: Dienstag 9. März 2004, 18:22

jens hat geschrieben:Auf pylucid.org nutzte ich, mangels Alternativen, noch immer phpBB2, so wie hier. Wenn dein Forum brauchbar ist, würde ich gern wechseln ;)
Gibt es in Python nix brauchbares? Ich hab mal vor 2 Jahren eins in PHP geschrieben. Hat zwar nicht sonderlich gut funktioniert, aber es hat funktioniert.
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Nein. Es gibt generell wenig brauchbare, freie Foren Software. Wir haben hier ja schon vor einiger Zeit nach Alternativen gesucht, weil uns einige Dinge am phpBB stören.

http://pocoo.org/ sollte ja mal die Nachfolge werden. Gestartet hat das Projekt im Oktober 2005, fertig ist es aber noch lange nicht. Dafür haben wir jetzt einige tolle Projekte (z.B. Jinja und Pygments)...

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
sma
User
Beiträge: 3018
Registriert: Montag 19. November 2007, 19:57
Wohnort: Kiel

Ah, ich habe das wohl verwechselt. Du baust das CMS mit Django, stimmt.

Ich hätte ja gesagt, es kann doch nicht so schwer sein, ein Forum mit Django zu bauen, aber offenbar ist es nicht so. Meine Idee im Hinterkopf war eigentlich, ein Forum als Beispiel für ein Tutorial in der Firma heranzuziehen, mit den ich gerne für Python und Django werben möchte.

Ich hatte geben nochmal in den Quelltext von beast, einem mit Rails geschriebenen Forum, geworfen, von dem beastly abgeschrieben hat, doch auch dort werden wohl nur mails verschickt, wenn sich etwas ändert.

Stefan
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Also wenn es nur ein Beispiel sein soll, dann würde ich das so einfach wie möglich aufsetzten. Also lass es einfach weg oder mach was ganz anderes.

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
Y0Gi
User
Beiträge: 1454
Registriert: Freitag 22. September 2006, 23:05
Wohnort: ja

Leonidas und ich arbeiten an einem Forum in Python to rule them all. Bis das allerdings komfortabel einsetzbar ist, wird noch einige Zeit ins Land gehen - daher ist das ganze noch nicht wirklich spruchreif.
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Las mal mehr Infos rüberkommen... Basiert es auf den pocoo code oder komplett neu aufgesetzt? Werden irgendwelche Frameworks genutzt? Sourcen online?

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
audax
User
Beiträge: 830
Registriert: Mittwoch 19. Dezember 2007, 10:38

Braucht ihr noch jemanden?
Y0Gi
User
Beiträge: 1454
Registriert: Freitag 22. September 2006, 23:05
Wohnort: ja

jens: Der Kern selbst ist schon einige Jahre alt und wurde intern genutzt. Es wurde mitsamt dem Rechtesystem aus dem umgebenden "Portal" ausgegliedert und eigenständig gemacht. Die ursprüngliche Version benutzte Paste/-Deploy/-Script, SQLObject und IIRC Kid. Die jetzige, portierte Version basiert auf Werkzeug 0.2, SQLAlchemy, Genshi und Babel.

Da das Forum wie gesagt bisher nur intern genutzt wurde, fehlen Funktionen und Spielereien wie u.a. erweiterte Moderationshilfen und überhaupt die Möglichkeit für Anwender, selbst Accounts erstellen und verwalten zu können. Sobald sowas drin ist, gibt es wahrscheinlich Code, den man zur ersten Evaluierung vorzeigen kann.

P.S.: ... und solange Ohloh kein Mercurial unterstützt, taucht das Projekt da auch nicht auf ;)

audax: Danke, wir brauchen vorerst keine Hilfe (nur Zeit).
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Y0Gi hat geschrieben:Da das Forum wie gesagt bisher nur intern genutzt wurde, fehlen Funktionen und Spielereien wie u.a. erweiterte Moderationshilfen und überhaupt die Möglichkeit für Anwender, selbst Accounts erstellen und verwalten zu können. Sobald sowas drin ist, gibt es wahrscheinlich Code, den man zur ersten Evaluierung vorzeigen kann.
Accounts selbst erstellen geht immerhin in meinem Branch schon. Zwar nicht besonders gut, aber immerhin muss man jetzt nicht mehr Programmieren um User anzulegen.

Der Code wird bisher nicht öffentlich released, ich würde das Releasedatum irgendwo zwischen Milestone 1 und 2 ansetzen. Liegt auch daran, dass wir nicht die Fehler von Pocoo wiederholen wollen. Dann würden wir uns auch nach weiteren Mitstreitern umsehen.
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Leonidas hat geschrieben:Liegt auch daran, dass wir nicht die Fehler von Pocoo wiederholen wollen.
Was meinst du damit genau?

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

jens hat geschrieben:
Leonidas hat geschrieben:Liegt auch daran, dass wir nicht die Fehler von Pocoo wiederholen wollen.
Was meinst du damit genau?
Große Hoffnungen wecken, von Null starten, großes Team, Overengineering.

Natürlich, letztendlich haben auch wir davon profitiert, mit Werkzeug und Pygments haben wir zwei super Libs, die wir in unserem Code verwenden. Dennoch sehe ich uns eher als Anti-Pocoo. "First make it work, then make it work well". Das erinnert zwar an den phpBB-Ansatz, aber wir schauen schon, dass die Basis nicht so durchweg kaputt ist wie die von phpBB. Da wir auf viele vorhandene, brauchbare Komponenten zugreifen können ist das für uns auch einfacher.
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Y0Gi hat geschrieben:Die jetzige, portierte Version basiert auf Werkzeug 0.2, SQLAlchemy, Genshi und Babel.
Denkt ihr das django dafür weniger geeignet ist?

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
sma
User
Beiträge: 3018
Registriert: Montag 19. November 2007, 19:57
Wohnort: Kiel

Y0Gi, wenn ihr ein Forum baut, wie löst ihr denn das Problem, gelesene bzw. ungelesene Beiträge pro Anwender zu verwalten?

Im Pocoo-Source gibt es übrigens neben den von mir bereits postulierten Tabellen noch

Code: Alles auswählen

class ReadForums(models.Model):
    user = models.ForeignKey(User)
    forum = models.ForeignKey(Forum)
    date = models.DateTimeField()
    
class ReadThreads(models.Model):
    user = models.ForeignKey(User)
    post = models.ForeignKey(Post)
    date = models.DateTimeField()
wobei mir nicht ganz klar ist, warum man beides braucht. Es sieht aber so aus, als wenn Pocoo nur "alle Beträge seit XY sind gelesen" speichern kann. Jedenfalls wird da ggf. `datetime.utcnow()` in einer Funktion `mark_forum_as_read` reingeschrieben.

Dieses Forum hier macht es besser - allerdings nur so lange, wie man sich nicht versucht, ein zweites Mal anzumelden während man angemeldet ist. Dabei werden offenbar alle Markierungen gelöscht - sehr lästig.

Stefan
burli
User
Beiträge: 1156
Registriert: Dienstag 9. März 2004, 18:22

sma hat geschrieben:Y0Gi, wenn ihr ein Forum baut, wie löst ihr denn das Problem, gelesene bzw. ungelesene Beiträge pro Anwender zu verwalten?
Ich hab das damals bei meinem PHP Forum recht einfach gemacht. Wenn sich ein User eingeloggt hat habe ich einfach alle Beiträge zwischen der letzten Aktivität und dem aktuellen Login in einer Tabelle eingetragen
sma
User
Beiträge: 3018
Registriert: Montag 19. November 2007, 19:57
Wohnort: Kiel

burli hat geschrieben:Ich hab das damals bei meinem PHP Forum recht einfach gemacht. Wenn sich ein User eingeloggt hat habe ich einfach alle Beiträge zwischen der letzten Aktivität und dem aktuellen Login in einer Tabelle eingetragen
Ah super. Der erste, die mal auf die Frage eingeht :)

Dieses Forum macht's wohl genauso, denn das würde erklären, warum nochmaliges Anmelden die Liste der ungelesenen Beiträge tilgt.

Stefan
burli
User
Beiträge: 1156
Registriert: Dienstag 9. März 2004, 18:22

sma hat geschrieben: Dieses Forum macht's wohl genauso, denn das würde erklären, warum nochmaliges Anmelden die Liste der ungelesenen Beiträge tilgt.
Das hat so nix zu sagen. Das kann man ja programmieren wie man will. Ich habe einfach alle Einträge in der "ungelesen" Tabelle, die älter als 1 Tag waren, bei der nächsten Anmeldung gelöscht. Man kann bei einer neuen Anmeldung des Users auch seine kompletten Einträge löschen, wie man will.

Wenn man noch ein Feld für das Unterforum einfügt kann man zb auch, wie hier, selektiv für jedes Unterforum einen Link "Forum als gelesen markieren" einfügen
Antworten