본문 바로가기
스파르타코딩 AI웹개발 3기

내일배움캠프_TIL_2022.11.25

by 청귤에이드 2022. 11. 26.

오늘의 코드 [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 commentsSerializerMethodField를 적용하여 불러온(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)

 

            }

 

        })

}