Flask-SQLAlchemy query.filter_by()

Django, Flask, Bottle, WSGI, CGI…
Antworten
naheliegend
User
Beiträge: 348
Registriert: Mittwoch 8. August 2018, 16:42

Freitag 26. März 2021, 11:03

Hi,

ich möchte alle Trainings haben bei denen gilt Slot.taken==True.

Wieso kann ich das nicht folgendermaßen abfragen und erhalte eine Fehlermeldung?

Code: Alles auswählen


class Training(db.Model):
    __tablename__ = 'trainings'
    id = db.Column(db.Integer, primary_key=True, index=True)
    (...)
    #relationships
    slot_id = db.Column(db.Integer, db.ForeignKey('slots.id')) #foreign key to the table name


class Slot(db.Model):
    __tablename__ = 'slots'
    id = db.Column(db.Integer, primary_key=True, index=True)
    (...)
    taken = db.Column(db.Boolean(), index=True)
    #relationships
    trainings = db.relationship('Training', backref='slots', uselist=False)


example = Training.query.filter_by(Training.slots.taken==True).first()


Fehler:

Code: Alles auswählen

AttributeError: Neither 'InstrumentedAttribute' object nor 'Comparator' object associated with Training.slots has an attribute 'taken'
__backjack__: "Jemand der VB oder PHP kann, der also was Programmieren angeht irgendwo im negativen Bereich liegt (...)"
naheliegend
User
Beiträge: 348
Registriert: Mittwoch 8. August 2018, 16:42

Freitag 26. März 2021, 12:27

Code: Alles auswählen

example = Training.query.join(Slot).filter_by(taken=True).first()
Funktioniert auch nicht....

Code: Alles auswählen

sqlalchemy.exc.InvalidRequestError: Entity namespace for "trainings" has no property "taken"
__backjack__: "Jemand der VB oder PHP kann, der also was Programmieren angeht irgendwo im negativen Bereich liegt (...)"
naheliegend
User
Beiträge: 348
Registriert: Mittwoch 8. August 2018, 16:42

Freitag 26. März 2021, 15:39

So funktioniert es:

Code: Alles auswählen

example = Training.query.join(Slot).filter(Slot.taken==True).first()
Intuitiv finde ich das aber nicht... da kann man ja fast besser sql schreiben.
__backjack__: "Jemand der VB oder PHP kann, der also was Programmieren angeht irgendwo im negativen Bereich liegt (...)"
Benutzeravatar
__blackjack__
User
Beiträge: 8573
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Freitag 26. März 2021, 18:38

@naheliegend: Es muss halt eindeutig sein. Wenn Du nicht sagst, dass das `taken` von `Slot` kommt muss man raten wo es her kommt und falls dann irgendwann `Training` auch mal ein `taken` bekommen sollte, dann geht das nicht mehr, oder bedeutet eventuell was anderes.

Das `join()` müsste man weglassen können, denn das ist implizit klar wenn in der Bedingung eine weitere Tabelle vorkommt.
“Dawn, n.: The time when men of reason go to bed.” — Ambrose Bierce, “The Devil's Dictionary”
naheliegend
User
Beiträge: 348
Registriert: Mittwoch 8. August 2018, 16:42

Freitag 26. März 2021, 20:16

__blackjack__ hat geschrieben:
Freitag 26. März 2021, 18:38
(...)

Das `join()` müsste man weglassen können, denn das ist implizit klar wenn in der Bedingung eine weitere Tabelle vorkommt.
Bekomme ohne join() eine Warnung:

Code: Alles auswählen

SAWarning: SELECT statement has a cartesian product between FROM element(s) "slots" and FROM element "trainings".  Apply join condition(s) between each element to resolve.
Und für bestimmte andere Queries bekomme ich auch verschiedene Ergebnisse...
__backjack__: "Jemand der VB oder PHP kann, der also was Programmieren angeht irgendwo im negativen Bereich liegt (...)"
strassi
User
Beiträge: 2
Registriert: Mittwoch 23. Dezember 2020, 21:31

Dienstag 27. April 2021, 10:33

Ohne es genau getestet zu haben und zwischen "Tür und Angel" würde ich folgendes vermuten:
Ändere mal die Referenz (slots), da du die Tabelle ja auch den Namen (slots) hat und er sich hier ggf. verhaspelt.... Ich hatte mit der Referenz und Tabellennamen auch schon die ein oder andere Schwierigkeit...

Code: Alles auswählen

class Slot(db.Model):
    __tablename__ = 'slots'
    id = db.Column(db.Integer, primary_key=True, index=True)
    (...)
    taken = db.Column(db.Boolean(), index=True)
    #relationships
    trainings = db.relationship('Training', backref='plaetze', uselist=False)
Generell bin ich bei __blackjack__ -> das join() brauchst du eigentlich nicht.
Antworten