차단 기능 구현 의사결정 과정

2star_·2025년 1월 16일
0

최종 프로젝트

목록 보기
18/32

1. 목표

Block 기능

  • 특정 유저를 차단하거나 차단 해제할 수 있도록 API를 제공
  • 차단된 유저의 리뷰가 블러 처리되거나 제외됨
  • 차단된 유저와의 채팅 제한

2. 의사결정 과정

2.1 차단 모델 설계

처음에는 Django의 Many-to-Many 필드를 사용하려고 했습니다. 하지만 아래와 같은 이유로 명시적인 Block 모델을 설계하기로 결정했습니다:
1. 추가 메타데이터 저장 필요성: 차단 시점(created_at)이나 차단 사유(reason)를 저장하려면 Many-to-Many 필드만으로는 한계가 있음
2. 명확한 관계 표현: blocker(차단자)와 blocked_user(차단된 사용자)의 비대칭적 관계를 명확히 하기 위해 중간 모델이 더 적합
3. 확장성: 추후 차단 상태 변경 이력 기록, 통계 분석 등의 기능을 고려

최종 모델

class Block(models.Model):
    blocker = models.ForeignKey(
        settings.AUTH_USER_MODEL,
        on_delete=models.CASCADE,
        related_name="blocked_users"
    )
    blocked_user = models.ForeignKey(
        settings.AUTH_USER_MODEL,
        on_delete=models.CASCADE,
        related_name="blocked_by_users"
    )
    created_at = models.DateTimeField(auto_now_add=True)

    class Meta:
        unique_together = [('blocker', 'blocked_user')]
        ordering = ['-created_at']

2.2 Serializer 필요 여부

초기에는 요청과 응답 데이터 처리를 위해 Serializer를 추가할지 고민했습니다. 하지만 구현 초기에 Serializer를 생략한 이유는 다음과 같습니다:
1. 단순한 데이터 처리:

  • 차단/차단 해제 요청은 단일 필드(blocked_user_id)로 이루어짐
  • 유효성 검증은 get_object_or_404로 충분히 처리 가능
  1. 직렬화할 데이터가 적음:
    • 클라이언트에게 반환하는 데이터는 간단한 상태 메시지와 차단된 유저 목록

하지만, 추후 확장성을 고려하여 Serializer를 추가하는 방안을 열어둠


2.3 차단 로직 구현

APIView를 기반으로 차단, 차단 해제, 차단된 유저 목록 조회 기능을 구현했습니다.

주요 고려사항

  1. 중복 차단 방지:
    • Block.objects.get_or_create를 사용하여 동일한 유저를 중복 차단하는 경우를 방지
  2. 차단 해제 처리:
    • Block 레코드 삭제 시 삭제된 레코드가 없으면 적절한 에러 메시지를 반환
  3. 목록 조회:
    • select_related를 사용해 쿼리 최적화를 고려

최종 뷰 코드

class BlockedUserAPIView(APIView):
    permission_classes = [IsAuthenticated]

    def get(self, request):
        blocked_users = Block.objects.filter(blocker=request.user).select_related('blocked_user')
        data = [{"id": block.blocked_user.id, "nickname": block.blocked_user.nickname} for block in blocked_users]
        return Response(data, status=status.HTTP_200_OK)

    def post(self, request):
        blocked_user_id = request.data.get("blocked_user_id")
        blocked_user = get_object_or_404(Account, id=blocked_user_id)
        block, created = Block.objects.get_or_create(blocker=request.user, blocked_user=blocked_user)
        if not created:
            return Response({"message": "이미 차단된 사용자입니다."}, status=status.HTTP_400_BAD_REQUEST)
        return Response({"message": "유저를 차단했습니다."}, status=status.HTTP_201_CREATED)

    def delete(self, request):
        blocked_user_id = request.data.get("blocked_user_id")
        blocked_user = get_object_or_404(Account, id=blocked_user_id)
        deleted, _ = Block.objects.filter(blocker=request.user, blocked_user=blocked_user).delete()
        if not deleted:
            return Response({"message": "차단된 유저가 아닙니다."}, status=status.HTTP_400_BAD_REQUEST)
        return Response({"message": "유저 차단을 해제했습니다."}, status=status.HTTP_204_NO_CONTENT)

2.4 리뷰 차단 처리

차단된 유저의 리뷰를 블러 처리하거나 목록에서 제외하는 방안을 결정했습니다.

방법

  1. 블러 처리:
    • 리뷰 내용 직렬화 시, 차단된 유저의 리뷰라면 "차단된 사용자가 작성한 리뷰입니다."를 반환
  2. 리뷰 제외:
    • ReviewAPIView에서 차단된 유저의 리뷰를 필터링

2.5 URL 구성

API 뷰를 다음 URL에 연결:

  • GET /accounts/block/ : 차단된 유저 목록
  • POST /accounts/block/ : 유저 차단
  • DELETE /accounts/block/ : 유저 차단 해제

3. 테스트

POSTMAN을 사용하여 다음 시나리오를 테스트:
1. 유저 차단: 동일 유저 중복 차단 방지 확인
2. 유저 차단 해제: 차단되지 않은 유저 해제 시 에러 반환
3. 차단된 유저 목록 조회: 올바른 데이터를 반환하는지 확인


4. 느낀 점 및 개선 방향

  • 현재의 단순 로직은 충분히 작동하지만, 차단 사유나 차단된 상태의 리뷰를 확인하는 버튼과 같은 추가 기능을 고민할 필요가 있음
  • 추후 차단 상태를 기준으로 알림, 채팅 제한 기능을 확장할 계획
profile
안녕하세요.

0개의 댓글

관련 채용 정보