• 카테고리

    질문 & 답변
  • 세부 분야

    백엔드

  • 해결 여부

    해결됨

(실습) ORM 적용 - HTTP Response 처리

24.01.23 16:10 작성 24.01.23 16:12 수정 조회수 336

0

from typing import List
from fastapi import FastAPI, Body, HTTPException, Depends
from pydantic import BaseModel
from sqlalchemy.orm import Session
from database.orm import ToDo

from database.connection import get_db
from database.repository import get_todos
from schema.response import ListToDoResponse, ToDoSchema

app = FastAPI()


@app.get("/")
def heath_check_handler():
    return {"ping": "pong"}

todo_data = {
    1: {
        "id": 1,
        "contents": "실전! FastAPI 섹션 0 수강",
        "is_done": True,
    },
    2: {
        "id": 2,
        "contents": "실전! FastAPI 섹션 1 수강",
         "is_done": False,
    },
    3: {
        "id": 3,
        "contents": "실전! FastAPI 섹션 2 수강",
        "is_done": False,
    },
}

@app.get("/todos", status_code=200)
def get_todos_handler(
        order: str | None = None,
        session: Session = Depends(get_db),
) -> ListToDoResponse:
    todos: List[ToDo] = get_todos(session=session)

    if order and order == "DESC":
        return ListToDoResponse(
            todos=[ToDoSchema.from_orm(todo) for todo in todos[::-1]]
        )
    return ListToDoResponse(
        todos=[ToDoSchema.from_orm(todo) for todo in todos]
    )

@app.get("/todos/{todo_id}", status_code=200)
def get_todo_handler(todo_id: int):
    todo = todo_data.get(todo_id)
    if todo:
        return todo
    raise HTTPException(status_code=404, detail="ToDo Not Found")

class CreateToDoRequest(BaseModel):
    id: int
    contents: str
    is_done: bool

@app.post("/todos", status_code=201)
def create_todo_handler(request: CreateToDoRequest):
    todo_data[request.id] = request.dict()
    return todo_data[request.id]

@app.patch("/todos/{todo_id}", status_code=200)
def update_todo_handler(
        todo_id: int,
        is_done: bool = Body(..., embed=True)
):
    todo = todo_data.get(todo_id)
    if todo:
        todo["is_done"] = is_done
        return todo
    raise HTTPException(status_code=404, detail="ToDo Not Found")

@app.delete("/todos/{todo_id}")
def delete_todo_handler(todo_id: int):
    todo = todo_data.pop(todo_id, None)
    if todo:
        return
    raise HTTPException(status_code=404, detail="ToDo Not Found")

 

from typing import List
from pydantic import BaseModel


class ToDoSchema(BaseModel):
    id: int
    contents: str
    is_done: bool

    class Config:
        orm_mode = True

class ListToDoResponse(BaseModel):
    todos: List[ToDoSchema]

 

from typing import List
from sqlalchemy import select
from sqlalchemy.orm import Session

from database.orm import ToDo

def get_todos(session: Session) -> List[ToDo]:
    return list(session.scalars(select(ToDo)))

 

from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker

DATABASE_URL = "mysql+pymysql://root:todos@127.0.0.1:3306/todos"

engine = create_engine(DATABASE_URL, echo=True)
SessionFactory = sessionmaker(autocommit=False, autoflush=False, bind=engine)

def get_db():
    session = SessionFactory()
    try:
        yield session
    finally:
        session.close()

 

from sqlalchemy import Boolean, Column, Integer, String
from sqlalchemy.orm import declarative_base

Base = declarative_base()

class ToDo(Base):
    __tablename__ = 'todo'

    id = Column(Integer, primary_key=True, index=True)
    contents = Column(String(256), nullable=False)
    is_done = Column(Boolean, nullable=False)

    def __repr__(self):
        return f"ToDo(id={self.id}, contents={self.contents}, is_done={self.is_done})"

 

에러가 납니다.

 

 

 

 

 

파이썬 콘솔

 

<input>:1: PydanticDeprecatedSince20: The from_orm method is deprecated;

 

 

from schema.response import ToDoSchema

from datagbase.orm import ToDo

Traceback (most recent call last):

File "C:\Program Files\JetBrains\PyCharm 2023.3.2\plugins\python\helpers\pydev\pydevconsole.py", line 364, in runcode

coro = func()

^^^^^^

File "<input>", line 1, in <module>

File "C:\Program Files\JetBrains\PyCharm 2023.3.2\plugins\python\helpers\pydev\_pydev_bundle\pydev_import_hook.py", line 21, in do_import

module = self._system_import(name, args, *kwargs)

^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

ModuleNotFoundError: No module named 'datagbase'

from database.orm import ToDo

todo = ToDo(id=100, contents="test", is_done=True)

ToDoSchema.from_orm(todo)

<input>:1: PydanticDeprecatedSince20: The from_orm method is deprecated; set model_config['from_attributes']=True and use model_validate instead. Deprecated in Pydantic V2.0 to be removed in V3.0. See Pydantic V2 Migration Guide at https://errors.pydantic.dev/2.5/migration/

Traceback (most recent call last):

File "C:\Program Files\JetBrains\PyCharm 2023.3.2\plugins\python\helpers\pydev\pydevconsole.py", line 364, in runcode

coro = func()

^^^^^^

File "<input>", line 1, in <module>

File "C:\Users\manag\pyProject\todos\Lib\site-packages\typing_extensions.py", line 2499, in wrapper

return arg(*args, **kwargs)

^^^^^^^^^^^^^^^^^^^^

File "C:\Users\manag\pyProject\todos\Lib\site-packages\pydantic\main.py", line 1126, in from_orm

raise PydanticUserError(

pydantic.errors.PydanticUserError: You must set the config attribute from_attributes=True to use from_orm

 

 

http://localhost:8000/docs#/default/get_todos_handler_todos_get

접속시 터미널

INFO: 127.0.0.1:56312 - "GET /docs HTTP/1.1" 200 OK

INFO: 127.0.0.1:56312 - "GET /openapi.json HTTP/1.1" 200 OK

2024-01-23 16:06:15,108 INFO sqlalchemy.engine.Engine BEGIN (implicit)

2024-01-23 16:06:15,109 INFO sqlalchemy.engine.Engine SELECT todo.id, todo.contents, todo.is_done

FROM todo

2024-01-23 16:06:15,109 INFO sqlalchemy.engine.Engine [cached since 826.5s ago] {}

2024-01-23 16:06:15,113 INFO sqlalchemy.engine.Engine ROLLBACK

INFO: 127.0.0.1:56312 - "GET /todos HTTP/1.1" 500 Internal Server Error

ERROR: Exception in ASGI application

Traceback (most recent call last):

File "C:\Users\manag\pyProject\todos\Lib\site-packages\uvicorn\protocols\http\h11_impl.py", line 404, in run_asgi

result = await app( # type: ignore[func-returns-value]

^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

File "C:\Users\manag\pyProject\todos\Lib\site-packages\uvicorn\middleware\proxy_headers.py", line 84, in call

return await self.app(scope, receive, send)

^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

File "C:\Users\manag\pyProject\todos\Lib\site-packages\fastapi\applications.py", line 1054, in call

await super().__call__(scope, receive, send)

File "C:\Users\manag\pyProject\todos\Lib\site-packages\starlette\applications.py", line 123, in call

await self.middleware_stack(scope, receive, send)

File "C:\Users\manag\pyProject\todos\Lib\site-packages\starlette\middleware\errors.py", line 186, in call

raise exc

File "C:\Users\manag\pyProject\todos\Lib\site-packages\starlette\middleware\errors.py", line 164, in call

await self.app(scope, receive, _send)

File "C:\Users\manag\pyProject\todos\Lib\site-packages\starlette\middleware\exceptions.py", line 62, in call

await wrap_app_handling_exceptions(self.app, conn)(scope, receive, send)

File "C:\Users\manag\pyProject\todos\Lib\site-packages\starlette\_exception_handler.py", line 64, in wrapped_app

raise exc

File "C:\Users\manag\pyProject\todos\Lib\site-packages\starlette\_exception_handler.py", line 53, in wrapped_app

await app(scope, receive, sender)

File "C:\Users\manag\pyProject\todos\Lib\site-packages\starlette\routing.py", line 762, in call

await self.middleware_stack(scope, receive, send)

File "C:\Users\manag\pyProject\todos\Lib\site-packages\starlette\routing.py", line 782, in app

await route.handle(scope, receive, send)

File "C:\Users\manag\pyProject\todos\Lib\site-packages\starlette\routing.py", line 297, in handle

await self.app(scope, receive, send)

File "C:\Users\manag\pyProject\todos\Lib\site-packages\starlette\routing.py", line 77, in app

await wrap_app_handling_exceptions(app, request)(scope, receive, send)

File "C:\Users\manag\pyProject\todos\Lib\site-packages\starlette\_exception_handler.py", line 64, in wrapped_app

raise exc

File "C:\Users\manag\pyProject\todos\Lib\site-packages\starlette\_exception_handler.py", line 53, in wrapped_app

await app(scope, receive, sender)

File "C:\Users\manag\pyProject\todos\Lib\site-packages\starlette\routing.py", line 72, in app

response = await func(request)

^^^^^^^^^^^^^^^^^^^

File "C:\Users\manag\pyProject\todos\Lib\site-packages\fastapi\routing.py", line 299, in app

raise e

File "C:\Users\manag\pyProject\todos\Lib\site-packages\fastapi\routing.py", line 294, in app

raw_response = await run_endpoint_function(

^^^^^^^^^^^^^^^^^^^^^^^^^^^^

File "C:\Users\manag\pyProject\todos\Lib\site-packages\fastapi\routing.py", line 193, in run_endpoint_function

return await run_in_threadpool(dependant.call, **values)

^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

File "C:\Users\manag\pyProject\todos\Lib\site-packages\starlette\concurrency.py", line 40, in run_in_threadpool

return await anyio.to_thread.run_sync(func, *args)

^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

File "C:\Users\manag\pyProject\todos\Lib\site-packages\anyio\to_thread.py", line 56, in run_sync

return await get_async_backend().run_sync_in_worker_thread(

^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

File "C:\Users\manag\pyProject\todos\Lib\site-packages\anyio\_backends\_asyncio.py", line 2134, in run_sync_in_worker_thread

return await future

^^^^^^^^^^^^

File "C:\Users\manag\pyProject\todos\Lib\site-packages\anyio\_backends\_asyncio.py", line 851, in run

result = context.run(func, *args)

^^^^^^^^^^^^^^^^^^^^^^^^

File "C:\Users\manag\pyProject\todos\src\main.py", line 48, in get_todos_handler

todos=[ToDoSchema.from_orm(todo) for todo in todos]

^^^^^^^^^^^^^^^^^^^^^^^^^

File "C:\Users\manag\pyProject\todos\Lib\site-packages\typing_extensions.py", line 2499, in wrapper

return arg(*args, **kwargs)

^^^^^^^^^^^^^^^^^^^^

File "C:\Users\manag\pyProject\todos\Lib\site-packages\pydantic\main.py", line 1126, in from_orm

raise PydanticUserError(

pydantic.errors.PydanticUserError: You must set the config attribute from_attributes=True to use from_orm

 

답변 2

·

답변을 작성해보세요.

0

안녕하세요! AI 인턴이 답변을 제법 잘 해주었네요. 잘 해결하셨다니 다행입니다!

pydantic 버전 때문에 발생하는 문제로, 자세한 내용은 강의 공지에 있습니다.

생각보다 어렵지 않으니 v2로 마이그레이션 하는 연습을 해보셔도 좋을 것 같습니다!

남은 강의도 화이팅하세요!

 

0

인프런 AI 인턴님의 프로필

인프런 AI 인턴

2024.01.23

안녕하세요, 인프런 AI 인턴입니다.

질문자님께서 겪고 계신 문제는 Pydantic 라이브러리의 버전 업데이트에 따라서 from_orm 메서드의 사용이 지원 중단(deprecated)되었기 때문에 발생하는 것으로 보입니다. Pydantic 버전 2.0부터 from_orm 메서드 대신 model_config['from_attributes']=True를 설정하고 model_validate를 사용해야 한다는 경고 메시지가 나옵니다.

이를 해결하기 위해서는 Pydantic 모델의 Config 내에 from_attributes=True 설정이 필요하며, 기존의 from_orm 사용 부분을 model_validate로 변경해야 합니다.

이 문제에 대한 유사한 질문 중 하나가 있으며, 아래 링크에서 확인하실 수 있습니다:

본 질문에서는 pydantic 버전 문제에 대한 답변도 함께 있으니 참고하시면 좋겠습니다. 기존의 from_orm 메서드 사용에서 발생한 문제를 해결하기 위해서는 Pydantic 모델을 업데이트하거나, Pydantic 버전을 downgrade하여 해결이 가능합니다.

저는 질문자님의 이해를 돕고자 지식공유자님의 기존 답변을 참고하여 유사한 답변 링크를 추천해드리고 있습니다.
현재 베타 기능으로 답변이 만족스럽지 않을 수 있는 점 양해 부탁드립니다. 🙏
추가적으로 궁금한 점이 있으시면, 이어서 질문해 주세요. 곧 지식공유자께서 답변해 주실 것입니다.