[英]Working with Generator Context Manager in fastapi db session
我在 fastapi session 中使用上下文管理器,我的設置如下:
from sqlmodel import create_engine, Session
from app.core.config import settings
engine = create_engine(settings.SQLALCHEMY_DATABASE_URI, pool_pre_ping=True)
SessionLocal = Session(autocommit=False, autoflush=False, bind=engine)
然后被消費
from contextlib import contextmanager
from sqlmodel import Session
from app.db.session import SessionLocal
@contextmanager
def get_session():
with SessionLocal as session:
yield session
這是端點使用的
@router.post("/")
def create_book(
*,
db: Session = Depends(get_session),
book_in: models.BookCreate,
current_user: models.User = Depends(get_current_active_user),
) -> models.BookCreate:
"""
Create new book.
"""
# print(current_user.id)
book = crud.book.create_with_owner(db=db, obj_in=book_in, owner_id=current_user.id)
return book
通過上面的設置,我希望一切正常,但事實並非如此; 相反,我收到以下錯誤:
backend-1 | File "/app/app/api/api_v1/endpoints/book.py", line 42, in create_book
backend-1 | book = crud.book.create_with_owner(db=db, obj_in=book_in, owner_id=current_user.id)
backend-1 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
backend-1 | File "/app/app/crud/crud_book.py", line 23, in create_with_owner
backend-1 | db.add(db_obj)
backend-1 | ^^^^^^
backend-1 | AttributeError: '_GeneratorContextManager' object has no attribute 'add'
以下是crud_book.py
的詳細信息
class CRUDBook(CRUDBase[Book, BookCreate, BookUpdate]):
def create_with_owner(
self, db: Session, *, obj_in: BookCreate, owner_id: UUID
) -> Book:
# with get_session() as db:
obj_in_data = jsonable_encoder(obj_in)
obj_in_data = dict(obj_in)
print(db)
# TODO: Check if owner_id is none
db_obj = self.model(**obj_in_data, owner_id=owner_id)
db.add(db_obj)
db.commit()
db.refresh(db_obj)
return db_obj
當使用crud_book.py
引入另一個上下文時,session 確實有效,但會帶來成本,因為 session 僅在 db 中創建書籍 object 時存在,但在出現以下錯誤后會在那里關閉
backend-1 | File "/usr/local/lib/python3.11/site-packages/sqlmodel/main.py", line 597, in validate
backend-1 | return cls.from_orm(value)
backend-1 | ^^^^^^^^^^^^^^^^^^^
backend-1 | File "/usr/local/lib/python3.11/site-packages/sqlmodel/main.py", line 552, in from_orm
backend-1 | values, fields_set, validation_error = validate_model(cls, obj)
backend-1 | ^^^^^^^^^^^^^^^^^^^^^^^^
backend-1 | File "pydantic/main.py", line 1056, in pydantic.main.validate_model
backend-1 | File "pydantic/utils.py", line 441, in pydantic.utils.GetterDict.get
backend-1 | File "/usr/local/lib/python3.11/site-packages/sqlalchemy/orm/attributes.py", line 482, in __get__
backend-1 | return self.impl.get(state, dict_)
backend-1 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
backend-1 | File "/usr/local/lib/python3.11/site-packages/sqlalchemy/orm/attributes.py", line 942, in get
backend-1 | value = self._fire_loader_callables(state, key, passive)
backend-1 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
backend-1 | File "/usr/local/lib/python3.11/site-packages/sqlalchemy/orm/attributes.py", line 978, in _fire_loader_callables
backend-1 | return self.callable_(state, passive)
backend-1 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
backend-1 | File "/usr/local/lib/python3.11/site-packages/sqlalchemy/orm/strategies.py", line 863, in _load_for_state
backend-1 | raise orm_exc.DetachedInstanceError(
backend-1 | sqlalchemy.orm.exc.DetachedInstanceError: Parent instance <Book at 0x7fc8a3087b90> is not bound to a Session; lazy load operation of attribute 'authors' cannot proceed (Background on this error at: https://sqlalche.me/e/14/bhk3)
為了以防萬一,以下是bookcreate
期間預期的詳細信息
import datetime
from uuid import uuid4, UUID
from typing import TYPE_CHECKING
from sqlmodel import SQLModel, Field, Relationship
# if TYPE_CHECKING:
from .genre import Genre # noqa: F401
from .author import Author # noqa: F401
from .narrator import Narrator # noqa: F401
from .publisher import Publisher # noqa: F401
from .user import User, UserRead # noqa: F401
from .book_genre_link import BookGenreLink # noqa: F401
from .book_author_link import BookAuthorLink # noqa: F401
from .book_narrator_link import BookNarratorLink # noqa: F401
from .book_publisher_link import BookPublisherLink # noqa: F401
class BookBase(SQLModel):
title: str = Field(index=True)
subtitle: str | None = Field(default=None, index=True)
description: str = Field(index=True)
runtime: datetime.time | None = Field(default=None)
rating: float | None = Field(default=None)
published_date: datetime.date | None = Field(default=None)
cover_image: str | None = Field(default=None)
class Book(BookBase, table=True):
id: UUID = Field(
default_factory=uuid4,
primary_key=True,
index=True,
nullable=False,
)
owner: list["User"] = Relationship(back_populates="books")
owner_id: UUID | None = Field(default=None, foreign_key="user.id")
authors: list["Author"] = Relationship(
back_populates="books", link_model=BookAuthorLink
)
publishers: list["Publisher"] = Relationship(
back_populates="books", link_model=BookPublisherLink
)
genres: list["Genre"] = Relationship(
back_populates="books", link_model=BookGenreLink
)
narrators: list["Narrator"] = Relationship(
back_populates="books", link_model=BookNarratorLink
)
# creation_date: datetime = Field(default=datetime.utcnow())
# update_date: datetime = Field(default=datetime.utcnow())
class BookCreate(BookBase):
authors: list["Author"] = []
publishers: list["Publisher"] = []
genres: list["Genre"] = []
narrators: list["Narrator"] = []
為什么我需要兩個多上下文管理器來處理 session,或者我哪里出錯了?
出於某種原因,FastAPI 依賴項應該是生成器,而不是上下文管理器(在文檔中提到)。 我通常做的是
from contextlib import contextmanager
def get_db():
# gaenerator using yield
db_context = contextmanager(get_db)
然后我可以在我的 FastAPI 端點中使用Depends(get_db)
,並在其他地方with db_context() as db:
例如 Celery 任務、CRON 作業等)。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.