SQLAlchemy Flask integrations Frage

Installation und Anwendung von Datenbankschnittstellen wie SQLite, PostgreSQL, MariaDB/MySQL, der DB-API 2.0 und sonstigen Datenbanksystemen.
Antworten
taake
User
Beiträge: 125
Registriert: Donnerstag 14. Oktober 2010, 08:49

Moin,
hab schon lange schon keine Frage mehr gestellt ;)

Ich hab ein Problem oder eher ein Verständnissproblem von SQLAlchemy mit meinem Flask Projekt.

Eigentlich läuft alles sauber (zumindest glaube ich das)
Allerdings bekomme ich von Alchemisten nur Datenobjekte zurück was nicht ganz dem Entspricht was ich eigentlich gerne hätte.

Sprich sowas wie

Code: Alles auswählen

[<app.models.Walkuere object at 0x7fc6e011d550>, <app.models.Walkuere object at 0x7fc6e011da90>, <app.models.Walkuere object at 0x7fc6e011ded0>, <app.models.Walkuere object at 0x7fc6e011d790>, <app.models.Walkuere object at 0x7fc6e011d910>, <app.models.Walkuere object at 0x7fc6e011d9d0>, <app.models.Walkuere object at 0x7fc6e011da10>, <app.models.Walkuere object at 0x7fc6e011d410>, <app.models.Walkuere object at 0x7fc6e011d3d0>, <app.models.Walkuere object at 0x7fc6e0130050>, <app.models.Walkuere object at 0x7fc6e01300d0>, <app.models.Walkuere object at 0x7fc6e0130190>, <app.models.Walkuere object at 0x7fc6e0130250>, <app.models.Walkuere object at 0x7fc6e0130310>, <app.models.Walkuere object at 0x7fc6e01303d0>, <app.models.Walkuere object at 0x7fc6e0130490>] 
Laut dem debug von SQLAlchemy sieht Anfrage gut aus, nur leider ist das was ich zurück bekomme nicht das was ich gerne hätte.

Was ich eigentlich haben wollte war eine Liste mit den Ergebnissen der Abfrage, leider habe ich keine Idee was hier genau falsch läuft.

Da es das erste mal ist das ich mit SQLAlchemy und Flask arbeite bitte ich zu berücksichtigen das ich mir das alles aus Tut's und Co angeeignet habe. Und patu keines finde was diese Thematik behandelt.

Einmal kurz zum aufbau:

Meine SQLAlchemy Class

Code: Alles auswählen

class Walkuere(db.Model):
    __tablename__ = 'data'
    data_id = db.Column(db.Integer, primary_key = True)
    art_nr = db.Column(db.String(20))
    art_name = db.Column(db.String(254))
    storename = db.Column(db.String(200))
    filesize = db.Column(db.String(40))
    katalog = db.Column(db.String(254))
mein View dafür

Code: Alles auswählen

@app.route('/search', methods = ['GET', 'POST'])
def search():
    form = SearchForm(request.form)
    if request.method == 'POST' and form.validate():
        search = (form.artnr.data, form.artname.data, form.katalog.data)
        katalog = Walkuere.query.filter_by(katalog=form.katalog.data).all()
        return render_template('matches.html', search=search, katalog=katalog)
    return render_template('search.html', form=form)
und schlussendlich die matches.html

Code: Alles auswählen

{% extends "layout.html" %}
{% block content %}
<h1>Hallo, ihre Sucheingabe war:</h1>
{{search[0]}}<br>
{{search[1]}}<br>
{{search[2]}}<br>

{{katalog}}
{% endblock %}
Sirius3
User
Beiträge: 17741
Registriert: Sonntag 21. Oktober 2012, 17:20

Was ist das Ergebnis einer Abfrage anderes als Objekte vom Typ des Models?
Wo ist Dein Problem? Außer dass Du glaubst, dass das was Du bekommst, nicht das ist, was Du willst?
taake
User
Beiträge: 125
Registriert: Donnerstag 14. Oktober 2010, 08:49

Sirius3 hat geschrieben:Was ist das Ergebnis einer Abfrage anderes als Objekte vom Typ des Models?
Wo ist Dein Problem? Außer dass Du glaubst, dass das was Du bekommst, nicht das ist, was Du willst?
taake hat geschrieben: Was ich eigentlich haben wollte war eine Liste mit den Ergebnissen der Abfrage, leider habe ich keine Idee was hier genau falsch läuft.
Wie geschrieben ist die Fragestellung, wie ich statt dem Ort wo sich das Element befindet das Element selbst in Form einer für Humanoide lesbaren Liste bekomme.
Am besten wäre es natürlich wenn es gleich eine 'Python-Liste' wäre.
Benutzeravatar
/me
User
Beiträge: 3555
Registriert: Donnerstag 25. Juni 2009, 14:40
Wohnort: Bonn

taake hat geschrieben:Wie geschrieben ist die Fragestellung, wie ich statt dem Ort wo sich das Element befindet das Element selbst in Form einer für Humanoide lesbaren Liste bekomme.
Ich glaube du verwechselst hier den Inhalt der Liste mit der angezeigten Repräsentation der Liste.

Code: Alles auswählen

>>> class Thing:
    def __init__(self, name):
        self.name = name
        
>>> data = [Thing('Eric'), Thing('Michael'), Thing('Terry')]
>>> print(data)
[<__main__.Thing object at 0x02D4C810>, <__main__.Thing object at 0x02D323B0>, <__main__.Thing object at 0x02D470D0>]
>>> print(data[0])
<__main__.Thing object at 0x02D4C810>
>>> print(data[0].name)
Eric
Wenn du in der enthaltenen Klasse __repr__ überschreibst, dann kannst du dir natürlich zurückgeben lassen was du möchtest.

Code: Alles auswählen

>>> class Thing:
    def __init__(self, name):
        self.name = name
    def __repr__(self):
        return 'Thing(name="{}")'.format(self.name)

>>> data = [Thing('Eric'), Thing('Michael'), Thing('Terry')]
>>> print(data)
[Thing(name="Eric"), Thing(name="Michael"), Thing(name="Terry")]
taake
User
Beiträge: 125
Registriert: Donnerstag 14. Oktober 2010, 08:49

danke /me
das hilft weiter, jetzt weiß ich zumindest wie ich an die Daten komme.

Mir stellt sich allerdings die Frage was das ganze soll, okay easy sql muss keine sql statments von hand forumlieren.
Aber warum muss ich mir derart einen abbrechen wenn ich die Daten[Human Readable] wiederhaben will?
BlackJack

@taake: Die wenigsten Objekte haben eine „human readable” Darstellung. Hauptsächlich die eingebauten Grunddatentypen. Und das war es dann auch fast schon. Wenn das „normal” wäre würdest Du sicher meckern dass viele Objekte Unmengen an Informationen über sich ausgeben weil sich das ja rekursiv auf alle Objekte auswirkt die als Attribute gesetzt sind. Der Witz bei Objekten ist ja gerade das man daraus komplexere Programme und Datensammlungen zusammensetzen kann. Und das möchte man nicht alles rekursiv in mehrere Kilobyte grossen Zeichenketten haben wenn man die Objekte ausgibt.

Ich sehe auch das „einen abbrechen” nicht wirklich. Du musst die Attribute halt namentlich hinschreiben. Das ist für's lesen allemal besser als irgendwelche nichtssagenden Indizes.

Wenn Du das gerne als Wörterbuch haben möchtest (beispielsweise) kannst Du ja eine Funktion schreiben die das generisch für so ein SA-Ergebnisobjekt löst. An die Spaltenattribute kommt man irgendwie dran. Sowas in der Richtung habe ich schon mal gemacht, weiss aber jetzt aus dem Kopf nicht mehr genau welche Attribute man da abfragen muss. Das war für ein „Kopierprogramm” von einer Datenbank in eine Andere mit Auswahl der Spalten und Abbildung von Quellspaltennamen auf Zielspaltennamen.
Benutzeravatar
/me
User
Beiträge: 3555
Registriert: Donnerstag 25. Juni 2009, 14:40
Wohnort: Bonn

taake hat geschrieben:Aber warum muss ich mir derart einen abbrechen wenn ich die Daten[Human Readable] wiederhaben will?
Ganz einfach. Woher soll Python wissen, welche Attribute der Instanz du wie formatiert in welcher Reihenfolge ausgeben möchtest. Es ist deine verdammte Pflicht und Schuldigkeit als Softwareentwickler das Verhalten festzulegen.
taake
User
Beiträge: 125
Registriert: Donnerstag 14. Oktober 2010, 08:49

Gestaltet sich gerade als ausgesprochen suboptimal heraus die konstellation flask sqlalchemy.
flask kann allem anschein nicht counten, jedenfalls verreckt er jedesmal wenn ich versuche sowas zu basteln
somit kann ich nichtmal rausfinden wie viele Datensätze ich überhaupt bekommen habe, sonst könnte ich mir irgendwas zusammenhacken, aber so steh ich gerade ziemlich auf dem schlauch.
Ebenfalls kennt flask kein len um einfach alles durchzulaufen. [for i in range(len(a)):]

kennst sich wer mit flask aus und weiß ob es da irgendwas besonderes gibt / gemacht werden muss um die datensätze zu zählen?
BlackJack

@taake: Das was Du da gerade Flask anlasten willst betrifft wohl eher die Template-Sprache. Da verwendet Flask soweit ich weiss Jinja zwei. Und das hat eine Funktion zum ermitteln der Länge, sogar unter zwei Namen, wovon einer `count` ist. Soviel zum nicht „counten” können.

Und genau wie in Python auch macht Jinja2 nicht so einen Unsinn wie ``for i in range(len(a))`` sondern iteriert direkt über die Elemente von `a`.

Du solltest solche Grundlagen hier vielleicht nicht fragen bevor Du die relevanten Tutorials durchgearbeitet und die Dokumentationen mal quergelesen hast. Ist ja nicht so das Jinja2 hunderte von Filtern und Funktionen in Templates zur Verfügung stellt. Die vorhandenen sollte man sich jedenfalls mal angeschaut haben, wenn man eine Funktionalität sucht. Bevor man andere fragt.

Die Konstellation Flask und SA ist hier nicht deutlich anders als die Konstellation von den gängigen anderen Webrahmenwerken und ORMs. Wenn Du *das* suboptimal findest, dann ist Webentwicklung vielleicht nichts für Dich, oder Du solltest Dich in einer ganz anderen Ecke umschauen.
Benutzeravatar
/me
User
Beiträge: 3555
Registriert: Donnerstag 25. Juni 2009, 14:40
Wohnort: Bonn

taake hat geschrieben:Ebenfalls kennt flask kein len um einfach alles durchzulaufen. [for i in range(len(a)):]

kennst sich wer mit flask aus und weiß ob es da irgendwas besonderes gibt / gemacht werden muss um die datensätze zu zählen?
Wenn das Resultat eine Liste ist, dann sollte len(variablenname) dir die Anzahl der Datensätze geben. Welches Problem hast du denn mit len? Das ist ein builtin von Python, deine Aussage dass flask kein len kennt, passt da irgendwie nicht.

Zudem wirst du doch wohl kein len verwenden um mit Elementen einer Liste etwas zu machen. Oder schreibst du solchen Code?

Code: Alles auswählen

data = [1, 2, 'C', 5, 4, 'B']
for i in range(len(data)):
    print(data[i])
Wenn ja, dann solltest du diese umständliche Art und Weise dringend ändern.

Code: Alles auswählen

data = [1, 2, 'C', 5, 4, 'B']
for element in data:
    print(element)
taake
User
Beiträge: 125
Registriert: Donnerstag 14. Oktober 2010, 08:49

Eigentlich nicht das war nur der Versuch ob es doch irgendwie geht weil das erste (normale) nicht ging.

Aber Buildin hin oder her, er bleibt dabei

Code: Alles auswählen

{% for i in range(len(katalog)): %}
UndefinedError: 'len' is undefined
Benutzeravatar
/me
User
Beiträge: 3555
Registriert: Donnerstag 25. Juni 2009, 14:40
Wohnort: Bonn

taake hat geschrieben:

Code: Alles auswählen

{% for i in range(len(katalog)): %}
UndefinedError: 'len' is undefined
Du weißt schon was Python ist und das das da keins ist, oder?

Wenn du hier eine spezielle Template-Sprache verwendest dann sag das doch vorher.

Ich kenne Flask und seine Template-Engine nicht und bin dann mal hier raus.
taake
User
Beiträge: 125
Registriert: Donnerstag 14. Oktober 2010, 08:49

yoa ...
warum einfach wenns auch umständlich, in den templates kann man jedenfalls nichts machen wieß aussieht.

Hab allerdings im view ne Möglichkeit gefunden:

Code: Alles auswählen

def sql_obj_to_list(query):
    sql_query = []
    for result in query:
        d = [result.data_id, \
            result.art_nr, \
            result.art_name, \
            result.storename, \
            result.filesize, \
            result.katalog]
        print result.data_id
        sql_query.append(d)
    return sql_query
Wird also wohl darauf hinauslaufen das ich mir ne class blaue um damit direkt den entsprechenden html code zu bauen und den übergebe, ist sicher nicht der königsweg, allerdings der einzige der mir zur zeit in den sinn kommt.
BlackJack

@/me: Flask verwendet Jinja2 als Template-Engine.

@taake: Das ist ein schlechter Scherz oder? Das was Du da machst ist komplizierter als es richtig mit der Template-Sprache zu machen. Wenn Du natürlich durch ausprobieren versuchst zu erraten was die Templatesprache kann und was nicht, statt in die Dokumentation zu schauen wie man sie benutzt und welche Sprachkonstrukte und Funktionen sie bietet, dann musst Du wohl irgendwelchen Schrott umständlich selber programmieren.

In der Dokumentation steht ganz am Anfang ein Beispiel in dem über Benutzerobjekte iteriert wird. Und wenn Du die Anzahl der Ergebnisse ausgeben möchtest, habe ich ja schon gesagt das es eine Funktion dafür in Templates gibt, die sogar unter zwei Namen verfügbar ist. Nur ist halt keiner von beiden `len()`. Du kannst jetzt weiter raten, oder mal die Dokumentation lesen.
Antworten