게시글 상세페이지에서
좋아요 : pk가 아니라> 이메일로 표시되게
(실제 front에서 처리할 때는 user 정보가 pk값으로 나오는 게 편리할 수 있다)
댓글이 같이 나오도록
수정한다.
우선 게시글 상세페이지에 쓰이고 있는 Serializer는 ArticleSerializer
다.
다음과 같이 SerializerMethodField()
를 써서 user의 경우 email이 나오게 되어 있다.
# articles/serializers.py
class ArticleSerializer(serializers.ModelSerializer):
user = serializers.SerializerMethodField()
def get_user(self, obj):
return obj.user.email # 유저 이메일이 나오게 되어 있다.
class Meta:
model = Article
fields = '__all__'
댓글을 불러오려면 comment와 article의 관계를 봐야 한다.
Article의 경우 다음과 같이 comment 섹션이 없다.
# articles/models.py
class Article(models.Model):
# 한 user가 여러 article. 1:many. FK
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)
# FK로 Article을 참조한다. related_name 필요
article = models.ForeignKey(Article, on_delete=models.CASCADE, related_name="comment_set")
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)
Comment 쪽에서 FK로 연결이 되어 있다.
모델에서 comment가 FK로 Article을 참조하고 있을 때는 related_name으로 Article에서 Comment를 참조한다.
related_name이 설정이 안 되어 있을 경우 comment_set
이 default다.
Article의 입장에서는 comment_set로 조회할 때 comment를 볼 수 있다.
여러 방식이 가능하지만
# articles/serializers.py
class ArticleSerializer(serializers.ModelSerializer):
user = serializers.SerializerMethodField()
comment_set = CommentSerializer(many=True) # 추가
def get_user(self, obj):
return obj.user.email # 유저 이메일이 돌아가게 되어 있다.
class Meta:
model = Article
fields = '__all__' # 팔드는 all로 되어 있어 자동으로 추가된다.
# 표시되는 댓글들의 형식은 CommentSerializer가 결정한다.
class CommentSerializer(serializers.ModelSerializer):
user = serializers.SerializerMethodField() # 이메일 형식으로 표시
def get_user(self, obj):
return obj.user.email
class Meta:
model = Comment
# fields = '__all__'
exclude = ("article",) # 불필요한 정보 1개만 제외할 때는 exclude를 쓰기도 한다.
만약 모델에서 related_name
을 설정한다면
# articles/models.py
class Comment(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
article = models.ForeignKey(Article, on_delete=models.CASCADE, related_name="comments") # 설정
content = models.TextField()
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
시리얼라이저에서도 다음과 같이 comment_set이 아니라 comments
로 접근해야 POSTMAN에서 실행할 수 있다.
# articles/serializers.py
class ArticleSerializer(serializers.ModelSerializer):
user = serializers.SerializerMethodField()
comments = CommentSerializer(many=True)
DRF Serializer relations 공식 문서
https://www.django-rest-framework.org/api-guide/relations/
원하는 기능 만들 때 유용하다. 꼭 읽어보기.
to represent the target of the relationship using its __str__
method.
# articles/serializers.py
class ArticleSerializer(serializers.ModelSerializer):
user = serializers.SerializerMethodField()
comments = CommentSerializer(many=True)
likes = serializers.StringRelatedField(many=True) # 추가
# users/serializers.py
class User(AbstractBaseUser):
...
def __str__(self):
return self.email
조회해보면 (설정한 related_name) "comments" = []
안에 댓글들이 나온다.
괄호 안의 괄호같은 방식을 Nested Relationship이라 한다.
https://www.django-rest-framework.org/api-guide/relations/
어려우니 drf 공식 문서를 참고하면서 한다.
모델에 없었던 부분이라도 함수를 이용해서 원하는 필드값을 추가할 수 있다.
# articles/serializers.py
class ArticleListSerializer(serializers.ModelSerializer):
user = serializers.SerializerMethodField()
likes_count = serializers.SerializerMethodField()
comments_count = serializers.SerializerMethodField()
def get_user(self, obj): # obj: 해당 article
return obj.user.email
def get_likes_count(self, obj):
return obj.likes.count()
def get_comments_count(self, obj):
return obj.comments.count() # 변경 주의. cf. comments_set
class Meta:
model = Article
fields = ("pk", "title", "image", "updated_at", "user", "likes_count", "comments_count") # 추가
front에서 이 데이터를 이용해 구현한다.