라오스 비엔티엔의 삶

Life|2021. 12. 11. 20:09
반응형

라오스에 없는 것들

라오스 비엔티엔에 온지 3년이 되었다. 처음 비엔티엔에 왔을때가 생각이 난다. 6시 무렵 메콩강 옆 아누봉파크에서 아주머니들이 음악에 맞추어 춤을 줬다.

방콕과 같은 빌딩 숲을 찾아 돌아 다녔지만 라오스의 수도라는 타이틀과 다르게 큰 건물은 찾기 어려웠다. "설마.. 없는건 아니겠지..?" "아니 내가 찾지 못하는걸 거야"

 

3년 전 활기 넘쳤던 공원

 

그런데 정말로 큰 빌딩을 찾을 수 없었다. 라오스의 수도 비엔티엔에서는 우리가 당연히 있을 거라고 생각한 맥도날드, 피자헛, 던킨도넛, KFC를 찾을 수 없다. 그뿐인가? 버스로 시내를 돌아다닐 생각조차 할 수 없다. 언제 버스가 올지 몇시에 끊길지 알 수 없다. 이 나라엔 버스가 없는 것인가 생각이 들 정도로 버스를 찾기 어렵다.  

 

이 나라 라오스에서는 차나 오토바이를 타야하는 것은 필수이다. 오토바이나 차가 없으면 어디 다니는 것을 정말 어렵다. 그나마 요즘은 택시 어플리케이션이 나와서 그나마 조금 나아진 것 같지만 그것도 비엔티엔 시내 아니면 이용하기 어렵다. 

 

조금만 시내의 중심을 빠져나오면 도로의 포장은 엉성하기 그지없다. 심지어 메인로드가 아닌 길목들은 아직도 포장이 되어 있지 않다. 동생에게 동영상을 찍어 보여주니 "형 참 힘들게 산다."라고 말했다. 아버지에게 그걸 보여주니 꼭 60년대 한국 길 같다고 말했다. 2021년 나는 한국의 60년대의 일부를 보고 있는 것일까.

 

음식은 뼁누아라고 불리는 화학조미료 투성이에 라오스 현지인들이 먹는 것을 잘못 먹으면 잘 못 먹으면 배아프기 십상이다. 여기서 배탈이 얼마나 무서운 것인지 확실히 경험했다. 

 

한국에서 온 나는 불만을 가질 수 밖에 없다. 이렇게 느리고 답답한 나라에 나는 왜 온 것인가...

이국적임과 새롭움을 느낄 수 있는 6개월 이후 나는 이 나라에 대해서 불만을 가지고 살아갔다.  

그런데 인간은 적응의 동물이라고 하지 않는가.

 

 

라오스 생활 2년 뒤에야 보이는 장점 

여기에 오기 전에 나는 호주에 있었다. 호주에서 아름다운 자연과 함게 했고 현대적인 고층 건물과 맑은 공기에서 살았다. 라오스에 있으며 호주에 대한 그리움이 때때로 찾아왔다. 하지만 코로나라는 놈 때문에 반 강제적으로 라오스에 산지 2년이 지난 뒤 한국에서의 기억과 호주의 시간이 흐릿해졌다. 라오스는 바다가 없기 때문에 간혹 가다 호주의 넓은 바다의 영상이 머릿속에 떠올를 때가 있지만 예전 같이 미친듯한 갈망은 느낄 수 없다. 

 

라오스의 많은 것들이 적응 되었다. 1년 내내 추위를 느끼기 어려운 이 비엔티엔이라는 도시 (겨울철 새벽은 춥다). 노후에는 최고의 나라 아닌가? 

 

음식

지금은 화학조미료가 들어간 현지인들이 먹는 음식은 자체해서 먹고, 맥도날드 보다 맛있는 수제 햄버거와 피자헛 보다 훨씬 더 맛있는 이탈리아 피자를 먹는다. 이민오는 사람들이 많아서 중국음식점은 중국인이 운영하고 이탈리아레스토랑은 이탈리아사람이 운영하고 한국음식은 물론 한국사람이 운영한다. 그렇기 때문에 정통현지 음식을 한국 보다 저렴한 가격에 먹을 수 있다. 그 뿐만이 아니라 이 나라는 커피의 생산국이다. 중산층은 커피의 맛에 빠져버렸고 3년 사이에 많은 카페들이 생겨 났다. 여기의 신선하고 퀄리티 높은 커피를 즐기다 보면 한국의 커피가 좀 아쉽다 느껴질지도 모른다. 물론 이런 좋은 음식들과 커피는 여러시도와 실패를 통해서 얻어낸 생활의 노하우이다. (나중에 나의 추천 리스트를 추천 리스트를 공유해볼까 한다.) 비엔티엔은 맛집들이 숨겨져있고 흩어져 있어서 처음 오면 아무것도 없다고 느끼기 쉽다.

던킨도넛은 없지만 이젠 새로 생긴 팍슨백화점과 SI HOM(시험)에 미스터도넛도 있고, 미스터 도넛보다 더 맛있는 도넛가게도 있다.

 

특히 비엔티엔에는 거주하고 있는 한국분들이 꽤 많다. (개인적으로 한국 분들이 라오스에 더 들어와 성공적으로 정착했으면 좋겠다.) 이 덕분에 한국 음식점과 한인마트 저렴한 가격에 한국음식 사 먹기도 편하다. 

비어라오 & 피자는 천상 조합이다.

 

 

친절한 라오스 사람들

처음 라오스 사람들이 운전하는 걸 보았을때 너무나도 아찔해 보였다. 앞에 있는 차량을 피하기 위한 역주행 차량들이 왜 이렇게 많은지.... 내가 여기서 운전을 할 수 있을까 생각이 들었다.  그런데 라오스에서 운전을 잘 못해도 상관없다. 앞에서 아주 천천히 운전을 해도 뒤에서 빵빵거리는 사람도 없고 알아서 피해간다. 사고가 나도 서로 화내지 않고 보험 회사가 오기를 기다린다. 아마 앞에서 천천히 운전하고 있는 라오스 운전자를 마주친다면 한국인으로서 짜증나고 화날 수도 있겠지만 그냥 쓱 피해서 가면된다. 

 

"왜 이런나라에 사사요?" 라는 질문에 꽤 많은 사람들이 "사람이 좋아서" 라는 말을 한다. 사업을 하면서 혹은 시장에 가서 혹은 여행을 가서 라오스 사람들을 보면 대부분 사람들 성격이 착하다. 불교의 문화 때문이 아닐까 생각도 든다.

 

한국이라면 좀 못난 동료가 있으면 왕따 시키거나 피하는 것을 볼 수 있는데 여기서는 조금 모자른 동료도 좀 놀리면서 잘 챙겨준다. 음식을 잊어버리고 안가져온 동료가 있으면 자기 음식을 나누어 준다. 정이 있다. 

 

친해지면 자신의 파티에 초대하고 싶어한다. 그리고 맥주와 음악을 틀고 음식을 먹고 노래 부르며 논다. 

집에 여유가 없지만 초대해서 같이 음식을 먹고 싶어한다. 잘산다고 잘 못사는 사람들 대놓고 무시하지 않는다. (물론 예의 없는 사람도 있다.) 많은 사람들이 엄청난 부자가 되는걸 꿈꾸는 것 같지 않다. 물론 더 잘 살길 원한다.

그런데 저 빌딩이 내꺼 였으면, 벤츠사고싶다. 이런생각하는 사람들은 보기 어려웠다. 대부분이 그냥 잘 먹고 안정된 가정을 꾸리고 더 편하게 일 하는걸 추구하는거 같아 보인다. 다른 나라 처럼 외국인이라고 딱히 가격을 바가지 썼다고 느낀적이 없다. 아침에 벤츠 타고 길거리에서 7,000kip짜리 카오삐약을 사서 먹는걸 볼 수 있다.

 

 

자연

비엔티안은 어째튼 도시기 때문에 자연을 기대하기 어렵다. 도시에 메콩강이 흐르긴 하지만 조경이 잘 구성되어 있지 않아서 쾌적하지는 않지만 왓따이 공항에서 30분 정도 거리에 도시를 볼 수 있는 산이 있다. 사실 이 산이 있다는 사실도 정말 늦게 알게 되어서 아쉽다. 비엔티엔을 고속도로를 타고 벗어나면 정말 경이로운 산들이 있는 방비엥으로 갈 수 있다. 대부분의 집은 마당이 있으며 마당에는 망고나무, 바나나나무, 잭푸릇나무 들이 자란다. 한 번은 라오스 동료 집에서 음식을 먹고 마당의자에 앉아있는데 갑자기 하늘에서 무언가가 떨어진다. 아래를 내려다 보니 망고 하나가 떨어져있다. '세상에 먹을게 하늘에서 떨어지다니...' 조금 부러웠다.

 

저녁이 올 무렵

 

 

 

비엔티안 3년간의 큰 변화

- 비엔티안에서 방비엥까지 고속도로를 타고 갈 수 있다. 통행시간이 2시간은 줄은 것 같다. 그전엔 비포장도로 거북이 처럼 지나가도 허리가 부러질 뻔 했다.

 

- 라오스 삶에 영향을 준 큰 변화는 팍슨 백화점이 생긴것 아닐까 싶다. 팍슨 슈퍼마켓에 들어가면 정말 여러가지 다양한 제품들이 보기좋게 정렬되있다. 상품들의 퀄리티도 확실히 좋다.

 

- 카페들이 많이 생겼다. 커피의 퀄리티도 한국 보다 나은 것 같다. (라오스는 커피의 생산지) 지금 스타벅스도 팍슨 백화점에 입점을 준비 중이다.

 

- 중국철도와 태국철도역이 건설되었다. 비싸지 않은 가격에 방비엥, 루앙프라방, 보텐을 여행 할 수 있다.  중국철도와 태국철도가 연결이 될지는 모르겠다만 중국과의 철도 연결이 가장 큰 이슈임에 틀림 없다.

 

- 푸드팬더의 성공. 배달어플 푸드팬더가 성공적으로 라오스에 진출해서 현지 업체를 다 꺽고 1위 배달앱이 되었다. 그 덕에 귀찮게 오토바이타고 멀리 나갈 필요가 없어졌다. 평점을 보면서 주문을 하면 괜찮은 음식들을 먹을 수 있다.

댓글()

라오스와 태국에서 본 사업 문화

비즈니스|2021. 12. 11. 19:15
반응형

태국에 놀러 갔을때 게스트 하우스를 창업한 여사장님을 알게 되었다. 30대의 젊고 아름다운 여자 사장님이였다. 나보다 조금 더 나이가 많긴 했지만 젊은 나이에 게스트하우스를 운영하고 있었고 사업을 실행할 수 있는 용기가 부럽고 대단했다. 현재 나는 라오스에 있는데 여기서도 사업에 관한 비슷한 문화적 패턴이 보이는 것 같아 적어보려 한다.

 

1. 여자들이 비즈니스에 관심이 많고 실행력이 좋다.

태국에는 많은 회사의 높은 관리직 혹은 CEO가 여성인 경우가 많다. 한국인의 입장에서는 이것이 신기하게 느껴졌다. 그래서 태국인 친구한테 '태국에서 여자들이 높은 위치에 있는 이유가 무엇인가'를 물어본 뒤에 망치로 뒷통수를 맞은 느낌이 들정도로 쇼킹했다. 그 친구는 이렇게 말했다. "직장은 여성이 유리하다. 커뮤니케이션 능력이 좋을 뿐더러 보통 남성들보다 섬세하다. 그거에다 남성들 보다 멀티테스킹 능력도 좋다.  남자는 원래 사냥을 해서 운동신경이 좋을 뿐이지 모든 사회활동이 여성한테 유리한 것이 당연한거 아니야?" 이렇게 말했다. 우리나라 사람들이 생각하는 것과 다르게 생각하는 것에 깜짝 놀랐다. 

 

 

2. 투잡 혹은 쓰리잡 

앞에서 적은 게스트하우스를 운영하는 여사장은 밤에는 레스토랑 무대에 올라가 가수를 했고, 시간이 나면 프리랜서 아티스트로 일을 했고 그와 함께 게스트하우스를 관리하는 것을 볼 수 있었다. 현재 한국도 N잡이 유행이라고 하지만 예전 한국을 생각하면 회사 끝난 뒤에 승진을 위한 자기개발이 더 유행이였던 것 같다. 이 여자 사장은 이미 N잡을 일찍이 하고 있었다. 나랑 같이 일했던 태국 동료도 현재 자기사업과 함께 프리랜서 영어강사로 일하고 있으며 내가 현재 살고 있는 라오스의 젊은 여성들은 회사의 월급만으로는 생활이 어려워서 그런지 대부분 N잡을 하고 있다. 그런데 내 주변만 그런지 몰라도 남성들은 여자들 보다 N잡을 하는 경우가 드문것 같았다.  

이전에는 보통 저녁에 복권을 파는일을 많이 했다면 요세는 대부분 온라인으로 물건을 팔면서 추가적으로 소득을 얻는다. 심지어 이렇게 부업하는 것이 직장에서 받는 월급 보다 많은 경우도 많다. 

 

 

3. 파트너쉽

한국에서는 동업하면 안된다는 이야기들이 많아서 동업을 기피하는 경향이 있다. 또한 한국사람들이 동남아 사람들 보다 돈에 대한 욕심이 더 많은 편이라 생각이 된다. 어쩌면 그렇기 때문에 더 빠른 경제 성장을 이룬것이 아닐까 생각도 들지만 라오스는 돈에 대한 욕심이 한국보다 많아 보이지는 않는다. 

3년간 있으면서 생각된 라오스의 문화는 타협의 문화이다. 여기에 살면서 사람들이 싸우는 걸 딱 한번만 봤고 판 물건이 늦어져도 사과하면서 더 기다려줄 수 있냐 하면 그냥 기다리는 고객을 많이 볼 수 있다. 이런 문제가 한국고객에게 발생했을 경우 너무 골치아프다. 하지만 라오스는 차가 도로 한복판에 주차되있어도 빵빵거리는 경우가 거의 없다. 그냥 알아서 그 차를 피해간다. 어떤 운전자가 자기 앞에서 거북이 처럼 스마트폰을 보면서 운전을 해도 그냥 그 차를 피해서 간다. 차 사고가 나서 자기 차가 정비소에 들어가도 서로 다친 곳 없냐고 물어보는 것을 보고 깜짝 놀랐다. 서로간의 갈등을 최대한 피하는 걸로 보인다. 동업도 비슷할 것이라고 생각이 된다. 여기 있으면서 4명의 친구가 함께 식당 하나를 차리는 것을 보았는데 동업에서의 갈등이 한국 보단 적을 것이라고 생각 된다. 

 

 

동남아 사람들이 한국 사람들 보다 대부분  경제적으로 못 사는 경우가 많다. 그것은 우리가 단순히 잘나서 그렇다고 보긴 어려운 것 같다. 어찌보면 단순히 한국이 경제적 기반이 먼저 갖추어졌고 기업이 월급을 많이 주기 때문에 더 잘사는 것이다.  또한 여기서의 비즈니스 성공 방식 또한 한국 사람들도 배울 수 있는 것 같다. 

댓글()

스벨트 파이어베이스 로그인 하기

Computer 관심/Svelte|2021. 11. 11. 16:58
반응형

파이어베이스 로그인 구현이 새롭게 바뀌면서 기존에 있던 튜토리얼과 예제들이 작동되지 않아서 약간 애를 먹었다.

그러므로 파이어베이스 로그인을 구현할때 예전의 예제를 보기보단 파이어베이스 사이트에서 새로운 버전으로 보는것이 좋다.

 

스벨트에서 구현은 다음과 같이 했다. 맞는지 아닌지는 모르겠지만... 물론 추가로 수정해야 할 부분들이 있다.

 

 

 

로그인 하기전

 

로그인 버튼 클릭했을때 팝업

 

 

파이어베이스로 방금 가입된 유저

 

 

로그인 되면 보인는 화면

 

1. 파이어베이스 사이트에 들어간 뒤 새로운 프로젝트를 만든다.

 

2. config 정보를 복사

 

3. __layout.svelte 파일에서 파이어베이스 init를 한다.

import { initializeApp } from 'firebase/app';
import { getAuth, onAuthStateChanged } from "firebase/auth";
import {isLogin} from '../store'


onMount(()=>{
    const firebaseConfig = {
        #config들어갈 정보 복사
        };
        // Initialize Firebase
        initializeApp(firebaseConfig);
        
        
        // 로그인 정보가 체인지가 될때 실행되는 리스너 함수
        const auth = getAuth();
        onAuthStateChanged(auth, (user) => {
        if (user) {
            // User is signed in, see docs for a list of available properties
            // https://firebase.google.com/docs/reference/js/firebase.User
            const uid = user.uid;
            console.log(user)
            $isLogin = true
        } else {
            // User is signed out
            // ...
        }
   });
})

 

4. 스토어에 등록한 isLogin 변수를 사용하여 로그인상태를 변경함

//store.js

import { writable } from 'svelte/store';
export const isLogin = writable(false);

 

5. 로그인로그아웃 필요한 페이지에서 구글로그인 로그아웃 함수 사용

import { getAuth, signInWithPopup, GoogleAuthProvider, signOut } from "firebase/auth";
import {isLogin} from '../store';

  async function loginWithGoogle() {
    const auth = getAuth();
    const provider = new GoogleAuthProvider();
    signInWithPopup(auth, provider)
    .then((result) => {
        // This gives you a Google Access Token. You can use it to access the Google API.
        const credential = GoogleAuthProvider.credentialFromResult(result);
        const token = credential.accessToken;
        // The signed-in user info.
        const user = result.user;
       console.log(user)
    }).catch((error) => {
        // Handle Errors here.
        const errorCode = error.code;
        const errorMessage = error.message;
        // The email of the user's account used.
        const email = error.email;
        // The AuthCredential type that was used.
        const credential = GoogleAuthProvider.credentialFromError(error);
        // ...
    });
  }
  
 async function signOutGoogle(){
    const auth = getAuth();
    console.log(auth)
    signOut(auth).then(() => {
        $isLogin = false
        }).catch((error) => {
        // An error happened.
        });
   }

댓글()

판다스와 플라스크 sqlAlchemy 연결하기

Computer 관심/Pandas|2021. 10. 18. 19:20
반응형

판다스에서 DB로

 

https://stackoverflow.com/questions/43571991/pandas-df-to-database-using-flask-sqlalchemy

 

Pandas df to database using flask-sqlalchemy

I'm trying to insert a pandas dataframe into a mysql database. I am using flask-sqlalchemy. I have created this table: class Client_Details(db.Model): __tablename__ = "client_history"

stackoverflow.com

 

DB에서 판다스로

 

https://stackoverflow.com/questions/29525808/sqlalchemy-orm-conversion-to-pandas-dataframe

 

SQLAlchemy ORM conversion to pandas DataFrame

Is there a solution converting a SQLAlchemy to a pandas DataFrame? Pandas has the capability to use pandas.read_sql but this requires use of raw SQL. I have two reasons for wan...

stackoverflow.com

 

댓글()

sveltekit에서 프린팅 하는 노하우 (scoped css)

Computer 관심/Svelte|2021. 10. 15. 20:41
반응형

웹으로 회사전산 시스템을 만들때 필연적으로 문서를 프린팅을 해야하는 기능이 필요하다.

스벨트킷에서 프린팅 기능을 만들때 필요한 CSS태그를 알아보자

 

내가 원했던 방법은 특정 요소만 프린팅을 하고 싶었다. 

div가 두개가 있는데 하나는 인풋용 하나는 출력용 프리뷰인 셈이다.

또한 출력할 화면에는 내가 원하지 않는 Navigation bar가 들어있었다.

 

 

인터넷을 찾아보니 아래와 같은 방법이 있었다.

function printDiv(divName) {
     var printContents = document.getElementById(divName).innerHTML;
     var originalContents = document.body.innerHTML;

     document.body.innerHTML = printContents;

     window.print();

     document.body.innerHTML = originalContents;
}

즉, 출력할 요소만 html로 만든뒤 출력 후 복사해낸 원래의 화면을 넣어주는 것이다. 프린팅은 되지만 원래 화면을 넣어줬을때 더 이상 스벨트킷이 아니게 된다. 

 

그래서 다른 방법을 적용하기로 하였고 이것은 CSS를 사용하는 방법이다.

프린팅 시 CSS에서 원하는 요소만 visible을 해주고 원하지 않는 요소는 display none을 해주는 방법이다. 여기에도 작은 문제가 있었다. layout에 추가한 navigation 까지 출력이 되는 것이였다. 어떻게 해결해야할지 몰라서 아는 방법으로 임시방편으로 링크를 통해 문서를 출력하는 페이지로 가게 만들고 그 스벨트 폴더에 __layout.reset.svelte를 추가해서 그페이지만 레이아웃 자체를 초기화 시켜버렸다.

  @media print { 
  
      @page {
          size: a4;
      }     
      #main_page{
        display: none;
      }
      #print-area {
        margin: auto;
        width: 220mm;
        min-height: 300mm;
        visibility: visible;
      }
   
     
  }

 

그렇게 쓰고 있다가 문제는 결국 CSS가 적용되는 scope의 문제 였다는게 떠올랐다. (문제가 뭔지 모르면 뭘 구글링 해야할지도 모른다.) 문제를 정확하게 알게 되니 답은 이미 나와있었다.

 

navigation 요소에 id를 만들고 css에 :global(#nav){} 를 추가한다. 여기서 :global()을 사용시 모든 컴포넌트의 # . 요소명이 있으면 CSS에 적용이 된다.

이 방법을 통해 컴포넌트파일 이외의 영역의 스타일을 변경하였다.

이래저래 검색하다가 찾게된 :not(요소명){} 저 요소명 빼고 다 스타일 적용도 유용하게 쓰일거 같다.

 

주의할것은 부모요소를 display: none해버리면 정작 출력하려는 자식요소도 안보여지게 되므로 프린트 하지 않을 형제요소와 다른 특정요소를 display: none하는 방법을 사용한다.  

 

  @media print { 
  
      @page {
          size: a4;
      }
      /* 추가 */
      :global(#nav){
        display: none;
      }
      #main_page{
        display: none;
      }
      #print-area {
        margin: auto;
        width: 220mm;
        min-height: 300mm;
        visibility: visible;
      }
   
     
  }

 

댓글()

pythonanywhere에서 DB 마이그레이션(migration) 하기

Computer 관심/Flask|2021. 10. 9. 23:34
반응형

https://flask-migrate.readthedocs.io/

 

 

로컬 마이그레이션 

set FLASK_APP=main.py

 

1. 마이그레이션 폴더를 추가함

flask db init

2.  마이그레이션 파일 생성

(생성된 파일을 잘 봐야 한다고 함. 왜냐면 테이블 이름이나 칼럼 이름을 바꿀경우 수동으로 수정 필요)

$ flask db migrate -m "Initial migration."

3. 마이그레이션 적용

$ flask db upgrade

 

깃 커밋

1. 깃 커밋 후 푸쉬

 

파이썬 애니웨어에 적용

1. 파이썬 애니웨어에서 git pull (이를통해 적용을 시킬 파일까지 불러 올 수 있다.)

2. 파이선 애니웨어에서도 마이그레이션 적용

$ flask db upgrade

로컬에서 db를 수정한뒤 flask db upgrade명령어를 적어서 pythonanywhere에 적용한 모습

※ 호스팅한 서버의 마이그레이션 파일과 개발서버의 마이그레이션 파일이 같으면 문제가 날 가능성이 적을 겉이다.

 

 

이렇게 마이그레이션이 작동이 안되는 경우 해결법 

해결법 1. 마이그레이션 관련 파일 삭제 후 초기화

 

로컬

1. 다운그레이드로 디비를 되돌림

 

2. migration 폴더를 삭제 +  alembic_version 테이블을 제거

3. 마이그레이션 폴더를 추가함

flask db init

4.  마이그레이션 파일 생성

(생성된 파일을 잘 봐야 한다고 함. 왜냐면 테이블 이름이나 칼럼 이름을 바꿀경우 수동으로 수정 필요)

$ flask db migrate -m "Initial migration."

5. 마이그레이션 적용

$ flask db upgrade

 

6. git push

 

적용서버

1. alembic_version테이블 제거

2. 깃 풀로 새로 만들어진 마이그레이션 파일을 다시 받아옴

3. 마이그레이션 파일 적용

export FLASK_APP=main.py

 

$ flask db upgrade

 

 

 

해결법 2.

서버와 같게 만들어줌 - python anywhere에서 bash가 아닌 mysql을 클릭

 

1. alembic_version을 업그레이드 이전 버전으로 맞춤. 

 

2. 만약 alembic_version테이블 자체가 없으면 sql 쿼리를 통해 테이블 생성을 함

 

 

-- 테이블 만들기

CREATE TABLE alembic_version (
    version_num varchar(32) NOT NULL PRIMARY KEY
);

 

-- 테이블에 데이타 변경하기

UPDATE alembic_version SET version_num = '52220a6a6d76' WHERE version_num = 'c2d3b91fd96e';

 

-- 마이그레이션에 엉뚱한 쿼리가 있으면 변경해 줌

 

$ flask db upgrade

 

 

해결법 3. 마이그레이션을 안쓰는법

sql문을 써서 직접 실제 서버의 테이블을 업데이트를 한뒤 ( ALTER TABLE 아래 링크는 sql로 수정하는 법)

https://stackoverflow.com/questions/92082/add-a-column-with-a-default-value-to-an-existing-table-in-sql-server

※ 유용한 쿼리 show tables;, describe <table name>;

 

그냥 git으로 파일을 push 한뒤 sql로 테이블 구조를 바꾸고 alembic_version 테이블에 값을 로컬에 있는 것과 똑같이 만들어줌

 

 

UPDATE alembic_version SET version_num = '52220a6a6d76' WHERE version_num = 'c2d3b91fd96e';

 

 

 

- nullable= false 인 필드를 추가 시켜야 하는 경우

https://medium.com/the-andela-way/alembic-how-to-add-a-non-nullable-field-to-a-populated-table-998554003134

 

Alembic: How to Add a Non-Nullable Field to a Populated Table

It is quite easy to add a non-nullable field to an empty table. Any migration tool, including Alembic, can automatically generate a…

medium.com

간단하게 말하자면 이건 자동이 아니다. ㅠㅠ 직접 마이그레이션 파일을 수정하는 것이다.

nullable = false로 바로 했을 경우 기존에 있던 row들에 값이 없기 때문에 

먼저 nullable = true로 만들어준 뒤 기존 필드에 값을 넣고 그걸 nullable =false로 바꾸어주는 방법이다.

 

 

-nullable = false면서 unique면...

nullable을 true로 바꾸고 기존에 값에 unique한 값 (row의 index나 uid) 을 넣어준 뒤

nullable을 false로 바꾸면 될 것이다. 

 

 

-메이저 체인지는 인식하는데(삭제, 생성) 값의 크기가 변경됬을때 작동 안하면

 

compare_type = True 추가해줘야함 (어디에 추가하는지 중요) 링크 참조

https://stackoverflow.com/questions/58532518/why-flask-migrations-does-not-detect-a-fields-length-change

 

 

- 만약 개발서버에서는 sqlite를 쓰고 실서버를 mysql을 쓰는 경우 엄청 고생하게 됨.

 

 

 

 

 

댓글()

sqlalchemy 사용시 db object를 jason으로 바꾸는 방법

Computer 관심/Flask|2021. 9. 24. 21:31
반응형

디비에서 얻어온 객체는 딕셔너리 형태로 바꿔줘야 한다. 

여러가지 방법을 시도했는데 가장 쉬운 방법은 아래와 같다.

 

 

플러터에서 객체를 json을 바꾸는 방법과 비슷하다.

디비모델에 as_dict함수를 추가한다.

class User(db.Model):
   def as_dict(self):
       return {c.name: getattr(self, c.name) for c in self.__table__.columns}

그리고 바꾸려는 객체.as_dict()를 하면 response를 할 수 있다.

 

이 방법을 안쓰면 하나하나 {'name':instant.value}와 같은 방식으로 딕셔너리를 만들어서 전달해야한다.

댓글()

2) 플라스크 api pythonanywhere MYSQL DB와 연결하기

Computer 관심/Flask|2021. 9. 23. 15:16
반응형

이전글에서 말했듯 그냥 SQLite 를 디비서버 대신 사용하려 했었다.

sqlite 파일이 파일루트에 생성된 것도 볼 수 있었는데

문제는 쓰기에서 파일의 변형으로 보아서인지 쓰기 동안 읽기도 불가능 한줄알았다.

(알고 보니 그게 문제는 아니였다.)

 

 

MYSQL DB로 옮겨보려고 한다.

 

 

* sqlite에서 mysql로 옮기면서 디비를 만들때 디비설정에서 여러에러 발생한다.

1) sqlite에서 string에 size를 정해줄 필요가 없었는데 mysql에서는 정해 줘야한다.

2) default에 false 대신 0를 넣어줌

3) server_default에서는 스트링만 받는다. 

4) 데이터 입력시 엑셀에 빈칸은 nan으로 되어 pandas

(nan can not be used with MySQL 에러가 발생)

5. foreign key 참조 값은 string인데 그거를 받는 필드값을 int로 설정한경우 (sqlite에서는 됬었다...)

 

등, MySQL을 설치하기 귀찮다고 로컬에서 안깔고 하니 더 고생이다.

 

이렇게 에러가 발생해서 클라이언트와 연결이 안되면 cors 에러를 보내기 때문에 엉뚱한데서 에러를 찾으려다 시간을 보낼 수가 있다.

 

 

 

일단 파이썬애니웨어에서 MySQL 디비를 만든다.

 

비밀번호를 잊어버리지 않으려고 엄청 쉽게 만들었더니 아래와 같이 나온다.

 

 

아래의 화면은 생성된 디비의 정보이다.

start a console on 저 링크를 클릭하면 콘솔로 들어가져서 여러가지 쿼리를 입력 할 수 있다.

 

 

 

SQL디비로 연결하는 기존의 코드는 이와 같다.

app = Flask(__name__)
CORS(app)
app.config["SQLALCHEMY_DATABASE_URI"] = "sqlite:///inventory.db"
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = True

bash 화면에서 pymysql을 설치하고 

pip install pymysql

import를 할 필요는 없다.

 

이러한 형식을 바꾸어줄것이다.

app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql+pymysql://username:password@localhost/db_name'
# flask sqlalchemy를 쓸 경우 추가. https://www.pythonanywhere.com/forums/topic/11116/
# 안쓰니 서버가 멈쳐버림
app.config['SQLALCHEMY_ENGINE_OPTIONS'] = {'pool_recycle' : 280}

 

 

이런식으로 들어가게 될 것이다. 

 

app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql+pymysql://seansoft:bbc123456@seansoft.mysql.pythonanywhere-services.com/seansoft$default'

 

깃이나 파일을 직접 올린뒤 WEB 메뉴에서 리로드를 한다.

 

bash console에 들어가 show tables를 치니 테이블들이 생성됨을 볼 수 있다.

 

row가 잘 생성됬는지 보기 위해선 

select count(*) from 테이블이름

 

 

자료 

플라스크 sqlalchemy 연결

https://stackoverflow.com/questions/27766794/switching-from-sqlite-to-mysql-with-flask-sqlalchemy

 

 

댓글()