묻고 답해요
164만명의 커뮤니티!! 함께 토론해봐요.
인프런 TOP Writers
-
해결됨[매일 완독 챌린지] 저자와 함께하는 <FastAPI로 기획에서 출시까지>
4주 1회차 과제
is_host / 캘린더 보유 여부 중에 어느 것을 사용할까? 둘 다?is_host 는 반드시 사용할 것 같음is_host 필드가 있으면 캘린더 라는 다른 엔티티에 의존하지 않고 is_host 만으로 호스트 여부를 판단할 수 있어서캘린더 보유 여부는 선택적일 것 같음아래와 같은 정책을 설정해야할 필요가 있을때is_host 인데 캘린더가 있는 경우s_host 인데 캘린더가 없는 경우 아니면 '호스트는 최소 하나 이상의 캘린더는 있어야 한다' 같은 정책
-
해결됨[매일 완독 챌린지] 저자와 함께하는 <FastAPI로 기획에서 출시까지>
4주 1회차 과제
기획의 관점에서 Host 체크 방법is_host 필드 체크사용자가 호스트인지 먼저 확인을 하게 되므로 호스트 등록, 호스트만 조회, 호스트에 주어진 권한 제어 등 호스트를 따로 관리하고 싶을때 장점이 있습니다캘린더 보유 체크캘린더로 호스트일 경우는 호스트, 게스트 구분이 회원 등급이나 종류가 아닌 모두가 호스트나 게스트가 될수 있고 예약이 서로에게 일어날 수 있을때 장점이 있습니다. 구글 캘린더로 예를 들면 모두가 초대가 가능하고 초대도 가능한 방식입니다. 내가 선택한다면저라면 기본적으로는 is_host 필드로 체크하고 실제 예약을 받는다면 캘린더 체크를 이후에 하겠습니다. 호스트 관리를 따로 하게 되면 호스트만 따로 조회도 가능하고 호스트를 하고 싶지 않을때는 호스트가 되지 않는 것도 가능합니다. 또한 is_host를 기본 true로 하게 되면 모두가 호스트가 되는 방식도 가능하므로 앞에서 가정한 모두가 호스트/게스트인 방식도 쉽게 전환이 가능합니다. 예약 가능한 캘린더 체크는 실제로 이사람이 호스트라고 하더라도 예약일자가 있는지에 따라 예약화면 컨트롤 등이 가능하기 때문에 체크가 필요합니다. 요약하면 is_host 체크를 할 때 상황에 따라 유연하게 호스트 <-> 게스트 전환이 쉽고 필요한 경우 호스트이면서 게스트인 정책도 가능하기 때문에 좀 더 유연한 방법이라고 생각합니다.
-
미해결[매일 완독 챌린지] 저자와 함께하는 <FastAPI로 기획에서 출시까지>
4주 4회차 과제 제출
쟁점 정리예약 일정 변경과 관련해서 결정해야 할 핵심은 다음과 같습니다:일자/타임슬롯 변경을 허용할 것인가? vs 취소 후 재예약만 가능하게 할 것인가?변경을 허용한다면, 언제까지 허용할 것인가?당일 변경은 불가능하다 (이건 확정)내가 선택한 정책일자/타임슬롯 변경을 허용하되, 예약일 24시간 전까지만 가능근거:"취소 → 재예약" 방식은 사용자가 불편하고, 원하는 시간이 이미 찼을 수도 있음24시간 전까지는 게스트에게 충분한 유연성을 주면서도, 호스트가 하루 전부터 안정적으로 준비할 수 있음규칙이 단순해서 사용자가 이해하기 쉽고, 구현도 간단함구현 시나리오시나리오 1: 여유 있는 변경 (성공)민수는 2월 10일 오후 2시를 예약했습니다.2월 7일에 2월 11일 오후 4시로 바꾸고 싶어졌습니다.→ 변경 가능 (24시간 이상 여유)→ "변경이 완료되었습니다."시나리오 2: 임박한 변경 시도 (실패)지영은 2월 10일 오후 2시를 예약했습니다.2월 9일 오후 3시에 시간을 바꾸려고 합니다.→ 변경 불가 (24시간 미만)→ "예약일 24시간 전까지만 변경 가능합니다. 취소 후 재예약해주세요."시나리오 3: 당일 변경 시도 (실패)현우는 2월 10일 오후 2시를 예약했습니다.2월 10일 오전 11시에 오후 4시로 바꾸려고 합니다.→ 변경 불가 (당일)→ "당일 일정 변경은 불가능합니다."이상입니다.
-
해결됨[매일 완독 챌린지] 저자와 함께하는 <FastAPI로 기획에서 출시까지>
4주 1회차 과제 제출합니다.
저는 is_host 필드와 calendar 존재 여부를 둘 다 검증해야 한다고 판단했습니다.왜 두 가지를 모두 사용해야 할까요?우선 두 요소는 서로 다른 의미를 가지고 있다고 생각합니다.is_host: 이 사용자가 호스트 자격이 있는가? (역할)calendar 존재: 이 호스트가 실제로 운영 중인가? (상태)현실로 비유하자면, is_host는 사업자등록증을 가지고 있는 상태이고, calendar가 있다는 건 실제로 가게를 오픈한 상태라고 볼 수 있습니다. 사업자등록증은 있지만 아직 가게를 열지 않은 사람도 있을 수 있잖아요?그래서 둘 중 하나만 체크하면 문제가 생긴다고 봅니다.만약 calendar 존재 여부만 체크한다면?calendar만 보고 판단하면 권한 체계가 무너질 수 있습니다. 예를 들어 일반 사용자가 억지로 캘린더를 생성하면 호스트로 둔갑할 수 있는 보안 문제가 생기죠. 또 호스트가 일시적으로 캘린더를 삭제했다가 다시 만들 때마다 권한 관리가 복잡해집니다.만약 is_host만 체크한다면?반대로 is_host만 체크하면, 캘린더가 없는데도 예약 관련 API를 호출할 수 있게 되어서 500 에러가 발생할 수 있습니다. "호스트인데 캘린더는 없는" 이상한 상태를 어떻게 처리해야 할지도 애매해지고요.두 가지를 순차적으로 검증하는 게 좋습니다저는 이렇게 단계적으로 확인하는 게 맞다고 봅니다:먼저 is_host로 호스트 자격이 있는지 확인그 다음 calendar 존재로 실제 운영 가능한지 확인이렇게 하면 사용자에게도 명확한 피드백을 줄 수 있어요. "호스트 권한이 없습니다" vs "캘린더를 먼저 생성해주세요" 처럼 무엇을 해야 하는지 정확히 알려줄 수 있죠.미래 확장성도 고려했습니다나중에 서비스가 커지면 호스트 상태를 더 세분화할 수도 있을 것 같아요:준비 중 호스트 (is_host=true, 캘린더 없음) → 대시보드 접근만 가능운영 중 호스트 (is_host=true, 캘린더 있음) → 모든 기능 사용 가능휴면 호스트 (is_host=true, 캘린더 비활성화) → 기존 예약 조회만 가능이런 식으로 관리하려면 역할과 리소스를 분리해서 체크하는 게 필수라고 생각합니다.성능 걱정은 없을까요?is_host는 User 모델의 필드라서 추가 DB 쿼리가 필요 없고, calendar 조회도 어차피 해야 하는 작업이라 성능에 큰 영향은 없다고 봅니다.
-
해결됨[매일 완독 챌린지] 저자와 함께하는 <FastAPI로 기획에서 출시까지>
4주 2회차 과제
안녕하세요. 과제를 잘 못 이해한건가 싶기도 하지만 아래와 같은 조건하에 구현을 해 봤습니다. 수업 과정에서 Front-end는 고정인 상황이기 때문에 기존 API는 변경이 없다는 가정하에 변경 해 봤습니다. 시간대1개와 요일n개의 설정이 하나의 row로 묶여있는 상태로는 요일별 시간대 변동에 대응하기 까다로운 것 같아 요일별 개별 row로 저장하도록 일부 수정 하였습니다. API endpoint 모델 변경을 피하기 위해서 내부적으로 여러개의 요일별 row로 나누어 저장하도록 했습니다. 고민중에 작가님께서 올려 놓으신 레퍼런스 코드를 봤는데, 책에서 언급하신 것 처럼 postgres 경우와 sqlite 경우로 코드가 분기 되는 것을 보았고, 지금은 교육 과정이기 때문이라고 생각 하지만 배포 코드와 개발 환경 코드가 다른것은 여러모로 좋지 않은 것 같아 현재는 sqlite 기준으로 개별 DB구현에서만 지원하는 것은 배제하는 방향으로 구현 했습니다. 1과 같이 변경 함으로써, 기 등록된 정보의 수정에서는 개별 날짜 별 시간대 설정 면에서 자유도가 생겼다고 생각 됩니다.타임슬롯의 변경과 삭제에 관해서는 내부적으로는 time-slot으로 관리하지만, 외부공개 id는 아니므로, 키 로서 start-time, end-time, weekday (API형태로서는 리스트)조합으로 정의 해서 동작 하도록 구현했습니다.특히 삭제의 경우는 부득이 delete method의 경우는 payload가 포함되는것이 받아들여지지 않는 경우도 있는것을 고려해서, 새 등록 값 두가지(new_start_time과, new_end_time) 값이 모두 제공되고 같은 경우를 특정하여 삭제 동작으로 정의하여 동작하도록 구현했습니다. class TimeSlotUpdateByGroupIn(SQLModel): start_time: time end_time: time weekdays: Weekdays new_start_time: time | None = None new_end_time: time | None = None new_weekdays: Weekdays | None = None @model_validator(mode="after") def check_update_fields(self): update_fields = { "new_start_time": self.new_start_time, "new_end_time": self.new_end_time, "new_weekdays": self.new_weekdays, } if not any(value is not None for value in update_fields.values()): raise ValueError("최소 하나의 수정 필드는 반드시 제공되어야 합니다.") return self @router.post("/time-slots", status_code=status.HTTP_201_CREATED, response_model=TimeSlotOut) async def create_time_slot( user: CurrentUserDep, session: DbSessionDep, payload: TimeSlotCreateIn, ) -> TimeSlotOut: if not user.is_host: raise GuestPermissionError() weekdays = sorted(set(payload.weekdays)) # dup. check with already exist one stmt = select(TimeSlot).where( and_( TimeSlot.calendar_id == user.calendar.id, TimeSlot.weekday.in_(weekdays), TimeSlot.start_time < payload.end_time, TimeSlot.end_time > payload.start_time, ) ) result = await session.execute(stmt) existing_time_slot = result.scalars().first() if existing_time_slot: raise TimeSlotOverlapError() time_slots = [ TimeSlot( calendar_id=user.calendar.id, start_time=payload.start_time, end_time=payload.end_time, weekday=weekday, ) for weekday in weekdays ] session.add_all(time_slots) await session.commit() if not time_slots: raise TimeSlotOverlapError() return TimeSlotOut( start_time=time_slots[0].start_time, end_time=time_slots[0].end_time, weekdays=weekdays, created_at=time_slots[0].created_at, updated_at=time_slots[0].updated_at, ) @router.get( "/time-slots/{host_username}", status_code=status.HTTP_200_OK, response_model=list[TimeSlotOut], ) async def get_host_timeslots( host_username: str, session: DbSessionDep, ) -> list[TimeSlotOut]: stmt = ( select(User) .where(User.username == host_username) .where(User.is_host.is_(true())) ) result = await session.execute(stmt) host = result.scalar_one_or_none() if host is None or host.calendar is None: raise HostNotFoundError() stmt = select(TimeSlot).where(TimeSlot.calendar_id == host.calendar.id) result = await session.execute(stmt) time_slots = result.scalars().all() grouped: dict[tuple[time, time], TimeSlotOut] = {} for time_slot in time_slots: key = (time_slot.start_time, time_slot.end_time) if key not in grouped: grouped[key] = TimeSlotOut( start_time=time_slot.start_time, end_time=time_slot.end_time, weekdays=[time_slot.weekday], created_at=time_slot.created_at, updated_at=time_slot.updated_at, ) continue grouped[key].weekdays.append(time_slot.weekday) if time_slot.created_at < grouped[key].created_at: grouped[key].created_at = time_slot.created_at if time_slot.updated_at > grouped[key].updated_at: grouped[key].updated_at = time_slot.updated_at if not grouped: raise TimeSlotNotFoundError() for time_slot in grouped.values(): time_slot.weekdays = sorted(set(time_slot.weekdays)) return list(grouped.values()) @router.patch( "/time-slots", status_code=status.HTTP_200_OK, response_model=TimeSlotOut | None, ) async def update_time_slot( user: CurrentUserDep, session: DbSessionDep, payload: TimeSlotUpdateByGroupIn, ) -> TimeSlotOut | None: if not user.is_host: raise GuestPermissionError() current_weekdays = sorted(set(payload.weekdays)) stmt = select(TimeSlot).where( and_( TimeSlot.calendar_id == user.calendar.id, TimeSlot.start_time == payload.start_time, TimeSlot.end_time == payload.end_time, ) ) result = await session.execute(stmt) current_slots = result.scalars().all() if not current_slots: raise TimeSlotNotFoundError() existing_weekdays = sorted({slot.weekday for slot in current_slots}) if existing_weekdays != current_weekdays: raise TimeSlotNotFoundError() delete_only = ( payload.new_start_time is not None and payload.new_end_time is not None and payload.new_start_time == payload.new_end_time ) if delete_only: current_ids = [slot.id for slot in current_slots] await session.execute(delete(TimeSlot).where(TimeSlot.id.in_(current_ids))) await session.commit() return None new_start_time = payload.new_start_time or payload.start_time new_end_time = payload.new_end_time or payload.end_time new_weekdays = sorted(set(payload.new_weekdays or payload.weekdays)) if new_start_time >= new_end_time: raise HTTPException( status_code=status.HTTP_422_UNPROCESSABLE_CONTENT, detail="시작 시간은 종료 시간보다 빨라야 합니다.", ) current_ids = [slot.id for slot in current_slots] stmt = select(TimeSlot).where( and_( TimeSlot.calendar_id == user.calendar.id, TimeSlot.weekday.in_(new_weekdays), TimeSlot.start_time < new_end_time, TimeSlot.end_time > new_start_time, TimeSlot.id.not_in(current_ids), ) ) result = await session.execute(stmt) existing_time_slot = result.scalars().first() if existing_time_slot: raise TimeSlotOverlapError() await session.execute(delete(TimeSlot).where(TimeSlot.id.in_(current_ids))) new_time_slots = [ TimeSlot( calendar_id=user.calendar.id, start_time=new_start_time, end_time=new_end_time, weekday=weekday, ) for weekday in new_weekdays ] session.add_all(new_time_slots) await session.commit() return TimeSlotOut( start_time=new_start_time, end_time=new_end_time, weekdays=new_weekdays, created_at=new_time_slots[0].created_at, updated_at=new_time_slots[0].updated_at, )
-
해결됨[매일 완독 챌린지] 저자와 함께하는 <FastAPI로 기획에서 출시까지>
patch 요청시 payload가 넘어가지 않습니다.
아래 두 요청 코드에서 patch 요청 시 payload가 엔드포인트 함수에서 None으로 잡혀 model_dump()에서 오류가 발생합니다. 원인을 잘 모르겠습니다.[오류][요청 코드]@pytest.mark.parametrize("payload", [ {"display_name": "푸딩캠프"}, {"email": "hannal@example.com"}, {"display_name": "푸딩캠프", "email": "hannal@example.com"}, ]) async def test_사용자가_변경하는_항목만_변경되고_나머지는_기존_값을_유지한다( client_with_auth: TestClient, # 인증을 받은 클라이언트 payload: dict, # 클라이언트 요청 페이로드 host_user: User, # 클라이언트 사용자 ): # 현재 사용자 정보를 보관한다. before_data = host_user.model_dump() response = client_with_auth.patch("/account/@me", json=payload) # (...)async def test_비밀번호_변경_시_해싱_처리한_비밀번호가_저장되어야_한다( client_with_auth: TestClient, host_user: User, db_session: AsyncSession, ): before_data = host_user.hashed_password payload = { "password": "new_password", "password_again": "new_password", } response = client_with_auth.patch("/account/@me", json=payload) # (...)[엔드포인트]@router.patch("/@me", response_model=UserDetailOut) async def update_user( user: CurrentUserDep, session: DbSessionDep, payload: UpdateUserPayload = Body(...), ) -> User: updated_data = payload.model_dump(exclude_none=True, exclude={"password", "password_again"}) stmt = update(User).where(User.id == user.id).values(**updated_data) await session.execute(stmt) await session.commit() await session.refresh(user) return user [스키마]class UpdateUserPayload(SQLModel): display_name: str | None = Field(default=None, min_length=4, max_length=40) email: EmailStr | None = Field(default=None, max_length=128) password: str | None = Field(default=None, min_length=8, max_length=128) password_again: str | None = Field(default=None, min_length=8, max_length=128) @model_validator(mode="after") def check_all_fields_are_none(self) -> Self: if not self.model_dump(exclude_none=True): raise ValueError("최소 하나의 필드는 반드시 제공되어야 합니다.") return self @model_validator(mode="after") def verify_password(self) -> Self: if self.password is not None or self.password_again is not None: # 둘 중 하나라도 들어오면 둘 다 있어야 함 if not self.password or not self.password_again: raise ValueError("비밀번호 변경 시 password와 password_again을 모두 제공해야 합니다.") if self.password != self.password_again: raise ValueError("비밀번호가 일치하지 않습니다.") @computed_field @property def hashed_password(self) -> str | None: if self.password: return hash_password(self.password) return None[픽스처]@pytest.fixture(autouse=True) async def db_session(): dsn = "sqlite+aiosqlite:///:memory:" engine = create_async_engine(dsn) async with engine.begin() as conn: await conn.run_sync(SQLModel.metadata.drop_all) await conn.run_sync(SQLModel.metadata.create_all) session_factory = create_session(engine) async with session_factory() as session: yield session await conn.run_sync(SQLModel.metadata.drop_all) await engine.dispose() @pytest.fixture() def fastapi_app(db_session: AsyncSession): app = FastAPI() include_routers(app) async def override_use_session(): yield db_session app.dependency_overrides[use_session] = override_use_session return app @pytest.fixture() async def host_user(db_session: AsyncSession): user = account_models.User( username="puddingcamp", hashed_password=hash_password("testtest"), email="puddingcamp@example.com", display_name="푸딩캠프", is_host=True, ) db_session.add(user) await db_session.flush() await db_session.commit() return user @pytest.fixture() def client_with_auth(fastapi_app: FastAPI, host_user: account_models.User): payload = LoginPayload.model_validate({ "username": host_user.username, "password": "testtest", }) with TestClient(fastapi_app) as client: response = client.post("/account/login", json=payload.model_dump()) assert response.status_code == status.HTTP_200_OK auth_token = response.cookies.get("auth_token") assert auth_token is not None client.cookies.set("auth_token", auth_token) yield client
-
미해결FastAPI 완벽 가이드
Update(수정)용 모델 질문 드립니다.
안녕하세요 교수님강의를 통해 많은 도움을 받고 있는 수강생입니다.수정 기능 구현 시, 전체 데이터를 Body에 담아 보내는 방식은 대용량 파일이나 멀티파트 폼 데이터 처리 시 효율성이 떨어지는 경험을 했습니다. 그래서 모든 필드를 Optional로 설정하여 부분 수정을 허용하게 하면 벨리데이션(Validation) 로직이 복잡해지는 문제가 발생했습니다. 현업에서는 어떤 식으로 업데이트 코드 스타일을 관리하는 것이 표준인지 교수님의 조언을 듣고 싶습니다.감사합니다.
-
해결됨[매일 완독 챌린지] 저자와 함께하는 <FastAPI로 기획에서 출시까지>
4주 1회차 과제
- is_host를 기준으로 호스트 사용자와 게스트 사용자를 구분하는 것은, 가입 당시부터 본인의 역할을 선택하여 구분 짓는 경우에 효과적인 것으로 판단됩니다. 가입 시점부터 역할(게스트/호스트)을 구분 지어서 관리하고자 하는 경우에 적절한 구조라고 생각되며, 호스트의 자격조건이 있거나, 검증이 필요한 서비스라면 이렇게 관리하는 방법이 적절해 보입니다. - 반면, 호스트/게스트의 타입을 캘린더의 존재 여부(또는 갯수)로 정의한다고 하면, 모든 가입자가 가입시에 동일한 자격을 갖는 가입자로서 가입처리가 되고, 추가 단계로서 캘린더를 생성 함으로 써, 호스트와 게스트의 역할을 자유롭게 넘나드는 자유도가 생기는 구조가 될 것 같습니다. - 지금은 커피챗을 목적으로 일정을 조율하는 목적을 갖는 시스템이므로, is_host를 사용하지 않는 결정을 하겠습니다. 전자상거래 시스템같은 판매자와/소비자 처럼 엄격한 구분과 자격을 검증해야 하는 시스템으로 여겨지지는 않기때문입니다. is_host 필드가 없어지는 경우에, 사용자의 상태(또는 역할)을 구분하기 위해서 매번 캘린더의 존재 여부를 확인해야 하지만 앞서 언급한 호스트와 게스트의 역할 변경에 열려있는 점이 중요하게 생각되기 때문입니다. 하지만 모든 가입자가 게스트로 시작하는 만큼 커피챗 호스트를 어떻게 유치할 것인가는 고민이 되는 부분입니다.
-
미해결Complete Full-Stack Python Developer Roadmap: Learn FastAPI, React, Database Design API Architecture
강의 업데이트에 대해 문의드립니다.
안녕하세요.커리큘럼을 봐도 현재 업데이트된 강의 시간내에 전부 커버가 안되고 있는 것으로 보이는데,강의는 어느정도 길이로 계획되어있고, 언제 업데이트가 전부 완료될지 예상 시점이 궁금하여 문의드립니다.
-
해결됨[매일 완독 챌린지] 저자와 함께하는 <FastAPI로 기획에서 출시까지>
페이지 144 코드 문의
def create_engine(dsn: str): return create_async_engine( dsn, echo=True, # SQLAlchemy가 실행하는 SQL을 콘솔에 출력하도록 함 ) def create_session(async_engine: AsyncEngine | None = None): if async_engine is None: async_engine = create_engine()위 코드중 마지막줄async_engine = create_engine() 여기에 dsn 인자가 없어서 오류 나지 않나요?
-
해결됨[매일 완독 챌린지] 저자와 함께하는 <FastAPI로 기획에서 출시까지>
책과 github 코드가 다릅니다 p130
책에서는 128pif TYPE_CHECKING: from appserver.apps.calendar.models import Calendar이렇게 appserver 부터 시작하니다 130페이지 하단에 보면https://gilbut.co/c/25069573YP커밋 참조하라고 되어있는데요깃헙에서는 if TYPE_CHECKING: from apps.calendar.models import Calendar여기는 apps부터 시작합니다. 초보에게는 이런거 하나하나가 어렵네요어떤게 맞는 건지 궁금합니다.
-
미해결FastAPI 완벽 가이드
API 라우트 설계 시 중첩 구조 분리 기준 질문
안녕하세요 교수님items나 users처럼 딱 떨어지는 리소스는 분리가 쉽지만, 실제로는 모델끼리 얽혀 있는 경우가 많아 라우팅이 모호해지곤 합니다.예를 들어, /products라는 경로가 있음에도 불구하고 특정 맥락에 따라 /users/{user_id}/products와 같이 nested 방식 으로 접근해야 하는 상황이 자주 발생하는데요. (반대인 경우도 발생)이렇게 데이터가 연결되어 있을 때 어디까지 경로를 중첩시킬지, 혹은 어느 시점에 라우트를 완전히 분리해야 할지 교수님만의 노하우나 팁이 있으실까요? 실무적인 관점에서 라우트 설계의 명확한 기준을 잡고 싶어 질문 드립니다.추가로 데이터 모델과 라우트 이름을 보통 같게 하나요?나중에 리팩토링 할 때 문제가 없을까요?감사합니다!
-
해결됨[매일 완독 챌린지] 저자와 함께하는 <FastAPI로 기획에서 출시까지>
120페이지 코드 질문드립니다.
120 페이지 코드 보면 created_at 코드가class OAuthAccount 코드하고 들여 쓰기 레벨이 같은데 맞는건가요?
-
해결됨[매일 완독 챌린지] 저자와 함께하는 <FastAPI로 기획에서 출시까지>
테스팅과 학습법의 관계 (?)
"6장: 테스팅 이해하기와 단위 테스트 연습하기" 강의 초반에 "테스팅을 잘하는 방법이 유용한 학습법과 맞닿아 있다" 고 하셨는데, 왜 그런지 궁금해서 글 남깁니다. 테스팅을 잘하는것과 학습이 어떻게 맞닿아 있는 것일까요. 강사님의 의견을 공유해주시면 감사하겠습니다.
-
해결됨[매일 완독 챌린지] 저자와 함께하는 <FastAPI로 기획에서 출시까지>
commit과 flush 관련
질문이 조금 많아서 죄송합니다. 다음 테스트 코드에서 commit()과 flush()의 위치가 이상해보였습니다.async def test_user_detail_for_real_user(client: TestClient, db_session: AsyncSession): user = User( username="test", password="test", email="test@example.com", display_name="test", is_host=True, ) db_session.add(user) await db_session.commit() await db_session.flush()commit()은 DB에 반영된 트랜잭션의 변경사항을 영속적으로 만들고 트랜잭션을 종료하는 코드로 이해하고 있고, flush()는 트랜잭션의 변경사항을 실제 DB에 SQL 구문을 통해 반영하는 것으로 알고 있습니다. 그래서 이 둘의 순서가 변경된 것이 아닌지 혹은 다른 의도가 있는 것인지 궁금합니다.
-
해결됨[매일 완독 챌린지] 저자와 함께하는 <FastAPI로 기획에서 출시까지>
Annotated 대 인자 기본값 관련해서
default_deps에서 기본 값으로 Depends 함수가 반환하는 객체가 할당되는 것까지는 이해했는데, 해당 동작이 왜 의도하지 않은 동작인 건지가 이해되지 않습니다. 오히려 아래 쪽이 기본값이 적용되니 더 편리해 보이기만해서 Annotated를 권장하는 이유가 와닿지 않더라구여. 이에 대해서 조금 더 구체적으로 알고 싶습니다.DbSeDep = Annotated[AsyncSession, Depends(use_session)] async def annotated_deps(session: DbSeDep): pass annotated_deps() async def default_deps(session: AsyncSession = Depends(use_session)): pass default_deps()
-
해결됨[매일 완독 챌린지] 저자와 함께하는 <FastAPI로 기획에서 출시까지>
import 경로 관련하여
5.4.3 Alembic 설정하기 부분에서 다음 문장이 잘 이해되지 않습니다."우리는 그동안 appserver 디렉터리 안을 시작점(root)으로 해왔습니다. 그래서 프로젝트 내 다른 패키지에 접근하는 경로도 from appserver.apps.account 나 from appserver.apps.calendar 또는 from appserver.db import DSN 처럼 접근했었죠."appserver 디렉터리 안이 시작점이 아니고 release-your-project-with-fastapi가 시작점(루트)이 되어야 하는 것 아닌가요? fastapi-dev를 실행한 것이 appserver 디렉터리가 위치한 곳이니 루트는 현재 위치한 폴더(release-your-project-with-fastapi)이지 appserver가 아니지 않나? 라는 의문이 들었습니다.
-
미해결[2025 신규] 어서와, Fast API는 처음이지?
설치오류
SQL 설치하는데 이거 왜이럴까요 ㅠㅠ
-
해결됨[매일 완독 챌린지] 저자와 함께하는 <FastAPI로 기획에서 출시까지>
사용자(User)의 정의에 대한 답변. & 토이 프로젝트 기획에 유용한 툴 질문
안녕하세요 :) 좋은 강의와 책 잘 보며 열심히 따라가고 있습니다! 이번 강의 중 언급하셨던 사용자에 대한 저만의 정의를 생각해봤습니다.시스템, 서비스 혹은 제품을 이용하게 될 주체이자, 프로젝트 진행 시 직/간접적인 경험 등을 우선적으로 고려할 대상.라고 생각합니다. 추가 질문으로 기획 시에 발생하는 아이디어나 문서 정리, 다이어그램 등 ERD, User flow 차트처럼 (1) 기록으로 남겨야 하는 것들은 어떤 게 있으며, (2) 어느 툴을 사용하는 게 유용할까요? 손으로 쓰는 것이 편해서 종이에 펜으로 그리면서 설계한 적이 많았습니다. 그 뒤에 Figma나 스프레드 시트로 표현했구요. 하지만, 추후 프로젝트 README.md 에 넣을 것도 고려하면 설계 혹은 기획부터 차근차근 리소스를 쌓아가는 게 어떤 가 싶어서 여쭙습니다! 무언갈 그려야 한다면 Figma를 사용하긴 하지만, 파워포인트 수준으로 밖에 활용하지 못하고 있는 것 같습니다. 전반적인 실험이나 개발 기록은 Notion(GitHub과 별개)을 활용하는 편 입니다. JIRA를 협업 및 이슈 추적에 Confluence는 Docs 관리로 써보고는 싶었지만, 현업에서 배우는 게 아닌 개인이나 4-5인 팀에서 제대로 활용하기가 어렵더군요.. (1) 설계 시 기록으로 남겨야 하는 것들은 어떤 게 있을까요?(2) 어느 툴을 사용하는 게 유용할까요? 감사합니다.
-
미해결Azure Native로 나만의 GPT 만들기
font.html azure blob에 다시 올려줘야하는거 맞을까요?
먼저 유사한 질문이 있었는지 검색해보세요.꼭 강의와 관련된 질문이 아니더라도, 최대한 답변해드리겠습니다.건의사항도 괜찮습니다.편하게 질문해주세요! 9:38에 html 소스 바꾸고, 다시 blob service에 다시 9:38에 변경한 소스파일을 다시 업로드해야하는거 맞을까요..?? 해당 작업을 해야되는게 맞다면 제 컴퓨터에서 수정했을 때 blob service에 수동으로 안올리고 자동으로 올려지게 하는게 ci/cd???같은건가요...?