Zum Inhalt springen

Automatische IDs, Keine Standardwerte und Datenaktualisierung

Im vorherigen Kapitel haben wir gesehen, wie man Zeilen mithilfe von SQLModel in die Datenbank einfügt.

Nun sprechen wir ein wenig darüber, warum das Feld id in der Datenbank nicht NULL sein kann, da es sich um einen Primärschlüssel handelt und wir es mit Field(primary_key=True) deklarieren.

Aber dasselbe Feld id kann im Python-Code None sein, daher deklarieren wir den Typ mit int | None und setzen den Standardwert auf Field(default=None)

# Code above omitted 👆

class Hero(SQLModel, table=True):
    id: int | None = Field(default=None, primary_key=True)
    name: str
    secret_name: str
    age: int | None = None

# Code below omitted 👇
👀 Vorschau der vollständigen Datei
from sqlmodel import Field, Session, SQLModel, create_engine


class Hero(SQLModel, table=True):
    id: int | None = Field(default=None, primary_key=True)
    name: str
    secret_name: str
    age: int | None = None


sqlite_file_name = "database.db"
sqlite_url = f"sqlite:///{sqlite_file_name}"

engine = create_engine(sqlite_url, echo=True)


def create_db_and_tables():
    SQLModel.metadata.create_all(engine)


def create_heroes():
    hero_1 = Hero(name="Deadpond", secret_name="Dive Wilson")
    hero_2 = Hero(name="Spider-Boy", secret_name="Pedro Parqueador")
    hero_3 = Hero(name="Rusty-Man", secret_name="Tommy Sharp", age=48)

    print("Before interacting with the database")
    print("Hero 1:", hero_1)
    print("Hero 2:", hero_2)
    print("Hero 3:", hero_3)

    with Session(engine) as session:
        session.add(hero_1)
        session.add(hero_2)
        session.add(hero_3)

        print("After adding to the session")
        print("Hero 1:", hero_1)
        print("Hero 2:", hero_2)
        print("Hero 3:", hero_3)

        session.commit()

        print("After committing the session")
        print("Hero 1:", hero_1)
        print("Hero 2:", hero_2)
        print("Hero 3:", hero_3)

        print("After committing the session, show IDs")
        print("Hero 1 ID:", hero_1.id)
        print("Hero 2 ID:", hero_2.id)
        print("Hero 3 ID:", hero_3.id)

        print("After committing the session, show names")
        print("Hero 1 name:", hero_1.name)
        print("Hero 2 name:", hero_2.name)
        print("Hero 3 name:", hero_3.name)

        session.refresh(hero_1)
        session.refresh(hero_2)
        session.refresh(hero_3)

        print("After refreshing the heroes")
        print("Hero 1:", hero_1)
        print("Hero 2:", hero_2)
        print("Hero 3:", hero_3)

    print("After the session closes")
    print("Hero 1:", hero_1)
    print("Hero 2:", hero_2)
    print("Hero 3:", hero_3)


def main():
    create_db_and_tables()
    create_heroes()


if __name__ == "__main__":
    main()
🤓 Andere Versionen und Varianten
from typing import Optional

from sqlmodel import Field, Session, SQLModel, create_engine


class Hero(SQLModel, table=True):
    id: Optional[int] = Field(default=None, primary_key=True)
    name: str
    secret_name: str
    age: Optional[int] = None


sqlite_file_name = "database.db"
sqlite_url = f"sqlite:///{sqlite_file_name}"

engine = create_engine(sqlite_url, echo=True)


def create_db_and_tables():
    SQLModel.metadata.create_all(engine)


def create_heroes():
    hero_1 = Hero(name="Deadpond", secret_name="Dive Wilson")
    hero_2 = Hero(name="Spider-Boy", secret_name="Pedro Parqueador")
    hero_3 = Hero(name="Rusty-Man", secret_name="Tommy Sharp", age=48)

    print("Before interacting with the database")
    print("Hero 1:", hero_1)
    print("Hero 2:", hero_2)
    print("Hero 3:", hero_3)

    with Session(engine) as session:
        session.add(hero_1)
        session.add(hero_2)
        session.add(hero_3)

        print("After adding to the session")
        print("Hero 1:", hero_1)
        print("Hero 2:", hero_2)
        print("Hero 3:", hero_3)

        session.commit()

        print("After committing the session")
        print("Hero 1:", hero_1)
        print("Hero 2:", hero_2)
        print("Hero 3:", hero_3)

        print("After committing the session, show IDs")
        print("Hero 1 ID:", hero_1.id)
        print("Hero 2 ID:", hero_2.id)
        print("Hero 3 ID:", hero_3.id)

        print("After committing the session, show names")
        print("Hero 1 name:", hero_1.name)
        print("Hero 2 name:", hero_2.name)
        print("Hero 3 name:", hero_3.name)

        session.refresh(hero_1)
        session.refresh(hero_2)
        session.refresh(hero_3)

        print("After refreshing the heroes")
        print("Hero 1:", hero_1)
        print("Hero 2:", hero_2)
        print("Hero 3:", hero_3)

    print("After the session closes")
    print("Hero 1:", hero_1)
    print("Hero 2:", hero_2)
    print("Hero 3:", hero_3)


def main():
    create_db_and_tables()
    create_heroes()


if __name__ == "__main__":
    main()

Als Nächstes zeige ich Ihnen etwas mehr über die Synchronisation von Daten zwischen der Datenbank und dem Python-Code.

Wann erhalten wir eine tatsächliche int aus der Datenbank in diesem Feld id? Sehen wir uns das alles an. 👇

Eine neue Hero-Instanz erstellen

Wenn wir eine neue Hero-Instanz erstellen, setzen wir die id nicht.

# Code above omitted 👆

def create_heroes():
    hero_1 = Hero(name="Deadpond", secret_name="Dive Wilson")
    hero_2 = Hero(name="Spider-Boy", secret_name="Pedro Parqueador")
    hero_3 = Hero(name="Rusty-Man", secret_name="Tommy Sharp", age=48)

# Code below omitted 👇
👀 Vorschau der vollständigen Datei
from sqlmodel import Field, Session, SQLModel, create_engine


class Hero(SQLModel, table=True):
    id: int | None = Field(default=None, primary_key=True)
    name: str
    secret_name: str
    age: int | None = None


sqlite_file_name = "database.db"
sqlite_url = f"sqlite:///{sqlite_file_name}"

engine = create_engine(sqlite_url, echo=True)


def create_db_and_tables():
    SQLModel.metadata.create_all(engine)


def create_heroes():
    hero_1 = Hero(name="Deadpond", secret_name="Dive Wilson")
    hero_2 = Hero(name="Spider-Boy", secret_name="Pedro Parqueador")
    hero_3 = Hero(name="Rusty-Man", secret_name="Tommy Sharp", age=48)

    print("Before interacting with the database")
    print("Hero 1:", hero_1)
    print("Hero 2:", hero_2)
    print("Hero 3:", hero_3)

    with Session(engine) as session:
        session.add(hero_1)
        session.add(hero_2)
        session.add(hero_3)

        print("After adding to the session")
        print("Hero 1:", hero_1)
        print("Hero 2:", hero_2)
        print("Hero 3:", hero_3)

        session.commit()

        print("After committing the session")
        print("Hero 1:", hero_1)
        print("Hero 2:", hero_2)
        print("Hero 3:", hero_3)

        print("After committing the session, show IDs")
        print("Hero 1 ID:", hero_1.id)
        print("Hero 2 ID:", hero_2.id)
        print("Hero 3 ID:", hero_3.id)

        print("After committing the session, show names")
        print("Hero 1 name:", hero_1.name)
        print("Hero 2 name:", hero_2.name)
        print("Hero 3 name:", hero_3.name)

        session.refresh(hero_1)
        session.refresh(hero_2)
        session.refresh(hero_3)

        print("After refreshing the heroes")
        print("Hero 1:", hero_1)
        print("Hero 2:", hero_2)
        print("Hero 3:", hero_3)

    print("After the session closes")
    print("Hero 1:", hero_1)
    print("Hero 2:", hero_2)
    print("Hero 3:", hero_3)


def main():
    create_db_and_tables()
    create_heroes()


if __name__ == "__main__":
    main()
🤓 Andere Versionen und Varianten
from typing import Optional

from sqlmodel import Field, Session, SQLModel, create_engine


class Hero(SQLModel, table=True):
    id: Optional[int] = Field(default=None, primary_key=True)
    name: str
    secret_name: str
    age: Optional[int] = None


sqlite_file_name = "database.db"
sqlite_url = f"sqlite:///{sqlite_file_name}"

engine = create_engine(sqlite_url, echo=True)


def create_db_and_tables():
    SQLModel.metadata.create_all(engine)


def create_heroes():
    hero_1 = Hero(name="Deadpond", secret_name="Dive Wilson")
    hero_2 = Hero(name="Spider-Boy", secret_name="Pedro Parqueador")
    hero_3 = Hero(name="Rusty-Man", secret_name="Tommy Sharp", age=48)

    print("Before interacting with the database")
    print("Hero 1:", hero_1)
    print("Hero 2:", hero_2)
    print("Hero 3:", hero_3)

    with Session(engine) as session:
        session.add(hero_1)
        session.add(hero_2)
        session.add(hero_3)

        print("After adding to the session")
        print("Hero 1:", hero_1)
        print("Hero 2:", hero_2)
        print("Hero 3:", hero_3)

        session.commit()

        print("After committing the session")
        print("Hero 1:", hero_1)
        print("Hero 2:", hero_2)
        print("Hero 3:", hero_3)

        print("After committing the session, show IDs")
        print("Hero 1 ID:", hero_1.id)
        print("Hero 2 ID:", hero_2.id)
        print("Hero 3 ID:", hero_3.id)

        print("After committing the session, show names")
        print("Hero 1 name:", hero_1.name)
        print("Hero 2 name:", hero_2.name)
        print("Hero 3 name:", hero_3.name)

        session.refresh(hero_1)
        session.refresh(hero_2)
        session.refresh(hero_3)

        print("After refreshing the heroes")
        print("Hero 1:", hero_1)
        print("Hero 2:", hero_2)
        print("Hero 3:", hero_3)

    print("After the session closes")
    print("Hero 1:", hero_1)
    print("Hero 2:", hero_2)
    print("Hero 3:", hero_3)


def main():
    create_db_and_tables()
    create_heroes()


if __name__ == "__main__":
    main()

Wie int | None hilft

Da wir die id nicht setzen, nimmt sie den Standardwert None von Python an, den wir in Field(default=None) festgelegt haben.

Dies ist der einzige Grund, warum wir sie mit int | None und einem Standardwert von None definieren.

Denn an diesem Punkt im Code, bevor wir mit der Datenbank interagieren, kann der Python-Wert tatsächlich None sein.

Wenn wir davon ausgehen würden, dass die id *immer* eine int ist, und die Typannotation ohne int | None hinzufügen würden, könnten wir am Ende fehlerhaften Code schreiben, wie z. B.:

next_hero_id = hero_1.id + 1

Wenn wir diesen Code ausführen würden, bevor wir den Helden in der Datenbank speichern, und die hero_1.id immer noch None wäre, würden wir einen Fehler erhalten wie

TypeError: unsupported operand type(s) for +: 'NoneType' and 'int'

Aber durch die Deklaration mit int | None hilft uns der Editor, fehlerhaften Code zu vermeiden, indem er uns eine Warnung anzeigt, die uns mitteilt, dass der Code ungültig sein könnte, wenn hero_1.id None ist. 🔍

Wir können dies bestätigen, indem wir unsere Helden ausgeben, bevor wir sie zur Datenbank hinzufügen.

# Code above omitted 👆

def create_heroes():
    hero_1 = Hero(name="Deadpond", secret_name="Dive Wilson")
    hero_2 = Hero(name="Spider-Boy", secret_name="Pedro Parqueador")
    hero_3 = Hero(name="Rusty-Man", secret_name="Tommy Sharp", age=48)

    print("Before interacting with the database")
    print("Hero 1:", hero_1)
    print("Hero 2:", hero_2)
    print("Hero 3:", hero_3)

# Code below omitted 👇
👀 Vorschau der vollständigen Datei
from sqlmodel import Field, Session, SQLModel, create_engine


class Hero(SQLModel, table=True):
    id: int | None = Field(default=None, primary_key=True)
    name: str
    secret_name: str
    age: int | None = None


sqlite_file_name = "database.db"
sqlite_url = f"sqlite:///{sqlite_file_name}"

engine = create_engine(sqlite_url, echo=True)


def create_db_and_tables():
    SQLModel.metadata.create_all(engine)


def create_heroes():
    hero_1 = Hero(name="Deadpond", secret_name="Dive Wilson")
    hero_2 = Hero(name="Spider-Boy", secret_name="Pedro Parqueador")
    hero_3 = Hero(name="Rusty-Man", secret_name="Tommy Sharp", age=48)

    print("Before interacting with the database")
    print("Hero 1:", hero_1)
    print("Hero 2:", hero_2)
    print("Hero 3:", hero_3)

    with Session(engine) as session:
        session.add(hero_1)
        session.add(hero_2)
        session.add(hero_3)

        print("After adding to the session")
        print("Hero 1:", hero_1)
        print("Hero 2:", hero_2)
        print("Hero 3:", hero_3)

        session.commit()

        print("After committing the session")
        print("Hero 1:", hero_1)
        print("Hero 2:", hero_2)
        print("Hero 3:", hero_3)

        print("After committing the session, show IDs")
        print("Hero 1 ID:", hero_1.id)
        print("Hero 2 ID:", hero_2.id)
        print("Hero 3 ID:", hero_3.id)

        print("After committing the session, show names")
        print("Hero 1 name:", hero_1.name)
        print("Hero 2 name:", hero_2.name)
        print("Hero 3 name:", hero_3.name)

        session.refresh(hero_1)
        session.refresh(hero_2)
        session.refresh(hero_3)

        print("After refreshing the heroes")
        print("Hero 1:", hero_1)
        print("Hero 2:", hero_2)
        print("Hero 3:", hero_3)

    print("After the session closes")
    print("Hero 1:", hero_1)
    print("Hero 2:", hero_2)
    print("Hero 3:", hero_3)


def main():
    create_db_and_tables()
    create_heroes()


if __name__ == "__main__":
    main()
🤓 Andere Versionen und Varianten
from typing import Optional

from sqlmodel import Field, Session, SQLModel, create_engine


class Hero(SQLModel, table=True):
    id: Optional[int] = Field(default=None, primary_key=True)
    name: str
    secret_name: str
    age: Optional[int] = None


sqlite_file_name = "database.db"
sqlite_url = f"sqlite:///{sqlite_file_name}"

engine = create_engine(sqlite_url, echo=True)


def create_db_and_tables():
    SQLModel.metadata.create_all(engine)


def create_heroes():
    hero_1 = Hero(name="Deadpond", secret_name="Dive Wilson")
    hero_2 = Hero(name="Spider-Boy", secret_name="Pedro Parqueador")
    hero_3 = Hero(name="Rusty-Man", secret_name="Tommy Sharp", age=48)

    print("Before interacting with the database")
    print("Hero 1:", hero_1)
    print("Hero 2:", hero_2)
    print("Hero 3:", hero_3)

    with Session(engine) as session:
        session.add(hero_1)
        session.add(hero_2)
        session.add(hero_3)

        print("After adding to the session")
        print("Hero 1:", hero_1)
        print("Hero 2:", hero_2)
        print("Hero 3:", hero_3)

        session.commit()

        print("After committing the session")
        print("Hero 1:", hero_1)
        print("Hero 2:", hero_2)
        print("Hero 3:", hero_3)

        print("After committing the session, show IDs")
        print("Hero 1 ID:", hero_1.id)
        print("Hero 2 ID:", hero_2.id)
        print("Hero 3 ID:", hero_3.id)

        print("After committing the session, show names")
        print("Hero 1 name:", hero_1.name)
        print("Hero 2 name:", hero_2.name)
        print("Hero 3 name:", hero_3.name)

        session.refresh(hero_1)
        session.refresh(hero_2)
        session.refresh(hero_3)

        print("After refreshing the heroes")
        print("Hero 1:", hero_1)
        print("Hero 2:", hero_2)
        print("Hero 3:", hero_3)

    print("After the session closes")
    print("Hero 1:", hero_1)
    print("Hero 2:", hero_2)
    print("Hero 3:", hero_3)


def main():
    create_db_and_tables()
    create_heroes()


if __name__ == "__main__":
    main()

Das wird ausgeben

$ python app.py

// Output above omitted 👆

Before interacting with the database
Hero 1: id=None name='Deadpond' secret_name='Dive Wilson' age=None
Hero 2: id=None name='Spider-Boy' secret_name='Pedro Parqueador' age=None
Hero 3: id=None name='Rusty-Man' secret_name='Tommy Sharp' age=48

Beachten Sie, dass sie alle id=None haben.

Das ist der Standardwert, den wir in der Modellklasse Hero definiert haben.

Was passiert, wenn wir diese Objekte zur Session adden?

Die Objekte zur Session hinzufügen

Nachdem wir die Hero-Instanzobjekte zur Session hinzugefügt haben, sind die IDs *immer noch* None.

Wir können dies verifizieren, indem wir eine Session mithilfe eines with-Blocks erstellen und die Objekte hinzufügen. Und sie dann erneut ausgeben.

# Code above omitted 👆

def create_heroes():
    hero_1 = Hero(name="Deadpond", secret_name="Dive Wilson")
    hero_2 = Hero(name="Spider-Boy", secret_name="Pedro Parqueador")
    hero_3 = Hero(name="Rusty-Man", secret_name="Tommy Sharp", age=48)

    print("Before interacting with the database")
    print("Hero 1:", hero_1)
    print("Hero 2:", hero_2)
    print("Hero 3:", hero_3)

    with Session(engine) as session:
        session.add(hero_1)
        session.add(hero_2)
        session.add(hero_3)

        print("After adding to the session")
        print("Hero 1:", hero_1)
        print("Hero 2:", hero_2)
        print("Hero 3:", hero_3)

# Code below omitted 👇
👀 Vorschau der vollständigen Datei
from sqlmodel import Field, Session, SQLModel, create_engine


class Hero(SQLModel, table=True):
    id: int | None = Field(default=None, primary_key=True)
    name: str
    secret_name: str
    age: int | None = None


sqlite_file_name = "database.db"
sqlite_url = f"sqlite:///{sqlite_file_name}"

engine = create_engine(sqlite_url, echo=True)


def create_db_and_tables():
    SQLModel.metadata.create_all(engine)


def create_heroes():
    hero_1 = Hero(name="Deadpond", secret_name="Dive Wilson")
    hero_2 = Hero(name="Spider-Boy", secret_name="Pedro Parqueador")
    hero_3 = Hero(name="Rusty-Man", secret_name="Tommy Sharp", age=48)

    print("Before interacting with the database")
    print("Hero 1:", hero_1)
    print("Hero 2:", hero_2)
    print("Hero 3:", hero_3)

    with Session(engine) as session:
        session.add(hero_1)
        session.add(hero_2)
        session.add(hero_3)

        print("After adding to the session")
        print("Hero 1:", hero_1)
        print("Hero 2:", hero_2)
        print("Hero 3:", hero_3)

        session.commit()

        print("After committing the session")
        print("Hero 1:", hero_1)
        print("Hero 2:", hero_2)
        print("Hero 3:", hero_3)

        print("After committing the session, show IDs")
        print("Hero 1 ID:", hero_1.id)
        print("Hero 2 ID:", hero_2.id)
        print("Hero 3 ID:", hero_3.id)

        print("After committing the session, show names")
        print("Hero 1 name:", hero_1.name)
        print("Hero 2 name:", hero_2.name)
        print("Hero 3 name:", hero_3.name)

        session.refresh(hero_1)
        session.refresh(hero_2)
        session.refresh(hero_3)

        print("After refreshing the heroes")
        print("Hero 1:", hero_1)
        print("Hero 2:", hero_2)
        print("Hero 3:", hero_3)

    print("After the session closes")
    print("Hero 1:", hero_1)
    print("Hero 2:", hero_2)
    print("Hero 3:", hero_3)


def main():
    create_db_and_tables()
    create_heroes()


if __name__ == "__main__":
    main()
🤓 Andere Versionen und Varianten
from typing import Optional

from sqlmodel import Field, Session, SQLModel, create_engine


class Hero(SQLModel, table=True):
    id: Optional[int] = Field(default=None, primary_key=True)
    name: str
    secret_name: str
    age: Optional[int] = None


sqlite_file_name = "database.db"
sqlite_url = f"sqlite:///{sqlite_file_name}"

engine = create_engine(sqlite_url, echo=True)


def create_db_and_tables():
    SQLModel.metadata.create_all(engine)


def create_heroes():
    hero_1 = Hero(name="Deadpond", secret_name="Dive Wilson")
    hero_2 = Hero(name="Spider-Boy", secret_name="Pedro Parqueador")
    hero_3 = Hero(name="Rusty-Man", secret_name="Tommy Sharp", age=48)

    print("Before interacting with the database")
    print("Hero 1:", hero_1)
    print("Hero 2:", hero_2)
    print("Hero 3:", hero_3)

    with Session(engine) as session:
        session.add(hero_1)
        session.add(hero_2)
        session.add(hero_3)

        print("After adding to the session")
        print("Hero 1:", hero_1)
        print("Hero 2:", hero_2)
        print("Hero 3:", hero_3)

        session.commit()

        print("After committing the session")
        print("Hero 1:", hero_1)
        print("Hero 2:", hero_2)
        print("Hero 3:", hero_3)

        print("After committing the session, show IDs")
        print("Hero 1 ID:", hero_1.id)
        print("Hero 2 ID:", hero_2.id)
        print("Hero 3 ID:", hero_3.id)

        print("After committing the session, show names")
        print("Hero 1 name:", hero_1.name)
        print("Hero 2 name:", hero_2.name)
        print("Hero 3 name:", hero_3.name)

        session.refresh(hero_1)
        session.refresh(hero_2)
        session.refresh(hero_3)

        print("After refreshing the heroes")
        print("Hero 1:", hero_1)
        print("Hero 2:", hero_2)
        print("Hero 3:", hero_3)

    print("After the session closes")
    print("Hero 1:", hero_1)
    print("Hero 2:", hero_2)
    print("Hero 3:", hero_3)


def main():
    create_db_and_tables()
    create_heroes()


if __name__ == "__main__":
    main()

Dies gibt erneut die ids der Objekte als None aus.

$ python app.py

// Output above omitted 👆

After adding to the session
Hero 1: id=None name='Deadpond' secret_name='Dive Wilson' age=None
Hero 2: id=None name='Spider-Boy' secret_name='Pedro Parqueador' age=None
Hero 3: id=None name='Rusty-Man' secret_name='Tommy Sharp' age=48

Wie wir bereits gesehen haben, ist die Session intelligent und spricht nicht jedes Mal mit der Datenbank, wenn wir etwas zur Änderung vorbereiten. Erst wenn wir bereit sind und ihr sagen, die Änderungen zu committen, sendet sie die gesamte SQL an die Datenbank, um die Daten zu speichern.

Die Änderungen in der Datenbank committen

Dann können wir die Änderungen in der Session committen und erneut ausgeben.

# Code above omitted 👆

    with Session(engine) as session:
        session.add(hero_1)
        session.add(hero_2)
        session.add(hero_3)

        print("After adding to the session")
        print("Hero 1:", hero_1)
        print("Hero 2:", hero_2)
        print("Hero 3:", hero_3)

        session.commit()

        print("After committing the session")
        print("Hero 1:", hero_1)
        print("Hero 2:", hero_2)
        print("Hero 3:", hero_3)

# Code below omitted 👇
👀 Vorschau der vollständigen Datei
from sqlmodel import Field, Session, SQLModel, create_engine


class Hero(SQLModel, table=True):
    id: int | None = Field(default=None, primary_key=True)
    name: str
    secret_name: str
    age: int | None = None


sqlite_file_name = "database.db"
sqlite_url = f"sqlite:///{sqlite_file_name}"

engine = create_engine(sqlite_url, echo=True)


def create_db_and_tables():
    SQLModel.metadata.create_all(engine)


def create_heroes():
    hero_1 = Hero(name="Deadpond", secret_name="Dive Wilson")
    hero_2 = Hero(name="Spider-Boy", secret_name="Pedro Parqueador")
    hero_3 = Hero(name="Rusty-Man", secret_name="Tommy Sharp", age=48)

    print("Before interacting with the database")
    print("Hero 1:", hero_1)
    print("Hero 2:", hero_2)
    print("Hero 3:", hero_3)

    with Session(engine) as session:
        session.add(hero_1)
        session.add(hero_2)
        session.add(hero_3)

        print("After adding to the session")
        print("Hero 1:", hero_1)
        print("Hero 2:", hero_2)
        print("Hero 3:", hero_3)

        session.commit()

        print("After committing the session")
        print("Hero 1:", hero_1)
        print("Hero 2:", hero_2)
        print("Hero 3:", hero_3)

        print("After committing the session, show IDs")
        print("Hero 1 ID:", hero_1.id)
        print("Hero 2 ID:", hero_2.id)
        print("Hero 3 ID:", hero_3.id)

        print("After committing the session, show names")
        print("Hero 1 name:", hero_1.name)
        print("Hero 2 name:", hero_2.name)
        print("Hero 3 name:", hero_3.name)

        session.refresh(hero_1)
        session.refresh(hero_2)
        session.refresh(hero_3)

        print("After refreshing the heroes")
        print("Hero 1:", hero_1)
        print("Hero 2:", hero_2)
        print("Hero 3:", hero_3)

    print("After the session closes")
    print("Hero 1:", hero_1)
    print("Hero 2:", hero_2)
    print("Hero 3:", hero_3)


def main():
    create_db_and_tables()
    create_heroes()


if __name__ == "__main__":
    main()
🤓 Andere Versionen und Varianten
from typing import Optional

from sqlmodel import Field, Session, SQLModel, create_engine


class Hero(SQLModel, table=True):
    id: Optional[int] = Field(default=None, primary_key=True)
    name: str
    secret_name: str
    age: Optional[int] = None


sqlite_file_name = "database.db"
sqlite_url = f"sqlite:///{sqlite_file_name}"

engine = create_engine(sqlite_url, echo=True)


def create_db_and_tables():
    SQLModel.metadata.create_all(engine)


def create_heroes():
    hero_1 = Hero(name="Deadpond", secret_name="Dive Wilson")
    hero_2 = Hero(name="Spider-Boy", secret_name="Pedro Parqueador")
    hero_3 = Hero(name="Rusty-Man", secret_name="Tommy Sharp", age=48)

    print("Before interacting with the database")
    print("Hero 1:", hero_1)
    print("Hero 2:", hero_2)
    print("Hero 3:", hero_3)

    with Session(engine) as session:
        session.add(hero_1)
        session.add(hero_2)
        session.add(hero_3)

        print("After adding to the session")
        print("Hero 1:", hero_1)
        print("Hero 2:", hero_2)
        print("Hero 3:", hero_3)

        session.commit()

        print("After committing the session")
        print("Hero 1:", hero_1)
        print("Hero 2:", hero_2)
        print("Hero 3:", hero_3)

        print("After committing the session, show IDs")
        print("Hero 1 ID:", hero_1.id)
        print("Hero 2 ID:", hero_2.id)
        print("Hero 3 ID:", hero_3.id)

        print("After committing the session, show names")
        print("Hero 1 name:", hero_1.name)
        print("Hero 2 name:", hero_2.name)
        print("Hero 3 name:", hero_3.name)

        session.refresh(hero_1)
        session.refresh(hero_2)
        session.refresh(hero_3)

        print("After refreshing the heroes")
        print("Hero 1:", hero_1)
        print("Hero 2:", hero_2)
        print("Hero 3:", hero_3)

    print("After the session closes")
    print("Hero 1:", hero_1)
    print("Hero 2:", hero_2)
    print("Hero 3:", hero_3)


def main():
    create_db_and_tables()
    create_heroes()


if __name__ == "__main__":
    main()

Und jetzt passiert etwas Unerwartetes. Schauen Sie sich die Ausgabe an. Es sieht so aus, als ob die Hero-Instanzobjekte überhaupt keine Daten hätten.

$ python app.py

// Output above omitted 👆

// Here the engine talks to the database, the SQL part
INFO Engine BEGIN (implicit)
INFO Engine INSERT INTO hero (name, secret_name, age) VALUES (?, ?, ?)
INFO Engine [generated in 0.00018s] ('Deadpond', 'Dive Wilson', None)
INFO Engine INSERT INTO hero (name, secret_name, age) VALUES (?, ?, ?)
INFO Engine [cached since 0.0008968s ago] ('Spider-Boy', 'Pedro Parqueador', None)
INFO Engine INSERT INTO hero (name, secret_name, age) VALUES (?, ?, ?)
INFO Engine [cached since 0.001143s ago] ('Rusty-Man', 'Tommy Sharp', 48)
INFO Engine COMMIT

// And now our prints
After committing the session
Hero 1:
Hero 2:
Hero 3:

// What is happening here? 😱

Was passiert ist, dass SQLModel (eigentlich SQLAlchemy) diese Objekte intern als "abgelaufen" markiert. Sie haben nicht die neueste Version ihrer Daten. Das liegt daran, dass wir einige Felder in der Datenbank aktualisiert haben könnten, zum Beispiel stellen Sie sich ein Feld updated_at: datetime vor, das automatisch aktualisiert wurde, als wir Änderungen gespeichert haben.

Auf die gleiche Weise könnten andere Werte geändert worden sein, daher ist die sicherste Option, die die Session hat, die Objekte einfach intern als abgelaufen zu markieren.

Und dann, wenn wir das nächste Mal auf jedes Attribut zugreifen, zum Beispiel mit

current_hero_name = hero_1.name

... wird SQLModel (eigentlich SQLAlchemy) sicherstellen, dass es die Datenbank kontaktiert und die aktuellste Version der Daten abruft, dieses Feld name in unserem Objekt aktualisiert und es dann für den Rest des Python-Ausdrucks verfügbar macht. Im obigen Beispiel könnte Python dann weiter ausführen und diesen (gerade aktualisierten) Wert hero_1.name verwenden, um ihn in die Variable current_hero_name zu setzen.

All das geschieht automatisch und im Hintergrund. ✨

Und hier ist das Lustige und Seltsame an unserem Beispiel:

print("Hero 1:", hero_1)

Wir haben nicht auf die Attribute des Objekts zugegriffen, wie hero.name. Wir haben nur das gesamte Objekt ausgegeben und gedruckt, daher hat SQLAlchemy keine Möglichkeit zu wissen, dass wir auf die Daten dieses Objekts zugreifen wollen.

Um zu bestätigen und zu verstehen, wie diese automatische Ablauf- und Aktualisierungsfunktion von Daten beim Zugriff auf Attribute funktioniert, können wir einige einzelne Felder (Instanzattribute) ausgeben.

# Code above omitted 👆

    with Session(engine) as session:
        session.add(hero_1)
        session.add(hero_2)
        session.add(hero_3)

        print("After adding to the session")
        print("Hero 1:", hero_1)
        print("Hero 2:", hero_2)
        print("Hero 3:", hero_3)

        session.commit()

        print("After committing the session")
        print("Hero 1:", hero_1)
        print("Hero 2:", hero_2)
        print("Hero 3:", hero_3)

        print("After committing the session, show IDs")
        print("Hero 1 ID:", hero_1.id)
        print("Hero 2 ID:", hero_2.id)
        print("Hero 3 ID:", hero_3.id)

        print("After committing the session, show names")
        print("Hero 1 name:", hero_1.name)
        print("Hero 2 name:", hero_2.name)
        print("Hero 3 name:", hero_3.name)

# Code below omitted 👇
👀 Vorschau der vollständigen Datei
from sqlmodel import Field, Session, SQLModel, create_engine


class Hero(SQLModel, table=True):
    id: int | None = Field(default=None, primary_key=True)
    name: str
    secret_name: str
    age: int | None = None


sqlite_file_name = "database.db"
sqlite_url = f"sqlite:///{sqlite_file_name}"

engine = create_engine(sqlite_url, echo=True)


def create_db_and_tables():
    SQLModel.metadata.create_all(engine)


def create_heroes():
    hero_1 = Hero(name="Deadpond", secret_name="Dive Wilson")
    hero_2 = Hero(name="Spider-Boy", secret_name="Pedro Parqueador")
    hero_3 = Hero(name="Rusty-Man", secret_name="Tommy Sharp", age=48)

    print("Before interacting with the database")
    print("Hero 1:", hero_1)
    print("Hero 2:", hero_2)
    print("Hero 3:", hero_3)

    with Session(engine) as session:
        session.add(hero_1)
        session.add(hero_2)
        session.add(hero_3)

        print("After adding to the session")
        print("Hero 1:", hero_1)
        print("Hero 2:", hero_2)
        print("Hero 3:", hero_3)

        session.commit()

        print("After committing the session")
        print("Hero 1:", hero_1)
        print("Hero 2:", hero_2)
        print("Hero 3:", hero_3)

        print("After committing the session, show IDs")
        print("Hero 1 ID:", hero_1.id)
        print("Hero 2 ID:", hero_2.id)
        print("Hero 3 ID:", hero_3.id)

        print("After committing the session, show names")
        print("Hero 1 name:", hero_1.name)
        print("Hero 2 name:", hero_2.name)
        print("Hero 3 name:", hero_3.name)

        session.refresh(hero_1)
        session.refresh(hero_2)
        session.refresh(hero_3)

        print("After refreshing the heroes")
        print("Hero 1:", hero_1)
        print("Hero 2:", hero_2)
        print("Hero 3:", hero_3)

    print("After the session closes")
    print("Hero 1:", hero_1)
    print("Hero 2:", hero_2)
    print("Hero 3:", hero_3)


def main():
    create_db_and_tables()
    create_heroes()


if __name__ == "__main__":
    main()
🤓 Andere Versionen und Varianten
from typing import Optional

from sqlmodel import Field, Session, SQLModel, create_engine


class Hero(SQLModel, table=True):
    id: Optional[int] = Field(default=None, primary_key=True)
    name: str
    secret_name: str
    age: Optional[int] = None


sqlite_file_name = "database.db"
sqlite_url = f"sqlite:///{sqlite_file_name}"

engine = create_engine(sqlite_url, echo=True)


def create_db_and_tables():
    SQLModel.metadata.create_all(engine)


def create_heroes():
    hero_1 = Hero(name="Deadpond", secret_name="Dive Wilson")
    hero_2 = Hero(name="Spider-Boy", secret_name="Pedro Parqueador")
    hero_3 = Hero(name="Rusty-Man", secret_name="Tommy Sharp", age=48)

    print("Before interacting with the database")
    print("Hero 1:", hero_1)
    print("Hero 2:", hero_2)
    print("Hero 3:", hero_3)

    with Session(engine) as session:
        session.add(hero_1)
        session.add(hero_2)
        session.add(hero_3)

        print("After adding to the session")
        print("Hero 1:", hero_1)
        print("Hero 2:", hero_2)
        print("Hero 3:", hero_3)

        session.commit()

        print("After committing the session")
        print("Hero 1:", hero_1)
        print("Hero 2:", hero_2)
        print("Hero 3:", hero_3)

        print("After committing the session, show IDs")
        print("Hero 1 ID:", hero_1.id)
        print("Hero 2 ID:", hero_2.id)
        print("Hero 3 ID:", hero_3.id)

        print("After committing the session, show names")
        print("Hero 1 name:", hero_1.name)
        print("Hero 2 name:", hero_2.name)
        print("Hero 3 name:", hero_3.name)

        session.refresh(hero_1)
        session.refresh(hero_2)
        session.refresh(hero_3)

        print("After refreshing the heroes")
        print("Hero 1:", hero_1)
        print("Hero 2:", hero_2)
        print("Hero 3:", hero_3)

    print("After the session closes")
    print("Hero 1:", hero_1)
    print("Hero 2:", hero_2)
    print("Hero 3:", hero_3)


def main():
    create_db_and_tables()
    create_heroes()


if __name__ == "__main__":
    main()

Jetzt greifen wir tatsächlich auf die Attribute zu, denn anstatt des gesamten Objekts hero_1 auszugeben,

print("Hero 1:", hero_1)

...geben wir jetzt das Attribut id in hero.id aus.

print("Hero 1 ID:", hero_1.id)

Durch den Zugriff auf das Attribut wird eine Menge Arbeit ausgelöst, die SQLModel (eigentlich SQLAlchemy) im Hintergrund leistet, um die Daten aus der Datenbank zu aktualisieren, sie dem id-Attribut des Objekts zuzuweisen und sie für den Python-Ausdruck verfügbar zu machen (in diesem Fall nur zum Ausgeben).

Lassen Sie uns sehen, wie es funktioniert.

$ python app.py

// Output above omitted 👆

// After committing, the objects are expired and have no values
After committing the session
Hero 1:
Hero 2:
Hero 3:

// Now we will access an attribute like the ID, this is the first print
After committing the session, show IDs

// Notice that before printing the first ID, the Session makes the Engine go to the database to refresh the data 🤓
INFO Engine BEGIN (implicit)
INFO Engine SELECT hero.id AS hero_id, hero.name AS hero_name, hero.secret_name AS hero_secret_name, hero.age AS hero_age
FROM hero
WHERE hero.id = ?
INFO Engine [generated in 0.00017s] (1,)

// Here's our first print, now we have the database-generated ID
Hero 1 ID: 1

// Before the next print, refresh the data for the second object
INFO Engine SELECT hero.id AS hero_id, hero.name AS hero_name, hero.secret_name AS hero_secret_name, hero.age AS hero_age
FROM hero
WHERE hero.id = ?
INFO Engine [cached since 0.001245s ago] (2,)

// Here's our print for the second hero with its auto-generated ID
Hero 2 ID: 2

// Before the third print, refresh its data
INFO Engine SELECT hero.id AS hero_id, hero.name AS hero_name, hero.secret_name AS hero_secret_name, hero.age AS hero_age
FROM hero
WHERE hero.id = ?
INFO Engine [cached since 0.002215s ago] (3,)

// And here's our print for the third hero
Hero 3 ID: 3

// What if we print another attribute like the name?
After committing the session, show names
Hero 1 name: Deadpond
Hero 2 name: Spider-Boy
Hero 3 name: Rusty-Man

// Because the Session already refreshed these objects with all their data and the session knows they are not expired, it doesn't have to go again to the database for the names 🤓

Objekte explizit aktualisieren

Sie haben gerade gelernt, wie die Session die Daten automatisch im Hintergrund aktualisiert, als Nebeneffekt, wenn Sie auf ein Attribut zugreifen.

Aber was ist, wenn Sie die Daten explizit aktualisieren möchten?

Das können Sie auch mit session.refresh(object) tun.

# Code above omitted 👆

    with Session(engine) as session:
        session.add(hero_1)
        session.add(hero_2)
        session.add(hero_3)

        print("After adding to the session")
        print("Hero 1:", hero_1)
        print("Hero 2:", hero_2)
        print("Hero 3:", hero_3)

        session.commit()

        print("After committing the session")
        print("Hero 1:", hero_1)
        print("Hero 2:", hero_2)
        print("Hero 3:", hero_3)

        print("After committing the session, show IDs")
        print("Hero 1 ID:", hero_1.id)
        print("Hero 2 ID:", hero_2.id)
        print("Hero 3 ID:", hero_3.id)

        print("After committing the session, show names")
        print("Hero 1 name:", hero_1.name)
        print("Hero 2 name:", hero_2.name)
        print("Hero 3 name:", hero_3.name)

        session.refresh(hero_1)
        session.refresh(hero_2)
        session.refresh(hero_3)

        print("After refreshing the heroes")
        print("Hero 1:", hero_1)
        print("Hero 2:", hero_2)
        print("Hero 3:", hero_3)

# Code below omitted 👇
👀 Vorschau der vollständigen Datei
from sqlmodel import Field, Session, SQLModel, create_engine


class Hero(SQLModel, table=True):
    id: int | None = Field(default=None, primary_key=True)
    name: str
    secret_name: str
    age: int | None = None


sqlite_file_name = "database.db"
sqlite_url = f"sqlite:///{sqlite_file_name}"

engine = create_engine(sqlite_url, echo=True)


def create_db_and_tables():
    SQLModel.metadata.create_all(engine)


def create_heroes():
    hero_1 = Hero(name="Deadpond", secret_name="Dive Wilson")
    hero_2 = Hero(name="Spider-Boy", secret_name="Pedro Parqueador")
    hero_3 = Hero(name="Rusty-Man", secret_name="Tommy Sharp", age=48)

    print("Before interacting with the database")
    print("Hero 1:", hero_1)
    print("Hero 2:", hero_2)
    print("Hero 3:", hero_3)

    with Session(engine) as session:
        session.add(hero_1)
        session.add(hero_2)
        session.add(hero_3)

        print("After adding to the session")
        print("Hero 1:", hero_1)
        print("Hero 2:", hero_2)
        print("Hero 3:", hero_3)

        session.commit()

        print("After committing the session")
        print("Hero 1:", hero_1)
        print("Hero 2:", hero_2)
        print("Hero 3:", hero_3)

        print("After committing the session, show IDs")
        print("Hero 1 ID:", hero_1.id)
        print("Hero 2 ID:", hero_2.id)
        print("Hero 3 ID:", hero_3.id)

        print("After committing the session, show names")
        print("Hero 1 name:", hero_1.name)
        print("Hero 2 name:", hero_2.name)
        print("Hero 3 name:", hero_3.name)

        session.refresh(hero_1)
        session.refresh(hero_2)
        session.refresh(hero_3)

        print("After refreshing the heroes")
        print("Hero 1:", hero_1)
        print("Hero 2:", hero_2)
        print("Hero 3:", hero_3)

    print("After the session closes")
    print("Hero 1:", hero_1)
    print("Hero 2:", hero_2)
    print("Hero 3:", hero_3)


def main():
    create_db_and_tables()
    create_heroes()


if __name__ == "__main__":
    main()
🤓 Andere Versionen und Varianten
from typing import Optional

from sqlmodel import Field, Session, SQLModel, create_engine


class Hero(SQLModel, table=True):
    id: Optional[int] = Field(default=None, primary_key=True)
    name: str
    secret_name: str
    age: Optional[int] = None


sqlite_file_name = "database.db"
sqlite_url = f"sqlite:///{sqlite_file_name}"

engine = create_engine(sqlite_url, echo=True)


def create_db_and_tables():
    SQLModel.metadata.create_all(engine)


def create_heroes():
    hero_1 = Hero(name="Deadpond", secret_name="Dive Wilson")
    hero_2 = Hero(name="Spider-Boy", secret_name="Pedro Parqueador")
    hero_3 = Hero(name="Rusty-Man", secret_name="Tommy Sharp", age=48)

    print("Before interacting with the database")
    print("Hero 1:", hero_1)
    print("Hero 2:", hero_2)
    print("Hero 3:", hero_3)

    with Session(engine) as session:
        session.add(hero_1)
        session.add(hero_2)
        session.add(hero_3)

        print("After adding to the session")
        print("Hero 1:", hero_1)
        print("Hero 2:", hero_2)
        print("Hero 3:", hero_3)

        session.commit()

        print("After committing the session")
        print("Hero 1:", hero_1)
        print("Hero 2:", hero_2)
        print("Hero 3:", hero_3)

        print("After committing the session, show IDs")
        print("Hero 1 ID:", hero_1.id)
        print("Hero 2 ID:", hero_2.id)
        print("Hero 3 ID:", hero_3.id)

        print("After committing the session, show names")
        print("Hero 1 name:", hero_1.name)
        print("Hero 2 name:", hero_2.name)
        print("Hero 3 name:", hero_3.name)

        session.refresh(hero_1)
        session.refresh(hero_2)
        session.refresh(hero_3)

        print("After refreshing the heroes")
        print("Hero 1:", hero_1)
        print("Hero 2:", hero_2)
        print("Hero 3:", hero_3)

    print("After the session closes")
    print("Hero 1:", hero_1)
    print("Hero 2:", hero_2)
    print("Hero 3:", hero_3)


def main():
    create_db_and_tables()
    create_heroes()


if __name__ == "__main__":
    main()

Wenn Python diesen Code ausführt.

session.refresh(hero_1)

...geht die Session hin und lässt die Engine mit der Datenbank kommunizieren, um die aktuellen Daten für dieses Objekt hero_1 abzurufen, und dann legt die Session die Daten in das Objekt hero_1 und markiert es als "frisch" oder "nicht abgelaufen".

Hier sehen Sie, wie die Ausgabe aussehen würde.

$ python app.py

// Output above omitted 👆

// The first refresh
INFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age
FROM hero
WHERE hero.id = ?
INFO Engine [generated in 0.00024s] (1,)

// The second refresh
INFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age
FROM hero
WHERE hero.id = ?
INFO Engine [cached since 0.001487s ago] (2,)

// The third refresh
INFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age
FROM hero
WHERE hero.id = ?
INFO Engine [cached since 0.002377s ago] (3,)

// Now print the data, as it's already refreshed there's no need for the Session to go and refresh it again
After refreshing the heroes
Hero 1: age=None id=1 name='Deadpond' secret_name='Dive Wilson'
Hero 2: age=None id=2 name='Spider-Boy' secret_name='Pedro Parqueador'
Hero 3: age=48 id=3 name='Rusty-Man' secret_name='Tommy Sharp'

Dies könnte zum Beispiel nützlich sein, wenn Sie eine Web-API zum Erstellen von Helden entwickeln. Und sobald ein Held mit einigen Daten erstellt wurde, geben Sie ihn an den Client zurück.

Sie möchten kein Objekt zurückgeben, das leer aussieht, weil die automatische Magie zur Aktualisierung der Daten nicht ausgelöst wurde.

In diesem Fall könnten Sie ihn nach dem Committen des Objekts in der Datenbank mit der Session aktualisieren und ihn dann an den Client zurückgeben. Dies würde sicherstellen, dass das Objekt seine frischen Daten enthält.

Nun können wir als letztes Experiment auch Daten ausgeben, nachdem die Session geschlossen wurde.

Hier gibt es keine Überraschungen, es funktioniert immer noch.

# Code above omitted 👆

    with Session(engine) as session:
        session.add(hero_1)
        session.add(hero_2)
        session.add(hero_3)

        print("After adding to the session")
        print("Hero 1:", hero_1)
        print("Hero 2:", hero_2)
        print("Hero 3:", hero_3)

        session.commit()

        print("After committing the session")
        print("Hero 1:", hero_1)
        print("Hero 2:", hero_2)
        print("Hero 3:", hero_3)

        print("After committing the session, show IDs")
        print("Hero 1 ID:", hero_1.id)
        print("Hero 2 ID:", hero_2.id)
        print("Hero 3 ID:", hero_3.id)

        print("After committing the session, show names")
        print("Hero 1 name:", hero_1.name)
        print("Hero 2 name:", hero_2.name)
        print("Hero 3 name:", hero_3.name)

        session.refresh(hero_1)
        session.refresh(hero_2)
        session.refresh(hero_3)

        print("After refreshing the heroes")
        print("Hero 1:", hero_1)
        print("Hero 2:", hero_2)
        print("Hero 3:", hero_3)

    print("After the session closes")
    print("Hero 1:", hero_1)
    print("Hero 2:", hero_2)
    print("Hero 3:", hero_3)

# Code below omitted 👇
👀 Vorschau der vollständigen Datei
from sqlmodel import Field, Session, SQLModel, create_engine


class Hero(SQLModel, table=True):
    id: int | None = Field(default=None, primary_key=True)
    name: str
    secret_name: str
    age: int | None = None


sqlite_file_name = "database.db"
sqlite_url = f"sqlite:///{sqlite_file_name}"

engine = create_engine(sqlite_url, echo=True)


def create_db_and_tables():
    SQLModel.metadata.create_all(engine)


def create_heroes():
    hero_1 = Hero(name="Deadpond", secret_name="Dive Wilson")
    hero_2 = Hero(name="Spider-Boy", secret_name="Pedro Parqueador")
    hero_3 = Hero(name="Rusty-Man", secret_name="Tommy Sharp", age=48)

    print("Before interacting with the database")
    print("Hero 1:", hero_1)
    print("Hero 2:", hero_2)
    print("Hero 3:", hero_3)

    with Session(engine) as session:
        session.add(hero_1)
        session.add(hero_2)
        session.add(hero_3)

        print("After adding to the session")
        print("Hero 1:", hero_1)
        print("Hero 2:", hero_2)
        print("Hero 3:", hero_3)

        session.commit()

        print("After committing the session")
        print("Hero 1:", hero_1)
        print("Hero 2:", hero_2)
        print("Hero 3:", hero_3)

        print("After committing the session, show IDs")
        print("Hero 1 ID:", hero_1.id)
        print("Hero 2 ID:", hero_2.id)
        print("Hero 3 ID:", hero_3.id)

        print("After committing the session, show names")
        print("Hero 1 name:", hero_1.name)
        print("Hero 2 name:", hero_2.name)
        print("Hero 3 name:", hero_3.name)

        session.refresh(hero_1)
        session.refresh(hero_2)
        session.refresh(hero_3)

        print("After refreshing the heroes")
        print("Hero 1:", hero_1)
        print("Hero 2:", hero_2)
        print("Hero 3:", hero_3)

    print("After the session closes")
    print("Hero 1:", hero_1)
    print("Hero 2:", hero_2)
    print("Hero 3:", hero_3)


def main():
    create_db_and_tables()
    create_heroes()


if __name__ == "__main__":
    main()
🤓 Andere Versionen und Varianten
from typing import Optional

from sqlmodel import Field, Session, SQLModel, create_engine


class Hero(SQLModel, table=True):
    id: Optional[int] = Field(default=None, primary_key=True)
    name: str
    secret_name: str
    age: Optional[int] = None


sqlite_file_name = "database.db"
sqlite_url = f"sqlite:///{sqlite_file_name}"

engine = create_engine(sqlite_url, echo=True)


def create_db_and_tables():
    SQLModel.metadata.create_all(engine)


def create_heroes():
    hero_1 = Hero(name="Deadpond", secret_name="Dive Wilson")
    hero_2 = Hero(name="Spider-Boy", secret_name="Pedro Parqueador")
    hero_3 = Hero(name="Rusty-Man", secret_name="Tommy Sharp", age=48)

    print("Before interacting with the database")
    print("Hero 1:", hero_1)
    print("Hero 2:", hero_2)
    print("Hero 3:", hero_3)

    with Session(engine) as session:
        session.add(hero_1)
        session.add(hero_2)
        session.add(hero_3)

        print("After adding to the session")
        print("Hero 1:", hero_1)
        print("Hero 2:", hero_2)
        print("Hero 3:", hero_3)

        session.commit()

        print("After committing the session")
        print("Hero 1:", hero_1)
        print("Hero 2:", hero_2)
        print("Hero 3:", hero_3)

        print("After committing the session, show IDs")
        print("Hero 1 ID:", hero_1.id)
        print("Hero 2 ID:", hero_2.id)
        print("Hero 3 ID:", hero_3.id)

        print("After committing the session, show names")
        print("Hero 1 name:", hero_1.name)
        print("Hero 2 name:", hero_2.name)
        print("Hero 3 name:", hero_3.name)

        session.refresh(hero_1)
        session.refresh(hero_2)
        session.refresh(hero_3)

        print("After refreshing the heroes")
        print("Hero 1:", hero_1)
        print("Hero 2:", hero_2)
        print("Hero 3:", hero_3)

    print("After the session closes")
    print("Hero 1:", hero_1)
    print("Hero 2:", hero_2)
    print("Hero 3:", hero_3)


def main():
    create_db_and_tables()
    create_heroes()


if __name__ == "__main__":
    main()

Und die Ausgabe zeigt wieder dieselben Daten.

$ python app.py

// Output above omitted 👆

// By finishing the with block, the Session is closed, including a rollback of any pending transaction that could have been there and was not committed
INFO Engine ROLLBACK

// Then we print the data, it works normally
After the session closes
Hero 1: age=None id=1 name='Deadpond' secret_name='Dive Wilson'
Hero 2: age=None id=2 name='Spider-Boy' secret_name='Pedro Parqueador'
Hero 3: age=48 id=3 name='Rusty-Man' secret_name='Tommy Sharp'

Den gesamten Code überprüfen

Lassen Sie uns nun diesen gesamten Code noch einmal überprüfen.

Tipp

Jede der nummerierten Blasen zeigt, was jede Zeile in der Ausgabe drucken wird.

Und da wir die Engine mit echo=True erstellt haben, können wir sehen, welche SQL-Anweisungen bei jedem Schritt ausgeführt werden.

from sqlmodel import Field, Session, SQLModel, create_engine


class Hero(SQLModel, table=True):
    id: int | None = Field(default=None, primary_key=True)
    name: str
    secret_name: str
    age: int | None = None


sqlite_file_name = "database.db"
sqlite_url = f"sqlite:///{sqlite_file_name}"

engine = create_engine(sqlite_url, echo=True)


def create_db_and_tables():
    SQLModel.metadata.create_all(engine)


def create_heroes():
    hero_1 = Hero(name="Deadpond", secret_name="Dive Wilson")  # (1)!
    hero_2 = Hero(name="Spider-Boy", secret_name="Pedro Parqueador")  # (2)!
    hero_3 = Hero(name="Rusty-Man", secret_name="Tommy Sharp", age=48)  # (3)!

    print("Before interacting with the database")  # (4)!
    print("Hero 1:", hero_1)  # (5)!
    print("Hero 2:", hero_2)  # (6)!
    print("Hero 3:", hero_3)  # (7)!

    with Session(engine) as session:  # (8)!
        session.add(hero_1)  # (9)!
        session.add(hero_2)  # (10)!
        session.add(hero_3)  # (11)!

        print("After adding to the session")  # (12)!
        print("Hero 1:", hero_1)  # (13)!
        print("Hero 2:", hero_2)  # (14)!
        print("Hero 3:", hero_3)  # (15)!

        session.commit()  # (16)!

        print("After committing the session")  # (17)!
        print("Hero 1:", hero_1)  # (18)!
        print("Hero 2:", hero_2)  # (19)!
        print("Hero 3:", hero_3)  # (20)!

        print("After committing the session, show IDs")  # (21)!
        print("Hero 1 ID:", hero_1.id)  # (22)!
        print("Hero 2 ID:", hero_2.id)  # (23)!
        print("Hero 3 ID:", hero_3.id)  # (24)!

        print("After committing the session, show names")  # (25)!
        print("Hero 1 name:", hero_1.name)  # (26)!
        print("Hero 2 name:", hero_2.name)  # (27)!
        print("Hero 3 name:", hero_3.name)  # (28)!

        session.refresh(hero_1)  # (29)!
        session.refresh(hero_2)  # (30)!
        session.refresh(hero_3)  # (31)!

        print("After refreshing the heroes")  # (32)!
        print("Hero 1:", hero_1)  # (33)!
        print("Hero 2:", hero_2)  # (34)!
        print("Hero 3:", hero_3)  # (35)!
    # (36)!

    print("After the session closes")  # (37)!
    print("Hero 1:", hero_1)  # (38)!
    print("Hero 2:", hero_2)  # (39)!
    print("Hero 3:", hero_3)  # (40)!


def main():
    create_db_and_tables()
    create_heroes()


if __name__ == "__main__":
    main()
  1. Erstellen Sie die hero_1.

    Generiert keine Ausgabe..

  2. Erstellen Sie die hero_2.

    Generiert keine Ausgabe..

  3. Erstellen Sie die hero_3.

    Generiert keine Ausgabe..

  4. Geben Sie die Zeile "Vor der Interaktion mit der Datenbank" aus.

    Generiert die Ausgabe.

    Before interacting with the database
    
  5. Geben Sie hero_1 vor der Interaktion mit der Datenbank aus.

    Generiert die Ausgabe.

    Hero 1: id=None name='Deadpond' secret_name='Dive Wilson' age=None
    
  6. Geben Sie hero_2 vor der Interaktion mit der Datenbank aus.

    Generiert die Ausgabe.

    Hero 2: id=None name='Spider-Boy' secret_name='Pedro Parqueador' age=None
    
  7. Geben Sie hero_3 vor der Interaktion mit der Datenbank aus.

    Generiert die Ausgabe.

    Hero 3: id=None name='Rusty-Man' secret_name='Tommy Sharp' age=48
    
  8. Erstellen Sie die Session in einem with-Block.

    Generiert keine Ausgabe..

  9. Fügen Sie hero_1 zur Session hinzu.

    Dies speichert es noch nicht in der Datenbank.

    Generiert keine Ausgabe..

  10. Fügen Sie hero_2 zur Session hinzu.

    Dies speichert es noch nicht in der Datenbank.

    Generiert keine Ausgabe..

  11. Fügen Sie hero_3 zur Session hinzu.

    Dies speichert es noch nicht in der Datenbank.

    Generiert keine Ausgabe..

  12. Geben Sie die Zeile "Nach dem Hinzufügen zur Session" aus.

    Generiert die Ausgabe.

    After adding to the session
    
  13. Geben Sie hero_1 nach dem Hinzufügen zur Session aus.

    Es hat immer noch dieselben Daten, da noch keine Interaktion mit der Datenbank stattgefunden hat. Beachten Sie, dass die id immer noch None ist.

    Generiert die Ausgabe.

    Hero 1: id=None name='Deadpond' secret_name='Dive Wilson' age=None
    
  14. Geben Sie hero_2 nach dem Hinzufügen zur Session aus.

    Es hat immer noch dieselben Daten, da noch keine Interaktion mit der Datenbank stattgefunden hat. Beachten Sie, dass die id immer noch None ist.

    Generiert die Ausgabe.

    Hero 2: id=None name='Spider-Boy' secret_name='Pedro Parqueador' age=None
    
  15. Geben Sie hero_3 nach dem Hinzufügen zur Session aus.

    Es hat immer noch dieselben Daten, da noch keine Interaktion mit der Datenbank stattgefunden hat. Beachten Sie, dass die id immer noch None ist.

    Generiert die Ausgabe.

    Hero 3: id=None name='Rusty-Man' secret_name='Tommy Sharp' age=48
    
  16. committen Sie die Session.

    Dies speichert alle Daten in der Datenbank. Die Session verwendet die Engine, um viel SQL auszuführen.

    Generiert die Ausgabe.

    INFO Engine BEGIN (implicit)
    INFO Engine INSERT INTO hero (name, secret_name, age) VALUES (?, ?, ?)
    INFO Engine [generated in 0.00018s] ('Deadpond', 'Dive Wilson', None)
    INFO Engine INSERT INTO hero (name, secret_name, age) VALUES (?, ?, ?)
    INFO Engine [cached since 0.0008968s ago] ('Spider-Boy', 'Pedro Parqueador', None)
    INFO Engine INSERT INTO hero (name, secret_name, age) VALUES (?, ?, ?)
    INFO Engine [cached since 0.001143s ago] ('Rusty-Man', 'Tommy Sharp', 48)
    INFO Engine COMMIT
    
  17. Geben Sie die Zeile "Nach dem Committen der Session" aus.

    Generiert die Ausgabe.

    After committing the session
    
  18. Geben Sie hero_1 nach dem Committen der Session aus.

    Der hero_1 ist jetzt intern als abgelaufen markiert, und bis er aktualisiert wird, sieht es so aus, als ob er keine Daten enthielte.

    Generiert die Ausgabe.

    Hero 1:
    
  19. Geben Sie hero_2 nach dem Committen der Session aus.

    Der hero_2 ist jetzt intern als abgelaufen markiert, und bis er aktualisiert wird, sieht es so aus, als ob er keine Daten enthielte.

    Generiert die Ausgabe.

    Hero 2:
    
  20. Geben Sie hero_3 nach dem Committen der Session aus.

    Der hero_3 ist jetzt intern als abgelaufen markiert, und bis er aktualisiert wird, sieht es so aus, als ob er keine Daten enthielte.

    Generiert die Ausgabe.

    Hero 3:
    
  21. Geben Sie die Zeile "Nach dem Committen der Session, IDs anzeigen" aus.

    Generiert die Ausgabe.

    After committing the session, show IDs
    
  22. Geben Sie hero_1.id aus. Hier passiert viel.

    Da wir auf das Attribut id von hero_1 zugreifen, kann SQLModel (eigentlich SQLAlchemy) erkennen, dass wir versuchen, auf Daten von hero_1 zuzugreifen.

    Es erkennt dann, dass hero_1 derzeit mit einer Session verbunden ist (da wir es zur Session hinzugefügt und committet haben) und als abgelaufen markiert ist.

    Dann verwendet es mit der Session die Engine, um alle SQL auszuführen, um die Daten für dieses Objekt aus der Datenbank abzurufen.

    Als Nächstes aktualisiert es das Objekt mit den neuen Daten und markiert es intern als "frisch" oder "nicht abgelaufen".

    Schließlich macht es den ID-Wert für den Rest des Python-Ausdrucks verfügbar. In diesem Fall gibt der Python-Ausdruck einfach die ID aus.

    Generiert die Ausgabe.

    INFO Engine BEGIN (implicit)
    INFO Engine SELECT hero.id AS hero_id, hero.name AS hero_name, hero.secret_name AS hero_secret_name, hero.age AS hero_age
    FROM hero
    WHERE hero.id = ?
    INFO Engine [generated in 0.00017s] (1,)
    
    Hero 1 ID: 1
    
  23. Geben Sie hero_2.id aus.

    Hier passiert viel, all die gleichen Dinge, die an Punkt 22 passiert sind, aber für dieses hero_2-Objekt.

    Generiert die Ausgabe.

    INFO Engine SELECT hero.id AS hero_id, hero.name AS hero_name, hero.secret_name AS hero_secret_name, hero.age AS hero_age
    FROM hero
    WHERE hero.id = ?
    INFO Engine [cached since 0.001245s ago] (2,)
    
    Hero 2 ID: 2
    
  24. Geben Sie hero_3.id aus.

    Hier passiert viel, all die gleichen Dinge, die an Punkt 22 passiert sind, aber für dieses hero_3-Objekt.

    Generiert die Ausgabe.

    INFO Engine SELECT hero.id AS hero_id, hero.name AS hero_name, hero.secret_name AS hero_secret_name, hero.age AS hero_age
    FROM hero
    WHERE hero.id = ?
    INFO Engine [cached since 0.002215s ago] (3,)
    
    
    Hero 3 ID: 3
    
  25. Geben Sie die Zeile "Nach dem Committen der Session, Namen anzeigen" aus.

    Generiert die Ausgabe.

    After committing the session, show names
    
  26. Geben Sie hero_1.name aus.

    Da hero_1 immer noch frisch ist, werden keine zusätzlichen Daten abgerufen, keine zusätzlichen SQL-Abfragen ausgeführt, und der Name ist verfügbar.

    Generiert die Ausgabe.

    Hero 1 name: Deadpond
    
  27. Geben Sie hero_2.name aus.

    Da hero_2 immer noch frisch ist, werden keine zusätzlichen Daten abgerufen, keine zusätzlichen SQL-Abfragen ausgeführt, und der Name ist verfügbar.

    Generiert die Ausgabe.

    Hero 2 name: Spider-Boy
    
  28. Geben Sie hero_3.name aus.

    Da hero_3 immer noch frisch ist, werden keine zusätzlichen Daten abgerufen, keine zusätzlichen SQL-Abfragen ausgeführt, und der Name ist verfügbar.

    Generiert die Ausgabe.

    Hero 3 name: Rusty-Man
    
  29. Aktualisieren Sie das Objekt hero_1 explizit.

    Die Session verwendet die Engine, um die notwendige SQL-Abfrage auszuführen, um frische Daten aus der Datenbank für das Objekt hero_1 abzurufen.

    Generiert die Ausgabe.

    INFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age
    FROM hero
    WHERE hero.id = ?
    INFO Engine [generated in 0.00024s] (1,)
    
  30. Aktualisieren Sie das Objekt hero_2 explizit.

    Die Session verwendet die Engine, um die notwendige SQL-Abfrage auszuführen, um frische Daten aus der Datenbank für das Objekt hero_2 abzurufen.

    Generiert die Ausgabe.

    INFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age
    FROM hero
    WHERE hero.id = ?
    INFO Engine [cached since 0.001487s ago] (2,)
    
  31. Aktualisieren Sie das Objekt hero_3 explizit.

    Die Session verwendet die Engine, um die notwendige SQL-Abfrage auszuführen, um frische Daten aus der Datenbank für das Objekt hero_3 abzurufen.

    Generiert die Ausgabe.

    INFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age
    FROM hero
    WHERE hero.id = ?
    INFO Engine [cached since 0.002377s ago] (3,)
    
  32. Geben Sie die Zeile "Nach dem Aktualisieren der Helden" aus.

    Generiert die Ausgabe.

    After refreshing the heroes
    
  33. Geben Sie hero_1 aus.

    Info

    Selbst wenn hero_1 nicht frisch wäre, würde dies keine refresh auslösen, die es der Session ermöglicht, die Engine zu verwenden, um Daten aus der Datenbank abzurufen, da kein Attribut aufgerufen wird.

    Da hero_1 frisch ist, sind alle seine Daten verfügbar.

    Generiert die Ausgabe.

    Hero 1: age=None id=1 name='Deadpond' secret_name='Dive Wilson'
    
  34. Geben Sie hero_2 aus.

    Info

    Selbst wenn hero_2 nicht frisch wäre, würde dies keine refresh auslösen, die es der Session ermöglicht, die Engine zu verwenden, um Daten aus der Datenbank abzurufen, da kein Attribut aufgerufen wird.

    Da hero_2 frisch ist, sind alle seine Daten verfügbar.

    Generiert die Ausgabe.

    Hero 2: age=None id=2 name='Spider-Boy' secret_name='Pedro Parqueador'
    
  35. Geben Sie hero_3 aus.

    Info

    Selbst wenn hero_3 nicht frisch wäre, würde dies keine refresh auslösen, die es der Session ermöglicht, die Engine zu verwenden, um Daten aus der Datenbank abzurufen, da kein Attribut aufgerufen wird.

    Da hero_3 frisch ist, sind alle seine Daten verfügbar.

    Generiert die Ausgabe.

    Hero 3: age=48 id=3 name='Rusty-Man' secret_name='Tommy Sharp'
    
  36. Der with-Block endet hier (es gibt keinen weiteren eingerückten Code), daher wird die Session geschlossen und ihr Schließungscode ausgeführt.

    Dies beinhaltet die Ausführung eines ROLLBACKs aller möglichen Transaktionen, die möglicherweise gestartet wurden.

    Generiert die Ausgabe.

    INFO Engine ROLLBACK
    
  37. Geben Sie die Zeile "Nach dem Schließen der Session" aus.

    Generiert die Ausgabe.

    After the session closes
    
  38. Geben Sie hero_1 nach dem Schließen der Session aus.

    Generiert die Ausgabe.

    Hero 1: age=None id=1 name='Deadpond' secret_name='Dive Wilson'
    
  39. Geben Sie hero_2 nach dem Schließen der Session aus.

    Generiert die Ausgabe.

    Hero 2: age=None id=2 name='Spider-Boy' secret_name='Pedro Parqueador'
    
  40. Geben Sie hero_3 nach dem Schließen der Session aus.

    Generiert die Ausgabe.

    Hero 3: age=48 id=3 name='Rusty-Man' secret_name='Tommy Sharp'
    
from typing import Optional

from sqlmodel import Field, Session, SQLModel, create_engine


class Hero(SQLModel, table=True):
    id: Optional[int] = Field(default=None, primary_key=True)
    name: str
    secret_name: str
    age: Optional[int] = None


sqlite_file_name = "database.db"
sqlite_url = f"sqlite:///{sqlite_file_name}"

engine = create_engine(sqlite_url, echo=True)


def create_db_and_tables():
    SQLModel.metadata.create_all(engine)


def create_heroes():
    hero_1 = Hero(name="Deadpond", secret_name="Dive Wilson")  # (1)!
    hero_2 = Hero(name="Spider-Boy", secret_name="Pedro Parqueador")  # (2)!
    hero_3 = Hero(name="Rusty-Man", secret_name="Tommy Sharp", age=48)  # (3)!

    print("Before interacting with the database")  # (4)!
    print("Hero 1:", hero_1)  # (5)!
    print("Hero 2:", hero_2)  # (6)!
    print("Hero 3:", hero_3)  # (7)!

    with Session(engine) as session:  # (8)!
        session.add(hero_1)  # (9)!
        session.add(hero_2)  # (10)!
        session.add(hero_3)  # (11)!

        print("After adding to the session")  # (12)!
        print("Hero 1:", hero_1)  # (13)!
        print("Hero 2:", hero_2)  # (14)!
        print("Hero 3:", hero_3)  # (15)!

        session.commit()  # (16)!

        print("After committing the session")  # (17)!
        print("Hero 1:", hero_1)  # (18)!
        print("Hero 2:", hero_2)  # (19)!
        print("Hero 3:", hero_3)  # (20)!

        print("After committing the session, show IDs")  # (21)!
        print("Hero 1 ID:", hero_1.id)  # (22)!
        print("Hero 2 ID:", hero_2.id)  # (23)!
        print("Hero 3 ID:", hero_3.id)  # (24)!

        print("After committing the session, show names")  # (25)!
        print("Hero 1 name:", hero_1.name)  # (26)!
        print("Hero 2 name:", hero_2.name)  # (27)!
        print("Hero 3 name:", hero_3.name)  # (28)!

        session.refresh(hero_1)  # (29)!
        session.refresh(hero_2)  # (30)!
        session.refresh(hero_3)  # (31)!

        print("After refreshing the heroes")  # (32)!
        print("Hero 1:", hero_1)  # (33)!
        print("Hero 2:", hero_2)  # (34)!
        print("Hero 3:", hero_3)  # (35)!
    # (36)!

    print("After the session closes")  # (37)!
    print("Hero 1:", hero_1)  # (38)!
    print("Hero 2:", hero_2)  # (39)!
    print("Hero 3:", hero_3)  # (40)!


def main():
    create_db_and_tables()
    create_heroes()


if __name__ == "__main__":
    main()
  1. Erstellen Sie die hero_1.

    Generiert keine Ausgabe..

  2. Erstellen Sie die hero_2.

    Generiert keine Ausgabe..

  3. Erstellen Sie die hero_3.

    Generiert keine Ausgabe..

  4. Geben Sie die Zeile "Vor der Interaktion mit der Datenbank" aus.

    Generiert die Ausgabe.

    Before interacting with the database
    
  5. Geben Sie hero_1 vor der Interaktion mit der Datenbank aus.

    Generiert die Ausgabe.

    Hero 1: id=None name='Deadpond' secret_name='Dive Wilson' age=None
    
  6. Geben Sie hero_2 vor der Interaktion mit der Datenbank aus.

    Generiert die Ausgabe.

    Hero 2: id=None name='Spider-Boy' secret_name='Pedro Parqueador' age=None
    
  7. Geben Sie hero_3 vor der Interaktion mit der Datenbank aus.

    Generiert die Ausgabe.

    Hero 3: id=None name='Rusty-Man' secret_name='Tommy Sharp' age=48
    
  8. Erstellen Sie die Session in einem with-Block.

    Generiert keine Ausgabe..

  9. Fügen Sie hero_1 zur Session hinzu.

    Dies speichert es noch nicht in der Datenbank.

    Generiert keine Ausgabe..

  10. Fügen Sie hero_2 zur Session hinzu.

    Dies speichert es noch nicht in der Datenbank.

    Generiert keine Ausgabe..

  11. Fügen Sie hero_3 zur Session hinzu.

    Dies speichert es noch nicht in der Datenbank.

    Generiert keine Ausgabe..

  12. Geben Sie die Zeile "Nach dem Hinzufügen zur Session" aus.

    Generiert die Ausgabe.

    After adding to the session
    
  13. Geben Sie hero_1 nach dem Hinzufügen zur Session aus.

    Es hat immer noch dieselben Daten, da noch keine Interaktion mit der Datenbank stattgefunden hat. Beachten Sie, dass die id immer noch None ist.

    Generiert die Ausgabe.

    Hero 1: id=None name='Deadpond' secret_name='Dive Wilson' age=None
    
  14. Geben Sie hero_2 nach dem Hinzufügen zur Session aus.

    Es hat immer noch dieselben Daten, da noch keine Interaktion mit der Datenbank stattgefunden hat. Beachten Sie, dass die id immer noch None ist.

    Generiert die Ausgabe.

    Hero 2: id=None name='Spider-Boy' secret_name='Pedro Parqueador' age=None
    
  15. Geben Sie hero_3 nach dem Hinzufügen zur Session aus.

    Es hat immer noch dieselben Daten, da noch keine Interaktion mit der Datenbank stattgefunden hat. Beachten Sie, dass die id immer noch None ist.

    Generiert die Ausgabe.

    Hero 3: id=None name='Rusty-Man' secret_name='Tommy Sharp' age=48
    
  16. committen Sie die Session.

    Dies speichert alle Daten in der Datenbank. Die Session verwendet die Engine, um viel SQL auszuführen.

    Generiert die Ausgabe.

    INFO Engine BEGIN (implicit)
    INFO Engine INSERT INTO hero (name, secret_name, age) VALUES (?, ?, ?)
    INFO Engine [generated in 0.00018s] ('Deadpond', 'Dive Wilson', None)
    INFO Engine INSERT INTO hero (name, secret_name, age) VALUES (?, ?, ?)
    INFO Engine [cached since 0.0008968s ago] ('Spider-Boy', 'Pedro Parqueador', None)
    INFO Engine INSERT INTO hero (name, secret_name, age) VALUES (?, ?, ?)
    INFO Engine [cached since 0.001143s ago] ('Rusty-Man', 'Tommy Sharp', 48)
    INFO Engine COMMIT
    
  17. Geben Sie die Zeile "Nach dem Committen der Session" aus.

    Generiert die Ausgabe.

    After committing the session
    
  18. Geben Sie hero_1 nach dem Committen der Session aus.

    Der hero_1 ist jetzt intern als abgelaufen markiert, und bis er aktualisiert wird, sieht es so aus, als ob er keine Daten enthielte.

    Generiert die Ausgabe.

    Hero 1:
    
  19. Geben Sie hero_2 nach dem Committen der Session aus.

    Der hero_2 ist jetzt intern als abgelaufen markiert, und bis er aktualisiert wird, sieht es so aus, als ob er keine Daten enthielte.

    Generiert die Ausgabe.

    Hero 2:
    
  20. Geben Sie hero_3 nach dem Committen der Session aus.

    Der hero_3 ist jetzt intern als abgelaufen markiert, und bis er aktualisiert wird, sieht es so aus, als ob er keine Daten enthielte.

    Generiert die Ausgabe.

    Hero 3:
    
  21. Geben Sie die Zeile "Nach dem Committen der Session, IDs anzeigen" aus.

    Generiert die Ausgabe.

    After committing the session, show IDs
    
  22. Geben Sie hero_1.id aus. Hier passiert viel.

    Da wir auf das Attribut id von hero_1 zugreifen, kann SQLModel (eigentlich SQLAlchemy) erkennen, dass wir versuchen, auf Daten von hero_1 zuzugreifen.

    Es erkennt dann, dass hero_1 derzeit mit einer Session verbunden ist (da wir es zur Session hinzugefügt und committet haben) und als abgelaufen markiert ist.

    Dann verwendet es mit der Session die Engine, um alle SQL auszuführen, um die Daten für dieses Objekt aus der Datenbank abzurufen.

    Als Nächstes aktualisiert es das Objekt mit den neuen Daten und markiert es intern als "frisch" oder "nicht abgelaufen".

    Schließlich macht es den ID-Wert für den Rest des Python-Ausdrucks verfügbar. In diesem Fall gibt der Python-Ausdruck einfach die ID aus.

    Generiert die Ausgabe.

    INFO Engine BEGIN (implicit)
    INFO Engine SELECT hero.id AS hero_id, hero.name AS hero_name, hero.secret_name AS hero_secret_name, hero.age AS hero_age
    FROM hero
    WHERE hero.id = ?
    INFO Engine [generated in 0.00017s] (1,)
    
    Hero 1 ID: 1
    
  23. Geben Sie hero_2.id aus.

    Hier passiert viel, all die gleichen Dinge, die an Punkt 22 passiert sind, aber für dieses hero_2-Objekt.

    Generiert die Ausgabe.

    INFO Engine SELECT hero.id AS hero_id, hero.name AS hero_name, hero.secret_name AS hero_secret_name, hero.age AS hero_age
    FROM hero
    WHERE hero.id = ?
    INFO Engine [cached since 0.001245s ago] (2,)
    
    Hero 2 ID: 2
    
  24. Geben Sie hero_3.id aus.

    Hier passiert viel, all die gleichen Dinge, die an Punkt 22 passiert sind, aber für dieses hero_3-Objekt.

    Generiert die Ausgabe.

    INFO Engine SELECT hero.id AS hero_id, hero.name AS hero_name, hero.secret_name AS hero_secret_name, hero.age AS hero_age
    FROM hero
    WHERE hero.id = ?
    INFO Engine [cached since 0.002215s ago] (3,)
    
    
    Hero 3 ID: 3
    
  25. Geben Sie die Zeile "Nach dem Committen der Session, Namen anzeigen" aus.

    Generiert die Ausgabe.

    After committing the session, show names
    
  26. Geben Sie hero_1.name aus.

    Da hero_1 immer noch frisch ist, werden keine zusätzlichen Daten abgerufen, keine zusätzlichen SQL-Abfragen ausgeführt, und der Name ist verfügbar.

    Generiert die Ausgabe.

    Hero 1 name: Deadpond
    
  27. Geben Sie hero_2.name aus.

    Da hero_2 immer noch frisch ist, werden keine zusätzlichen Daten abgerufen, keine zusätzlichen SQL-Abfragen ausgeführt, und der Name ist verfügbar.

    Generiert die Ausgabe.

    Hero 2 name: Spider-Boy
    
  28. Geben Sie hero_3.name aus.

    Da hero_3 immer noch frisch ist, werden keine zusätzlichen Daten abgerufen, keine zusätzlichen SQL-Abfragen ausgeführt, und der Name ist verfügbar.

    Generiert die Ausgabe.

    Hero 3 name: Rusty-Man
    
  29. Aktualisieren Sie das Objekt hero_1 explizit.

    Die Session verwendet die Engine, um die notwendige SQL-Abfrage auszuführen, um frische Daten aus der Datenbank für das Objekt hero_1 abzurufen.

    Generiert die Ausgabe.

    INFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age
    FROM hero
    WHERE hero.id = ?
    INFO Engine [generated in 0.00024s] (1,)
    
  30. Aktualisieren Sie das Objekt hero_2 explizit.

    Die Session verwendet die Engine, um die notwendige SQL-Abfrage auszuführen, um frische Daten aus der Datenbank für das Objekt hero_2 abzurufen.

    Generiert die Ausgabe.

    INFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age
    FROM hero
    WHERE hero.id = ?
    INFO Engine [cached since 0.001487s ago] (2,)
    
  31. Aktualisieren Sie das Objekt hero_3 explizit.

    Die Session verwendet die Engine, um die notwendige SQL-Abfrage auszuführen, um frische Daten aus der Datenbank für das Objekt hero_3 abzurufen.

    Generiert die Ausgabe.

    INFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age
    FROM hero
    WHERE hero.id = ?
    INFO Engine [cached since 0.002377s ago] (3,)
    
  32. Geben Sie die Zeile "Nach dem Aktualisieren der Helden" aus.

    Generiert die Ausgabe.

    After refreshing the heroes
    
  33. Geben Sie hero_1 aus.

    Info

    Selbst wenn hero_1 nicht frisch wäre, würde dies keine refresh auslösen, die es der Session ermöglicht, die Engine zu verwenden, um Daten aus der Datenbank abzurufen, da kein Attribut aufgerufen wird.

    Da hero_1 frisch ist, sind alle seine Daten verfügbar.

    Generiert die Ausgabe.

    Hero 1: age=None id=1 name='Deadpond' secret_name='Dive Wilson'
    
  34. Geben Sie hero_2 aus.

    Info

    Selbst wenn hero_2 nicht frisch wäre, würde dies keine refresh auslösen, die es der Session ermöglicht, die Engine zu verwenden, um Daten aus der Datenbank abzurufen, da kein Attribut aufgerufen wird.

    Da hero_2 frisch ist, sind alle seine Daten verfügbar.

    Generiert die Ausgabe.

    Hero 2: age=None id=2 name='Spider-Boy' secret_name='Pedro Parqueador'
    
  35. Geben Sie hero_3 aus.

    Info

    Selbst wenn hero_3 nicht frisch wäre, würde dies keine refresh auslösen, die es der Session ermöglicht, die Engine zu verwenden, um Daten aus der Datenbank abzurufen, da kein Attribut aufgerufen wird.

    Da hero_3 frisch ist, sind alle seine Daten verfügbar.

    Generiert die Ausgabe.

    Hero 3: age=48 id=3 name='Rusty-Man' secret_name='Tommy Sharp'
    
  36. Der with-Block endet hier (es gibt keinen weiteren eingerückten Code), daher wird die Session geschlossen und ihr Schließungscode ausgeführt.

    Dies beinhaltet die Ausführung eines ROLLBACKs aller möglichen Transaktionen, die möglicherweise gestartet wurden.

    Generiert die Ausgabe.

    INFO Engine ROLLBACK
    
  37. Geben Sie die Zeile "Nach dem Schließen der Session" aus.

    Generiert die Ausgabe.

    After the session closes
    
  38. Geben Sie hero_1 nach dem Schließen der Session aus.

    Generiert die Ausgabe.

    Hero 1: age=None id=1 name='Deadpond' secret_name='Dive Wilson'
    
  39. Geben Sie hero_2 nach dem Schließen der Session aus.

    Generiert die Ausgabe.

    Hero 2: age=None id=2 name='Spider-Boy' secret_name='Pedro Parqueador'
    
  40. Geben Sie hero_3 nach dem Schließen der Session aus.

    Generiert die Ausgabe.

    Hero 3: age=48 id=3 name='Rusty-Man' secret_name='Tommy Sharp'
    

Und hier ist die gesamte Ausgabe, die durch das Ausführen dieses Programms erzeugt wird, alles zusammen.

$ python app.py

INFO Engine BEGIN (implicit)
INFO Engine PRAGMA main.table_info("hero")
INFO Engine [raw sql] ()
INFO Engine PRAGMA temp.table_info("hero")
INFO Engine [raw sql] ()
INFO Engine
CREATE TABLE hero (
        id INTEGER,
        name VARCHAR NOT NULL,
        secret_name VARCHAR NOT NULL,
        age INTEGER,
        PRIMARY KEY (id)
)


INFO Engine [no key 0.00018s] ()
INFO Engine COMMIT
Before interacting with the database
Hero 1: id=None name='Deadpond' secret_name='Dive Wilson' age=None
Hero 2: id=None name='Spider-Boy' secret_name='Pedro Parqueador' age=None
Hero 3: id=None name='Rusty-Man' secret_name='Tommy Sharp' age=48
After adding to the session
Hero 1: id=None name='Deadpond' secret_name='Dive Wilson' age=None
Hero 2: id=None name='Spider-Boy' secret_name='Pedro Parqueador' age=None
Hero 3: id=None name='Rusty-Man' secret_name='Tommy Sharp' age=48
INFO Engine BEGIN (implicit)
INFO Engine INSERT INTO hero (name, secret_name, age) VALUES (?, ?, ?)
INFO Engine [generated in 0.00022s] ('Deadpond', 'Dive Wilson', None)
INFO Engine INSERT INTO hero (name, secret_name, age) VALUES (?, ?, ?)
INFO Engine [cached since 0.001127s ago] ('Spider-Boy', 'Pedro Parqueador', None)
INFO Engine INSERT INTO hero (name, secret_name, age) VALUES (?, ?, ?)
INFO Engine [cached since 0.001483s ago] ('Rusty-Man', 'Tommy Sharp', 48)
INFO Engine COMMIT
After committing the session
Hero 1:
Hero 2:
Hero 3:
After committing the session, show IDs
INFO Engine BEGIN (implicit)
INFO Engine SELECT hero.id AS hero_id, hero.name AS hero_name, hero.secret_name AS hero_secret_name, hero.age AS hero_age
FROM hero
WHERE hero.id = ?
INFO Engine [generated in 0.00029s] (1,)
Hero 1 ID: 1
INFO Engine SELECT hero.id AS hero_id, hero.name AS hero_name, hero.secret_name AS hero_secret_name, hero.age AS hero_age
FROM hero
WHERE hero.id = ?
INFO Engine [cached since 0.002132s ago] (2,)
Hero 2 ID: 2
INFO Engine SELECT hero.id AS hero_id, hero.name AS hero_name, hero.secret_name AS hero_secret_name, hero.age AS hero_age
FROM hero
WHERE hero.id = ?
INFO Engine [cached since 0.003367s ago] (3,)
Hero 3 ID: 3
After committing the session, show names
Hero 1 name: Deadpond
Hero 2 name: Spider-Boy
Hero 3 name: Rusty-Man
INFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age
FROM hero
WHERE hero.id = ?
INFO Engine [generated in 0.00025s] (1,)
INFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age
FROM hero
WHERE hero.id = ?
INFO Engine [cached since 0.001583s ago] (2,)
INFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age
FROM hero
WHERE hero.id = ?
INFO Engine [cached since 0.002722s ago] (3,)
After refreshing the heroes
Hero 1: age=None id=1 name='Deadpond' secret_name='Dive Wilson'
Hero 2: age=None id=2 name='Spider-Boy' secret_name='Pedro Parqueador'
Hero 3: age=48 id=3 name='Rusty-Man' secret_name='Tommy Sharp'
INFO Engine ROLLBACK
After the session closes
Hero 1: age=None id=1 name='Deadpond' secret_name='Dive Wilson'
Hero 2: age=None id=2 name='Spider-Boy' secret_name='Pedro Parqueador'
Hero 3: age=48 id=3 name='Rusty-Man' secret_name='Tommy Sharp'

Zusammenfassung

Sie haben das alles gelesen! Das war viel! Essen Sie ein Stück Kuchen, Sie haben es sich verdient. 🍰

Wir haben besprochen, wie die Session die Engine verwendet, um SQL an die Datenbank zu senden, um Daten zu erstellen und auch abzurufen. Wie sie "abgelaufene" und "frische" Daten verfolgt. Zu welchen Zeitpunkten sie automatisch Daten abruft (beim Zugriff auf Instanzattribute) und wie diese Daten zwischen Objekten im Speicher und der Datenbank über die Session synchronisiert werden.

Wenn Sie das alles verstanden haben, wissen Sie jetzt viel über SQLModel, SQLAlchemy und wie die Interaktionen von Python mit Datenbanken im Allgemeinen funktionieren.

Wenn Sie das nicht alles verstanden haben, ist das in Ordnung, Sie können jederzeit zurückkommen, um die Konzepte zu refreshen.

Ich glaube, dies könnte eine der Hauptarten von Fehlern sein, die Probleme verursachen und einen zum Nachdenken anregen. Also, gut gemacht, dass Sie sich damit beschäftigt haben! 💪