APP/
ㄴ models.py --> 작업할 공간
# 이전 상태에서 추가로 import 해줘야 할 라이브러리
from sqlalchemy.sql.schema import ForeignKey
class TsItem(BaseMin, Base):
__tablename__ = "tsitem"
dialect = Column(String(255), nullable=False)
standard = Column(String(255), nullable=False)
english = Column(String(255), nullable=False)
chinese = Column(String(255), nullable=False)
japanese = Column(String(255), nullable=False)
owner_id = Column(Integer, ForeignKey("user.id"))
owner = relationship("User", back_populates="items")
from fastapi import Depends, APIRouter, status
from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials
from sqlalchemy.orm.session import Session
from typing import List
from app.database import get_db
from .schema import TsItemAdd, TsItem, TsItemDelete
from .service import addTsItem, findTsItems, deleteTsItem
router = APIRouter()
security = HTTPBearer()
# TsItem 테이블의 모든 row 로드
@router.get("", response_model=List[TsItem])
async def get_item_list(db: Session = Depends(get_db)):
return await findTsItems(db)
# TsItem 테이블에 Item 추가
@router.post("", response_model=TsItem, status_code=status.HTTP_201_CREATED)
async def add_item(
data: TsItemAdd,
cred: HTTPAuthorizationCredentials = Depends(security),
db: Session = Depends(get_db),
):
return await addTsItem(data, cred, db)
# TsItem 테이블에서 Item 제거
@router.delete("/{id}", response_model=TsItemDelete, status_code=status.HTTP_202_ACCEPTED)
async def delete_item(
id: int,
cred: HTTPAuthorizationCredentials = Depends(security),
db: Session = Depends(get_db),
):
return await deleteTsItem(id, cred, db)
@router.get("", response_model=List[TsItem])
async def get_item_list(db: Session = Depends(get_db)):
return await findTsItems(db)
findtsItems
에서 받아온 정보를 TsItem으로 이루어진 List 형태에 맞춰 반환한다.@router.post("", response_model=TsItem, status_code=status.HTTP_201_CREATED)
async def add_item(
data: TsItemAdd,
cred: HTTPAuthorizationCredentials = Depends(security),
db: Session = Depends(get_db),
):
return await addTsItem(data, cred, db)
addTsItem
에서 받아온 정보를 TsItem 형식에 맞게 반환한다.@router.delete("/{id}", response_model=TsItemDelete, status_code=status.HTTP_202_ACCEPTED)
async def delete_item(
id: int,
cred: HTTPAuthorizationCredentials = Depends(security),
db: Session = Depends(get_db),
):
return await deleteTsItem(id, cred, db)
deleteTsItem
에서 받아온 정보를 TsItem 형식에 맞게 반환한다.from ..user import utils
from .utils import add_tsitem, find_tsitems, delete_tsitem
async def addTsItem(data, cred, db):
decoded_dict = await utils.verify_user(cred)
row = await add_tsitem(data, decoded_dict.get("id"), db)
return row
async def findTsItems(db):
return await find_tsitems(db)
async def deleteTsItem(id, cred, db):
decoded_dict = await utils.verify_user(cred)
return await delete_tsitem(id, decoded_dict.get("id"), db)
async def addTsItem(data, cred, db):
decoded_dict = await utils.verify_user(cred)
row = await add_tsitem(data, decoded_dict.get("id"), db)
return row
user/utils.py 의
verify_user
에서 반환되는 딕셔너리 객체에는 JWT 토큰을 인코딩할 때 사용되었던 정보들이 들어있다. ex) email, id
verify_user
함수에 받아온 토큰 값을 넣어 해독된 딕셔너리를 받아온다.add_tsitem
으로 사투리,표준어,...,일본어를 DB에 저장한다.async def findTsItems(db):
return await find_tsitems(db)
find_tsitems
함수에서 반환된 정보를 반환한다.async def deleteTsItem(id, cred, db):
decoded_dict = await utils.verify_user(cred)
return await delete_tsitem(id, decoded_dict.get("id"), db)
verify_user
함수에 받아온 토큰 값을 넣어 해독된 딕셔너리를 받아온다.delete_tsitem
함수로 TsItem 테이블에서 row를 삭제한 뒤 정보를 반환한다.from fastapi import HTTPException, status
from app.models import TsItem
async def add_tsitem(data, id, db):
try:
row = TsItem(**data.dict(), owner_id=id)
db.add(row)
db.commit()
return row
except Exception as e:
raise HTTPException(
status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
detail=f"{e} occured while adding tsitem",
)
async def find_tsitems(db):
row = db.query(TsItem).all()
return row
async def delete_tsitem(id, user_id, db):
row = db.query(TsItem).filter_by(id=id).first()
if row is None:
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail="No Item Found",
)
if row.owner_id == user_id:
db.delete(row)
db.commit()
else:
raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail="It's not owner")
return row
async def add_tsitem(data, id, db):
try:
row = TsItem(**data.dict(), owner_id=id)
db.add(row)
db.commit()
return row
except Exception as e:
raise HTTPException(
status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
detail=f"{e} occured while adding tsitem",
)
async def find_tsitems(db):
row = db.query(TsItem).all()
return row
all() 메소드로 query를 사용하면 리스트 형태로 반환된다.
async def delete_tsitem(id, user_id, db):
row = db.query(TsItem).filter_by(id=id).first()
if row is None:
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail="No Item Found",
)
if row.owner_id == user_id:
db.delete(row)
db.commit()
else:
raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail="It's not owner")
return row
sqlalchemy에서 row를 찾지못하면 None 값을 반환한다.
from pydantic import BaseModel
class TsItemAdd(BaseModel):
dialect: str
standard: str
english: str
chinese: str
japanese: str
class TsItem(TsItemAdd):
id: int
owner_id: int
class Config:
from_attributes = True
class TsItemDelete(BaseModel):
id: int
생성한 Table에는 owner 라는 relationship으로 회원과 TsItem이 일대다 관계를 맺고 있지만, 위에 작성된 엔드포인트 중에서 relationship을 사용해서 query문을 작성한 적이 없다. 이는 모든 TsItem을 불러오는 엔드포인트만 존재하기 때문인데, 이 글을 읽고 있는 독자(있나?)가 있다면 이 부분을 생각해보면서 회원 별로 생성한 TsItem을 불러오는 엔드포인트를 작성해보면 좋을 것 같다.
[참고]
필자가 모든 TsItem을 불러오는 엔드포인트로 작성한 이유는, 캡스톤디자인 경연대회 당일날에 다른 사람들은 어떤 문장을 번역해봤을지 늦게 온 사람들도 확인해볼 수 있도록 하기 위해서였다.
위의 내용들을 잘 따라왔다면 사진처럼 Swagger에서 확인이 될 것이다.
이번에도 필자는 리팩토링 이 후 사진이라 V2로 태깅이 되어있다.
다음 게시글에서는 방명록 관련해서 작성하겠다.