Hello It's good to be back ^_^

[POTG] - 팁/디버깅 본문

Project/[POTG] 오픈SW플랫폼

[POTG] - 팁/디버깅

HongYeon 2024. 12. 3. 15:12

2024-2학기 이화여자대학교 컴퓨터공학과 오픈SW플랫폼을 수강하면서 배운 팁/디버깅 방법에 대해 소개하고자 한다.

 

본격적으로 개발에 들어가 Flask로 백엔드 작업을 하다보면 가장 많이 마주하게 될 화면..

 

바로 이 에러화면이다...

 

참고로 해당 화면은 flask로 run할때 --debug를 붙여주면 에러가 날때 어디서 나는지 알려주므로

꼭 --debug를 붙여서 웹을 실행하자. 많은 도움이 된다.

 

내가 개발을 하면서 만났던 다양한 문제 상황들을 정리해보았다.

 

1.Error: Could not locate a Flask application. Use the 'flask -app' option, 'FLASK_APP' environment variable, or a 'wsgi.py' or 'app.py' file in the current directory.

 

설명을 읽어보며 알겠지만 터미널이 app.py 파일을 찾지 못해서 일어나는 오류이다.

분명 flask를 맞게 설치했는데도 다음과 같은 오류가 뜬다면 app.py가 지금 어디에 위치해있는지 잘 보도록 하자.

 

 

나같은 경우에는 폴더 경로가 조금 헷갈리는 구조였기에 초반에 애를 먹었는데 사진을 보면 알겠지만 app.py의 위치가 POTG/POTG/app.py이다. 그러니까 POTG 폴더 안에 또 POTG 폴더가 있고 그 안에 app.py 파일이 있는 것이다. 다시 터미널에서 입력했던 경로를 보자

 

 

잘 보면 상위 POTG 폴더에서 바로 flask run을 실행하려 한다. 그러니 당연히 app.py를 찾을 수 없다.

 

 

cd 명령어를 이용해 app.py가 존재하는 폴더로 이동했다.

 

 

이후 flaks run 명렁어 실행시에도 잘 작동한다 굳!

 

2. link 경로를 맞게 연결했는데도 연결이 안돼요 / 사진 경로를 맞게 입력했는데도 사진이 안떠요

분명 html 상에서 파일을 열었을 때는 잘 연결되고 사진도 잘 나왔는데 이상하게 flask run해서 서버를 열었을 때는 안된다면 경로를 다음과 같이 작성해보자

 

바로 url_for을 이용해 작성하는 것이다.

일반적으로 "상대경로 / 절대경로" 로 작성해 파일이나 이미지를 불러오지만 이상하게 서버를 열었을 때는 작동을 하지 않을 때가 있다. 안전하게 url_for('해당 파일이 위치하는 폴더명'), filename = '파일명')으로 작성해보자. 단 jinja문법이므로 {{}} 괄호 2개 붙이는 것도 잊지말자

 

이미지도 똑같은 방식으로 작성하면 된다

 

그리고 무엇보다도 경로를 맞게 입력했는지 눈 크게뜨고 잘보자. 대문자라든가, s를 빼먹었든가 정말 사소한 실수때문에 연결이 안되기도 한다.

 

3. KeyError:

 

아마 가장 자주 나는 오류 아닐까 싶다. 하지만 제일 해결하기 쉽다.

다음은 실제로 내가 마주했던 오류 메세지이다.

Traceback (most recent call last): 
File "C:\Users\user\anaconda3\envs\POTG\lib\site-packages\flask\app.py", line 1498, in __call__ return self.wsgi_app(environ, start_response)
File "C:\Users\user\anaconda3\envs\POTG\lib\site-packages\flask\app.py", line 1476, in wsgi_app response = self.handle_exception(e) 
File "C:\Users\user\anaconda3\envs\POTG\lib\site-packages\flask\app.py", line 1473, in wsgi_app response = self.full_dispatch_request() 
File "C:\Users\user\anaconda3\envs\POTG\lib\site-packages\flask\app.py", line 882, in full_dispatch_request rv = self.handle_user_exception(e) 
File "C:\Users\user\anaconda3\envs\POTG\lib\site-packages\flask\app.py", line 880, in full_dispatch_request rv = self.dispatch_request() 
File "C:\Users\user\anaconda3\envs\POTG\lib\site-packages\flask\app.py", line 865, in dispatch_request return self.ensure_sync(self.view_functions[rule.endpoint])(**view_args) # type: ignore[no-any-return] 
File "C:\Users\user\Documents\GitHub\POTG\POTG\app.py", line 89, in reg_item_submit_post print(data['name'], data['seller'], data['address'], data['category'], data['method'], data['status'], data['phone']) 
File "C:\Users\user\anaconda3\envs\POTG\lib\site-packages\werkzeug\datastructures\structures.py", line 196, in __getitem__ raise exceptions.BadRequestKeyError(key) werkzeug.exceptions.
BadRequestKeyError: 400 Bad Request: The browser (or proxy) sent a request that this server could not understand. 
KeyError: 'address'

 

 

파일 경로만 보고 어디서 에러가 났는지 추측하기는 어려워 보인다.

우리가 집중해야하는 부분은 마지막 KeyError부분이다.

KeyError부분 바로 위에서 브러우저가 서버가 이해하지 못하는 요청을 보낸다고 한다.

즉 'address'라는 데이터 요청을 보냈지만 서버는 '그런 단어 없는데요' 라고 대답하고 있는 것이다.

이럴 땐 db를 작성한 파일이나 해당 함수를 호출하는 html 파일의 input 부분을 잘 보자.

높은 확률로 오타나 input 태그의 name 속성을 잘못 작성한 것이다.

 

 

실제 서버로 데이터를 넘겨줄 때, 데이터를 구분하는 기준이 되는 속성은 id가 아니라 name이므로 꼭 헷갈리지 말자. 만약 내가 address라는 값을 사용자에게 입력받아 db에 저장하고 싶다면 input 태그에 name = "address" 인 부분이 있어야 한다.

 

4. jinja2.exceptions.UndefinedError: 'list object' has no attribute 'items'

 

처음에 나온 AttributeError이다. 내가 겪은 문제는 list형을 dictionary형으로 다루어서 발생한 문제였다.

그러나 이상한점은 분명 db에 정보를 등록할 때 dictionary형으로 넣었다는 점이다.

따라서 데이터가 list형으로 리턴되는건 말이 안되는 경우였다. 

 

원인은 db에 삽입된 key값이 0, 1과 같은 정수형이라는 것이었다.

Firebase는 기본적으로 key값이 문자열이면 데이터를 딕셔너리로 반환하고, 키값이 숫자일 경우 데이터를 리스트로 반환한다. 

 

이런 식으로 우리팀은 상품명을 db에 key로 삽입해서 이용했는데, 이렇게 귀찮다고 상품명을 1과 같은 숫자로 입력해서 등록하게 되면 db에 다음과 같이 등록된다.

 

 

그러나 이 db에 등록된 아이템을 가져와 다루는 html 코드 중에 당연히 데이터가 딕셔너리라고 가정하고 작성한 부분이 있었기에 오류가 났다.

 

바로 이 코드의 for문 부분에서 .items() 메소드를 사용한 것이 문제였다. 

Jinja2의 items 메서드는 딕셔너리에서 키-값 쌍을 반복(iterate)할 때 사용하기 때문에 만약 템플릿에 데이터가 리스트형으로 전달된다면 items() 메서드를 사용할 수 없다.

따라서 만약 꼭 데이터를 딕셔너리형으로 써야한다면 리스트를 딕셔너리로 변환하는 코드를 넣어준다.

 

if isinstance(data, list):
            data = {
                str(index): item for index, item in enumerate(data) if item is not None
            }

 

data 부분은 본인이 맞게 수정하면 된다. 

 

 

개발 팁

f12 눌러서 개발자 도구 보는걸 생활화하자. 

 

이런식으로 요소에 마우스를 올릴 때마다 해당 요소가 웹 페이지 상에서 어떻게 구성되어있는지 한눈에 파악할 수 있다.

 

이런식으로 바로 CSS를 변경할 수도 있다. 단 저장은 안되니 결과물 확인용으로 사용하면 좋다.

 

 

이런식으로 요소를 꾸욱 눌러서 드래그 하면 위치도 바꿀 수 있다. 실시간으로 결과물이 보이니 어느 부분을 수정하면 좋을지 바로 확인할 수 있다.

 

 

'Project > [POTG] 오픈SW플랫폼' 카테고리의 다른 글

[POTG] - 해설1  (0) 2024.12.03
[POTG] - 개념 소개  (1) 2024.12.03