Daten lesen - SELECT¶
Wir haben bereits eine Datenbank und eine Tabelle mit einigen Daten darin, die ungefähr so aussieht
| id | name | secret_name | age |
|---|---|---|---|
| 1 | Deadpond | Dive Wilson | null |
| 2 | Spider-Boy | Pedro Parqueador | null |
| 3 | Rusty-Man | Tommy Sharp | 48 |
Die Dinge werden aufregender! Lassen Sie uns nun sehen, wie man Daten aus der Datenbank liest! 🤩
Fortfahren vom vorherigen Code¶
Wir machen mit dem letzten Code weiter, den wir verwendet haben, um einige Daten zu erstellen.
👀 Vorschau der gesamten 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)
with Session(engine) as session:
session.add(hero_1)
session.add(hero_2)
session.add(hero_3)
session.commit()
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)
with Session(engine) as session:
session.add(hero_1)
session.add(hero_2)
session.add(hero_3)
session.commit()
def main():
create_db_and_tables()
create_heroes()
if __name__ == "__main__":
main()
Wir erstellen ein SQLModel Hero-Klassenmodell und einige Datensätze.
Wir benötigen das Hero-Modell und die Engine, aber wir erstellen eine neue Sitzung, um Daten in einer neuen Funktion abzufragen.
Daten mit SQL lesen¶
Bevor wir Python-Code schreiben, werfen wir einen kurzen Blick darauf, wie das Abfragen von Daten mit SQL aussieht.
SELECT id, name, secret_name, age
FROM hero
Das bedeutet, mehr oder weniger
Hallo SQL-Datenbank 👋, bitte wähle einige Daten für mich aus.
Ich sage dir zuerst, welche Spalten ich möchte
idnamesecret_nameageUnd ich möchte, dass du sie aus der Tabelle namens
"hero"holst.
Dann geht die Datenbank die Daten abrufen und dir in einer Tabelle wie dieser zurückgeben.
| id | name | secret_name | age |
|---|---|---|---|
| 1 | Deadpond | Dive Wilson | null |
| 2 | Spider-Boy | Pedro Parqueador | null |
| 3 | Rusty-Man | Tommy Sharp | 48 |
Sie können das in DB Browser for SQLite ausprobieren.

Warnung
Hier holen wir alle Zeilen.
Wenn Sie Tausende von Zeilen haben, kann dies für die Datenbank teuer sein.
Normalerweise würden Sie die Zeilen filtern wollen, um nur die gewünschten zu erhalten. Aber das lernen wir später im nächsten Kapitel.
Eine SQL-Abkürzung¶
Wenn wir wie im obigen Fall alle Spalten abrufen möchten, gibt es in SQL eine Abkürzung: Anstatt jede einzelne Spalte anzugeben, könnten wir ein * schreiben.
SELECT *
FROM hero
Das würde zum selben Ergebnis führen. Obwohl wir das für SQLModel nicht verwenden werden.
SELECT Weniger Spalten¶
Wir können auch weniger Spalten auswählen, zum Beispiel
SELECT id, name
FROM hero
Hier wählen wir nur die Spalten id und name aus.
Und das würde zu einer Tabelle wie dieser führen.
| id | name |
|---|---|
| 1 | Deadpond |
| 2 | Spider-Boy |
| 3 | Rusty-Man |
Und hier gibt es etwas Interessantes zu beachten. SQL-Datenbanken speichern ihre Daten in Tabellen. Und sie kommunizieren ihre Ergebnisse immer in Tabellen.
SELECT Varianten¶
Die SQL-Sprache erlaubt an mehreren Stellen mehrere Varianten.
Eine dieser Varianten ist, dass Sie in SELECT-Anweisungen die Namen der Spalten direkt verwenden können, oder Sie können ihnen den Namen der Tabelle und einen Punkt voranstellen.
Zum Beispiel könnte derselbe SQL-Code wie oben geschrieben werden als
SELECT hero.id, hero.name, hero.secret_name, hero.age
FROM hero
Dies wird später besonders wichtig, wenn Sie gleichzeitig mit mehreren Tabellen arbeiten, die für einige Spalten den gleichen Namen haben könnten.
Zum Beispiel hero.id und team.id oder hero.name und team.name.
Eine weitere Variante ist, dass die meisten SQL-Schlüsselwörter wie SELECT auch in Kleinbuchstaben geschrieben werden können, wie select.
Ergebnistabellen müssen nicht existieren¶
Das ist der interessante Teil. Die von SQL-Datenbanken zurückgegebenen Tabellen müssen nicht als eigenständige Tabellen in der Datenbank existieren. 🧙
Zum Beispiel haben wir in unserer Datenbank nur eine Tabelle mit allen Spalten: id, name, secret_name, age. Und hier erhalten wir eine Ergebnistabelle mit weniger Spalten.
Einer der Hauptpunkte von SQL ist die Möglichkeit, die Daten in verschiedenen Tabellen strukturiert zu halten, ohne Daten zu wiederholen usw., und dann die Datenbank auf viele Arten abzufragen und viele verschiedene Tabellen als Ergebnis zu erhalten.
Daten mit SQLModel lesen¶
Lassen Sie uns nun dieselbe Abfrage ausführen, um alle Helden zu lesen, aber mit SQLModel.
Eine Session erstellen¶
Der erste Schritt ist die Erstellung einer Session, genauso wie wir es beim Erstellen der Zeilen getan haben.
Wir beginnen damit in einer neuen Funktion select_heroes().
# Code above omitted 👆
def select_heroes():
with Session(engine) as session:
# Code below omitted 👇
👀 Vorschau der gesamten Datei
from sqlmodel import Field, Session, SQLModel, create_engine, select
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)
with Session(engine) as session:
session.add(hero_1)
session.add(hero_2)
session.add(hero_3)
session.commit()
def select_heroes():
with Session(engine) as session:
statement = select(Hero)
results = session.exec(statement)
for hero in results:
print(hero)
def main():
create_db_and_tables()
create_heroes()
select_heroes()
if __name__ == "__main__":
main()
🤓 Andere Versionen und Varianten
from typing import Optional
from sqlmodel import Field, Session, SQLModel, create_engine, select
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)
with Session(engine) as session:
session.add(hero_1)
session.add(hero_2)
session.add(hero_3)
session.commit()
def select_heroes():
with Session(engine) as session:
statement = select(Hero)
results = session.exec(statement)
for hero in results:
print(hero)
def main():
create_db_and_tables()
create_heroes()
select_heroes()
if __name__ == "__main__":
main()
Eine select-Anweisung erstellen¶
Als Nächstes, ziemlich ähnlich wie wir oben eine SQL SELECT-Anweisung geschrieben haben, erstellen wir nun eine SQLModel select-Anweisung.
Zuerst müssen wir select von sqlmodel am Anfang der Datei importieren.
from sqlmodel import Field, Session, SQLModel, create_engine, select
# Code below omitted 👇
👀 Vorschau der gesamten Datei
from sqlmodel import Field, Session, SQLModel, create_engine, select
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)
with Session(engine) as session:
session.add(hero_1)
session.add(hero_2)
session.add(hero_3)
session.commit()
def select_heroes():
with Session(engine) as session:
statement = select(Hero)
results = session.exec(statement)
for hero in results:
print(hero)
def main():
create_db_and_tables()
create_heroes()
select_heroes()
if __name__ == "__main__":
main()
🤓 Andere Versionen und Varianten
from typing import Optional
from sqlmodel import Field, Session, SQLModel, create_engine, select
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)
with Session(engine) as session:
session.add(hero_1)
session.add(hero_2)
session.add(hero_3)
session.commit()
def select_heroes():
with Session(engine) as session:
statement = select(Hero)
results = session.exec(statement)
for hero in results:
print(hero)
def main():
create_db_and_tables()
create_heroes()
select_heroes()
if __name__ == "__main__":
main()
Und dann werden wir es verwenden, um eine SELECT-Anweisung in Python-Code zu erstellen.
from sqlmodel import Field, Session, SQLModel, create_engine, select
# Code here omitted 👈
def select_heroes():
with Session(engine) as session:
statement = select(Hero)
# Code below omitted 👇
👀 Vorschau der gesamten Datei
from sqlmodel import Field, Session, SQLModel, create_engine, select
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)
with Session(engine) as session:
session.add(hero_1)
session.add(hero_2)
session.add(hero_3)
session.commit()
def select_heroes():
with Session(engine) as session:
statement = select(Hero)
results = session.exec(statement)
for hero in results:
print(hero)
def main():
create_db_and_tables()
create_heroes()
select_heroes()
if __name__ == "__main__":
main()
🤓 Andere Versionen und Varianten
from typing import Optional
from sqlmodel import Field, Session, SQLModel, create_engine, select
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)
with Session(engine) as session:
session.add(hero_1)
session.add(hero_2)
session.add(hero_3)
session.commit()
def select_heroes():
with Session(engine) as session:
statement = select(Hero)
results = session.exec(statement)
for hero in results:
print(hero)
def main():
create_db_and_tables()
create_heroes()
select_heroes()
if __name__ == "__main__":
main()
Es ist eine sehr einfache Codezeile, die viele Informationen vermittelt.
statement = select(Hero)
Dies entspricht der ersten obigen SQL SELECT-Anweisung.
SELECT id, name, secret_name, age
FROM hero
Wir übergeben die Klassenmodell Hero an die Funktion select(). Und das sagt ihr, dass wir alle für die Klasse Hero notwendigen Spalten auswählen möchten.
Und beachten Sie, dass wir in der Funktion select() nicht explizit den FROM-Teil angeben. Für SQLModel (tatsächlich für SQLAlchemy) ist es bereits offensichtlich, dass wir FROM der Tabelle hero auswählen wollen, da dies diejenige ist, die mit dem Klassenmodell Hero verbunden ist.
Tipp
Der von select() zurückgegebene Wert von statement ist ein spezielles Objekt, das es uns ermöglicht, andere Dinge zu tun.
Das erzähle ich dir in den nächsten Kapiteln.
Die Anweisung ausführen¶
Jetzt, da wir die select-Anweisung haben, können wir sie mit der Session ausführen.
# Code above omitted 👆
def select_heroes():
with Session(engine) as session:
statement = select(Hero)
results = session.exec(statement)
# Code below omitted 👇
👀 Vorschau der gesamten Datei
from sqlmodel import Field, Session, SQLModel, create_engine, select
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)
with Session(engine) as session:
session.add(hero_1)
session.add(hero_2)
session.add(hero_3)
session.commit()
def select_heroes():
with Session(engine) as session:
statement = select(Hero)
results = session.exec(statement)
for hero in results:
print(hero)
def main():
create_db_and_tables()
create_heroes()
select_heroes()
if __name__ == "__main__":
main()
🤓 Andere Versionen und Varianten
from typing import Optional
from sqlmodel import Field, Session, SQLModel, create_engine, select
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)
with Session(engine) as session:
session.add(hero_1)
session.add(hero_2)
session.add(hero_3)
session.commit()
def select_heroes():
with Session(engine) as session:
statement = select(Hero)
results = session.exec(statement)
for hero in results:
print(hero)
def main():
create_db_and_tables()
create_heroes()
select_heroes()
if __name__ == "__main__":
main()
Dies weist die Session an, die Engine zu verwenden, um diese SELECT-Anweisung in der Datenbank auszuführen und die Ergebnisse zurückzubringen.
Da wir die Engine mit echo=True erstellt haben, wird die ausgeführte SQL in der Ausgabe angezeigt.
Dieses session.exec(statement) erzeugt diese Ausgabe.
INFO Engine BEGIN (implicit)
INFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age
FROM hero
INFO Engine [no key 0.00032s] ()
Die Datenbank gibt die Tabelle mit allen Daten zurück, genau wie oben, als wir SQL direkt geschrieben haben.
| id | name | secret_name | age |
|---|---|---|---|
| 1 | Deadpond | Dive Wilson | null |
| 2 | Spider-Boy | Pedro Parqueador | null |
| 3 | Rusty-Man | Tommy Sharp | 48 |
Die Ergebnisse durchlaufen¶
Das results-Objekt ist ein iterable, mit dem jede Zeile durchlaufen werden kann.
Nun können wir es in eine for-Schleife setzen und jeden der Helden ausgeben.
# Code above omitted 👆
def select_heroes():
with Session(engine) as session:
statement = select(Hero)
results = session.exec(statement)
for hero in results:
print(hero)
# Code below omitted 👇
👀 Vorschau der gesamten Datei
from sqlmodel import Field, Session, SQLModel, create_engine, select
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)
with Session(engine) as session:
session.add(hero_1)
session.add(hero_2)
session.add(hero_3)
session.commit()
def select_heroes():
with Session(engine) as session:
statement = select(Hero)
results = session.exec(statement)
for hero in results:
print(hero)
def main():
create_db_and_tables()
create_heroes()
select_heroes()
if __name__ == "__main__":
main()
🤓 Andere Versionen und Varianten
from typing import Optional
from sqlmodel import Field, Session, SQLModel, create_engine, select
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)
with Session(engine) as session:
session.add(hero_1)
session.add(hero_2)
session.add(hero_3)
session.commit()
def select_heroes():
with Session(engine) as session:
statement = select(Hero)
results = session.exec(statement)
for hero in results:
print(hero)
def main():
create_db_and_tables()
create_heroes()
select_heroes()
if __name__ == "__main__":
main()
Dies gibt die Ausgabe aus.
id=1 name='Deadpond' age=None secret_name='Dive Wilson'
id=2 name='Spider-Boy' age=None secret_name='Pedro Parqueador'
id=3 name='Rusty-Man' age=48 secret_name='Tommy Sharp'
select_heroes() zu main() hinzufügen¶
Fügen Sie nun einen Aufruf von select_heroes() in die Funktion main() ein, damit er ausgeführt wird, wenn wir das Programm von der Kommandozeile ausführen.
# Code above omitted 👆
def select_heroes():
with Session(engine) as session:
statement = select(Hero)
results = session.exec(statement)
for hero in results:
print(hero)
def main():
create_db_and_tables()
create_heroes()
select_heroes()
# Code below omitted 👇
👀 Vorschau der gesamten Datei
from sqlmodel import Field, Session, SQLModel, create_engine, select
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)
with Session(engine) as session:
session.add(hero_1)
session.add(hero_2)
session.add(hero_3)
session.commit()
def select_heroes():
with Session(engine) as session:
statement = select(Hero)
results = session.exec(statement)
for hero in results:
print(hero)
def main():
create_db_and_tables()
create_heroes()
select_heroes()
if __name__ == "__main__":
main()
🤓 Andere Versionen und Varianten
from typing import Optional
from sqlmodel import Field, Session, SQLModel, create_engine, select
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)
with Session(engine) as session:
session.add(hero_1)
session.add(hero_2)
session.add(hero_3)
session.commit()
def select_heroes():
with Session(engine) as session:
statement = select(Hero)
results = session.exec(statement)
for hero in results:
print(hero)
def main():
create_db_and_tables()
create_heroes()
select_heroes()
if __name__ == "__main__":
main()
Den Code überprüfen¶
Großartig, Sie können jetzt Daten aus der Datenbank lesen! 🎉
Lassen Sie uns den bisherigen Code überprüfen.
from sqlmodel import Field, Session, SQLModel, create_engine, select # (1)!
class Hero(SQLModel, table=True): # (2)!
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) # (3)!
def create_db_and_tables():
SQLModel.metadata.create_all(engine) # (4)!
def create_heroes():
hero_1 = Hero(name="Deadpond", secret_name="Dive Wilson") # (5)!
hero_2 = Hero(name="Spider-Boy", secret_name="Pedro Parqueador")
hero_3 = Hero(name="Rusty-Man", secret_name="Tommy Sharp", age=48)
with Session(engine) as session: # (6)!
session.add(hero_1)
session.add(hero_2)
session.add(hero_3)
session.commit()
def select_heroes():
with Session(engine) as session: # (7)!
statement = select(Hero) # (8)!
results = session.exec(statement) # (9)!
for hero in results: # (10)!
print(hero) # (11)!
# (12)!
def main():
create_db_and_tables()
create_heroes()
select_heroes() # (13)!
if __name__ == "__main__":
main()
-
Importieren Sie von
sqlmodelalles, was wir verwenden werden, einschließlich der neuen Funktionselect(). -
Erstellen Sie das
Hero-Klassenmodell, das die Tabelleherorepräsentiert. -
Erstellen Sie die Engine. Wir sollten eine einzige verwenden, die von der gesamten Anwendungslogik geteilt wird, und das tun wir hier.
-
Erstellen Sie alle Tabellen für die Modelle, die in
SQLModel.metadataregistriert sind.Dies erstellt auch die Datenbank, falls sie noch nicht existiert.
-
Erstellen Sie jeden der
Hero-Objekte.Sie haben dies möglicherweise nicht in Ihrer Version, wenn Sie die Daten bereits in der Datenbank erstellt haben.
-
Erstellen Sie eine neue Session und verwenden Sie sie, um die Helden zur Datenbank hinzuzufügen und dann die Änderungen zu
commiten. -
Erstellen Sie eine neue Session, um Daten abzufragen.
Tipp
Beachten Sie, dass dies eine neue Session ist, die unabhängig von der anderen Funktion oben ist.
Sie verwendet jedoch immer noch dieselbe Engine. Wir haben immer noch eine Engine für die gesamte Anwendung.
-
Verwenden Sie die Funktion
select(), um eine Anweisung zu erstellen, die alleHero-Objekte auswählt.Dies wählt alle Zeilen in der Tabelle
heroaus. -
Verwenden Sie
session.exec(statement), um die Session die Engine verwenden zu lassen, um die interne SQL-Anweisung auszuführen.Dies geht zur Datenbank, führt das SQL aus und holt die Ergebnisse zurück.
Es gibt ein spezielles iterierbares Objekt zurück, das wir der Variablen
resultszuweisen.Dies erzeugt die Ausgabe.
INFO Engine BEGIN (implicit) INFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age FROM hero INFO Engine [no key 0.00032s] () -
Iterieren Sie für jedes
Hero-Objekt in denresults. -
Geben Sie jeden
heroaus.Die 3 Iterationen in der
for-Schleife erzeugen diese Ausgabe.id=1 name='Deadpond' age=None secret_name='Dive Wilson' id=2 name='Spider-Boy' age=None secret_name='Pedro Parqueador' id=3 name='Rusty-Man' age=48 secret_name='Tommy Sharp' -
Zu diesem Zeitpunkt, nach dem
with-Block, wird die Session geschlossen.Dies erzeugt die Ausgabe.
INFO Engine ROLLBACK -
Fügen Sie diese Funktion
select_heroes()zur Funktionmain()hinzu, damit sie aufgerufen wird, wenn wir dieses Programm von der Kommandozeile ausführen.
from typing import Optional
from sqlmodel import Field, Session, SQLModel, create_engine, select # (1)!
class Hero(SQLModel, table=True): # (2)!
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) # (3)!
def create_db_and_tables():
SQLModel.metadata.create_all(engine) # (4)!
def create_heroes():
hero_1 = Hero(name="Deadpond", secret_name="Dive Wilson") # (5)!
hero_2 = Hero(name="Spider-Boy", secret_name="Pedro Parqueador")
hero_3 = Hero(name="Rusty-Man", secret_name="Tommy Sharp", age=48)
with Session(engine) as session: # (6)!
session.add(hero_1)
session.add(hero_2)
session.add(hero_3)
session.commit()
def select_heroes():
with Session(engine) as session: # (7)!
statement = select(Hero) # (8)!
results = session.exec(statement) # (9)!
for hero in results: # (10)!
print(hero) # (11)!
# (12)!
def main():
create_db_and_tables()
create_heroes()
select_heroes() # (13)!
if __name__ == "__main__":
main()
-
Importieren Sie von
sqlmodelalles, was wir verwenden werden, einschließlich der neuen Funktionselect(). -
Erstellen Sie das
Hero-Klassenmodell, das die Tabelleherorepräsentiert. -
Erstellen Sie die Engine. Wir sollten eine einzige verwenden, die von der gesamten Anwendungslogik geteilt wird, und das tun wir hier.
-
Erstellen Sie alle Tabellen für die Modelle, die in
SQLModel.metadataregistriert sind.Dies erstellt auch die Datenbank, falls sie noch nicht existiert.
-
Erstellen Sie jeden der
Hero-Objekte.Sie haben dies möglicherweise nicht in Ihrer Version, wenn Sie die Daten bereits in der Datenbank erstellt haben.
-
Erstellen Sie eine neue Session und verwenden Sie sie, um die Helden zur Datenbank hinzuzufügen und dann die Änderungen zu
commiten. -
Erstellen Sie eine neue Session, um Daten abzufragen.
Tipp
Beachten Sie, dass dies eine neue Session ist, die unabhängig von der anderen Funktion oben ist.
Sie verwendet jedoch immer noch dieselbe Engine. Wir haben immer noch eine Engine für die gesamte Anwendung.
-
Verwenden Sie die Funktion
select(), um eine Anweisung zu erstellen, die alleHero-Objekte auswählt.Dies wählt alle Zeilen in der Tabelle
heroaus. -
Verwenden Sie
session.exec(statement), um die Session die Engine verwenden zu lassen, um die interne SQL-Anweisung auszuführen.Dies geht zur Datenbank, führt das SQL aus und holt die Ergebnisse zurück.
Es gibt ein spezielles iterierbares Objekt zurück, das wir der Variablen
resultszuweisen.Dies erzeugt die Ausgabe.
INFO Engine BEGIN (implicit) INFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age FROM hero INFO Engine [no key 0.00032s] () -
Iterieren Sie für jedes
Hero-Objekt in denresults. -
Geben Sie jeden
heroaus.Die 3 Iterationen in der
for-Schleife erzeugen diese Ausgabe.id=1 name='Deadpond' age=None secret_name='Dive Wilson' id=2 name='Spider-Boy' age=None secret_name='Pedro Parqueador' id=3 name='Rusty-Man' age=48 secret_name='Tommy Sharp' -
Zu diesem Zeitpunkt, nach dem
with-Block, wird die Session geschlossen.Dies erzeugt die Ausgabe.
INFO Engine ROLLBACK -
Fügen Sie diese Funktion
select_heroes()zur Funktionmain()hinzu, damit sie aufgerufen wird, wenn wir dieses Programm von der Kommandozeile ausführen.
Tipp
Schauen Sie sich die Nummernblasen an, um zu sehen, was jede Codezeile bewirkt.
Hier wird deutlicher, warum wir eine einzige Engine für die gesamte Anwendung haben sollten, aber verschiedene Sessions für jede Gruppe von Operationen.
Diese neue Sitzung, die wir erstellt haben, verwendet dieselbe Engine, ist aber eine neue und unabhängige Session.
Der obige Code zum Erstellen der Modelle könnte zum Beispiel in einer Funktion leben, die Web-API-Anfragen bearbeitet und Modelle erstellt.
Und der zweite Abschnitt, der Daten aus der Datenbank liest, könnte in einer anderen Funktion für andere Anfragen sein.
Beide Abschnitte könnten also an verschiedenen Orten sein und bräuchten ihre eigenen Sessions.
Info
Fairerweise könnte in diesem Beispiel der gesamte Code tatsächlich dieselbe Session teilen, es gibt hier eigentlich keinen Bedarf für zwei.
Aber es erlaubt mir, Ihnen zu zeigen, wie sie getrennt werden könnten, und die Idee zu verstärken, dass Sie eine Engine pro Anwendung und mehrere Sessions, eine pro Gruppe von Operationen, haben sollten.
Eine Liste von Hero-Objekten abrufen¶
Bisher verwenden wir die results, um sie zu durchlaufen.
Aber aus verschiedenen Gründen möchten Sie vielleicht sofort die vollständige Liste der Hero-Objekte haben, anstatt nur ein *iterable*. Zum Beispiel, wenn Sie sie in einer Web-API zurückgeben möchten.
Das spezielle results-Objekt hat auch eine Methode results.all(), die eine Liste mit allen Objekten zurückgibt.
# Code above omitted 👆
def select_heroes():
with Session(engine) as session:
statement = select(Hero)
results = session.exec(statement)
heroes = results.all()
print(heroes)
# Code below omitted 👇
👀 Vorschau der gesamten Datei
from sqlmodel import Field, Session, SQLModel, create_engine, select
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)
with Session(engine) as session:
session.add(hero_1)
session.add(hero_2)
session.add(hero_3)
session.commit()
def select_heroes():
with Session(engine) as session:
statement = select(Hero)
results = session.exec(statement)
heroes = results.all()
print(heroes)
def main():
create_db_and_tables()
create_heroes()
select_heroes()
if __name__ == "__main__":
main()
🤓 Andere Versionen und Varianten
from typing import Optional
from sqlmodel import Field, Session, SQLModel, create_engine, select
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)
with Session(engine) as session:
session.add(hero_1)
session.add(hero_2)
session.add(hero_3)
session.commit()
def select_heroes():
with Session(engine) as session:
statement = select(Hero)
results = session.exec(statement)
heroes = results.all()
print(heroes)
def main():
create_db_and_tables()
create_heroes()
select_heroes()
if __name__ == "__main__":
main()
Damit haben wir nun alle Helden in einer Liste in der Variablen heroes.
Nachdem wir sie ausgegeben haben, würden wir etwas wie das sehen:
[
Hero(id=1, name='Deadpond', age=None, secret_name='Dive Wilson'),
Hero(id=2, name='Spider-Boy', age=None, secret_name='Pedro Parqueador'),
Hero(id=3, name='Rusty-Man', age=48, secret_name='Tommy Sharp')
]
Info
Es würde eigentlich kompakter aussehen, ich formatiere es ein wenig für Sie, damit Sie sehen, dass es tatsächlich eine Liste mit allen Daten ist.
Kompakte Version¶
Ich habe mehrere Variablen erstellt, um Ihnen erklären zu können, was jede Sache tut.
Aber wenn wir wissen, was jedes Objekt ist und was es tut, können wir es etwas vereinfachen und in eine kompaktere Form bringen.
# Code above omitted 👆
def select_heroes():
with Session(engine) as session:
heroes = session.exec(select(Hero)).all()
print(heroes)
# Code below omitted 👇
👀 Vorschau der gesamten Datei
from sqlmodel import Field, Session, SQLModel, create_engine, select
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)
with Session(engine) as session:
session.add(hero_1)
session.add(hero_2)
session.add(hero_3)
session.commit()
def select_heroes():
with Session(engine) as session:
heroes = session.exec(select(Hero)).all()
print(heroes)
def main():
create_db_and_tables()
create_heroes()
select_heroes()
if __name__ == "__main__":
main()
🤓 Andere Versionen und Varianten
from typing import Optional
from sqlmodel import Field, Session, SQLModel, create_engine, select
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)
with Session(engine) as session:
session.add(hero_1)
session.add(hero_2)
session.add(hero_3)
session.commit()
def select_heroes():
with Session(engine) as session:
heroes = session.exec(select(Hero)).all()
print(heroes)
def main():
create_db_and_tables()
create_heroes()
select_heroes()
if __name__ == "__main__":
main()
Hier packen wir alles in eine einzige Zeile. Wahrscheinlich werden Sie die SELECT-Anweisungen öfter in einer einzigen Zeile wie dieser platzieren.
SQLModel oder SQLAlchemy - Technische Details¶
SQLModel ist eigentlich, mehr oder weniger, nur SQLAlchemy und Pydantic darunter, die zusammengefasst sind.
Es verwendet und gibt dieselben Objekttypen zurück und ist mit beiden Bibliotheken kompatibel.
Dennoch definiert SQLModel einige eigene interne Teile, um die Entwicklererfahrung zu verbessern.
In diesem Kapitel berühren wir einige davon.
SQLModels select¶
Wenn Sie von sqlmodel die Funktion select() importieren, verwenden Sie die Version von select von SQLModel.
SQLAlchemy hat auch seine eigene select, und die select von SQLModel verwendet intern die select von SQLAlchemy.
Aber die Version von SQLModel macht viele Tricks mit Typ-Annotationen, um sicherzustellen, dass Sie die beste Editor-Unterstützung erhalten, egal ob Sie VS Code, PyCharm oder etwas anderes verwenden. ✨
Info
Es gab viel Arbeit und Forschung mit verschiedenen Versionen des internen Codes, um dies so weit wie möglich zu verbessern. 🤓
SQLModels session.exec¶
📢 Dies ist einer, dem Sie besondere Aufmerksamkeit schenken sollten.
Die eigene Session von SQLAlchemy hat eine Methode session.execute(). Sie hat keine Methode session.exec().
Wenn Sie SQLAlchemy-Tutorials sehen, werden sie immer session.execute() verwenden.
Die eigene Session von SQLModel erbt direkt von der Session von SQLAlchemy und fügt diese zusätzliche Methode session.exec() hinzu. Intern verwendet sie dieselbe session.execute().
Aber session.exec() macht mehrere Tricks in Kombination mit den Tricks in session(), um Ihnen die beste Editor-Unterstützung zu bieten, mit Autovervollständigung und Inline-Fehlern überall, auch nach dem Abrufen von Daten aus einem Select. ✨
Zum Beispiel müssten Sie in SQLAlchemy hier ein .scalars() hinzufügen.
heroes = session.execute(select(Hero)).scalars().all()
Aber Sie müssten es entfernen, wenn Sie mehrere Dinge auswählen (das werden wir später sehen).
SQLModels session.exec() kümmert sich darum für Sie, so dass Sie das .scalars() nicht hinzufügen müssen.
Das ist etwas, das SQLAlchemy derzeit nicht bieten kann, da die reguläre session.execute() mehrere andere Anwendungsfälle unterstützt, einschließlich Legacy-Anwendungsfälle. Daher kann sie nicht alle internen Typ-Annotationen und Tricks zur Unterstützung dieses Falls haben.
Darüber hinaus macht die session.exec() von SQLModel auch einige Tricks, um die Menge des von Ihnen zu schreibenden Codes zu reduzieren und ihn so intuitiv wie möglich zu gestalten.
Aber die Session von SQLModel hat immer noch Zugriff auf session.execute().
Tipp
Ihr Editor wird Ihnen Autovervollständigung für session.exec() und session.execute() geben.
📢 Denken Sie daran, immer session.exec() zu verwenden, um die beste Editor-Unterstützung und Entwicklererfahrung zu erhalten.
Vorbehalte der SQLModel-Variante¶
SQLModel wurde entwickelt, um die beste Entwicklererfahrung für eine engere Auswahl an sehr gängigen Anwendungsfällen zu bieten. ✨
Sie können es immer noch direkt mit SQLAlchemy kombinieren und alle Funktionen von SQLAlchemy nutzen, wenn Sie sie benötigen, einschließlich Low-Level-SQL-Konstrukte, exotische Muster und sogar Legacy-Muster. 🤓
Aber das Design von SQLModel (z. B. Typ-Annotationen) geht davon aus, dass Sie es auf die Weise verwenden, wie ich es hier in der Dokumentation erkläre.
Dadurch erhalten Sie so viel Autovervollständigung und Inline-Fehler wie möglich. 🚀
Das bedeutet aber auch, dass Ihr Editor möglicherweise meldet, dass *ein Fehler vorliegt*, wenn Sie SQLModel mit etwas exotischeren Mustern von SQLAlchemy verwenden, obwohl der Code tatsächlich funktionieren würde.
Das ist der Kompromiss. 🤷
Aber für Situationen, in denen Sie diese exotischen Muster benötigen, können Sie immer SQLAlchemy direkt in Kombination mit SQLModel verwenden (unter Verwendung derselben Modelle usw.).