-
Notifications
You must be signed in to change notification settings - Fork 0
Open
Description
🐛 [Troubleshooting] 마이페이지 자산 조회 및 회원 탈퇴 시 500 Internal Server Error 해결
📅 일시: 2025.11.19
📂 관련 레포/파일/경로:
- 레포:cardbenepick-app
backend/app/api/endpoints/assets.pybackend/app/api/endpoints/users.py
🏷 태그: #FastAPI #SQLModel #Python #NameError #AttributeError
1. 문제 상황 (Context & Problem)
-
작업 내용: 마이페이지(
MyPage) 기능을 구현하면서 **'연동된 자산 목록 조회(GET)'**와 '회원 탈퇴(DELETE)' API를 테스트하고 있었음. -
발생 오류: 두 API 모두 호출 시
500 Internal Server Error가 발생함.로그 확인 결과:
GET /api/assets/:NameError: name 'select' is not definedDELETE /api/users/me:db.exec(select(...)).delete()구문 실행 중AttributeError또는 트랜잭션 롤백 발생
2. 시도 및 해결 (Try & Solution)
-
원인 분석: 1. Import 누락:
assets.py에서sqlmodel의select함수를 사용하고 있었으나, 상단 import 구문에 포함되지 않음.
2. SQLModel 문법 오해:db.exec(select(...))는 쿼리 실행 결과(Result객체)를 반환하는데, 여기에 바로.delete()메서드를 체이닝하려고 해서 에러 발생. SQLModel(SQLAlchemy)에서는 조회 쿼리에 바로 delete를 붙일 수 없음. -
해결 방법:
[문제 1: 자산 조회]
assets.py파일 상단에from sqlmodel import select구문 추가하여 해결.
[문제 2: 회원 탈퇴]
- 시도 1 (Bulk Delete):
db.exec(delete(CardTransaction).where(...))처럼delete구문을 직접 사용해 보았으나, 트랜잭션 처리나 버전 호환성 문제로ROLLBACK이 발생하며 실패. - 최종 해결 (Fetch & Delete): 데이터를 먼저 조회(
select)한 뒤, 반복문을 돌며 객체를 하나씩 삭제(db.delete)하는 방식으로 변경하여 안정성 확보.
-
코드 변경 (회원 탈퇴 로직):
# 변경 전 (AS-IS): 잘못된 문법 db.exec(select(CardTransaction).where(CardTransaction.user_id == user_id)).delete() # 변경 후 (TO-BE): 조회 후 개별 삭제 (안전한 방식) transactions = db.exec(select(CardTransaction).where(CardTransaction.user_id == user_id)).all() for transaction in transactions: db.delete(transaction)
3. 배운 점 (Retrospective)
- SQLModel의 동작 방식:
db.exec()는 실행 결과를 리턴할 뿐, 쿼리 빌더 자체를 리턴하는 게 아니다. ORM을 쓸 때는 메서드 체이닝이 가능한 객체인지 항상 타입을 확인해야 한다. - Bulk Delete의 주의점: 한 번에 지우는 쿼리(
DELETE FROM table WHERE ...)가 성능은 좋지만, ORM 레벨에서 제약조건이나 Cascade 설정이 복잡할 때는 **'조회 후 삭제'**가 가장 확실하고 디버깅하기 쉬운 방법일 수 있다. - Import 확인: 코드를 복사/붙여넣기 하거나 수정할 때, 사용된 함수(
select등)가 제대로 import 되었는지 IDE의 린트 기능을 통해 꼼꼼히 확인하자.
Action Item: 향후 데이터 양이 많아져서 삭제 성능이 중요해지면, SQLModel/SQLAlchemy의 delete() 구문을 정확히 사용하는 방법(Bulk Delete)을 다시 학습하여 리팩토링하기.
Metadata
Metadata
Assignees
Labels
No labels