오늘의 코드 [2022.11.25]
중요해서 반드시 기억할 필요가 있거나, 주의해야 할 코드를 답안 형식으로 주석(저의 코멘트)과 함께 정리해 보았습니다.
Q. 유화프로젝트 관련 코드
어제 TIL에서는 profile.js에서 개인페이지에 필요한 개인정보(username, email, profile_image)와 게시물 사진데이터를 불러오는 작업에 대해 다루었는데, 금일 TIL에서도 이 부분에서 보완한 내용을 적어보려고 합니다. 결과물은 어제와 유사하게 아래와 같습니다.

먼저 프로필 화면을 보여주기 위한 view를 ProfileView라고 지정합니다.
#users/views.py
class ProfileView(APIView): # 프로필 화면 뷰
def get(self, request, username):
user = get_object_or_404(User, username=username)
serializer = UserProfileSerializer(user)
return Response(serializer.data)
개인페이지이므로, 로그인한 유저 본인이 작성한 게시물만 불러오도록 하기 위해 user에서 User모델의 username이 username인 데이터를 불러오게 하였고, serializer는 UserProfileSerializer 로 두었습니다.
UserProfileSerializer은 기본적으로 User모델을 기반으로 하며, fields에서 다른 변수들은 모두 User의 변수이지만 마지막에 “post_user”를 조금 눈여겨 볼 필요가 있습니다. post_user 변수는 PostListSerializer를 가져오도록 했는데 Post 모델을 토대로 작성했다는 것을 유추할 수 있습니다.
#users/serializers.py
class UserProfileSerializer(serializers.ModelSerializer):
post_user = PostListSerializer(many=True)
class Meta:
model = User
fields = ("username", "email", "profile_image", "is_active", "followings","post_user")
PostListSerializer는 예상대로 class Meta를 통해 Post 모델을 기반으로 만들어졌으며, Post 모델의 변수도 포함되어 있고, likes와 comments에 SerializerMethodField를 적용하여 불러온(get) 데이터에 .count() 를 적용하여 좋아요와 게시글 수에 대한 정보를 얻을 수 있게 한 것을 알 수 있고 user_filter에 대해서는 FilterSerializer를 적용하도록 하였습니다.
#post/serialzer.py
class PostListSerializer(serializers.ModelSerializer):
user = serializers.SerializerMethodField()
likes_count = serializers.SerializerMethodField()
comments_count = serializers.SerializerMethodField()
used_filter = FilternameSerializer()
def get_user(self, obj):
return obj.user.username
def get_likes_count(self, obj):
return obj.likes.count()
def get_comments_count(self, obj):
return obj.comment_post.count()
class Meta:
model = Post
fields = ("pk", "title", "post_image", "updated_at", "user", "likes_count", "comments_count", "used_filter")
다시 users/serializers.py를 아래 Post모델과 비교하면 Post 모델의 user의 related_name인 ‘post_user’를 가져온 것을 알 수 있는데, 이는 user를 통해 User모델을 외래키로 설정했으므로, Post모델은 User 모델의 정참조 관계이지만, 반대로 User모델은 Post모델의 역참조 관계입니다.
#users/serializers.py
class UserProfileSerializer(serializers.ModelSerializer):
post_user = PostListSerializer(many=True)
class Meta:
model = User
fields = ("username", "email", "profile_image", "is_active", "followings","post_user")
Post 모델 또는 이를 바탕으로 만든 Post관련 Serializer를 반드시 related_name 으로 지정한 변수(또는 테이블명소문자_set )에 넣어야 올바르게 작동합니다. (역참조 방식을 올바르게 적용하지 않고 User모델과 Post모델을 상호 참조하게 되면 순환참조 에러가 발생합니다.)
#post/models.py
class Post(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='post_user')
title = models.CharField(max_length=50)
content = models.TextField()
post_image = models.ImageField(blank=True, upload_to='post/%Y/%m/')
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
likes = models.ManyToManyField(User, related_name="post_likes", blank=True)
used_filter = models.ForeignKey(FilterImage, blank=True, null=True, on_delete=models.CASCADE, related_name='post_filter')
def __str__(self):
return str(self.title)
UserProfileSerializer는 앞서 언급한 것처럼 User모델을 바탕으로 만든 직렬화된 데이터와 로그인 유저의 PostListSerializer의 데이터가 “post_user”라는 key에 담겨 함께 출력되는 것을 확인할 수 있습니다.

자바스크립트 코드는 어제와 거의 유사하나, 한 가지 주의할 점은 for문으로 이미지 카드 div를 만들 때 data 변수 안에 있는 “post_user” 에서 for문을 돌려야 한다. (특히, for (i = 0; i < data['post_user'].length; i++) 이 부분 실수하지 않도록 주의)
//profile.js
window.onload = () => {
console.log("게시글 생성 js 로딩완료");
show_profile_fuc()
show_img_fuc()
}
async function show_profile_fuc() {
const response = await fetch('http://127.0.0.1:8000/users/jskim/', {
method: 'GET',
})
// backend에서 받은 데이터 가져오기
.then(response => {
return response.json();
})
.then(data => {
console.log(data)
// 프로필 정보 불러오는 함수
//프로필 사진 들어갈 div 지정
const profile_image_frame = document.getElementById("profile-image-frame");
profile_image_frame.setAttribute('class', 'profile-image-frame')
//프로필 사진 불러오기
const profile_image = document.createElement("img")
profile_image.setAttribute('class', 'profile-image')
profile_image.src = "http://127.0.0.1:8000" + data["profile_image"] + '/'
profile_image_frame.appendChild(profile_image)
//프로필 정보 입력할 div 지정
const profile_info = document.getElementById("profile-info");
//username 불러오기
const profile_username = document.createElement("div")
profile_username.setAttribute('class', 'profile-username')
profile_username.innerText = data['username']
profile_info.appendChild(profile_username)
//email 불러오기
const profile_email = document.createElement("div")
profile_email.setAttribute('class', 'profile-email')
profile_email.innerText = data['email']
profile_info.appendChild(profile_email)
// 이미지 카드 생성
const pd_box = document.getElementById("pd-box")
const pd_filter = document.createElement("div")
pd_filter.setAttribute('class', "pd-filter pd-filter-grid pd-row")
pd_filter.setAttribute('id', 'pd-filter')
pd_box.appendChild(pd_filter)
console.log(data)
for (i = 0; i < data['post_user'].length; i++) {
console.log(data)
// 이미지카드 들어갈 위치 div 지정
console.log(data['post_user'])
const pd_list_grid = document.createElement("div")
pd_list_grid.setAttribute('class', 'pd-list-grid pd-col-md-4')
pd_filter.appendChild(pd_list_grid)
const pd_card = document.createElement("div")
pd_card.setAttribute('class', 'pd-card')
pd_list_grid.appendChild(pd_card)
// 아웃풋 이미지 불러오기
const output_image = document.createElement("img")
output_image.setAttribute('class', 'pd-card-img-top')
output_image.src = "http://127.0.0.1:8000" + data["post_user"][i]["post_image"] + '/'
pd_card.appendChild(output_image)
console.log(data)
console.log(data['post_user'])
const pd_card_body = document.createElement("div")
pd_card_body.setAttribute('class', 'pd-card-body')
pd_card.appendChild(pd_card_body)
// 이미지카드 제목 불러오기
const pd_card_title = document.createElement("b")
pd_card_title.setAttribute('class', 'pd-card-title')
pd_card_title.innerText = data["post_user"][i]["title"]
pd_card_body.appendChild(pd_card_title)
// 이미지카드 좋아요 수 불러오기
const pd_card_text = document.createElement("p")
pd_card_text.setAttribute('class', 'pd-card-text')
pd_card_text.innerText = "💗 : " + data["post_user"][i]["likes_count"]
pd_card_body.appendChild(pd_card_text)
}
})
}'스파르타코딩 AI웹개발 3기' 카테고리의 다른 글
| 내일배움캠프_WIL_2022.11.27 (0) | 2022.11.29 |
|---|---|
| 내일배움캠프_TIL_2022.11.28 (0) | 2022.11.29 |
| 내일배움캠프_TIL_2022.11.24 (0) | 2022.11.25 |
| 내일배움캠프_TIL_2022.11.23 (0) | 2022.11.24 |
| 내일배움캠프_TIL_2022.11.22 (0) | 2022.11.23 |