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을 쓰는 경우 엄청 고생하게 됨.

 

 

 

 

 

반응형

댓글()

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

 

 

반응형

댓글()

1) 플라스크 api 서버 pythonanywhere에 배포

Computer 관심/Flask|2021. 9. 20. 22:05
반응형

그냥 과정을 나열하면 복잡하다고 느낄 수 있기 때문에

4개의 섹션으로 나누었다. 

1. 파일준비

2. 파이썬애니웨어에 파일설치

3. 파이썬애니웨어에 앱생성

4. 세팅(앱과 파일연결)

 

자신의 컴퓨터에서 해야할 부분

1. 파일준비

1) requirements.txt생성

2) 커밋한뒤 깃허브에 푸쉬하기

 

섹션 1 파일준비 끝

 

파이썬애니웨어에서 해야할 부분

2. 파일설치

1) 콘솔에 들어가 가상환경설치 (가상환경의 이름을 myvenv로 만듬)

mkvirtualenv myvenv --python=/usr/bin/python3.8

 

2) 깃에서 클론하기 

git clone https://github.com/깃이름/프로젝트이름.git

깃허브의 아이디와 비밀번호를 입력하라고 하는데 비밀번호 대신에 엑세스토큰을 붙여 넣는다.

 

3) 가상환경으로 들어가기

workon myvenv

 

파이썬 애니웨어 FILE 메뉴에 가보면 아래처럼 폴더와 파일들이 설치된 걸 볼 수 있다.

 .virtualenvs/

프로젝트명/

 

4) 패키지 설치하기 (프로젝트로 들어가 requirements.txt를 설치)

cd 프로젝트명

pip  install -r requirements.txt

 

섹션 2 파일 설치 끝

 

 

3. 앱 생성하기

이제 이렇게 설치한 파이썬파일과 연결할 앱을 만들어 주어야 한다.

1) 웹앱 만들기

웹앱이 없다고 하는데 하나 만들어줌

2) 프레임워크 선택

프래임워크를 고르라고 하는데 이미 플라스크와 가상환경을 만들었기 때문에 매뉴얼 컨피그레이션을 선택

 

3) 설치한 파이썬 버전을 선택

 

 

이렇게하면 웹앱이 생성완료

 

4. 세팅하기 

파이썬애니웨어에 올린 파이썬 파일과 방금 생성한 앱을 연결 시켜주는 것이다.

 

1) 소스코드를 연결시키기

프로젝트명 폴더명 적어줌

2) WSGI 컨피그레이션 수정

아래 링크를 클릭해서 헬로우월드 색션을 모두 지워줌

여기 부터 

여기까지 다 지워줌 

 

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

여기는 아래처럼 수정을 할 것이다.  (main.py에서 app을 가져옴)

참조 애플리케이션 팩토리 패턴을 사용한다면 

from 디렉토리네임 import app as application

아니면 함수로 실행하는 경우 app = create_app()

(플라스크팩토리팩턴)

 

2-02 플라스크 애플리케이션 팩토리

`[완성 소스]` : [github.com/pahkey/flaskbook/tree/2-02](https://github.com/pahkey/flaskbook/tree/2-0 ...

wikidocs.net

 

https://flask.palletsprojects.com/en/2.0.x/patterns/appfactories/

 

Application Factories — Flask Documentation (2.0.x)

Application Factories If you are already using packages and blueprints for your application (Modular Applications with Blueprints) there are a couple of really nice ways to further improve the experience. A common pattern is creating the application object

flask.palletsprojects.com

https://flask-sqlalchemy.palletsprojects.com/en/2.x/contexts/

 

Introduction into Contexts — Flask-SQLAlchemy Documentation (2.x)

Introduction into Contexts If you are planning on using only one application you can largely skip this chapter. Just pass your application to the SQLAlchemy constructor and you’re usually set. However if you want to use more than one application or creat

flask-sqlalchemy.palletsprojects.com

https://www.py4u.net/discuss/201960

 

How to get Flask-SQLAlchemy to work with the Application Factory Pattern

Answer #1: At the point that code is doing db.create_all(), models haven't been imported. Importing them has the side-effect of populating some data structures that SQLAlchemy uses behind the scenes. If the db.create_all() happens before SQLAlchemy knows a

www.py4u.net

 

 

 

3) 가상환경을 연결시켜주고

 

끝 실행해봄

 

이렇게 나와서 조금 놀랐지만 / 로 향하는 리퀘스트를 만들어 놓지 않아서 그런것 이였다.

작동결과 잘됬다.

 

 

※코드를 바꿔야하는 경우.

넷틀리파이에서는 깃에 푸쉬를 하면 자동으로 바뀐 코드가 적용이 되지만 

파이썬 애니웨어는 그렇지 않다. 그래서 

 

1) 소스 수정시 깃허브에 푸쉬

2) 파이썬 애니웨어에서 git pull를 한뒤 리로드를 하면 됨.

 

 

 

디비는 그냥 sqlite3를 임시로 쓰고 있는데 파이썬애니웨어에서

따로 디비를 생성할 필요가 없었다. 그냥 파일 하나가 아래 처럼 생성이된다. (아래 보이는 inventory.db는 sqlite파일이다.)

 

SQLAlchemy가 아닌를 사용하지 않고 mysql데이터베이스를 연결 하고 싶으면 아래 블로그에 잘 나와있다. 

https://seyeon-hello.tistory.com/2

 

pythonanywhere flask 배포하기

안녕하세요. 오늘은 pythonanywhere를 이용해서 파이썬 flask 웹 프레임워크를 배포하는 과정을 설명해드리겠습니다 ~ 장고는 관련 게시물이 많은데, 플라스크는 찾기 어렵더라구요. 그래서 간단하게

seyeon-hello.tistory.com

 

 

 

다음 글은 SQLAlchemy를 사용하여 my-sql DB를 연결하는 방법에 대해 설명하려고 한다.

 

반응형

댓글()