해결된 질문
작성
·
320
0
안녕하세요 강사님 수업 열심히 따라가고 있습니다. class 기반뷰로 작성을 해보았는데, 이런식으로 작성하는 것이 맞는지 질문 드립니다.
기본 로직은 같고 APIView를 사용하였습니다.
class UserFollow(APIView):
def post(self, request):
username = request.data['username']
follow_user = get_object_or_404(get_user_model(), username=username, is_active=True)
request.user.following_set.add(follow_user)
return Response(status.HTTP_204_NO_CONTENT)
답변 1
1
강의의 "User 모델에 Follow-Unfollow 관계 필드를 구현하고, Follow 기능 구현" 수업에서 비디오 플레이어 아래의 보충 설명을 참고해보시겠어요?
제가 강의에서는 symmetrical 설명을 누락되었었는데, 이에 대한 보충입니다.
M2M 에 대한 질문은 제가 질문이 잘 이해가 안 되어서요. 질문을 보충해서 좀 더 상세히 부탁드려도 될까요? // LIke 모델과 User Follower에는 어떤 관계가 있나요?
아.. 코드를 잘 못 올렸었습니다.
2개씩 생성되고 삭제되는 것은 symmetrical를 이용하여 해결하였습니다! 감사합니다.
M2M에 대한 질문은 제가 Post.like 부분에서 M2M으로 작성하였는데 아래와 같이 했었습니다.
# models.py
class Post(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
title = models.CharField(max_length=30)
content = models.TextField(blank=True)
like = models.ManyToManyField(settings.AUTH_USER_MODEL, related_name='post_like_set', through='Like')
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
def __str__(self):
return str(self.title)
class Like(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
post = models.ForeignKey(Post, on_delete=models.CASCADE, related_name='like_post_set')
# views.py
class LikeAPIView(ListCreateAPIView):
serializer_class = LikeSerializer
def get_queryset(self):
user = self.request.user
post = Post.objects.get(pk=self.kwargs['pk'])
return Like.objects.filter(user=user, post=post)
def perform_create(self, serializer, *args, **kwargs):
if self.get_queryset().exists():
self.get_queryset().delete()
return Response(status=status.HTTP_204_NO_CONTENT)
serializer.save(user=self.request.user, post=Post.objects.get(pk=self.kwargs['pk']))
through를 통해 Like 테이블에 접근할 수 있도록 하였는데 이렇게 작성하니 M2M을 제대로 사용하지 못하다 생각이 들었었습니다. 그래서 User.follow는 through를 사용하지 않고 views를 작성하다가 query_set을 어떻게 주어야할지 고민했었는데, 현재는 아래와 같이 작성하여 해결했습니다!!
**그런데, add할 때 status 코드가 정상적으로 201이 오는데 remove할때 status 코드 204를 줬는데도 201이 오는 이유가 있을까요??
class FollowAPIView(ListCreateAPIView):
serializer_class = FollowSerializer
def get_queryset(self):
user = self.request.user
follower_user = get_user_model().objects.filter(pk=self.kwargs['pk'], follower_set=user)
return follower_user
def perform_create(self, serializer, *args, **kwargs):
follower_user = get_user_model().objects.filter(pk=self.kwargs['pk']).first()
if self.get_queryset().exists():
self.request.user.following_set.remove(follower_user.id)
return Response(status=status.HTTP_204_NO_CONTENT)
self.request.user.following_set.add(follower_user.id)
M2M 필드에서 .add 에서는 내부적으로 중복을 체크합니다. 여러번 .add 해도 처음 1회만 관계를 저장합니다. 그러니 굳이 삭제하지 않으시고, add 만 하셔도 충분합니다. // .exists, .remove 등을 하실 필요가 없는 거죠.
M2M 관계는 서로 복수 관계를 다룹니다. 그러니 아래와 같이 like 이름처럼 단수형으로 쓰지 마시고,
like = models.ManyToManyField(settings.AUTH_USER_MODEL, related_name='post_like_set', through='Like')
저라면 아래와 같이 쓰겠습니다.
liked_user_set = models.ManyToManyField(settings.AUTH_USER_MODEL, related_name='liked_post_set', through='Like')
그럼 post.liked_user_set.add(user) 와 같이 쓰시거나,
user.liked_post_set.add(post) 처럼 쓰실 수 있습니다.
204 응답이 오는 것은 204 루틴을 탔기 때문일 것입니다. 로직을 차근차근 확인해보시고, 디버거를 사용해보지 않으셨다면, VSCode 혹은 PyCharm 디버거를 물려서 코드를 한 줄씩 실행해보시며, 실행흐름을 파악해보셔도 좋습니다.
화이팅입니다. :-)
안녕하세요 강사님!
generics view를 이용한 팔로우 기능을 개발해보고 있는데, MTM를 이용하여 만들어진 테이블 접근 하는 것이 궁금합니다.
get_queryset()을 이용하여 MTM으로 만들어진 테이블에 접근 후 쿼리 결과가 있으면 삭제, 없으면 생성을 하고싶은데, MTM으로 만들어진 테이블에 접근하는 방법을 모르겠어서 막혀있는 상태입니다.
혹시 models.py에서 Follow라는 테이블을 만들어 사용하여 접근하는 것이 더 좋은 것인지 아니면 MTM 테이블에 접근방법이 있는지 또는 다른 방법이 있는지 궁금해서 질문드립니다.
위 로직의 문제는 following하는 상황만이 아닌 follower까지 함께 생성되어 MTM테이블에 2개의 행이 생성되고, 삭제는 MTM테이블의 모든 행이 삭제가 됩니다..