class Article(MPInsideBase):
"""Модель Article."""
__tablename__ = "wb_ws_article"
id = Column(BigInteger(), ForeignKey(Product.id), unique=True, primary_key=True)
product: Mapped[Product] = Relationship(
remote_side=Product.id, foreign_keys="Article.id",
)
class Product(MPInsideBase):
"""Модель продукта."""
__tablename__ = "wb_products"
id = Column(BigInteger(), unique=True, primary_key=True)
article: Mapped["Article"] = Relationship("Article", back_populates="product")
async with self.db.session() as session:
print(filter_stmt.get('id'))
stmt = select(Article, Product).join(Product).filter_by(**filter_stmt)
if options:
for option in options:
stmt = stmt.options(option)
result = await session.scalars(stmt)
model = result.one()
product = model.product
print(vars(product))
return model
sqlalchemy.exc.MissingGreenlet: greenlet_spawn has not been called; can't call await_only() here. Was IO attempted in an unexpected place? (Background on this error at: https://sqlalche.me/e/20/xd2s)
import logging
import typing
from asyncio import current_task
from contextlib import asynccontextmanager
from dataclasses import dataclass
from typing import Any, AsyncGenerator
from fastapi_utils.camelcase import camel2snake
from sqlalchemy import inspect, literal, orm, select
from sqlalchemy.ext.asyncio import (
AsyncSession,
async_scoped_session,
create_async_engine,
)
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import Session, declared_attr
logger = logging.getLogger(__name__)
class Base:
id: typing.Any
__name__: str
@classmethod
def get_real_column_name(cls, attr_name: str) -> str:
return getattr(inspect(cls).c, attr_name).name
@declared_attr
def __tablename__(cls) -> str:
return camel2snake(cls.__name__)
@dataclass
class Database:
CONNECT_KWARGS = {
"max_overflow": 10,
"pool_pre_ping": True,
"pool_recycle": 3600,
"echo_pool": True,
}
def __init__(
self,
db_connect_url: str,
db_alias: str,
connect_kwargs: dict[str, Any],
debug: bool = True,
) -> None:
self._engine = create_async_engine(url=db_connect_url, **connect_kwargs, echo=debug)
self._db_alias = db_alias
self._async_session = async_scoped_session(
orm.sessionmaker(
autocommit=False,
autoflush=False,
class_=AsyncSession,
expire_on_commit=False,
bind=self._engine,
),
scopefunc=current_task,
)
async def create_tables_by_base(self, sqlalchemy_base: declarative_base) -> None:
async with self._engine.begin() as conn:
await conn.run_sync(sqlalchemy_base.metadata.create_all)
async def get_status(self) -> dict[str, str]:
async with self.session() as session:
db_status = await session.execute(
select(
[
literal("ready").label("status"),
literal(self._db_alias).label("name"),
],
),
)
return db_status.first()._asdict()
@asynccontextmanager
async def session(self) -> AsyncGenerator[Session, None]:
session: Session = self._async_session()
try:
yield session
except Exception:
logger.exception("Session rollback because of exception")
await session.rollback()
raise
finally:
await session.close()
await self._async_session.remove()
async def disconnect(self) -> None:
await self._engine.dispose()
2024-12-29 17:51:04.399 | INFO | logging:callHandlers:1736 - ROLLBACK
INFO: 127.0.0.1:64696 - "GET /api/v1/articles/229109785 HTTP/1.1" 500 Internal Server Error
2024-12-29 17:51:04.458 | ERROR | logging:callHandlers:1736 - Exception in ASGI application
Traceback (most recent call last):
File "/Users/alan/Dev/MPinside_Backend/api/venv/bin/uvicorn", line 8, in <module>
sys.exit(main())
File "/Users/alan/Dev/MPinside_Backend/api/venv/lib/python3.13/site-packages/click/core.py", line 1157, in __call__
return self.main(*args, **kwargs)
File "/Users/alan/Dev/MPinside_Backend/api/venv/lib/python3.13/site-packages/click/core.py", line 1078, in main
rv = self.invoke(ctx)
File "/Users/alan/Dev/MPinside_Backend/api/venv/lib/python3.13/site-packages/click/core.py", line 1434, in invoke
return ctx.invoke(self.callback, **ctx.params)
File "/Users/alan/Dev/MPinside_Backend/api/venv/lib/python3.13/site-packages/click/core.py", line 783, in invoke
return __callback(*args, **kwargs)
File "/Users/alan/Dev/MPinside_Backend/api/venv/lib/python3.13/site-packages/uvicorn/main.py", line 410, in main
run(
File "/Users/alan/Dev/MPinside_Backend/api/venv/lib/python3.13/site-packages/uvicorn/main.py", line 577, in run
server.run()
File "/Users/alan/Dev/MPinside_Backend/api/venv/lib/python3.13/site-packages/uvicorn/server.py", line 65, in run
return asyncio.run(self.serve(sockets=sockets))
File "/opt/homebrew/Cellar/python@3.13/3.13.1/Frameworks/Python.framework/Versions/3.13/lib/python3.13/asyncio/runners.py", line 194, in run
return runner.run(main)
File "/opt/homebrew/Cellar/python@3.13/3.13.1/Frameworks/Python.framework/Versions/3.13/lib/python3.13/asyncio/runners.py", line 118, in run
return self._loop.run_until_complete(task)
> File "/Users/alan/Dev/MPinside_Backend/api/venv/lib/python3.13/site-packages/uvicorn/protocols/http/h11_impl.py", line 406, in run_asgi
result = await app( # type: ignore[func-returns-value]
File "/Users/alan/Dev/MPinside_Backend/api/venv/lib/python3.13/site-packages/uvicorn/middleware/proxy_headers.py", line 70, in __call__
return await self.app(scope, receive, send)
File "/Users/alan/Dev/MPinside_Backend/api/venv/lib/python3.13/site-packages/fastapi/applications.py", line 1054, in __call__
await super().__call__(scope, receive, send)
File "/Users/alan/Dev/MPinside_Backend/api/venv/lib/python3.13/site-packages/starlette/applications.py", line 113, in __call__
await self.middleware_stack(scope, receive, send)
File "/Users/alan/Dev/MPinside_Backend/api/venv/lib/python3.13/site-packages/starlette/middleware/errors.py", line 187, in __call__
raise exc
File "/Users/alan/Dev/MPinside_Backend/api/venv/lib/python3.13/site-packages/starlette/middleware/errors.py", line 165, in __call__
await self.app(scope, receive, _send)
File "/Users/alan/Dev/MPinside_Backend/api/venv/lib/python3.13/site-packages/starlette/middleware/exceptions.py", line 62, in __call__
await wrap_app_handling_exceptions(self.app, conn)(scope, receive, send)
File "/Users/alan/Dev/MPinside_Backend/api/venv/lib/python3.13/site-packages/starlette/_exception_handler.py", line 62, in wrapped_app
raise exc
File "/Users/alan/Dev/MPinside_Backend/api/venv/lib/python3.13/site-packages/starlette/_exception_handler.py", line 51, in wrapped_app
await app(scope, receive, sender)
File "/Users/alan/Dev/MPinside_Backend/api/venv/lib/python3.13/site-packages/starlette/routing.py", line 715, in __call__
await self.middleware_stack(scope, receive, send)
File "/Users/alan/Dev/MPinside_Backend/api/venv/lib/python3.13/site-packages/starlette/routing.py", line 735, in app
await route.handle(scope, receive, send)
File "/Users/alan/Dev/MPinside_Backend/api/venv/lib/python3.13/site-packages/starlette/routing.py", line 288, in handle
await self.app(scope, receive, send)
File "/Users/alan/Dev/MPinside_Backend/api/venv/lib/python3.13/site-packages/starlette/routing.py", line 76, in app
await wrap_app_handling_exceptions(app, request)(scope, receive, send)
File "/Users/alan/Dev/MPinside_Backend/api/venv/lib/python3.13/site-packages/starlette/_exception_handler.py", line 62, in wrapped_app
raise exc
File "/Users/alan/Dev/MPinside_Backend/api/venv/lib/python3.13/site-packages/starlette/_exception_handler.py", line 51, in wrapped_app
await app(scope, receive, sender)
File "/Users/alan/Dev/MPinside_Backend/api/venv/lib/python3.13/site-packages/starlette/routing.py", line 73, in app
response = await f(request)
File "/Users/alan/Dev/MPinside_Backend/api/venv/lib/python3.13/site-packages/fastapi/routing.py", line 301, in app
raw_response = await run_endpoint_function(
File "/Users/alan/Dev/MPinside_Backend/api/venv/lib/python3.13/site-packages/fastapi/routing.py", line 212, in run_endpoint_function
return await dependant.call(**values)
File "/Users/alan/Dev/MPinside_Backend/api/app/aricles/views.py", line 33, in get_article_detail
article = await articles_service.get_article_by_id(article_id)
File "/Users/alan/Dev/MPinside_Backend/api/app/core/articles/services.py", line 11, in get_article_by_id
return await self.repository.get_article(id=article_id)
File "/Users/alan/Dev/MPinside_Backend/api/app/core/articles/repository.py", line 41, in get_article
product = model.product
File "/Users/alan/Dev/MPinside_Backend/api/venv/lib/python3.13/site-packages/sqlalchemy/orm/attributes.py", line 566, in __get__
return self.impl.get(state, dict_) # type: ignore[no-any-return]
File "/Users/alan/Dev/MPinside_Backend/api/venv/lib/python3.13/site-packages/sqlalchemy/orm/attributes.py", line 1086, in get
value = self._fire_loader_callables(state, key, passive)
File "/Users/alan/Dev/MPinside_Backend/api/venv/lib/python3.13/site-packages/sqlalchemy/orm/attributes.py", line 1121, in _fire_loader_callables
return self.callable_(state, passive)
File "/Users/alan/Dev/MPinside_Backend/api/venv/lib/python3.13/site-packages/sqlalchemy/orm/strategies.py", line 967, in _load_for_state
return self._emit_lazyload(
File "/Users/alan/Dev/MPinside_Backend/api/venv/lib/python3.13/site-packages/sqlalchemy/orm/strategies.py", line 1068, in _emit_lazyload
return loading.load_on_pk_identity(
File "/Users/alan/Dev/MPinside_Backend/api/venv/lib/python3.13/site-packages/sqlalchemy/orm/loading.py", line 694, in load_on_pk_identity
session.execute(
File "/Users/alan/Dev/MPinside_Backend/api/venv/lib/python3.13/site-packages/sqlalchemy/orm/session.py", line 2362, in execute
return self._execute_internal(
File "/Users/alan/Dev/MPinside_Backend/api/venv/lib/python3.13/site-packages/sqlalchemy/orm/session.py", line 2247, in _execute_internal
result: Result[Any] = compile_state_cls.orm_execute_statement(
File "/Users/alan/Dev/MPinside_Backend/api/venv/lib/python3.13/site-packages/sqlalchemy/orm/context.py", line 305, in orm_execute_statement
result = conn.execute(
File "/Users/alan/Dev/MPinside_Backend/api/venv/lib/python3.13/site-packages/sqlalchemy/engine/base.py", line 1418, in execute
return meth(
File "/Users/alan/Dev/MPinside_Backend/api/venv/lib/python3.13/site-packages/sqlalchemy/sql/elements.py", line 515, in _execute_on_connection
return connection._execute_clauseelement(
File "/Users/alan/Dev/MPinside_Backend/api/venv/lib/python3.13/site-packages/sqlalchemy/engine/base.py", line 1640, in _execute_clauseelement
ret = self._execute_context(
File "/Users/alan/Dev/MPinside_Backend/api/venv/lib/python3.13/site-packages/sqlalchemy/engine/base.py", line 1846, in _execute_context
return self._exec_single_context(
File "/Users/alan/Dev/MPinside_Backend/api/venv/lib/python3.13/site-packages/sqlalchemy/engine/base.py", line 1986, in _exec_single_context
self._handle_dbapi_exception(
File "/Users/alan/Dev/MPinside_Backend/api/venv/lib/python3.13/site-packages/sqlalchemy/engine/base.py", line 2358, in _handle_dbapi_exception
raise exc_info[1].with_traceback(exc_info[2])
File "/Users/alan/Dev/MPinside_Backend/api/venv/lib/python3.13/site-packages/sqlalchemy/engine/base.py", line 1967, in _exec_single_context
self.dialect.do_execute(
File "/Users/alan/Dev/MPinside_Backend/api/venv/lib/python3.13/site-packages/sqlalchemy/engine/default.py", line 941, in do_execute
cursor.execute(statement, parameters)
File "/Users/alan/Dev/MPinside_Backend/api/venv/lib/python3.13/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py", line 572, in execute
self._adapt_connection.await_(
File "/Users/alan/Dev/MPinside_Backend/api/venv/lib/python3.13/site-packages/sqlalchemy/util/_concurrency_py3k.py", line 123, in await_only
raise exc.MissingGreenlet(
sqlalchemy.exc.MissingGreenlet: greenlet_spawn has not been called; can't call await_only() here. Was IO attempted in an unexpected place? (Background on this error at: https://sqlalche.me/e/20/xd2s)
File "/Users/alan/Dev/MPinside_Backend/api/app/core/articles/repository.py", line 41, in get_articleну вот место исключения намекает что все такие тут не хватает что-то уровня eagerly loading, разбирайся
product = model.product