[점프 투 플라스크] sqlite 데이터 불러오고 쓰기 응용 중 에러 발생해요 ㅠ
안녕하세요
덕분에 거의 초보단계임에도 플라스크를 이용한 테스트 서비스를 거의 구현하였는데요,
최종적으로 크롤링으로 얻은 데이터를 sqlite에 있나 확인하고
- 있다면 기존 데이터를 불러오고 없다면 새로 데이터베이스에 저장하는 기능에서 막혔습니다.
sqlite데이터는 잘 생성되었구요..
다음과 같이 작성한 코드에서 어디가 틀렸는지 알려주실 수 있으면 감사하겠습니다.
@bp.route("/search", methods = ["POST", "GET"])
def search():
if request.method == "POST":
keyword = request.form.get("new_keyword")
# print("post", keyword) 잘 작동하고 있어요.
else:
keyword = request.args.get("new_keyword") # ok
# print("get", keyword) 여기도 잘 작동합니다.
name = Restaurants.name
if keyword == None:
return redirect("/")
elif db.session.query(name).filter(name == keyword).first() != None:
results = db.session.query(name).filter(name == keyword).all()
first_address = results[0]['address']
else:
naver = naver_search_restaurant(keyword)
mango = mango_search_restaurant(keyword)
results = naver + mango
first_address = results[0]['address']
# 여기까진 잘 되는 것 콘솔에 출력해서 확인했는데요. 이 아래 데이터 쓰는 곳에서 문제가 생기는 것 같습니다 ㅠ
for result in results:
db.session.add(result)
db.session.commit()
return render_template("search.html", keyword=keyword, results=results, address=first_address)
[콘솔에 출력된 results, first_address 예시]
[{'source': '네이버', 'date': '2023-04-07 18:15:18', 'keyword': '베트남이랑 ', 'name': '베트남이랑', 'type': '베트남음식', 'score': '4.44', 'review': '1578', 'address': '서울 서초구 서초대로77길 15 대경빌딩 지하 1층', 'telephone': '02-1544-3734', 'link': 'https://map.naver.com/v5/entry/place/1890424195?lng=127.0260866&lat=37.49893589999999&placePath=%2Fhome&entry=plt'}, {'source': '망고플레이트', 'date': '2023-04-07 18:15:22', 'keyword': '베트남이랑 ', 'name': '베트남이랑', 'type': '베트남 음식', 'score': '3.9', 'review': '119', 'address': '서울특별시 마포구 월드컵북로2길 97 2F', 'telephone': '02-334-9777', 'link': 'https://www.mangoplate.com/restaurants/aS0tIsyF7jUR'}] 서울 서초구 서초대로77길 15 대경빌딩 지하 1층
[데이터 에러 메세지]
(...생략)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/Library/Frameworks/Python.framework/Versions/3.11/lib/python3.11/site-packages/sqlalchemy/orm/session.py", line 3321, in add
raise exc.UnmappedInstanceError(instance) from err
sqlalchemy.orm.exc.UnmappedInstanceError: Class 'builtins.dict' is not mapped
도와주세요 ㅠ
올리브 님 1116
M 2023년 4월 7일 6:20 오후
3개의 답변이 있습니다. 1 / 1 Page
안녕하세요.
개인적인 생각 몇자 적습니다 :)
우선 대략 3가지 이슈가 있는데요.
첫번째는 db.session.add(result)
입니다.
SQLAlchemy에서는 ORM 객체를 데이터베이스에
저장하는 방법이 많지만 크게 2가지 있습니다.
.add(orm_object)
와 .add_all(list_of_orm_object)
입니다.
현재 결과는 딕셔너리들이 리스트에 들어 있습니다.
즉 2개 이상(복수) 개의 객체를 데이터베이스에 저장하실려고 한다면,
db.session.all(result)
가 아니라 db.sesssion.add_all(result)
를 써야합니다.
두번째는 db.session.all()
, db.session.add_all()
에 들어가는 인자입니다.
.add_all()
을 사용할 경우 ORM 객체가 리스트형태로 담겨져 있어야합니다.
근데 글쓴이님의 result는 ORM 객체가 리스트형태로 담겨진게 아니라
딕셔너리가 리스트형태로 담겨져 있습니다.
그래서 방법은 리스트안에 딕셔너리 하나하나를 Restaurant
의 객체로 만들거나
SQLAlchemy core bulk insert 등의 기능을 사용해야합니다.
전체코드가 없어서 틀릴수도 있지만 가령 이런식으로 해야 합니다.
orm_object_list = []
for shop in result:
orm_object_list.append(Restaurant(**shop))
db.session.add_all(orm_object_list)
세번째는 여담이지만 .filter(name == keyword).all()
이 맞는 문법인지 모르겟습니다.
SQLAlchemy 버전이 몇인지 모르겠으나 제가 알기론 .filter(key=value)
형식으로 ==
이 아닌 =
이 되어야 될거 같은데요...
이상입니다. 다른 고수분들께서 답변 달아주실 겁니다.
결국 핵심은 딕셔너리 리스트로는 ORM을 통해 DB에 삽입이 안됩니다.
딕셔너리 리스트를 ORM 객체가 담긴 리스트로 바꿔서 add_all을 하거나
딕셔너리 리스트를 그대로 사용하면서 session에서 bulk insert로 넣어야 될것 같습니다.
이해가 안되신다면... github repo나 디스코드 등 제가 코드를 직접 manipulate 할수 있는
상황을 제공해주신다면... 더 설명드리겠습니다. (틀린 설명일 수 있습니다. :)
그럼 keep hacking!
로디 님
2023년 4월 11일 10:41 오전
로디님,
덕분에 힌트를 얻어서 sqlite에 검색결과를 저장하는 것은 다음과 같이 해결했어요.
for result in results:
result_db = Restaurants(**result)
db.session.add(result_db)
db.session.commit()
아직 기존 DB에 있으면 해당 내용을 불러오는 기능은 잘 작동을 안 하지만 좀 더 고민해 보면 될 것 같습니다.
너무너무 감사합니다.
올리브 님
M 2023년 4월 12일 2:15 오후
🙏🙏🙏
filter
부분은 제가 완전히 틀렸네요.
filter
와 filter_by
를 헷갈렸습니다. 제가 본문에 말한 부분은 filter_by(key=value)
입니다. :)
로디 님
M 2023년 4월 12일 4:59 오후