2026/03/02 Blog - 12

김기훈·2026년 3월 2일

TIL

목록 보기
152/194
post-thumbnail

코딩테스트(11050)


기능 구현

시리즈 시작 전

model 의문

class Series(TimeStampedModel):
    user = models.ForeignKey(
        settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name="series"
    )
    name = models.CharField(max_length=100)

    class Meta:
        db_table = "series"
        constraints = [
            models.UniqueConstraint(fields=["user", "name"], name="uk_series_user_name")
        ]
  • user의 존재 이유

    • user가 없으면 현재 전체 블로그 플랫폼에서 시리즈이름을 한 유저가 1개 생성하면
    • 동일한 시리즈 이름을 다른 유저는 사용할 수 없음
  • UniqueConstraint(fields=["user", "name"])

    • "한 명의 유저는 중복된 이름의 시리즈를 만들 수 없지만, 서로 다른 유저는 같은 이름의 시리즈를 가질 수 있다"

model 개선

  • series_order = models.BigIntegerField(null=True, blank=True)

    • BigIntegerField는 오버스펙
      • BigIntegerField는 -922경부터 922경까지의 숫자를 저장
      • 하나의 시리즈에 포스트가 수십억 개가 들어가는 일은 사실상 불가능
      • models.PositiveIntegerField()models.PositiveSmallIntegerField() 로 변경
  • models.PositiveIntegerField()

    • 일반적인 크기의 양수 정수를 저장
    • 0부터 2,147,483,647 (약 21억) 까지 저장 가능(보통 4바이트(Byte)를 차지)
    • 숫자가 꽤 커질 수 있는 경우에 사용
  • models.PositiveSmallIntegerField()

    • 비교적 작은 크기의 양수 정수를 저장(보통 2바이트(Byte)를 차지)

시리즈 Create/list


models

class Series(TimeStampedModel):
    user = models.ForeignKey(
        settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name="series"
    )
    name = models.CharField(max_length=100)

    class Meta:
        db_table = "series"
        constraints = [
            models.UniqueConstraint(fields=["user", "name"], name="uk_series_user_name")
        ]

serializer

class SeriesCreateSerializer(serializers.ModelSerializer):
    """시리즈 생성을 위한 시리얼라이저입니다."""

    class Meta:
        model = Series
        fields = ["name"]


class SeriesListSerializer(serializers.ModelSerializer):
    """시리즈 목록 조회를 위한 시리얼라이저입니다."""

    class Meta:
        model = Series
        fields = ["id", "name", "created_at", "updated_at"]

service

def get_my_series(*, user: User) -> QuerySet[Series]:
    """특정 유저(본인)가 만든 시리즈 목록을 조회하는 서비스 로직입니다."""

    # 1. Series 테이블에서 user 필드가 전달받은 user와 일치하는 데이터만 필터링(+ 최신순 정렬)
    return Series.objects.filter(user=user).order_by("-created_at")

def create_series(*, user: User, name: str) -> Series:
    """새로운 시리즈를 생성하는 서비스 로직입니다."""

    try:
        # 1. 전달받은 user와 name으로 새로운 Series 객체를 데이터베이스에 생성
        series = Series.objects.create(user=user, name=name)

        # 2. 생성된 객체 반환
        return series

    # 3. UniqueConstraint(user, name) 제약 조건(시리즈 이름 중복)
    except IntegrityError:
        raise BaseCustomException(ErrorMessage.SERIES_ALREADY_EXISTS)

view

    @extend_schema(tags=["시리즈"], summary="내 시리즈 목록 조회")
    def get(self, request: Request):
        # 1. User 타입 지정
        user = cast(User, request.user)

        # 2. 서비스 레이어 호출
        series_list = get_my_series(user=user)

        # 3. 데이터 직렬화 및 응답
        serializer = SeriesListSerializer(series_list, many=True)

        return Response(serializer.data, status=status.HTTP_200_OK)

    @extend_schema(
        tags=["시리즈"], summary="새 시리즈 생성", request=SeriesCreateSerializer
    )
    def post(self, request: Request):
        # 1. 입력 데이터 검증
        serializer = SeriesCreateSerializer(data=request.data)
        serializer.is_valid(raise_exception=True)

        # 2. User 타입 지정
        user = cast(User, request.user)

        # 3. 서비스 레이어 호출 (시리즈 생성)
        series = create_series(user=user, name=serializer.validated_data["name"])

        # 4. 생성 완료 응답
        return Response(
            {"id": series.id, "message": "시리즈가 성공적으로 생성되었습니다."},
            status=status.HTTP_201_CREATED,
        )

profile
안녕하세요.

0개의 댓글