FastAPI and SQLAlchemy issue with getting backref data (async)

103 Views Asked by At

I am getting an error while getting models backref related data:

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)

models.py:

import uuid

from sqlalchemy_utils import EmailType, Timestamp, UUIDType


from sqlalchemy import Boolean, Column, ForeignKey, String, UniqueConstraint
from sqlalchemy.orm import relationship
from app.db import Base


class User(Base, Timestamp):
    __tablename__ = "users"

    id = Column(UUIDType(), default=uuid.uuid4, primary_key=True)
    name = Column(String, nullable=False)
    email = Column(EmailType, unique=True, nullable=False)
    hashed_password = Column(String, nullable=False)
    is_active = Column(Boolean, default=True, nullable=False)

    def __repr__(self):
        return f"User(id={self.id}, name={self.email})"

class Company(Base, Timestamp):
    __tablename__ = "companies"

    id = Column(UUIDType(binary=False), default=uuid.uuid4, primary_key=True)
    name = Column(String, nullable=False)
    is_active = Column(Boolean, default=True, nullable=False)

    def __repr__(self):
        return f"<Company(id={self.id}, name={self.name}, is_active={self.is_active})>"


class CompanyUser(Base, Timestamp):
    __tablename__ = "company_users"
    __table_args__ = (UniqueConstraint("company_id", "user_id", name="user_company"),)

    id = Column(UUIDType(binary=False), default=uuid.uuid4, primary_key=True)
    company_id = Column(
        UUIDType(binary=False),
        ForeignKey("companies.id", ondelete="CASCADE"),
        nullable=False,
    )
    company = relationship(
        "Company",
        order_by="Company.id",
        backref="company_users",
        lazy="subquery",
    )
    user_id = Column(
        UUIDType(binary=False),
        ForeignKey("users.id", ondelete="CASCADE"),
        nullable=False,
    )
    user = relationship(
        "User",
        order_by="User.id",
        backref="user_companies",
        lazy="subquery",
    )
    role = Column(String, nullable=False)

    def __repr__(self):
        return f"<CompanyUser(id={self.id}, company_id={self.company_id}, user_id={self.user_id}, is_active={self.is_active})>"

app/db.py:

from typing import Any

from sqlalchemy.ext.asyncio import AsyncSession, async_sessionmaker, create_async_engine
from sqlalchemy.orm import DeclarativeBase

from app.core.config import settings

async_engine = create_async_engine(str(settings.ASYNC_DATABASE_URL), pool_pre_ping=True)

async_session_maker = async_sessionmaker(
    async_engine,
    class_=AsyncSession,
    expire_on_commit=False,
    autocommit=False,
    autoflush=False,
)


class Base(DeclarativeBase):
    id: Any

router.py:

from fastapi import APIRouter
from sqlalchemy import select

from app.deps.db import CurrentAsyncSession
from app.deps.users import CurrentUser
from app.models import User
from app.schemas.user import UserSchema

router = APIRouter(prefix="/users")


@router.get("/me")
async def me(user: CurrentUser, session: CurrentAsyncSession) -> UserSchema:
    print(user.companies)
    # tried this also
    user = await session.get(User, user.id)
    print(user.companies)
    

    return user

My point was to use it in schema but found that even printing in the router is not working.

What is a solution here? This wasn't a problem on Flask with sync sqlalchemy.

requirements.txt:

fastapi==0.104.1
uvicorn==0.23.2
alembic==1.12.1
SQLAlchemy==2.0.22
pydantic-settings==2.0.3
sqlalchemy-utils==0.41.1
asyncpg==0.28.0
psycopg2==2.9.9
fastapi-users[sqlalchemy]==12.1.2
0

There are 0 best solutions below