"Rückantwort" Parameter in yield Funktion übergeben -> Erstellung einer sinnvollen relationalen DB mit Peewee

  • Hallo,

    hab gerade das erste mal eine nützliche Verwendung von yield für mich entdeckt.

    Für mich stellt sich jetzt nur die Frage, ob man in die ausführende Funktion die yield enthält, eine "Rückantwort" geben kann.

    Wie ich mir das ganze vorstelle, hoffe ich wird ersichtlich durch die Kommentare an den Zeilen 26,27 und 34.


    Die alternative was mir natürlich jetzt unterm schreiben einfällt wäre, den yield Generator innerhalb einer Klasse zu erstellen. Über die Klasse stelle ich dann ein Attribut zur Verfügung was sich außerhalb verändern lassen würde....richtig?

    Aber dennoch wäre es auch mit dem aktuell vorhandenen Code möglich?

  • Hallo,


    wobei IMHO das ganze Konstrukt quatsch ist. Du iterierst in `get_new_message` über alle Nachrichten nach einem bestimmten Kriterium, baust daraus einen Generator, nur damit du in `__main___` nochmal exakt die gleiche Iteration machen kannst. Warum? Außer extra umständlich hat das eigentlich null Vorteile.


    Beim Funktionsname `get_new_message` würde man vom Namen der erwarten, dass _eine_ Nachricht zurück geliefert wird.

    `read_liste` ist a) denglisch und b) ist es ein String und keine Liste.

    Wenn man in einer relationalen Datenbank der Meinung ist, eine Liste anlegen zu müssen, sollte man zumindest sein DB-Modell überdenken, ob dass _wirklich_ sinnvoll ist. Das macht man normalerweise über Relationen.


    Ich weiß ja nicht genau, was du vorhast, aber wenn das ein selbstgebautes Publisher-Subscriber Ding werden soll: Redis kann sowas OOTB und Redis 5.0 gibt es den Stream Data Type (habe ich aber selber noch nicht genutzt). Redis läuft seit Version 4.0 auch auf dem Raspi :-)


    Gruß, noisefloor

  • a) denglisch

    hab ich gern (: da es hauptsächlich nur für mich bestimmt ist, denke ich ists verkraftbar. Aber ja grundsätzlich hast du recht, aber pures Englisch mag ich nicht .... und vermischt ist schnell mal was.



    b) ist es ein String und keine Liste.

    Das kann gut sein das das anders besser zu lösen ist...für Vorschläge bin ich immer offen. Lern natürlich gern dazu.



    Beim Funktionsname `get_new_message` würde man vom Namen der erwarten, dass _eine_ Nachricht zurück geliefert wird.

    dann nenn ich sie get_new_messages;)

    nur damit du in `__main___` nochmal exakt die gleiche Iteration machen kannst. Warum?

    Ich weiß ja nicht genau, was du vorhast

    Der __main__ Block ist natürlich jetzt nur in Verwendung um das ganze einfach und schnell testen zu können. Das ganze soll später in meinem Projekt: Kaffeemaschine automatische Abrechnung zum Einsatz kommen.

    Hierbei möchte ich bei Anmeldungen eines User (mittels RFID) (das ganze läuft übrigends auch schon) prüfen ob dieser ungelesene Nachrichten hat. Wenn ja, soll die Nachricht am 2 zeiligen LCD Display ausgegeben werden. Wird die Nachricht mit dem OK Taster Bestätigt wird hinterlegt das die Nachricht gelesen und bestätigt worden ist. Hierbei denke ich an zum einen manuell erstellte Nachrichten von mir, wie z.B der HInweis auf neue Funktionen oder aber auch automatisch generierte Nachrichten vom System, wie z.B wer zuletzt die Maschine gereinigt hat, wie lange man selbst die Maschine schon nicht mehr gereinigt hat etc.

  • Hallo,


    dann wäre das Datenmodell aber IMHO so besser:


    Tabelle 1: user, Felder: uid, Name, ...

    Tabelle 2: message, message_id, meassage_text, ...

    Tabelle 3: message_read_by, Felder: message_id, uid


    In Tabelle 3 würden dann die zwei Spalten ein ForeignKey auf jeweils Tabelle `user` und Tabelle `message` sein und auf beiden Felder zusammen müsste ein "unique constrain" liegen bzw. sie sind zusammen ein "composed primary key" (habe gerade nicht im Kopf, ob SQLite das überhaupt kann bzw. auch, ob PeeWee das abbilden kann).


    Und ich würde nach wie vor in `get_new_messages` eine Liste der Nachrichten zurück liefern und nicht einen Generator draus bauen. Wenn du den DB-Entwurf sauber relational durchziehst, ist das wahrscheinlich sogar unumgänglich...


    Gruß, noisefloor

  • ind zusammen ein "composed primary key" (habe gerade nicht im Kopf, ob SQLite das überhaupt kann bzw. auch, ob PeeWee das abbilden kann).

    Das dürfte dann das hier sein was du meinst? http://docs.peewee-orm.com/en/…wee/api.html#CompositeKey


    Und ich würde nach wie vor in `get_new_messages` eine Liste der Nachrichten zurück liefern und nicht einen Generator draus bauen. Wenn du den DB-Entwurf sauber relational durchziehst, ist das wahrscheinlich sogar unumgänglich...

    Da du vielmehr Erfahrung besitzt als ich, geh ich mal stark davon aus, dass du recht hast ;). Dann bin ich wieder soweit, dass ich noch nie yield benötigt habe :lol: und ich dachte schon ich hätte einen Verwendungszweck gefunden.

    Werde mal in Peewee die Modelle wie du sie vorgeschlagen hast abbilden und versuchen die nötige Logik dahinter zu packen. Kann aber sein dass ich mich nochmal melden werde. :shy:


    Größtes Problem dabei was ich auf anhieb sehe ist, dass dieses backref= wieder verwendet wird. Da tu ich mich über den Sinn noch etwas schwer...das hat Linus schon mal versucht mir zu vermitteln ;)

  • Hallo,


    gut, PeeWee kann Composite Keys :-)


    Bzgl. `backref`: das ist eigentlich nicht schwierig und in der PeeWee-Doku hier erklärt: http://docs.peewee-orm.com/en/…nships.html#relationships bzw. das Beispiel mit den Tweets ist eigentlich ganz anschaulich. `backref` dient dazu, die Zusammenhänge zwischen Tabellen besser im ORM abbilden/abfragen zu können. SQLAlchemy macht das AFAIK genau so, beim Django ORM ist das anders gelöst. Das kennt auch diese Rückwärts-Referenzen, legt diese aber implizit basierend auf den Modellen an.


    Gruß, noisefloor

  • So ist der aktuelle Stand, aber irgendwie fehlt mir im Moment die Fähigkeit des Relationalen Denkens um hierbei Sinnvolle Abfragen zu krieren und wie man diese Foreign Keys auch passend in Szene setzt.

    Ich würd das wie so lösen, dass ich erstmals alle message_id mir von der Klasse Message hole.

    Anschließend prüfe ich zur Übergebenen UID welche übergeben wird, ob diese UID auch die ID in einer Zeile stehen hat...Klingt ziemlich umständlich und falsch...

  • Hallo,


    wenn du dich drauf verlassen kannst, dass `message_id` strikt aufsteigend ist bzw. das sicherstellen kannst, dann würde ich alle Nachrichten aus`Message`, wo `Message.message_id` > max(MessageReadBy.message_id` für `MessageReadBy.User` ist.


    Und mit jeder gelesenen Nachricht schreibst du einen neuen Eintrag in `MessageReadBy`.


    Gruß, noisefloor

  • Also mein Hauptproblem ist das Datenfeld ForeignKeyField().

    Damit komm ich irgendwie überhaupt nicht zurecht und weiß auch nicht wie man das passend verwenden soll. Auch die Durcharbeit der Example App auf der Peewee Seite (als auch das http://docs.peewee-orm.com/en/…nships.html#relationships) macht mich nicht schlauer.


    Hat hier vielleicht wer ein auf Peewee basierendes anderes Veranschaulichungsbeispiel für mich auf Lager?!

  • Hofei

    Changed the title of the thread from “"Rückantwort" Parameter in yield Funktion übergeben” to “"Rückantwort" Parameter in yield Funktion übergeben -> Erstellung einer sinnvollen relationalen DB mit Peewee”.
  • Hallo,


    ein ForeignKey dient grundsätzlich dazu, Daten in der Datenbank zu normalisieren, spricht das du am Ende auf einer der drei Normalenformen kommst.


    Oder auf Deutsch: keine doppelten / redundanten Daten in einer relationalen Datenbank. Weil: dafür gibt es Relationen :-)


    ForeignKey ist eine klassichen "Many-to-One" Beziehung. Bei dir: jede Message gibt es genau 1x, kann aber X verschiedenen Usern zugeordnet sein.


    Sonst poste doch mal den DB-Modell und zeig', was nicht funktioniert bzw. was du abfragen willst.


    Gruß, noisefloor

  • Sonst poste doch mal den DB-Modell und zeig', was nicht funktioniert bzw. was du abfragen willst.

    Hab ich in #8 schon mal gemacht aber hier nochmals der aktuelle Zustand.

    def set_read_message(uid): ist keine fertige Funktion, hier habe ich nur etwas geschummelt damit ich mal Einträge in MessageReadBy bekomme.

    Probleme gibts allgemeint in def get_new_message(uid):. Zum einen die maximal Abfrage und dann auch die weitere Verknüpfung um die passende Abfrage zusammen zu stellen.

    So siehts im Moment aus:


    Bei der aktuellen Form von get_new_message erfolgt keine Ausgabe und das Skript wird aber auch niemals fertig.


    EDIT:


    Mittlerweile hab ich eine "funktionierende" Lösung...Passt das so? wie kann mans besser machen?

  • Hallo,


    hier ist mal mein (funktionierender) Ansatz zum abfragen der ungelesenen Nachrichten. Der eventuelle Vorteile ist, dass die Nachrichten grundsätzlich beliebig durchnummeriert sein dürfen.


    Gruß, noisefloor

  • Vielen Dank für deinen Ansatz!

    Wenn ich das richtig verstehe muss ich aber beim Start die "User" Objekte anlegen - richtig? D.H von der DB auslesen, denn sonst wär ja z.B rainer unbekannt. Wohl am besten die Objekte in ein Dictionary ablegen mit der uid als Key :conf:


    Das was du als Ansatz geliefert hast, daran bin ich gescheitert. Das die Nachrichten beliebig nummeriert sein dürfen.



    wenn du dich drauf verlassen kannst, dass `message_id` strikt aufsteigend ist bzw. das sicherstellen kannst, dann würde ich alle Nachrichten aus`Message`, wo `Message.message_id` > max(MessageReadBy.message_id` für `MessageReadBy.User` ist.

    Hierfür würd ich gern nochmals meinen Ansatz zeigen:

  • Hallo,


    Quote

    Wenn ich das richtig verstehe muss ich aber beim Start die "User" Objekte anlegen - richtig?

    Nein - das ist im Beispiel nur, damit ich für User $FOO Nachrichten als gelesen markieren kann - zum Testen halt.


    Quote

    Das was du als Ansatz geliefert hast, daran bin ich gescheitert. Das die Nachrichten beliebig nummeriert sein dürfen.

    :-) Wie gesagt, mein Ansatz mit `in` ist robuster, was die Nummerierung des Nachrichten angeht - deiner funktioniert aber mit den passenden Rahmenbedingungen sicherlich aber auch.


    Die Zeile 1`message_id = peewee.AutoField(primary_key=True)` ist IMHO nicht notwendig, da PeeWee das auch automatisch, aber mit der Garantie, dass `id` immer aufsteigend ist. Bei deinem Ansatz könnte SQLite freie / übersprungende IDs (wieder-) verwenden, so dass du keine Garantie der aufsteigenden Zählung hast, womit der max-Ansatz hinfällig ist. Das ist, wenn ich mich richtig erinnere, auch irgendwo in der PeeWee Doku erwähnt. Da ist auch erklärt, wie man dem mit einem SQLite-Pragma entgegenwirken kann.


    Gruß, noisefloor

  • So vielen Dank nochmals für die Hilfe und den Beispielen! :danke_ATDE:


    Hier mein Ergebnis:

    Ist auch schon Erfolgreich in das Projekt integriert (nur der Code ist im Forum noch nicht aktuell): Kaffeemaschine automatische Abrechnung