본문 바로가기
DEV/Web 개발

Web 개발 :: 파이썬 Django Rest Framework(12) _ Serializer 보완(Likes count, Comments count)

by 올커 2022. 11. 5.

DRF(Django Rest Framework)(12) _ Serializer 보완

01. 게시글 상세페이지 수정하기

 - 현재 게시글 상세페이지를 GET 요청하면 아래와 같이 볼 수 있다. 추가한 코멘트가 현재 보이지 않고, 좋아요는 사용자 id로 나오고 있다. 코멘트를 추가하고 사용자 이메일로 나타나게 하려한다.

 - 아래 models.py를 살펴보면 Article에는 Comment에 대한 정보가 없지만, Comment에는 Article을 ForeignKey로 가져오고 있기 때문에 comment_set이라는 related_name으로 사용할 수 있다. 이를 활용해서 serializer를 수정한다.

# articles/models.py

class Article(models.Model):
    user = models.ForeignKey(User, on_delete=models.CASCADE)
    title = models.CharField(max_length=50)
    content = models.TextField()
    image = models.ImageField(blank=True, upload_to='%Y/%m/')
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)
    likes = models.ManyToManyField(User, related_name='like_articles')

    def __str__(self):
        return str(self.title)

class Comment(models.Model):
    user = models.ForeignKey(User, on_delete=models.CASCADE)
    article = models.ForeignKey(Article, on_delete=models.CASCADE)
    content = models.TextField()
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

    def __str__(self):
        return str(self.content)

 

 - ArticleSerializer에 comment_set을 추가해준다.

# articles/serializers.py

class ArticleSerializer(serializers.ModelSerializer):
    # user에 id값이 아닌 email을 가져오게 함
    user = serializers.SerializerMethodField()
    def get_user(self, obj):
        return obj.user.email

    comment_set = CommentSerializer(many=True)

    class Meta:
        model = Article
        fields = '__all__'

 - 이제 articles에서도 comment를 읽어올 수 있게 되었다.

 - comment_set의 내용에서 article 정보는 어차피 동일하기 때문에 빼주어도 된다. 이 때 사용할 수 있는 것이 exclude이다. CommentSerializer에서 Fields의 전체에서 일부를 뺄 경우에는 아래와 같이 사용할 수 있다.

# articles/serializers.py

class CommentSerializer(serializers.ModelSerializer):
    class Meta:
        model = Comment
        exclude = ("article", )

 - article 번호에 대한 내용이 제거된 것을 확인할 수 있다.

 - user값이 email로 나오도록 변경하기 위해 아래와 같이 코드를 작성했다. 가져온 부분은 이전에 ArticleSerializer에서 user에 email을 가져오기 위해 작성했던 내용과 동일하다.

# articles/serializers.py

class CommentSerializer(serializers.ModelSerializer):
    
    # user에 id값이 아닌 email을 가져오게 함
    user = serializers.SerializerMethodField()
    def get_user(self, obj):
        return obj.user.email

    class Meta:
        model = Comment
        exclude = ("article", )

 - user도 이제 이메일 값을 받아오게 할 수 있다.

 - 아직 likes는 pk 넘버로 보여지고 있다. 이 부분도 수정해주어야 한다.

 - 참고 링크의 StringRelatedField를 참고해본다. (※ 참고 링크)

 - users앱의 models.py를 확인해보면 User모델의 string Field(__str__)에 self.email이 지정되어 있다.

# users/models.py

class User(AbstractBaseUser):
    ...

    def __str__(self):
        return self.email

   아래와 같이 StringRelatedField를 넣어주면 위의 __str__을 가져오게 된다.

# articles/serializers.py

class ArticleSerializer(serializers.ModelSerializer):
    ...
    likes = serializers.StringRelatedField(many=True)
    ...


02. 게시글 리스트 페이지 수정하기

 - 리스트 페이지에서는 comment와 like는 다른 정보는 제외하고 해당 게시글의 comment와 like의 갯수만 가져오도록 하고 싶다. 아래와 같이 likes_count 함수를 만들어주고, class Meta의 fields에 "likes_count"를 추가해준다.

# articles/serializers.py

class ArticleListSerializer(serializers.ModelSerializer):
    ...
    # likes의 갯수를 세어 출력함
    likes_count = serializers.SerializerMethodField()
    def get_likes_count(self, obj):
        return obj.likes.count()

    class Meta:
        model = Article
        fields = ('pk', 'title', 'image', 'updated_at', 'user', "likes_count")

 - 그러면 아래와 같이 "likes_count"가 추가된 것을 확인할 수 있다.

 - comment도 위의 likes_count와 동일하게 설정해주면 된다. 

# articles/serializers.py

class ArticleListSerializer(serializers.ModelSerializer):
    ...
    # comments의 갯수를 세어 출력함
    comments_count = serializers.SerializerMethodField()
    def get_comments_count(self, obj):
        return obj.comments.count()

    class Meta:
        model = Article
        fields = ('pk', 'title', 'image', 'updated_at', 'user', "likes_count", "comments_count")

 - 이 때 주의할 점으로는 return obj.comments.count()에서 comments는 models에서 정의된 related_name이어야 한다는 점이다. 만약 related_name이 지정되지 않았다면 comment_set으로 사용해야 한다.

# articles/models.py

class Comment(models.Model):
    ...
    article = models.ForeignKey(Article, on_delete=models.CASCADE, related_name="comments")
    ...

 

반응형

댓글