1

I am trying to return connected data via foreign key in FastAPI but when I use a class in response_model that contains the data, the endpoint throws a greenlet error. I am using FastAPI and SQLModel (I know about the error with SQLModel relationships and SQLAlchemy and I downgrade to sqlalchemy 1.4.35). My code is the following:

models.py

class BaseQuestion(SQLModel):
    survey_id: Optional[int] = Field(default=None, foreign_key="survey.id")
    title: Optional[str] = Field(default=None, max_length=45)
    help: Optional[str] = Field(default=None, max_length=45)
    priority: Optional[int] = Field(default=None)
    is_mandatory: Optional[int] = Field(default=None)


class Question(BaseQuestion, table=True):
    id: Optional[int] = Field(default=None, primary_key=True)

    answers: List["Answer"] = Relationship(back_populates="question")
    survey: Optional[Survey] = Relationship(back_populates="questions")

class QuestionOut(BaseQuestion):
    id: Optional[int] = Field(default=None, primary_key=True)


class BaseAnswer(SQLModel):
    question_id: Optional[int] = Field(default=None, foreign_key="question.id")
    text: Optional[str] = Field(default=None, max_length=45)
    help: Optional[str] = Field(default=None, max_length=45)
    priority: Optional[str] = Field(default=None, max_length=45)
    is_stoping: Optional[int] = Field(default=0)


class Answer(BaseAnswer, table=True):
    id: Optional[int] = Field(default=None, primary_key=True)

    question: Optional[Question] = Relationship(back_populates="answers")


class AnswerOut(BaseAnswer):
    id: Optional[int] = Field(default=None, primary_key=True)


class QuestionWithAnswer(QuestionOut):
    answers: List[Answer] = []

api.py

@app.get("/questions/{question_id}", response_model=questionnaire.QuestionOut)
async def get_question(question_id: int, session: db.Session = Depends(session)):
    db_question = await session.get(questionnaire.Question, question_id)
    if not db_question:
        raise HTTPException(status_code=404, detail="Question not found")

    return db_question

db.py

def create_engine(host: str, username: str, password: str, name: str) -> AsyncEngine:
    return create_async_engine(
        URL.create(
            drivername="mariadb+aiomysql",
            host=host,
            username=username,
            password=password,
            database=name,
        ),
    )


def session_factory(app: FastAPI) -> Callable:
    async def session() -> AsyncGenerator[Session, None]:
        async with Session(app.state.engine) as session:
            yield session

    return session

And the error is:

concurrency_py3k.py", line 67, in await_only
survey-service-1  |     raise exc.MissingGreenlet(
survey-service-1  | sqlalchemy.exc.StatementError: (sqlalchemy.exc.MissingGreenlet) greenlet_spawn has not been called; can't call await_() here. Was IO attempted in an unexpected place?
survey-service-1  | [SQL: SELECT answer.question_id AS answer_question_id, answer.text AS answer_text, answer.help AS answer_help, answer.priority AS answer_priority, answer.is_stoping AS answer_is_stoping, answer.id AS answer_id 
survey-service-1  | FROM answer 
survey-service-1  | WHERE %s = answer.question_id]
survey-service-1  | [parameters: [{'%(140173137451136 param)s': 1}]]
survey-service-1  | (Background on this error at: https://sqlalche.me/e/14/xd2s)
Cheekou
  • 35
  • 6

1 Answers1

0

Finally, I found the solution here https://github.com/tiangolo/sqlmodel/issues/74

Cheekou
  • 35
  • 6
  • Hi, congratulations on figuring this out on yourself. However, this answer isn't so helpful. Can you kindly add what the issue was and what changes you made in your code to fix it. – aydow Nov 01 '22 at 15:30