自動ID、Noneデフォルト、およびデータの更新¶
前の章では、**SQLModel** を使用してデータベースに行を追加する方法について説明しました。
ここでは、id
フィールドが**主キー**であるため、データベースでは**NULL
にできない**理由、およびField(primary_key=True)
を使用して宣言する理由について少し説明します。
しかし、同じid
フィールドは、Pythonコードでは実際に**None
にすることができます**。そのため、型をOptional[int]
で宣言し、デフォルト値を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 👇
# Code above omitted 👆
class Hero(SQLModel, table=True):
id: Optional[int] = Field(default=None, primary_key=True)
name: str
secret_name: str
age: Optional[int] = None
# Code below omitted 👇
👀 ファイルプレビュー全体
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()
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()
次に、データベースとPythonコード間のデータの同期についてもう少し詳しく説明します。
いつid
フィールドからデータベースの実際のint
を取得するのでしょうか?それらすべてを見ていきましょう。👇
新しいHero
インスタンスの作成¶
新しいHero
インスタンスを作成するときは、id
を設定しません。
# 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 👇
# 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 👇
👀 ファイルプレビュー全体
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()
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()
Optional
の役割¶
id
を設定しないため、Field(default=None)
で設定したPythonのデフォルト値None
が使用されます。
これが、Optional
とデフォルト値None
で定義する唯一の理由です。
コードのこの時点では、**データベースとやり取りする前**に、Pythonの値は実際にNone
になる可能性があります。
id
が常にint
であると仮定し、Optional
なしで型アノテーションを追加した場合、次のような壊れたコードを作成することになります。
next_hero_id = hero_1.id + 1
heroをデータベースに保存する前にこのコードを実行し、hero_1.id
がまだNone
だった場合、次のようなエラーが発生します。
TypeError: unsupported operand type(s) for +: 'NoneType' and 'int'
しかし、Optional[int]
で宣言することで、エディターはhero_1.id
がNone
の場合にコードが無効になる可能性があることを警告することで、壊れたコードの記述を回避するのに役立ちます。🔍
デフォルトのid
値の出力¶
データベースに追加する前にヒーローを出力することで、それを確認できます。
# 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 👇
# 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 👇
👀 ファイルプレビュー全体
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()
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()
これが出力されます。
$ 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
すべてid=None
であることに注意してください。
これは、Hero
モデルクラスで定義したデフォルト値です。
これらのオブジェクトを**セッション**にadd
すると何が起こるのでしょうか?
オブジェクトをセッションに追加¶
Hero
インスタンスオブジェクトを**セッション**に追加した後も、IDは依然としてNone
です。
with
ブロックを使用してセッションを作成し、オブジェクトを追加することで検証できます。そして、もう一度出力してみましょう。
# 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 👇
# 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 👇
👀 ファイルプレビュー全体
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()
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()
これにより、オブジェクトのid
は再びNone
として出力されます。
$ 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
前述のように、**セッション**はスマートで、何かを変更する準備をするたびにデータベースと通信するわけではなく、準備が整って変更をcommit
するように指示するまで、すべてのSQLをデータベースに送信してデータを保存しません。
データベースへの変更のコミット¶
次に、セッションの変更をcommit
して、再度出力してみましょう。
# 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 👇
# 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 👇
👀 ファイルプレビュー全体
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()
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()
そして今、予期せぬことが起こります。出力を見てください。Hero
インスタンスオブジェクトにはまったくデータがないように見えます。
$ 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? 😱
SQLModel(実際にはSQLAlchemy)は、内部的にこれらのオブジェクトを「期限切れ」としてマークしています。それらは**データの最新バージョンを持っていない**のです。これは、たとえば、変更を保存したときに自動的に更新されたupdated_at: datetime
などのフィールドがデータベースで更新される可能性があるためです。
同様に、他の値も変更される可能性があるため、**セッション**が確実に安全にするためのオプションは、オブジェクトを内部的に期限切れとしてマークすることだけです。
そして、次に各属性にアクセスするとき(たとえば、以下のように)
current_hero_name = hero_1.name
…SQLModel(実際にはSQLAlchemy)はデータベースに接続して**データの最新バージョンを取得し**、オブジェクトのname
フィールドを更新し、Python式で使用できるようにします(この例では、単に出力します)。上記の例では、その時点でPythonは、そのhero_1.name
値(ちょうど更新された)を使用して変数current_hero_name
に入れることができます。
これらはすべて自動的に、そして舞台裏で行われます。✨
そして、私たちの例では面白く奇妙なことが起こります。
print("Hero 1:", hero_1)
hero.name
のようにオブジェクトの属性にアクセスしませんでした。オブジェクト全体にアクセスして出力しただけなので、**SQLAlchemyは**私たちがこのオブジェクトのデータにアクセスしたいことを知る方法がありません。
単一フィールドの出力¶
このデータの**自動的な期限切れと更新**が属性へのアクセス時にどのように機能するかを確認して理解するために、いくつかの個々のフィールド(インスタンス属性)を出力できます。
# 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 👇
# 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 👇
👀 ファイルプレビュー全体
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()
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()
ここでは、オブジェクト全体hero_1
を出力する代わりに
print("Hero 1:", hero_1)
…hero.id
のid
属性を出力しています。
print("Hero 1 ID:", hero_1.id)
属性にアクセスすることで、**SQLModel(実際にはSQLAlchemy)**は舞台裏で多くの作業を**トリガー**して**データベースからデータを更新し**、オブジェクトのid
属性に設定し、Python式で使用できるようにします(この場合は単に出力します)。
それがどのように機能するか見てみましょう。
$ 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 🤓
オブジェクトの明示的な更新¶
あなたは、**セッション**が属性にアクセスするという副作用として、舞台裏でデータを自動的に更新する方法を学びました。
しかし、データを**明示的に更新**したい場合はどうでしょうか?
session.refresh(object)
を使用して実行することもできます。
# 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 👇
# 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 👇
👀 ファイルプレビュー全体
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()
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()
Pythonがこのコードを実行すると
session.refresh(hero_1)
…**セッション**は、このオブジェクトhero_1
の最新のデータを取得するために**エンジン**がデータベースと通信するようにし、次に**セッション**はデータをhero_1
オブジェクトに配置し、「新鮮」または「期限切れではない」としてマークします。
出力は次のようになります。
$ 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'
これは、たとえば、ヒーローを作成するWeb APIを構築する場合に役立ちます。ヒーローがいくつかのデータで作成されると、クライアントに返されます。
データの更新をトリガーする自動的な魔法が実行されなかったため、空のように見えるオブジェクトを返すことは望ましくありません。
この場合、**セッション**を使用してオブジェクトをデータベースにコミットした後、更新してクライアントに返すことができます。これにより、オブジェクトに最新のデータが含まれることが保証されます。
セッションクローズ後のデータ出力¶
最後に、**セッション**が閉じられた後もデータを出力してみましょう。
ここには驚くべきことはありません。それでも機能します。
# 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 👇
# 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 👇
👀 ファイルプレビュー全体
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()
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()
そして、出力は再び同じデータを示します。
$ 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'
全コードのレビュー¶
もう一度、このコード全体を確認してみましょう。
ヒント
番号付きのバブルごとに、各行が出力に表示される内容を示しています。
そして、echo=True
で**エンジン**を作成したので、各ステップで実行されているSQL文を確認できます。
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()
-
hero_1
を作成します。何も出力しません。.
-
hero_2
を作成します。何も出力しません。.
-
hero_3
を作成します。何も出力しません。.
-
「データベースとのやり取り前」という行を出力します。
出力が生成されます。
Before interacting with the database
-
データベースとのやり取り前に
hero_1
を出力します。出力が生成されます。
Hero 1: id=None name='Deadpond' secret_name='Dive Wilson' age=None
-
データベースとのやり取り前に
hero_2
を出力します。出力が生成されます。
Hero 2: id=None name='Spider-Boy' secret_name='Pedro Parqueador' age=None
-
データベースとのやり取り前に
hero_3
を出力します。出力が生成されます。
Hero 3: id=None name='Rusty-Man' secret_name='Tommy Sharp' age=48
-
with
ブロックでSession
を作成します。何も出力しません。.
-
hero_1
をセッションに追加します。これはまだデータベースに保存されません。
何も出力しません。.
-
hero_2
をセッションに追加します。これはまだデータベースに保存されません。
何も出力しません。.
-
hero_3
をセッションに追加します。これはまだデータベースに保存されません。
何も出力しません。.
-
「セッションに追加後」という行を出力します。
出力が生成されます。
After adding to the session
-
セッションに追加後の
hero_1
を出力します。まだデータベースとのやり取りがないため、同じデータのままです。
id
はまだNone
であることに注意してください。出力が生成されます。
Hero 1: id=None name='Deadpond' secret_name='Dive Wilson' age=None
-
セッションに追加後の
hero_2
を出力します。まだデータベースとのやり取りがないため、同じデータのままです。
id
はまだNone
であることに注意してください。出力が生成されます。
Hero 2: id=None name='Spider-Boy' secret_name='Pedro Parqueador' age=None
-
セッションに追加後の
hero_3
を出力します。まだデータベースとのやり取りがないため、同じデータのままです。
id
はまだNone
であることに注意してください。出力が生成されます。
Hero 3: id=None name='Rusty-Man' secret_name='Tommy Sharp' age=48
-
**セッション**を
commit
します。これにより、すべてのデータがデータベースに**保存**されます。**セッション**は**エンジン**を使用して多くのSQLを実行します。
出力が生成されます。
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
-
「セッションコミット後」という行を出力します。
出力が生成されます。
After committing the session
-
セッションコミット後の
hero_1
を出力します。hero_1
は内部的に期限切れとしてマークされており、更新されるまで、データが含まれていないように見えます。出力が生成されます。
Hero 1:
-
セッションコミット後の
hero_2
を出力します。hero_2
は内部的に期限切れとマークされており、更新されるまでデータを含んでいないように見えます。出力が生成されます。
Hero 2:
-
セッションコミット後に
hero_3
を出力します。hero_3
は内部的に期限切れとマークされており、更新されるまでデータを含んでいないように見えます。出力が生成されます。
Hero 3:
-
"After committing the session, show IDs"
という行を出力します。出力が生成されます。
After committing the session, show IDs
-
hero_1.id
を出力します。ここで多くの処理が行われます。hero_1
のid
属性にアクセスしているため、**SQLModel**(実際にはSQLAlchemy)はhero_1
からデータにアクセスしようとしていることを検出できます。その後、
hero_1
が現在**セッション**に関連付けられており(セッションに追加してコミットしたため)、期限切れとマークされていることを検出します。次に、**セッション**を使用して**エンジン**を介して、データベースからこのオブジェクトのデータを取得するためのすべてのSQLを実行します。
次に、新しいデータでオブジェクトを更新し、内部的に「新鮮」または「期限切れではない」とマークします。
最後に、Python式の残りの部分でID値を使用できるようにします。この場合、Python式はIDを出力するだけです。
出力が生成されます。
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
-
hero_2.id
を出力します。22番目のポイントで行われたものと同じ処理がすべてここで行われますが、これは
hero_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.001245s ago] (2,) Hero 2 ID: 2
-
hero_3.id
を出力します。22番目のポイントで行われたものと同じ処理がすべてここで行われますが、これは
hero_3
オブジェクトに対して行われます。出力が生成されます。
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
-
"After committing the session, show names"
という行を出力します。出力が生成されます。
After committing the session, show names
-
hero_1.name
を出力します。hero_1
はまだ新鮮なので、追加のデータは取得されず、追加のSQLは実行されず、名前が利用可能です。出力が生成されます。
Hero 1 name: Deadpond
-
hero_2.name
を出力します。hero_2
はまだ新鮮なので、追加のデータは取得されず、追加のSQLは実行されず、名前が利用可能です。出力が生成されます。
Hero 2 name: Spider-Boy
-
hero_3.name
を出力します。hero_3
はまだ新鮮なので、追加のデータは取得されず、追加のSQLは実行されず、名前が利用可能です。出力が生成されます。
Hero 3 name: Rusty-Man
-
hero_1
オブジェクトを明示的に更新します。**セッション**は**エンジン**を使用して、
hero_1
オブジェクトのデータベースから新しいデータを取得するために必要なSQLを実行します。出力が生成されます。
INFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age FROM hero WHERE hero.id = ? INFO Engine [generated in 0.00024s] (1,)
-
hero_2
オブジェクトを明示的に更新します。**セッション**は**エンジン**を使用して、
hero_2
オブジェクトのデータベースから新しいデータを取得するために必要なSQLを実行します。出力が生成されます。
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,)
-
hero_3
オブジェクトを明示的に更新します。**セッション**は**エンジン**を使用して、
hero_3
オブジェクトのデータベースから新しいデータを取得するために必要なSQLを実行します。出力が生成されます。
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,)
-
"After refreshing the heroes"
という行を出力します。出力が生成されます。
After refreshing the heroes
-
hero_1
を出力します。!!! info
hero_1
が新鮮でなかったとしても、これは属性にアクセスしていないため、**セッション**が**エンジン**を使用してデータベースからデータを取得するrefresh
をトリガーしません。hero_1
は新鮮なので、すべてのデータが利用可能です。出力が生成されます。
Hero 1: age=None id=1 name='Deadpond' secret_name='Dive Wilson'
-
hero_2
を出力します。!!! info
hero_2
が新鮮でなかったとしても、これは属性にアクセスしていないため、**セッション**が**エンジン**を使用してデータベースからデータを取得するrefresh
をトリガーしません。hero_2
は新鮮なので、すべてのデータが利用可能です。出力が生成されます。
Hero 2: age=None id=2 name='Spider-Boy' secret_name='Pedro Parqueador'
-
hero_3
を出力します。!!! info
hero_3
が新鮮でなかったとしても、これは属性にアクセスしていないため、**セッション**が**エンジン**を使用してデータベースからデータを取得するrefresh
をトリガーしません。hero_3
は新鮮なので、すべてのデータが利用可能です。出力が生成されます。
Hero 3: age=48 id=3 name='Rusty-Man' secret_name='Tommy Sharp'
-
with
ブロックはここで終了します(インデントされたコードはもうありません)。そのため、**セッション**が閉じられ、すべてのクローズコードが実行されます。これには、開始されている可能性のあるトランザクションの
ROLLBACK
が含まれます。出力が生成されます。
INFO Engine ROLLBACK
-
"After the session closes"
という行を出力します。出力が生成されます。
After the session closes
-
セッションのクローズ後に
hero_1
を出力します。出力が生成されます。
Hero 1: age=None id=1 name='Deadpond' secret_name='Dive Wilson'
-
セッションのクローズ後に
hero_2
を出力します。出力が生成されます。
Hero 2: age=None id=2 name='Spider-Boy' secret_name='Pedro Parqueador'
-
セッションのクローズ後に
hero_3
を出力します。出力が生成されます。
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()
-
hero_1
を作成します。何も出力しません。.
-
hero_2
を作成します。何も出力しません。.
-
hero_3
を作成します。何も出力しません。.
-
「データベースとのやり取り前」という行を出力します。
出力が生成されます。
Before interacting with the database
-
データベースとのやり取り前に
hero_1
を出力します。出力が生成されます。
Hero 1: id=None name='Deadpond' secret_name='Dive Wilson' age=None
-
データベースとのやり取り前に
hero_2
を出力します。出力が生成されます。
Hero 2: id=None name='Spider-Boy' secret_name='Pedro Parqueador' age=None
-
データベースとのやり取り前に
hero_3
を出力します。出力が生成されます。
Hero 3: id=None name='Rusty-Man' secret_name='Tommy Sharp' age=48
-
with
ブロックでSession
を作成します。何も出力しません。.
-
hero_1
をセッションに追加します。これはまだデータベースに保存されません。
何も出力しません。.
-
hero_2
をセッションに追加します。これはまだデータベースに保存されません。
何も出力しません。.
-
hero_3
をセッションに追加します。これはまだデータベースに保存されません。
何も出力しません。.
-
「セッションに追加後」という行を出力します。
出力が生成されます。
After adding to the session
-
セッションに追加後の
hero_1
を出力します。まだデータベースとのやり取りがないため、同じデータのままです。
id
はまだNone
であることに注意してください。出力が生成されます。
Hero 1: id=None name='Deadpond' secret_name='Dive Wilson' age=None
-
セッションに追加後の
hero_2
を出力します。まだデータベースとのやり取りがないため、同じデータのままです。
id
はまだNone
であることに注意してください。出力が生成されます。
Hero 2: id=None name='Spider-Boy' secret_name='Pedro Parqueador' age=None
-
セッションに追加後の
hero_3
を出力します。まだデータベースとのやり取りがないため、同じデータのままです。
id
はまだNone
であることに注意してください。出力が生成されます。
Hero 3: id=None name='Rusty-Man' secret_name='Tommy Sharp' age=48
-
**セッション**を
commit
します。これにより、すべてのデータがデータベースに**保存**されます。**セッション**は**エンジン**を使用して多くのSQLを実行します。
出力が生成されます。
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
-
「セッションコミット後」という行を出力します。
出力が生成されます。
After committing the session
-
セッションコミット後の
hero_1
を出力します。hero_1
は内部的に期限切れとしてマークされており、更新されるまで、データが含まれていないように見えます。出力が生成されます。
Hero 1:
-
セッションコミット後の
hero_2
を出力します。hero_2
は内部的に期限切れとマークされており、更新されるまでデータを含んでいないように見えます。出力が生成されます。
Hero 2:
-
セッションコミット後に
hero_3
を出力します。hero_3
は内部的に期限切れとマークされており、更新されるまでデータを含んでいないように見えます。出力が生成されます。
Hero 3:
-
"After committing the session, show IDs"
という行を出力します。出力が生成されます。
After committing the session, show IDs
-
hero_1.id
を出力します。ここで多くの処理が行われます。hero_1
のid
属性にアクセスしているため、**SQLModel**(実際にはSQLAlchemy)はhero_1
からデータにアクセスしようとしていることを検出できます。その後、
hero_1
が現在**セッション**に関連付けられており(セッションに追加してコミットしたため)、期限切れとマークされていることを検出します。次に、**セッション**を使用して**エンジン**を介して、データベースからこのオブジェクトのデータを取得するためのすべてのSQLを実行します。
次に、新しいデータでオブジェクトを更新し、内部的に「新鮮」または「期限切れではない」とマークします。
最後に、Python式の残りの部分でID値を使用できるようにします。この場合、Python式はIDを出力するだけです。
出力が生成されます。
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
-
hero_2.id
を出力します。22番目のポイントで行われたものと同じ処理がすべてここで行われますが、これは
hero_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.001245s ago] (2,) Hero 2 ID: 2
-
hero_3.id
を出力します。22番目のポイントで行われたものと同じ処理がすべてここで行われますが、これは
hero_3
オブジェクトに対して行われます。出力が生成されます。
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
-
"After committing the session, show names"
という行を出力します。出力が生成されます。
After committing the session, show names
-
hero_1.name
を出力します。hero_1
はまだ新鮮なので、追加のデータは取得されず、追加のSQLは実行されず、名前が利用可能です。出力が生成されます。
Hero 1 name: Deadpond
-
hero_2.name
を出力します。hero_2
はまだ新鮮なので、追加のデータは取得されず、追加のSQLは実行されず、名前が利用可能です。出力が生成されます。
Hero 2 name: Spider-Boy
-
hero_3.name
を出力します。hero_3
はまだ新鮮なので、追加のデータは取得されず、追加のSQLは実行されず、名前が利用可能です。出力が生成されます。
Hero 3 name: Rusty-Man
-
hero_1
オブジェクトを明示的に更新します。**セッション**は**エンジン**を使用して、
hero_1
オブジェクトのデータベースから新しいデータを取得するために必要なSQLを実行します。出力が生成されます。
INFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age FROM hero WHERE hero.id = ? INFO Engine [generated in 0.00024s] (1,)
-
hero_2
オブジェクトを明示的に更新します。**セッション**は**エンジン**を使用して、
hero_2
オブジェクトのデータベースから新しいデータを取得するために必要なSQLを実行します。出力が生成されます。
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,)
-
hero_3
オブジェクトを明示的に更新します。**セッション**は**エンジン**を使用して、
hero_3
オブジェクトのデータベースから新しいデータを取得するために必要なSQLを実行します。出力が生成されます。
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,)
-
"After refreshing the heroes"
という行を出力します。出力が生成されます。
After refreshing the heroes
-
hero_1
を出力します。!!! info
hero_1
が新鮮でなかったとしても、これは属性にアクセスしていないため、**セッション**が**エンジン**を使用してデータベースからデータを取得するrefresh
をトリガーしません。hero_1
は新鮮なので、すべてのデータが利用可能です。出力が生成されます。
Hero 1: age=None id=1 name='Deadpond' secret_name='Dive Wilson'
-
hero_2
を出力します。!!! info
hero_2
が新鮮でなかったとしても、これは属性にアクセスしていないため、**セッション**が**エンジン**を使用してデータベースからデータを取得するrefresh
をトリガーしません。hero_2
は新鮮なので、すべてのデータが利用可能です。出力が生成されます。
Hero 2: age=None id=2 name='Spider-Boy' secret_name='Pedro Parqueador'
-
hero_3
を出力します。!!! info
hero_3
が新鮮でなかったとしても、これは属性にアクセスしていないため、**セッション**が**エンジン**を使用してデータベースからデータを取得するrefresh
をトリガーしません。hero_3
は新鮮なので、すべてのデータが利用可能です。出力が生成されます。
Hero 3: age=48 id=3 name='Rusty-Man' secret_name='Tommy Sharp'
-
with
ブロックはここで終了します(インデントされたコードはもうありません)。そのため、**セッション**が閉じられ、すべてのクローズコードが実行されます。これには、開始されている可能性のあるトランザクションの
ROLLBACK
が含まれます。出力が生成されます。
INFO Engine ROLLBACK
-
"After the session closes"
という行を出力します。出力が生成されます。
After the session closes
-
セッションのクローズ後に
hero_1
を出力します。出力が生成されます。
Hero 1: age=None id=1 name='Deadpond' secret_name='Dive Wilson'
-
セッションのクローズ後に
hero_2
を出力します。出力が生成されます。
Hero 2: age=None id=2 name='Spider-Boy' secret_name='Pedro Parqueador'
-
セッションのクローズ後に
hero_3
を出力します。出力が生成されます。
Hero 3: age=48 id=3 name='Rusty-Man' secret_name='Tommy Sharp'
そして、このプログラムを実行して生成されたすべての出力がここにまとめてあります。
$ 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'
要約¶
すべて読みましたね!大変でしたね!ご褒美にケーキをどうぞ。🍰
**セッション**が**エンジン**を使用してSQLをデータベースに送信し、データを作成してデータを取得する方法、そして「**期限切れ**」と「**新鮮**」なデータをどのように追跡するかについて説明しました。インスタンス属性にアクセスする場合に自動的に**データを取得する**タイミングと、**セッション**を介してメモリ内のオブジェクトとデータベース間のデータがどのように同期されるかについて説明しました。
これらすべてを理解したのであれば、**SQLModel**、SQLAlchemy、そして一般的にPythonからデータベースとのやり取りがどのように機能するのかについて多くのことを知っています。
すべて理解できなかったとしても大丈夫です。後でいつでも戻ってきて、概念をrefresh
することができます。
これは、問題を引き起こし、頭を悩ませる主なバグの種類の1つだと思います。だから、頑張って勉強してくれてありがとう!💪