Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[BUG] AttributeError: get_motor_collection when setting fetch_links=True #1056

Open
tdoan2010 opened this issue Oct 17, 2024 · 0 comments
Open

Comments

@tdoan2010
Copy link

Describe the bug
AttributeError: get_motor_collection when setting fetch_links=True.

To Reproduce
I'm using Beanie with FastAPI. For example, my Beanie models look like this:

class Project(Document):
    id: PydanticObjectId = Field(default_factory=PydanticObjectId)
    items: list[Link[ItemDB]] | None = None

class ItemDB(Document):
    creator: Indexed(str)

When getting a Project by ID, I also want to prefetch its related items. So, my endpoint looks like this:

@router.get('/{project_id}', status_code=status.HTTP_200_OK, summary='Get a project',
            response_model_exclude_none=True)
async def get_project(project_id: str) -> Project:
    project = await Project.get(project_id, fetch_links=True)
    if not project:
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND)
    return project

But I got the error:

ERROR:    Exception in ASGI application
Traceback (most recent call last):
  File "my-project/.venv/lib/python3.12/site-packages/uvicorn/protocols/http/httptools_impl.py", line 419, in run_asgi
    result = await app(  # type: ignore[func-returns-value]
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "my-project/.venv/lib/python3.12/site-packages/uvicorn/middleware/proxy_headers.py", line 84, in __call__
    return await self.app(scope, receive, send)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "my-project/.venv/lib/python3.12/site-packages/fastapi/applications.py", line 1054, in __call__
    await super().__call__(scope, receive, send)
  File "my-project/.venv/lib/python3.12/site-packages/starlette/applications.py", line 113, in __call__
    await self.middleware_stack(scope, receive, send)
  File "my-project/.venv/lib/python3.12/site-packages/starlette/middleware/errors.py", line 187, in __call__
    raise exc
  File "my-project/.venv/lib/python3.12/site-packages/starlette/middleware/errors.py", line 165, in __call__
    await self.app(scope, receive, _send)
  File "my-project/.venv/lib/python3.12/site-packages/starlette/middleware/exceptions.py", line 62, in __call__
    await wrap_app_handling_exceptions(self.app, conn)(scope, receive, send)
  File "my-project/.venv/lib/python3.12/site-packages/starlette/_exception_handler.py", line 62, in wrapped_app
    raise exc
  File "my-project/.venv/lib/python3.12/site-packages/starlette/_exception_handler.py", line 51, in wrapped_app
    await app(scope, receive, sender)
  File "my-project/.venv/lib/python3.12/site-packages/starlette/routing.py", line 715, in __call__
    await self.middleware_stack(scope, receive, send)
  File "my-project/.venv/lib/python3.12/site-packages/starlette/routing.py", line 735, in app
    await route.handle(scope, receive, send)
  File "my-project/.venv/lib/python3.12/site-packages/starlette/routing.py", line 288, in handle
    await self.app(scope, receive, send)
  File "my-project/.venv/lib/python3.12/site-packages/starlette/routing.py", line 76, in app
    await wrap_app_handling_exceptions(app, request)(scope, receive, send)
  File "my-project/.venv/lib/python3.12/site-packages/starlette/_exception_handler.py", line 62, in wrapped_app
    raise exc
  File "my-project/.venv/lib/python3.12/site-packages/starlette/_exception_handler.py", line 51, in wrapped_app
    await app(scope, receive, sender)
  File "my-project/.venv/lib/python3.12/site-packages/starlette/routing.py", line 73, in app
    response = await f(request)
               ^^^^^^^^^^^^^^^^
  File "my-project/.venv/lib/python3.12/site-packages/fastapi/routing.py", line 301, in app
    raw_response = await run_endpoint_function(
                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "my-project/.venv/lib/python3.12/site-packages/fastapi/routing.py", line 212, in run_endpoint_function
    return await dependant.call(**values)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "my-project/app/routers/project.py", line 46, in get_project
    project = await Project.get(project_id, fetch_links=True)
              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "my-project/.venv/lib/python3.12/site-packages/beanie/odm/documents.py", line 276, in get
    return await cls.find_one(
           ^^^^^^^^^^^^^^^^^^^
  File "my-project/.venv/lib/python3.12/site-packages/beanie/odm/queries/find.py", line 1024, in __await__
    document = yield from self._find_one().__await__()  # type: ignore
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "my-project/.venv/lib/python3.12/site-packages/beanie/odm/queries/find.py", line 982, in _find_one
    return await self.document_model.find_many(
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "my-project/.venv/lib/python3.12/site-packages/beanie/odm/queries/find.py", line 689, in first_or_none
    res = await self.limit(1).to_list()
          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "my-project/.venv/lib/python3.12/site-packages/beanie/odm/queries/cursor.py", line 67, in to_list
    cursor = self.motor_cursor
             ^^^^^^^^^^^^^^^^^
  File "my-project/.venv/lib/python3.12/site-packages/beanie/odm/queries/find.py", line 661, in motor_cursor
    self.build_aggregation_pipeline()
  File "my-project/.venv/lib/python3.12/site-packages/beanie/odm/queries/find.py", line 610, in build_aggregation_pipeline
    construct_lookup_queries(
  File "my-project/.venv/lib/python3.12/site-packages/beanie/odm/utils/find.py", line 29, in construct_lookup_queries
    construct_query(
  File "my-project/.venv/lib/python3.12/site-packages/beanie/odm/utils/find.py", line 271, in construct_query
    "from": link_info.document_class.get_motor_collection().name,  # type: ignore
            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "my-project/.venv/lib/python3.12/site-packages/pydantic/_internal/_model_construction.py", line 242, in __getattr__
    raise AttributeError(item)
AttributeError: get_motor_collection

If I remove fetch_links=True and later on call

await project.fetch_all_links()

then it works fine.

I'm sure that the database was initialized properly because everything else works normally, only this fetch_links has problem. Just to be sure, here is how the database was initialized:

async def init_db(db_url: str):
    client = AsyncIOMotorClient(host=db_url, tz_aware=True)
    await init_beanie(
        database=client.get_default_database(default='myDB'),
        document_models=[Project, ItemDB],
        allow_index_dropping=True
    )

This function is then called in the startup part of FastAPI:

@asynccontextmanager
async def lifespan(app: FastAPI):
    await init_db(settings.db_url)
    yield


app = FastAPI(
    lifespan=lifespan
)

So, did I miss something? Or it's a bug of Beanie? I'm using FastAPI 0.115.2 and Beanie 1.27.0.

Expected behavior
Document.get(id, fetch_links=True) should work without error.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant