A ship in harbor is safe, but that is not what ships are built for.

개발일지/AI 캠프

내일배움캠프 AI - 60일차 TIL, 2022.11.24

플리피나리 2022. 11. 28. 10:50
반응형

스파르타 코딩클럽 내일배움캠프 AI 웹개발자양성과정 3회차

2022.11.24. 60일차 - TIL

 

 

1. datetime 라이브러리 문자열 변환 에러

사용자가 업로드한 이미지를 유화로 변환해 저장할 때 중복되지 않은 이름으로 생성해야 한다고 생각했고, 이에 현재 시간을 파일 이름으로 저장하도록 코드를 짰다.

# articles앱의 views.py

time = datetime.now().strftime('%Y-%m-%d%H:%M:%s')
cv2.imwrite(f'output/{time}.jpeg', output)
result = f'output/{time}.jpeg'

하지만 media폴더에 해당 결과 이미지 파일이 저장되지 않았고, 때문에 게시글을 가져올 때 media에 해당 이름의 파일이 없다고 뜨는 에러가 발생했다. 우리끼리 이리저리 고민해보다가(문자열 형식이 잘못되었나 아니면 저장경로가 잘못 지정되었나 하는...) 결국 해결하지 못하고 튜터님께 도움을 요청했다. 운좋게 같은 문제로 오류가 발생한 다른 팀이 있었고 해당 팀의 도움을 받아 해결법을 얻을 수 있었다.

오류의 원인은 datetime 라이브러리의 now 함수를 문자열로 변환하는 과정에서 발생하는 오류였다. 기본적으로 우리가 시간을 : 로 표현하지만 애석하게도 이게 파일 이름으로 들어가면 오류를 발생시킨다.

OSError: [WinError 123] 파일 이름, 디렉터리 이름 또는 볼륨 레이블 구문이 잘못되었습니다: 'C:\\Users\\winki\\Desktop\\BlackMarket\\BlackMarket\\media\\output\\2022-11-28_20:11:40.jpeg'

그래서 저 : 가 포함되지 않게 파일 이름을 지정하면 된다. 프로젝트에는 공유받은 방법인 아래로 코드를 작성했다.

from datetime import datetime
import time

ts = time.time()
file_name = datetime.fromtimestamp(ts).strftime('%d-%m-%Y_%H-%M-%S')

지금 다시 보니 아래와 같이 코드를 작성해도 정상 동작하는 것을 확인할 수 있다. 중요한 것은 : 없이 형식에 맞추어 작성하면 된다는 것! 실제로 '%Y-%m-%d_%H-%M-%s' 라고 작성하면 ValueError: Invalid format string 오류가 발생한다.

file_name = datetime.now().strftime('%Y-%m-%d_%H%M%S')

 

 

2. 유저에서 게시글을 가져오기 위한 역참조 에러

강의를 통해 배운 역참조 개념이 낯설어 직접 혼자 이론을 정리하면서 개념을 확실히 익혔다. 그래서 Article의 user필드가 User모델을 참조하기 때문에 반대로 User에서 Article을 역참조할 수 있다고 생각했다.

//profile.js

now_user = await getProfile(user_id);

//프론트엔드에서 태그 id 확인하기
const image = document.getElementById("image");
const author = document.getElementById("nickname");
const content = document.getElementById("introduce");
const gallery_container = document.getElementById("gallery_container");

const profile_img = document.createElement("img");
profile_img.setAttribute("src", `${backend_base_url}${now_user.profile_img}`)
profile_img.setAttribute("style", "width: 100px; height: 100px;")
author.innerText = now_user.nickname
content.innerText = now_user.introduce
    
//게시글을 하나씩 프론트에 붙이기
image.appendChild(profile_img);
for (let i = 0; i < now_user.article_set.length; i++) {
   const myarticle = document.createElement("div");
   myarticle.classList.add("gallery-item");
   myarticle.setAttribute("tabindex", "0");
    
   const imageFrame = document.createElement("img");
   imageFrame.classList.add("gallery-image");
   mageFrame.setAttribute("src", `${backend_base_url}${now_user.article_set[i].image}`)
   imageFrame.setAttribute("id", now_user.article_set[i].pk);
   imageFrame.setAttribute("onclick", "articleDetail(this.id)")
      
   myarticle.appendChild(imageFrame);
   gallery_container.appendChild(myarticle);

하지만 console.log(now_user)을 찍어도 article_set이 찍히지 않는 것을 확인했다. serializer의 fields에 article_set을 포함시켰는데도 오지 않아 한참을 고민했다. 이유는 생각보다 간단했으니... 문제는 바로 기존 User 모델에는 article_set 필드가 없다는 것이다. 그렇다면 어떻게 하면 되는가... article에 관련된 serializer로 article_set을 받으면 된다. 코드는 아래와 같이 수정했다.

class UserProfileSerializer(serializers.ModelSerializer):
    
    class Meta:
        model = User
        fields = ("id", "email", "nickname", "profile_img", "introduce", "password", "article_set",)

##########################Change#########################################################################

class UserProfileSerializer(serializers.ModelSerializer):
    article_set = ArticleListSerializer(many=True)
    
    class Meta:
        model = User
        fields = ("id", "email", "nickname", "profile_img", "introduce", "password", "article_set",)

 

그러면 정상적으로 특정 유저의 article의 여러 필드에 접근 가능할 것을 확인할 수 있다.

반응형