Flask 프로젝트의 test 코드에서 다음과 같은 에러가 발생했다.



A conflicting state is already present in the identity map for key


db.session.delete(object) 해당 스크립트 실행에서 발생한 에러인데 각 session 의 경우 다른 thread에서 동작하게 되는데 동시에 해당 객체에 대해서 


접근하려고 해서 발생하는 에러이다.



내 테스트 코드 구조


post 요청 ex) category 생성, subcategory 생성시에 category id가 필요해서 생성.


object


post 요청 ex) subcategory 생성


another object


db.session.delete(object) 



이런 순서로 코드가 구성되어 있었다. 이런 상황에서 두 개의 세션에서 object에 접근하려하다 보니 해당 에러가 발생한다.



- 해결 방법


1) 테스트마다 category 를 생성하는 것이 아니다 setup 쪽에서 생성하는 방법이 있고,


2) db.session.delete(subcategory.category) 이렇게 조인을 통해 삭제하는 방법이 있다. 








Flask 에서 DB Class 코드를 지운 후


migration 후 upgrade 명령어를 수행하는 중에


'Cannot delete or update a parent row: a foreign key constraint fails' 다음과 같은 에러가 발생했다.



foreignkey 관계의 같은 경우


ex ) post - comment 인 경우 post가 삭제 될 때 comment 를 casecade 로 삭제하도록 설정하지 않은 경우


위와 같은 에러가 발생할 수 있다.



위와 같은 경우는 mysql 서버에 접속한 후 


SET Global FOREIGN_KEY_CHECKS=0; 


global 을 붙이지 않으면 shell 에서 python manage.py db upgrade 명령시에는 적용되지 않고,


mysql 서버에서만 해당 테이블을 삭제할 수 있기 때문에 global 을 붙여줘야 한다.


명령어를 입력하면 foreign_key 관게를 확인하지 않고 db table을 삭제해준다.



DB를 삭제한 후에는 다시 SET Global FOREIGN_KEY_CHECKS=1;


다시 원상태로 복구하는 것이 좋다. 



누군가에는 도움이 되길..!






  1. 오호선 2017.11.10 22:24 신고

    큰도움이 될거에요:)







homebrew 를 통해 다른 라이브러리를 설치하다가


jpeg 라이브러리 버전이 변경되어 버린 것 같다...


Library not loaded: /usr/local/opt/jpeg/lib/libjpeg.8.dylib




stackoverflow에서 찾아보니 jpeg 버전을 변경이 필요하다는 것을 확인할 수 있었다.



brew switch jpeg 8d 해당 명령어로 기존의 jpeg 버젼으로 변경해주면 기존 처럼 잘 동작한다.



이 에러는 저를 5시간 동안..... 미치게 만들었습니다... !


구글링을 열심히 했지만, 그 당시는 왜 이렇게 해결이 안 되는 건지 도저히 이해가 가지 않았고,


하루가 지나고 천천히 정리하다보니 조금 씩 정리가 되었습니다.


대부분의 자료들이 영어로 되어 있다보니 이해가 늦어서 제가 보았던 해결책들을 한글로 번역해서 자료를 만들게 됐습니다. 



ImportError: attempted relative import with no known parent package 


어떤 상황에서 발생하는 에러인가 ?



위와 같은 디렉토리 구조를 가진 프로젝트가 있습니다.


mymath.py 에는 다음과 같은 함수가 있고,

def my_add(x,y):
return x+y

mypath.py 에는

from ..mymath import my_add

a = my_add(1,2)

print(a)


다음과 같이 구현이 되어 있습니다.



여기서 mypath.py 를 터미널에서 실행시키기 위해 터미널의 현재위치를 cd package/package 를 통해 이동합니다.


그리고 mypath.py를 실행시키면 위와 같은 에러가 발생합니다.






*원인


-> 이제 언제 이런 에러가 발생하는지 확인을 했으니 에러가 발생한 원인을 찾아보도록 하겠습니다.


원인은 python interpreter는 relative import 의 module 위치를 정할 때 즉, 기준이 되는 모듈의 위치를 정할 때


__name__속성에 의해 결정됩니다. 알고 계신분들도 있고, 잊고 계신 분들도 있겠지만 터미널에서 직접 python 파일을 실행시킬 때


__name__ == '__main__' 이 됩니다. 그러면 당연히 __main__이라는 모듈의 위치를 파이썬 interpreter는 알 수가 없기 때문에 에러가 발생합니다.



- module 과 package 개념이 헷갈리시는 분은


http://myjorney.tistory.com/19 여기서 개념을 확인하시면 됩니다.



* 해결 방안


1. python 의 -m 옵션을 이용한다.



-m mod : run library module as a script (terminates option list)


-m 옵션은 모듈을 스크립트로 수행할 때 쓰는 옵션입니다.(즉, 모듈이야 라고 말해주는 거죠.)


1) 먼저 프로젝트 root directory인 test2 디렉토리로 이동합니다.


2) 그리고 python3 -m package.package.mypath 를 입력하여 실행시키면 해결됩니다.



pakage 구조를 알려줬기 때문에 python은 상대경로를 찾을 수 있습니다.



참조: https://www.napuzba.com/story/import-error-relative-no-parent/




2. python의 절대경로를 이용한다.

if __name__ == '__main__':
if __package__ is None:
import sys
from os import path
print(path.dirname( path.dirname( path.abspath(__file__) ) ))
sys.path.append(path.dirname( path.dirname( path.abspath(__file__) ) ))
from mymath import my_add
else:
from ..mymath import my_add

a = my_add(1,2)
print(a)


__name__ == '__main__' 은 터미널에서 스크립트 형태로 실행시켰을 때는 절대경로를 이용해서 import 해주고


그가 아닌 경우 상대경로를 이용합니다. print() 함수로 디렉토리 위치를 확인하면서 하면 훨씬 좋습니다.




 정리하고 나니 마음이 너무 편하네요 :)


 감사합니다! 도움이 되셨으면 좋겠네요~






  1. 나그네 2017.11.10 16:35 신고

    좋은 내용 감사합니다.

    다른 글과는 다르게 이 글만 스크롤 바가 4개나 생기니까 읽기 쉽지 않아서 고생을 좀 했네요.. -_-;; (1024*768 휴..)

  2. 나그네2 2017.11.16 18:53 신고

    안녕하세요 왕초보입니다.
    root directory인 test2로 들어간다고하셨는데 개인프로젝트파일로 들어간다는건가요?
    답변달아주시면 감사하겠습니다😅

    • jordan_bae jordan17 2017.11.16 22:10 신고

      프로제트 디렉토리가 있다면 프로젝트 디렉토리를 의미합니다. 파이썬 프로젝트에서 가장 상위 단의 위치입니다. 혹시, 설명이 부족하다면 댓글 남겨주세요:)

  3. 생초보 2018.01.25 13:51 신고

    감사합니다! 구글링해도 잘 안 나오던데 공유해주셔서!

  4. Mr.jjong 2018.02.13 17:04 신고

    감사합니다! 덕분에 금방해결되었어요.
    저장용으로 링크를 퍼가도 될까요?

  5. Hojong 2018.05.18 22:45 신고

    덕분에 빠르게 해결하였습니다




TypeError: expected string or bytes-like object



python/django 에서 해당 오류가 어떤 form의 데이터를 모델에 저장하는 경우 발생한다면


model의 field가 not invalid 해서 발생했을 가능성이 있다.



datetimefield를 생성했다가 field 형식을 맞추기 귀찮아서 그냥 default =False 로 설정하였는데 


해당 오류가 발생했다.






'module' object is not callable


다음과 같은 에러는 왜 발생하는걸까요!!




주피터 노트북에서 다음과 같이 발생했습니다!


저는 처음에 왜 내가 만든 함수가 module 이지?! class 도 아니고 callable 객체로 만들어 줄 필요도 없는데! 


먼소리야!!!!!


라고 내면에 외치고 있었는데


생각을 해보니 '내가 import 한 time 이 모듈일 수 있겠구나' 라는 생각이 들었습니다.


먼저 모듈의 정확히 파악하고 넘어가시죠!


모듈이란?


다수의 함수/클래스들을 정의해둔 파이썬 소스코드 파일 


-> 제가 모듈의 의미를 정확하게 알았다면 바로 에러를 잡았겠죠!... 기본의 중요성!






time 은 모듈이기 때문에 불러올 수 없고 time의 함수인 time을 불러오기 위해서는 


time.time() 이라고 해야 불러올 수 있습니다.




저와 같은 실수는 하지 않으시길...!




다음과 같이 해결했습니다!





TypeError: expected string or bytes-like object 오류! 음 문자열이나 바이트 형식의 객체에 예상된다는데...



def fullmatch(pattern, string, flags=0):




이 코드에서 발생했습니다! 음 그대로 옮겨 적은 코드인데 오류가 발생하다니 나는 바보인가?라는 질문의 답을 찾으려고 합니다...!



음 다음과 같은 상황입니다.


입력받은 url 주소의 html코드를 파싱한 후 그 html에서 한글의 글자수를 count하는 함수입니다.


입력받은 인자의 type에서 에러가 나고 있기 때문에 이쪽 부분을 손대야 할 것 같습니다~



문자열이나 바이트 형식의 객체가 핵심인 것 같습니다!


이를 확인하기 위해 pattern 부분을 문자열로 바꿔보겠습니다.



에러가 발생하지 않았습니다!


하지만, 제가 원하는 바가 아닙니다. 저는 여러개의 문자열 리스트에서 원하는 형태의 문자열을 출력하고 싶은 것이기 때문에


여러개의 문자열을 받아야 합니다.


-------------------------------


답이 나왔습니다..... 제가 뻘짓을 했네요!!!!!!ㅎㅎ



 word = soup.text.split() #단어별로 리스트형식으로 변환

    

    

 korean_word =[kword for kword in word if re.match(r'^[ᄀ-힣]+$', kword)]



저희는 릐스트 형식의 문자열을 문자열 하나씩 받아서 체크하기 위해서 for 문으로 하나씩 받아서 체크해어야 했는데


 korean_word =[kword for kword in word if re.match(r'^[ᄀ-힣]+$', word)]


저는 이렇게 코드를 썼었어요...... 역사는 반복되겠지... 그 때 이 포스팅을 볼듯합니다!


그래도 문제해결!







에러가 난 지점

-> CreateView를 이용해서 post_new요청을 만드는 부분입니다. 


post_new = CreateView.as_view(model=Post) 바로 이 코드 부분입니다.

modelform에 fields 쪽에 문제가 있는거 같습니다..

fields 속성이 금지된다는데....


modelform 쪽 코드를 살펴보니

class PostModelForm(forms.ModelForm):
class Meta:
model =Post
fields = ['title', 'content','user_agent']
widgets = {
# JavaScript로 브라우저 UserAgent정보를 담을 것이기에, 구지 UI에 노출할 필요가 없음.
'user_agent': forms.HiddenInput, # user_agent 필드 위젯 변경 }
}

이와 같이 작성되어있습니다..(제가 짠 코드이지만 항상 낯설죠...ㅎㅎ)




django 레퍼런스를 찾아보면


ModelFormMixin

class django.views.generic.edit.ModelFormMixin

A form mixin that works on ModelForms, rather than a standalone form.

Since this is a subclass of SingleObjectMixin, instances of this mixin have access to the model and queryset attributes, describing the type of object that the ModelForm is manipulating.

If you specify both the fields and form_class attributes, an ImproperlyConfigured exception will be raised.



fields

A list of names of fields. This is interpreted the same way as the Meta.fields attribute of ModelForm.

This is a required attribute if you are generating the form class automatically (e.g. using model). Omitting this attribute will result in an ImproperlyConfigured exception.

다음과 같이 나와있습니다.


해석해보면 fields는 list 형식으로 modelform의 meta fields와 같이 해석된다고 합니다.


form class를 자동으로 발생하기 위해서는 이 속성이 필요하다고 하네요... 생략하면 저처럼 에러가 뜬다고...!


post_new = CreateView.as_view(model=Post, fields=['title', 'content','user_agent'])


다음과 같이 코드를 고친 후!!


아 이코드 말고도 다른 방법도 있었습니다.

form_class 옵션 : 미제공시, ModelForm 생성/적용, form_class 옵션을 통해 해결할 수 있네요

post_new = CreateView.as_view(model=Post, form_class=PostModelForm)


이 코드가 더 깔끔하네요!



해결했습니다 !!!!!


행복하네요 ㅎㅎㅎ 역시 reference가..! 좋군요!


https://docs.djangoproject.com/en/1.10/ref/class-based-views/generic-editing/


reference 주소입니다! 더 자세한 것들이 알고싶은분들은 직접보셔도 좋을 것 같아요~


이제부터 개인적으로 오류/예외를 해결한 과정을 포스팅하려고 합니다!


도움이 되셨다면 공감! 부탁드려요~






+ Recent posts