728x90
320x100
친구추가 기능 구현하기
이번에 구현하고 싶었던 것은 친구추가 기능이다.
기존 팔로우, 팔로워랑은 다르게 관계가 언제나 쌍방이라는 차이점이 있고,신청 후 수락하는 과정이 필요하다.
일단 팔로우 할 때 했던 대로 ManyToMany필드를 만들었는데
friends = models.ManyToManyField("self", related_name='friends', blank=True)
이러면 일방이고 쌍방이고를 정하기도 전에 신청 > 수락이 되질 않는다. 실행되면 바로 DB가 업데이트 되어버리기 때문
그래서 기존 팔로우에 한 단계(신청)가 더 있는 만큼, 중간 테이블을 하나 추가하기로 했다.
ManyToMany필드 때문에 생기는 테이블이 친구상태(누구와 누가 친구인지) 테이블이므로 친구신청상태 모델을 새로 만들어야 한다.
# user > models.py
class Friend(models.Model):
from_user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='sent_friend_requests')
to_user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='received_friend_requests')
created_at = models.DateTimeField(auto_now_add=True)
status = models.CharField(max_length=20, choices=[('pending', '신청중'), ('accepted', '수락됨'), ('rejected', '거절됨')], default='신청중')
그리고 얘네로 시리얼라이저를 만들고
# user/serializers.py
class FriendSerializer(serializers.Serializer):
from_user = serializers.SlugRelatedField(
default=serializers.CurrentUserDefault(),
queryset=User.objects.all(),
)
to_user = serializers.SlugRelatedField(
queryset=User.objects.all(),
)
status = serializers.CharField(read_only=True)
def validate(self, data):
from_user = data['from_user']
to_user = data['to_user']
if from_user == to_user:
raise serializers.ValidationError("자기 자신에게 친구 신청할 수 없습니다.")
if from_user.friends.filter(id=to_user.id).exists():
raise serializers.ValidationError("이미 친구입니다.")
if from_user.sent_friend_requests.filter(to_user=to_user).exists():
raise serializers.ValidationError("이미 친구 신청을 보냈습니다.")
if from_user.received_friend_requests.filter(from_user=to_user).exists():
raise serializers.ValidationError("상대방이 이미 친구 신청을 보냈습니다.")
return data
def create(self, validated_data):
friend_request = Friend.objects.create(
from_user=validated_data['from_user'],
to_user=validated_data['to_user'],
status='pending'
)
return friend_request
뷰 함수를 만들어야 하는데 신청 수락 거절을 따로 만드는 방법밖에 안 떠올라서 그대로 하기로 함....
user/views.py
# 친구신청
class FriendView(APIView):
permission_classes = [IsAuthenticated]
def post(self, request, user_id):
from_user = request.user
to_user = get_object_or_404(User, id=user_id)
serializer = FriendSerializer(data={'from_user': from_user, 'to_user': to_user})
serializer.is_valid(raise_exception=True)
friend_request = serializer.save()
return Response({"message": "친구 신청을 보냈습니다."}, status=status.HTTP_201_CREATED)
# 친구신청 수락
class FriendAcceptView(APIView):
permission_classes = [IsAuthenticated]
def post(self, request, friend_request_id):
friend_request = get_object_or_404(Friend, id=friend_request_id)
if friend_request.to_user != request.user:
return Response({"message": "권한이 없습니다."}, status=status.HTTP_403_FORBIDDEN)
if friend_request.status != 'pending':
return Response({"message": "이미 처리된 요청입니다."}, status=status.HTTP_400_BAD_REQUEST)
friend_request.status = 'accepted'
friend_request.save()
from_user = friend_request.from_user
to_user = friend_request.to_user
from_user.friends.add(to_user)
return Response({"message": "친구 신청을 수락했습니다."}, status=status.HTTP_200_OK)
# 친구신청 거절
class FriendRejectView(APIView):
permission_classes = [IsAuthenticated]
def post(self, request, friend_request_id):
friend_request = get_object_or_404(Friend, id=friend_request_id)
if friend_request.to_user != request.user:
return Response({"message": "권한이 없습니다."}, status=status.HTTP_403_FORBIDDEN)
if friend_request.status != 'pending':
return Response({"message": "이미 처리된 요청입니다."}, status=status.HTTP_400_BAD_REQUEST)
friend_request.status = 'rejected'
friend_request.save()
return Response({"message": "친구 신청을 거절했습니다."}, status=status.HTTP_200_OK)
300x250
반응형
GitHub 댓글