개발일지/스파르타코딩클럽

파이썬 장고 실무 심화 4주차 : 인스타그램 기능 클론(4)

마이구미+ 2023. 4. 26. 11:51

<실습>

- Profile 페이지 api 만들어보기

  • 먼저 url을 작성한다
# users/urls.py

...

urlpatterns = [
    ...
    path('<int:user_id>/', views.ProfileView.as_view(), name='profile_view'),
]
  • 다음으로 serializer를 작성한다
# users/serializers.py

class UserProfileSerializer(serializers.ModelSerializer):
    class Meta:
        model = User
        fields = "__all__"
  • 이제 view를 작성한다
# users/views.py

...
class ProfileView(APIView):
    def get(self, request, user_id):
        """프로필 페이지"""
        user = get_object_or_404(User, id=user_id)
        serializer = UserProfileSerializer(user)
        return Response(serializer.data)
  • 포스트맨에서 띄워본다

  • 잘 나오긴 하는데 쓸데없는 정보가 너무 많다 여기서 id, email, followings만 있으면 될 것 같다
  • 다시 시리얼라이저를 수정한다
fields = ("id", "email", "followings",)
  • UserProfileSerializer에 fields를 "__all__"에서 위와 같이 수정한다
  • 다시 포스트맨에서 실행해보면 원하는 값이 잘 나오는 것을 확인할 수 있다

  • 그런데 followers도 있으면 좋을 것 같다
  • ArticleSerializer에서 likes 필드를 추가한 것처럼 StringRelatedField를 사용한다 follower도 여러 명일 수 있으니 many=True를 꼭 넣어준다
# users/serializers.py

class UserProfileSerializer(serializers.ModelSerializer):
    followers = serializers.StringRelatedField(many=True)	# 여기 추가!

    class Meta:
        model = User
        fields = ("id", "email", "followings", "followers",)	# 여기도 잊지말고!
  • 포스트맨에서 다시 실행해보면 followers 필드가 추가된 것을 확인할 수 있다

  • 그런데 아무것도 안 보이니 팔로잉, 팔로워를 추가해주면 좋을 것 같다
  • 일단 지금 로그인 되어 있으니 포스트맨 follow 리퀘스트에서 다른 사용자를 팔로우 했다

  • 이제 팔로워도 만들고 싶다 근데 포스트맨에서 하려면 로그인을 해서 토큰을 다시 복붙하고...굉장히 귀찮은 과정이다
  • admin 페이지에 가면 like 했던 것처럼 클릭으로 쉽게 팔로잉을 할 수 있다

  • 그런데 user에 들어가서 아무 사용자나 클릭해보면 followings 필드가 없다

  • 그리고 유저 목록을 보면 user id가 안 보여서 누가 1번이고 누가 8번인지 알 수 없다
  • 데이터베이스에는 id로 나오니까 이 페이지에도 아이디를 같이 볼 수 있게 해보자
# users/admin.py

...

class UserAdmin(BaseUserAdmin):
    ...
    list_display = ["email", "is_admin"]
  • list_display는 위 캡쳐처럼 유저목록에 보이는 부분들이다 현재는 email과 is_admin만 있어서 저렇게 보인다
  • 여기에 email 앞에 "id"를 추가해보자
list_display = ["id", "email", "is_admin"]

  • id를 추가하고 저장한 뒤 admin 페이지를 새로고침 하니 id가 유저 목록에 같이 보이기 시작했다
  • 이제 유저 수정 페이지에 followings 필드를 추가해보자
# users/admin.py

...

class UserAdmin(BaseUserAdmin):
    ...
    fieldsets = [
        (None, {"fields": ["email", "password"]}),
        ...
    ]
  • 현재 fieldsets에 email과 password가 있다 여기에 followings를 추가해보자
(None, {"fields": ["email", "password", "followings"]}),

  • followings 필드가 추가됐다 이제 여기서 팔로우를 할 수 있다
  • 몇몇 유저의 팔로우를 추가하고 다시 포스트맨에서 실행해보면 팔로잉과 팔로워에 추가된 것을 확인할 수 있다

  • 근데 followings와 followers가 보이는 게 다르다 하나로 통일해주면 좋을 것 같다
  • 메일형식으로 보이게 followings를 고쳐보고자 한다
# users/serializers.py

class UserProfileSerializer(serializers.ModelSerializer):
    followers = serializers.StringRelatedField(many=True)
    followings = serializers.StringRelatedField(many=True)	#여기 추가!

    class Meta:
        model = User
        fields = ("id", "email", "followings", "followers",)
  • followers와 똑같이 stringrelatedfield를 사용하면 아이디가 이메일로 보인다

  • 혹시 아이디번호로 보이게 하고 싶다면 PrimaryKeyRelatedField가 있는데 이걸 사용하면 된다
followers = serializers.PrimaryKeyRelatedField(many=True, read_only=True)
  • followings는 이미 아이디로 보이니까 따로 추가하지 않아도 된다
  • read_only=True를 빼먹으면 넣으라고 에러메시지가 뜬다
  • 이렇게 수정하고 다시 포스트맨에서 실행하면 팔로잉, 팔로워 모두 아이디 번호로 뜨는 것을 확인할 수 있다

  • 근데 이메일로 보이는 게 좋기 때문에 다시 바꿀 예정이다
  • 그리고 지금 admin 페이지에서 유저 수정페이지 가서 팔로잉을 선택하지 않고 저장을 누르면 필수값이니 클릭하라고 나온다

  • 유저 모델에 가서 followings 필드를 blank=True로 변경해주면 된다
# users/models.py

...

class User(AbstractBaseUser):
    ...
    followings = models.ManyToManyField(
        "self", symmetrical=False, related_name="followers", blank=True)
    ...
  • models.py 수정 후에는 makemigrations, migrate를 잊지 말 것!
  • 이제 프로필페이지에 내가 쓴 글과 내가 좋아요한 게시글이 나오면 좋을 것 같다는 생각이 든다
  • 유저프로필시리얼라이저에 이어서 작성해보자
# users/serializers.py

...
from articles.serializers import ArticleListSerializer

class UserProfileSerializer(serializers.ModelSerializer):
    ...
    article_set = ArticleListSerializer(many=True)
    like_articles = ArticleListSerializer(many=True)

    class Meta:
        model = User
        fields = ("id", "email", "followings", "followers",
                  "article_set", "like_articles")
  • 일단 Article모델에 가면 user필드의 related_name이 설정되어 있지 않다
  • 유저에서 아티클을 역참조하는 것이므로 article_set이라는 필드명으로 해줘야 한다
  • 아티클 모델에 likes필드의 related_name은 like_articles로 설정해놨기 때문에 like_articles 라는 이름으로 사용하면 된다
  • 시리얼라이저는 ArticleListSerializer를 사용해서 import를 해줬다
  • 이렇게 하고 포스트맨에서 실행하면 내가 쓴 글, 내가 좋아요 한 글이 뜨는 것을 확인할 수 있다


- Feed 페이지 api 만들어보기

# articles/urls.py

urlpatterns = [
    ...
    path('feed/', views.FeedView.as_view(), name='fedd_view'),
    ...
]
  • 이제 views.py로 가서 FeedView를 작성한다
# articles/views.py

from django.db.models.query_utils import Q
...

class FeedView(APIView):
    permission_classes = [permissions.IsAuthenticated]
    def get(self, request):
        """팔로잉 게시글 모아보기"""
        q = Q()
        for user in request.user.followings.all():
            q.add(Q(user=user), q.OR)
        feeds = Article.objects.filter(q)
        serializer = ArticleListSerializer(feeds, many=True)
        return Response(serializer.data, status=status.HTTP_200_OK)
  • 위 문서에서 나온 Q라는 건데..뭔지는 잘 모르겠다..
  • 필터링 걸 때 필요한 거라고 한다
  • q 라는 변수에 Q()를 넣어서 오브젝트를 만든다
  • 로그인한 사용자가 팔로잉한 사람들을 for문에 돌려서 한 사람씩 q오브젝트에 추가한다
  • q.OR로 써있는 이유는 조건에 user가 팔로잉한 사람 중 한 사람씩 계속 추가되는 건데 and로 엮으면 게시글 작성자가 팔로잉1이고, 팔로잉2고 팔로잉3인...그러니까...작성자가 여러 명인(로그인한 유저가 팔로잉한 그 유저들이 쓴 하나의의) 게시글을 찾을 거라서 send를 보내면 만족하는 게시글이 없어서 빈리스트만 뜬다 현재 게시글은 1명의 유저만 쓰게끔 되어 있어서 조건을 만족할 수가 없다
  • feeds라는 변수에 게시글을 가져올 건데 필터를 걸어서 q 조건에 해당하는(로그인한 사용자가 팔로잉한 유저와 글작성자가 같은) 게시글만 가져온다

  • 현재 로그인한 유저의 팔로잉 목록은 다음과 같다

  • 이중 gu4와 gu7만 게시글을 써서 2개만 보인다