Baked Queries

baked bietet ein alternatives Erstellungsmuster für Query-Objekte, das das Caching der Objektkonstruktion und der String-Kompilierungsschritte ermöglicht. Das bedeutet, dass für ein bestimmtes Query-Erstellungsszenario, das mehr als einmal verwendet wird, alle Python-Funktionsaufrufe, die an der Erstellung der Query von ihrer anfänglichen Konstruktion bis zur Generierung eines SQL-Strings beteiligt sind, nur einmal erfolgen, anstatt bei jeder Erstellung und Ausführung dieser Query.

Der Grund für dieses System ist die drastische Reduzierung des Overhead des Python-Interpreters für alles, was vor der Ausgabe von SQL geschieht. Das Caching des „baked“ Systems reduziert in keiner Weise SQL-Aufrufe oder speichert die Rückgabeergebnisse aus der Datenbank. Eine Technik, die das Caching von SQL-Aufrufen und Ergebnisdatensätzen selbst demonstriert, finden Sie unter Dogpile Caching.

Veraltet seit Version 1.4: SQLAlchemy 1.4 und 2.0 verfügen über ein komplett neues, direktes Query-Caching-System, das die Notwendigkeit des BakedQuery-Systems überflüssig macht. Caching ist nun für alle Core- und ORM-Queries transparent aktiv, ohne dass der Benutzer etwas unternehmen muss, unter Verwendung des unter SQL-Kompilierungs-Caching beschriebenen Systems.

Deep Alchemy

Die sqlalchemy.ext.baked-Erweiterung ist nicht für Anfänger gedacht. Die korrekte Verwendung erfordert ein gutes, übergeordnetes Verständnis davon, wie SQLAlchemy, der Datenbanktreiber und die Backend-Datenbank miteinander interagieren. Diese Erweiterung bietet eine sehr spezifische Art der Optimierung, die normalerweise nicht benötigt wird. Wie oben erwähnt, cacht sie keine Queries, sondern nur die String-Formulierung des SQL selbst.

Zusammenfassung

Die Nutzung des „baked“-Systems beginnt mit der Erzeugung einer sogenannten „bakery“, die die Speicherung für eine bestimmte Reihe von Query-Objekten darstellt

from sqlalchemy.ext import baked

bakery = baked.bakery()

Die obige „bakery“ speichert gecachte Daten in einem LRU-Cache, der standardmäßig 200 Elemente umfasst. Beachten Sie, dass eine ORM-Query typischerweise einen Eintrag für die aufgerufene ORM-Query sowie einen Eintrag pro Datenbankdialekt für den SQL-String enthält.

Die bakery ermöglicht es uns, ein Query-Objekt zu erstellen, indem wir seine Konstruktion als Reihe von Python-Aufrufbaren definieren, die typischerweise Lambdas sind. Für eine prägnante Nutzung überschreibt sie den Operator +=, sodass eine typische Query-Erstellung wie folgt aussieht:

from sqlalchemy import bindparam


def search_for_user(session, username, email=None):
    baked_query = bakery(lambda session: session.query(User))
    baked_query += lambda q: q.filter(User.name == bindparam("username"))

    baked_query += lambda q: q.order_by(User.id)

    if email:
        baked_query += lambda q: q.filter(User.email == bindparam("email"))

    result = baked_query(session).params(username=username, email=email).all()

    return result

Im Folgenden einige Beobachtungen zum obigen Code

  1. Das baked_query-Objekt ist eine Instanz von BakedQuery. Dieses Objekt ist im Wesentlichen der „Builder“ für ein echtes ORM- Query-Objekt, ist aber selbst nicht das tatsächliche Query-Objekt.

  2. Das tatsächliche Query-Objekt wird erst ganz am Ende der Funktion erstellt, wenn Result.all() aufgerufen wird.

  3. Die Schritte, die dem baked_query-Objekt hinzugefügt werden, sind alle als Python-Funktionen, typischerweise Lambdas, ausgedrückt. Das erste Lambda, das der bakery()-Funktion übergeben wird, erhält eine Session als Argument. Die verbleibenden Lambdas erhalten jeweils eine Query als Argument.

  4. Im obigen Code werden, auch wenn unsere Anwendung search_for_user() viele Male aufruft und selbst wenn wir innerhalb jeder Ausführung ein komplett neues BakedQuery-Objekt erstellen, alle Lambdas nur einmal aufgerufen. Jedes Lambda wird niemals ein zweites Mal aufgerufen, solange diese Query in der bakery gecached ist.

  5. Das Caching wird erreicht, indem Referenzen auf die Lambda-Objekte selbst gespeichert werden, um einen Cache-Schlüssel zu formulieren; das heißt, die Tatsache, dass der Python-Interpreter diesen Funktionen eine In-Python-Identität zuweist, bestimmt, wie die Query bei aufeinanderfolgenden Ausführungen identifiziert wird. Bei den Aufrufen von search_for_user(), bei denen der Parameter email angegeben ist, ist das aufrufbare Objekt lambda q: q.filter(User.email == bindparam('email')) Teil des abgerufenen Cache-Schlüssels; wenn email None ist, ist dieses aufrufbare Objekt kein Teil des Cache-Schlüssels.

  6. Da die Lambdas alle nur einmal aufgerufen werden, ist es unerlässlich, dass keine Variablen, die sich über Aufrufe hinweg ändern können, innerhalb der Lambdas referenziert werden; stattdessen verwenden wir, vorausgesetzt, es handelt sich um Werte, die in den SQL-String gebunden werden sollen, bindparam(), um benannte Parameter zu konstruieren, deren tatsächliche Werte wir später mit Result.params() anwenden.

Performance

Die „baked query“ wirkt wahrscheinlich etwas seltsam, etwas unbeholfen und etwas ausführlich. Die Einsparungen bei der Python-Performance für eine Query, die in einer Anwendung sehr oft aufgerufen wird, sind jedoch sehr dramatisch. Die Beispielsuite short_selects, die in Performance demonstriert wird, zeigt einen Vergleich von Queries, die jeweils nur eine Zeile zurückgeben, wie die folgende reguläre Query:

session = Session(bind=engine)
for id_ in random.sample(ids, n):
    session.query(Customer).filter(Customer.id == id_).one()

im Vergleich zur entsprechenden „baked“ Query

bakery = baked.bakery()
s = Session(bind=engine)
for id_ in random.sample(ids, n):
    q = bakery(lambda s: s.query(Customer))
    q += lambda q: q.filter(Customer.id == bindparam("id"))
    q(s).params(id=id_).one()

Der Unterschied in der Anzahl der Python-Funktionsaufrufe bei einer Iteration von 10.000 Aufrufen für jeden Block beträgt:

test_baked_query : test a baked query of the full entity.
                   (10000 iterations); total fn calls 1951294

test_orm_query :   test a straight ORM query of the full entity.
                   (10000 iterations); total fn calls 7900535

In Bezug auf die Sekunden auf einem leistungsstarken Laptop ergibt sich Folgendes:

test_baked_query : test a baked query of the full entity.
                   (10000 iterations); total time 2.174126 sec

test_orm_query :   test a straight ORM query of the full entity.
                   (10000 iterations); total time 7.958516 sec

Beachten Sie, dass dieser Test absichtlich Queries mit nur einer zurückgegebenen Zeile enthält. Bei Queries, die viele Zeilen zurückgeben, wird der Leistungsvorteil der „baked query“ mit zunehmender Zeit für das Abrufen der Zeilen immer geringer. Es ist entscheidend zu bedenken, dass die Funktion „baked query“ nur für die Erstellung der Query selbst gilt, nicht für das Abrufen von Ergebnissen. Die Verwendung der „baked“-Funktion ist keineswegs eine Garantie für eine viel schnellere Anwendung; es ist nur eine potenziell nützliche Funktion für Anwendungen, bei denen gemessen wurde, dass sie von dieser speziellen Art von Overhead betroffen sind.

Rationale

Der obige „Lambda“-Ansatz ist eine Obermenge dessen, was ein traditionellerer „parametrisierter“ Ansatz wäre. Angenommen, wir möchten ein einfaches System erstellen, bei dem wir eine Query nur einmal erstellen und dann in einem Wörterbuch zur Wiederverwendung speichern. Dies ist derzeit möglich, indem man die Query einfach erstellt und ihre Session durch Aufrufen von my_cached_query = query.with_session(None) entfernt.

my_simple_cache = {}


def lookup(session, id_argument):
    if "my_key" not in my_simple_cache:
        query = session.query(Model).filter(Model.id == bindparam("id"))
        my_simple_cache["my_key"] = query.with_session(None)
    else:
        query = my_simple_cache["my_key"].with_session(session)

    return query.params(id=id_argument).all()

Der obige Ansatz bringt uns einen sehr geringen Leistungsvorteil. Durch die Wiederverwendung einer Query sparen wir die Python-Arbeit innerhalb des Konstruktors session.query(Model) sowie den Aufruf von filter(Model.id == bindparam('id')), was uns das Erstellen des Core-Ausdrucks und dessen Übergabe an Query.filter() erspart. Der Ansatz generiert jedoch bei jedem Aufruf von Query.all() immer noch jedes Mal den vollständigen Select-Objekt und sendet zusätzlich diesen brandneuen Select jedes Mal an den String-Kompilierungsschritt, was bei einem einfachen Fall wie dem obigen etwa 70 % des Overheads ausmacht.

Um den zusätzlichen Overhead zu reduzieren, benötigen wir speziellere Logik, eine Möglichkeit, die Erstellung des Select-Objekts und die Erstellung des SQL zu memoisieren. Es gibt ein Beispiel dafür im Wiki im Abschnitt BakedQuery, ein Vorläufer dieser Funktion. In diesem System cachen wir jedoch nicht die Erstellung der Query. Um den gesamten Overhead zu entfernen, müssen wir sowohl die Erstellung der Query als auch die SQL-Kompilierung cachen. Nehmen wir an, wir passen das Rezept auf diese Weise an und erstellen eine Methode .bake(), die das SQL für die Query vorkompiliert und ein neues Objekt erzeugt, das mit minimalem Overhead aufgerufen werden kann. Unser Beispiel wird:

my_simple_cache = {}


def lookup(session, id_argument):
    if "my_key" not in my_simple_cache:
        query = session.query(Model).filter(Model.id == bindparam("id"))
        my_simple_cache["my_key"] = query.with_session(None).bake()
    else:
        query = my_simple_cache["my_key"].with_session(session)

    return query.params(id=id_argument).all()

Oben haben wir die Performance-Situation behoben, aber wir haben immer noch diesen String-Cache-Schlüssel zu bewältigen.

Wir können den „bakery“-Ansatz verwenden, um das Obige neu zu formulieren, sodass es weniger ungewöhnlich aussieht als der „Lambda-Erstellungs“-Ansatz und mehr wie eine einfache Verbesserung des einfachen „Query wiederverwenden“-Ansatzes:

bakery = baked.bakery()


def lookup(session, id_argument):
    def create_model_query(session):
        return session.query(Model).filter(Model.id == bindparam("id"))

    parameterized_query = bakery.bake(create_model_query)
    return parameterized_query(session).params(id=id_argument).all()

Oben verwenden wir das „baked“-System auf eine Weise, die dem simplen „Query cachen“-System sehr ähnlich ist. Es benötigt jedoch zwei Zeilen weniger Code, muss keinen Cache-Schlüssel „my_key“ herstellen und beinhaltet dieselbe Funktion wie unsere benutzerdefinierte „bake“-Funktion, die 100 % der Python-Aufrufarbeit vom Konstruktor der Query über den Filteraufruf bis zur Erstellung des Select-Objekts bis zum String-Kompilierungsschritt cached.

Wenn wir uns von oben fragen: „Was ist, wenn die Suche bedingte Entscheidungen über die Struktur der Query treffen muss?“, wird hoffentlich deutlich, warum „baked“ so ist, wie es ist. Anstatt einer parametrisierten Query, die von genau einer Funktion ausgeht (wie wir ursprünglich dachten, dass baked funktionieren würde), können wir sie aus beliebiger Anzahl von Funktionen aufbauen. Betrachten wir unser naives Beispiel, wenn wir eine zusätzliche Klausel in unserer Query bedingt haben müssten:

my_simple_cache = {}


def lookup(session, id_argument, include_frobnizzle=False):
    if include_frobnizzle:
        cache_key = "my_key_with_frobnizzle"
    else:
        cache_key = "my_key_without_frobnizzle"

    if cache_key not in my_simple_cache:
        query = session.query(Model).filter(Model.id == bindparam("id"))
        if include_frobnizzle:
            query = query.filter(Model.frobnizzle == True)

        my_simple_cache[cache_key] = query.with_session(None).bake()
    else:
        query = my_simple_cache[cache_key].with_session(session)

    return query.params(id=id_argument).all()

Unser „einfaches“ parametrisiertes System muss nun Cache-Schlüssel generieren, die berücksichtigen, ob das Flag „include_frobnizzle“ übergeben wurde oder nicht, da die Anwesenheit dieses Flags bedeutet, dass das generierte SQL völlig anders wäre. Es sollte ersichtlich sein, dass mit zunehmender Komplexität der Query-Erstellung die Aufgabe, diese Queries zu cachen, sehr schnell mühsam wird. Wir können das obige Beispiel direkt in die Verwendung von „bakery“ umwandeln:

bakery = baked.bakery()


def lookup(session, id_argument, include_frobnizzle=False):
    def create_model_query(session):
        return session.query(Model).filter(Model.id == bindparam("id"))

    parameterized_query = bakery.bake(create_model_query)

    if include_frobnizzle:

        def include_frobnizzle_in_query(query):
            return query.filter(Model.frobnizzle == True)

        parameterized_query = parameterized_query.with_criteria(
            include_frobnizzle_in_query
        )

    return parameterized_query(session).params(id=id_argument).all()

Oben cachen wir nicht nur das Query-Objekt, sondern auch alle Arbeiten, die erforderlich sind, um SQL zu generieren. Wir müssen uns auch nicht mehr darum kümmern, einen Cache-Schlüssel zu generieren, der alle strukturellen Modifikationen, die wir vorgenommen haben, korrekt berücksichtigt; dies wird nun automatisch und fehlerfrei gehandhabt.

Diese Code-Beispiel ist ein paar Zeilen kürzer als das naive Beispiel, eliminiert die Notwendigkeit, sich mit Cache-Schlüsseln zu befassen, und bietet die enormen Leistungsvorteile des vollständigen sogenannten „baked“-Features. Aber immer noch etwas ausführlich! Daher nehmen wir Methoden wie BakedQuery.add_criteria() und BakedQuery.with_criteria() und kürzen sie zu Operatoren, und ermutigen (aber verlangen keineswegs!) die Verwendung einfacher Lambdas, nur um die Ausführlichkeit zu reduzieren:

bakery = baked.bakery()


def lookup(session, id_argument, include_frobnizzle=False):
    parameterized_query = bakery.bake(
        lambda s: s.query(Model).filter(Model.id == bindparam("id"))
    )

    if include_frobnizzle:
        parameterized_query += lambda q: q.filter(Model.frobnizzle == True)

    return parameterized_query(session).params(id=id_argument).all()

Wo oben der Ansatz einfacher zu implementieren ist und im Codefluss dem einer nicht-gecacheden Query-Funktion viel ähnlicher ist, wodurch der Code leichter zu portieren ist.

Die obige Beschreibung ist im Wesentlichen eine Zusammenfassung des Designprozesses, der zum aktuellen „baked“-Ansatz führte. Beginnend mit den „normalen“ Ansätzen mussten die zusätzlichen Probleme der Cache-Schlüssel-Erstellung und -Verwaltung, die Entfernung aller redundanten Python-Ausführung und bedingt erstellte Queries berücksichtigt werden, was zum endgültigen Ansatz führte.

Spezielle Query-Techniken

Dieser Abschnitt beschreibt Techniken für spezifische Query-Situationen.

Verwendung von IN-Ausdrücken

Die Methode ColumnOperators.in_() in SQLAlchemy rendert historisch eine variable Anzahl von gebundenen Parametern, basierend auf der Liste der Elemente, die der Methode übergeben werden. Dies funktioniert nicht für „baked queries“, da die Länge dieser Liste bei verschiedenen Aufrufen variieren kann. Um dieses Problem zu lösen, unterstützt der Parameter bindparam.expanding einen spät gerenderten IN-Ausdruck, der sicher innerhalb einer „baked query“ gecached werden kann. Die tatsächliche Liste der Elemente wird zur Laufzeit der Anweisung gerendert, anstatt zur Kompilierungszeit der Anweisung.

bakery = baked.bakery()

baked_query = bakery(lambda session: session.query(User))
baked_query += lambda q: q.filter(User.name.in_(bindparam("username", expanding=True)))

result = baked_query.with_session(session).params(username=["ed", "fred"]).all()

Verwendung von Subqueries

Bei der Verwendung von Query-Objekten ist es oft notwendig, dass ein Query-Objekt verwendet wird, um eine Subquery innerhalb einer anderen zu generieren. Wenn die Query sich derzeit im „baked“-Format befindet, kann eine Übergangsmethode verwendet werden, um das Query-Objekt mithilfe der Methode BakedQuery.to_query() abzurufen. Diese Methode erhält die Session oder Query, die das Argument für den Lambda-Aufruf ist, der zur Generierung eines bestimmten Schritts der „baked query“ verwendet wird.

bakery = baked.bakery()

# a baked query that will end up being used as a subquery
my_subq = bakery(lambda s: s.query(User.id))
my_subq += lambda q: q.filter(User.id == Address.user_id)

# select a correlated subquery in the top columns list,
# we have the "session" argument, pass that
my_q = bakery(lambda s: s.query(Address.id, my_subq.to_query(s).as_scalar()))

# use a correlated subquery in some of the criteria, we have
# the "query" argument, pass that.
my_q += lambda q: q.filter(my_subq.to_query(q).exists())

Neu in Version 1.3.

Verwendung des before_compile-Events

Ab SQLAlchemy 1.3.11 verhindert die Verwendung des Events QueryEvents.before_compile() gegen eine bestimmte Query, dass das „baked query“-System die Query cacht, wenn der Event-Hook ein neues Query-Objekt zurückgibt, das sich von dem übergebenen unterscheidet. Dies geschieht, damit der Hook QueryEvents.before_compile() jedes Mal gegen eine bestimmte Query aufgerufen werden kann, um Hooks zu unterstützen, die die Query jedes Mal anders ändern. Um zu erlauben, dass ein Hook QueryEvents.before_compile() ein sqlalchemy.orm.Query()-Objekt ändert, aber das Ergebnis dennoch gecached werden kann, kann das Event unter Angabe des Flags bake_ok=True registriert werden.

@event.listens_for(Query, "before_compile", retval=True, bake_ok=True)
def my_event(query):
    for desc in query.column_descriptions:
        if desc["type"] is User:
            entity = desc["entity"]
            query = query.filter(entity.deleted == False)
    return query

Die obige Strategie ist für ein Event geeignet, das eine gegebene Query jedes Mal auf exakt dieselbe Weise modifiziert, unabhängig von spezifischen Parametern oder externem Zustand, der sich ändert.

Neu in Version 1.3.11: - das „bake_ok“-Flag wurde dem Event QueryEvents.before_compile() hinzugefügt und das Caching durch die „baked“-Erweiterung wurde für Event-Handler, die ein neues Query-Objekt zurückgeben, deaktiviert, wenn dieses Flag nicht gesetzt ist.

Deaktivieren von Baked Queries Sitzungsweit

Das Flag Session.enable_baked_queries kann auf False gesetzt werden, wodurch alle „baked queries“ gegen diese Session nicht den Cache verwenden.

session = Session(engine, enable_baked_queries=False)

Wie alle Session-Flags wird es auch von Factory-Objekten wie sessionmaker und Methoden wie sessionmaker.configure() akzeptiert.

Der unmittelbare Grund für dieses Flag ist, dass eine Anwendung, die Probleme sieht, die möglicherweise auf Cache-Schlüsselkonflikte von benutzerdefinierten „baked queries“ oder andere Probleme mit „baked queries“ zurückzuführen sind, das Verhalten deaktivieren kann, um „baked queries“ als Ursache eines Problems zu identifizieren oder zu eliminieren.

Neu seit Version 1.2.

Lazy Loading Integration

Geändert in Version 1.4: Ab SQLAlchemy 1.4 ist das „baked query“-System kein Teil des Beziehungs-Lade-Systems mehr. Stattdessen wird das native Caching-System verwendet.

API-Dokumentation

Objektname Beschreibung

BakedQuery

Ein Builder-Objekt für Query-Objekte.

bakery

Konstruiert eine neue bakery.

Bakery

Aufrufbare Funktion, die eine BakedQuery zurückgibt.

function sqlalchemy.ext.baked.bakery(size=200, _size_alert=None)

Konstruiert eine neue bakery.

Gibt zurück:

eine Instanz von Bakery

class sqlalchemy.ext.baked.BakedQuery

Ein Builder-Objekt für Query-Objekte.

method sqlalchemy.ext.baked.BakedQuery.add_criteria(fn, *args)

Fügt dieser BakedQuery eine Kriteriumsfunktion hinzu.

Dies entspricht der Verwendung des Operators +=, um eine BakedQuery inplace zu modifizieren.

classmethod sqlalchemy.ext.baked.BakedQuery.bakery(size=200, _size_alert=None)

Konstruiert eine neue bakery.

Gibt zurück:

eine Instanz von Bakery

method sqlalchemy.ext.baked.BakedQuery.for_session(session)

Gibt ein Result-Objekt für diese BakedQuery zurück.

Dies entspricht dem Aufrufen der BakedQuery als Python-Aufrufbare, z.B. result = my_baked_query(session).

method sqlalchemy.ext.baked.BakedQuery.spoil(full=False)

Hebt jegliches Query-Caching auf, das für dieses BakedQuery-Objekt stattfinden würde.

Die BakedQuery kann weiterhin normal verwendet werden, jedoch werden zusätzliche Erstellungsfunktionen nicht mehr gecached; sie werden bei jeder Ausführung aufgerufen.

Dies dient zur Unterstützung des Falls, in dem ein bestimmter Schritt beim Erstellen einer „baked query“ die Query für das Caching disqualifiziert, z. B. eine Variante, die auf einem nicht-cachebaren Wert beruht.

Parameter:

full – wenn False, werden nur Funktionen, die diesem BakedQuery-Objekt nach dem Schritt spoil hinzugefügt wurden, nicht zwischengespeichert; der Zustand des BakedQuery bis zu diesem Zeitpunkt wird aus dem Cache bezogen. Wenn True, dann wird das gesamte Query-Objekt jedes Mal von Grund auf neu aufgebaut, wobei alle Erstellungsfunktionen bei jeder Invokation aufgerufen werden.

method sqlalchemy.ext.baked.BakedQuery.to_query(query_or_session)

Gibt das Query-Objekt für die Verwendung als Subquery zurück.

Diese Methode sollte innerhalb des Lambda-Aufrufs verwendet werden, der zum Generieren eines Schritts einer umschließenden BakedQuery verwendet wird. Der Parameter sollte normalerweise das Query-Objekt sein, das an das Lambda übergeben wird

sub_bq = self.bakery(lambda s: s.query(User.name))
sub_bq += lambda q: q.filter(User.id == Address.user_id).correlate(Address)

main_bq = self.bakery(lambda s: s.query(Address))
main_bq += lambda q: q.filter(sub_bq.to_query(q).exists())

In dem Fall, dass die Subquery in dem ersten Aufruf gegen eine Session verwendet wird, wird auch die Session akzeptiert

sub_bq = self.bakery(lambda s: s.query(User.name))
sub_bq += lambda q: q.filter(User.id == Address.user_id).correlate(Address)

main_bq = self.bakery(
    lambda s: s.query(Address.id, sub_bq.to_query(q).scalar_subquery())
)
Parameter:

query_or_session

ein Query-Objekt oder ein Klassen-Session-Objekt, das sich im Kontext eines umschließenden BakedQuery-Aufrufs befindet.

Neu in Version 1.3.

method sqlalchemy.ext.baked.BakedQuery.with_criteria(fn, *args)

Fügt ein Kriteriumsfunktion zu einem von diesem geklonten BakedQuery hinzu.

Dies entspricht der Verwendung des Operators +, um ein neues BakedQuery mit Modifikationen zu erzeugen.

class sqlalchemy.ext.baked.Bakery

Aufrufbare Funktion, die eine BakedQuery zurückgibt.

Dieses Objekt wird von der Klassenmethode BakedQuery.bakery() zurückgegeben. Es existiert als Objekt, damit der "Cache" leicht inspiziert werden kann.

Neu seit Version 1.2.

class sqlalchemy.ext.baked.Result

Ruft eine BakedQuery gegen eine Session auf.

Das Result-Objekt ist der Ort, an dem das tatsächliche Query-Objekt erstellt oder aus dem Cache abgerufen wird, gegen eine Ziel-Session, und dann für Ergebnisse aufgerufen wird.

method sqlalchemy.ext.baked.Result.all()

Gibt alle Zeilen zurück.

Entspricht Query.all().

method sqlalchemy.ext.baked.Result.count()

Gibt die 'Anzahl' zurück.

Entspricht Query.count().

Beachten Sie, dass dies eine Subquery verwendet, um eine genaue Anzahl unabhängig von der Struktur der ursprünglichen Anweisung zu gewährleisten.

method sqlalchemy.ext.baked.Result.first()

Gibt die erste Zeile zurück.

Entspricht Query.first().

method sqlalchemy.ext.baked.Result.get(ident)

Ruft ein Objekt anhand der Identität ab.

Entspricht Query.get().

method sqlalchemy.ext.baked.Result.one()

Gibt genau ein Ergebnis zurück oder löst eine Ausnahme aus.

Entspricht Query.one().

method sqlalchemy.ext.baked.Result.one_or_none()

Gibt ein oder null Ergebnisse zurück oder löst eine Ausnahme für mehrere Zeilen aus.

Entspricht Query.one_or_none().

method sqlalchemy.ext.baked.Result.params(*args, **kw)

Gibt Parameter an, die in die SQL-Anweisung eingefügt werden sollen.

method sqlalchemy.ext.baked.Result.scalar()

Gibt das erste Element des ersten Ergebnisses oder None zurück, wenn keine Zeilen vorhanden sind. Wenn mehrere Zeilen zurückgegeben werden, wird MultipleResultsFound ausgelöst.

Entspricht Query.scalar().

method sqlalchemy.ext.baked.Result.with_post_criteria(fn)

Fügt eine Kriteriumsfunktion hinzu, die nach dem Caching angewendet wird.

Dies fügt eine Funktion hinzu, die auf das Query-Objekt angewendet wird, nachdem es aus dem Cache abgerufen wurde. Dies beinhaltet derzeit **nur** die Methoden Query.params() und Query.execution_options().

Warnung

Result.with_post_criteria()-Funktionen werden auf das Query-Objekt angewendet, **nachdem** das SQL-Anweisungsobjekt der Abfrage aus dem Cache abgerufen wurde. Nur die Methoden Query.params() und Query.execution_options() sollten verwendet werden.

Neu seit Version 1.2.